From 92539cad6895b02b9e309d45962b1e81aa94d650 Mon Sep 17 00:00:00 2001 From: Bellman <54757707+Yeachan-Heo@users.noreply.github.com> Date: Tue, 26 May 2026 06:00:45 +0800 Subject: [PATCH] Prevent pre-push contract drift (#3113) Add a lightweight regression for the documented local pre-push build gate so the skip hatch and lockfile-grade cargo build command stay aligned with operator docs. Constraint: Issue #696 scope is limited to pre-push hook contract drift after ROADMAP #694.\nRejected: Reworking the hook harness or roadmap board | unnecessary for the focused drift guard.\nConfidence: high\nScope-risk: narrow\nDirective: Keep the hook docs, skip hatch, and cargo --locked command in sync when changing local push gates.\nTested: bash -n .github/hooks/pre-push; python3 tests/test_pre_push_hook_contract.py -v; git diff --check\nNot-tested: Full cargo workspace build; Rust code was not touched. --- ...dmap-pinpoints-693-695-verification-map.md | 3 ++ tests/test_pre_push_hook_contract.py | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/test_pre_push_hook_contract.py diff --git a/docs/g013-roadmap-pinpoints-693-695-verification-map.md b/docs/g013-roadmap-pinpoints-693-695-verification-map.md index 0c113e61..2f925e88 100644 --- a/docs/g013-roadmap-pinpoints-693-695-verification-map.md +++ b/docs/g013-roadmap-pinpoints-693-695-verification-map.md @@ -19,6 +19,8 @@ covered by the Claw Code 2.0 board. - Install command: `git config core.hooksPath .github/hooks` - Gate: `cargo build --manifest-path rust/Cargo.toml --workspace --locked` - Escape hatch: `SKIP_CLAW_PRE_PUSH_BUILD=1` prints an explicit skip message. +- Regression test: `tests/test_pre_push_hook_contract.py` locks the skip + hatch and `--locked` build command contract. - Purpose: mirror the CI build job locally so stale field/variant references are caught before push. @@ -41,6 +43,7 @@ python3 scripts/generate_cc2_board.py python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json bash -n .github/hooks/pre-push +python3 tests/test_pre_push_hook_contract.py -v cargo fmt --manifest-path rust/Cargo.toml --all -- --check cargo test --manifest-path rust/Cargo.toml -p claw-analog rag_response_ -- --nocapture cargo test --manifest-path rust/Cargo.toml -p runtime startup_preflight -- --nocapture diff --git a/tests/test_pre_push_hook_contract.py b/tests/test_pre_push_hook_contract.py new file mode 100644 index 00000000..b38a5d45 --- /dev/null +++ b/tests/test_pre_push_hook_contract.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import os +import subprocess +import unittest +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +PRE_PUSH_HOOK = REPO_ROOT / '.github' / 'hooks' / 'pre-push' + + +class PrePushHookContractTests(unittest.TestCase): + def test_skip_escape_hatch_exits_successfully_with_stderr_notice(self) -> None: + env = os.environ.copy() + env['SKIP_CLAW_PRE_PUSH_BUILD'] = '1' + + result = subprocess.run( + ['bash', str(PRE_PUSH_HOOK)], + cwd=REPO_ROOT, + env=env, + check=True, + capture_output=True, + text=True, + ) + + self.assertEqual('', result.stdout) + self.assertIn('SKIP_CLAW_PRE_PUSH_BUILD=1', result.stderr) + self.assertIn('skipping cargo workspace build', result.stderr) + + def test_default_build_gate_uses_workspace_locked_cargo_build(self) -> None: + hook = PRE_PUSH_HOOK.read_text() + + self.assertIn( + 'cargo build --manifest-path rust/Cargo.toml --workspace --locked', + hook, + ) + self.assertIn( + 'build_cmd=(cargo build --manifest-path rust/Cargo.toml --workspace --locked)', + hook, + ) + + +if __name__ == '__main__': + unittest.main()