From b84667a697ab88e7eb09b78ba6b00175729937b2 Mon Sep 17 00:00:00 2001 From: weichen Date: Mon, 5 Oct 2026 13:07:10 +0000 Subject: [PATCH] Close review gaps in cleanup and evidence handling Why: independent review found shared submodule metadata risk, quoted header leakage, stale JSON receipt blindness and missing abandon coverage. Evidence: SELF 92 governance regressions pass; the original review receipt and replay output are recorded in the task card. Impact: preserves external component worktrees, handles both evidence formats and adds targeted failure-path coverage; no product behavior changes. Refs: .task/feature-governance-reliability.md; .task/reviews/governance-reliability.json --- .task/feature-governance-reliability.md | 94 ++++++ .task/reviews/governance-reliability.json | 381 ++++++++++++++++++++++ Makefile | 1 + policy/governance.md | 5 +- scripts/check-evidence.py | 136 ++++++++ scripts/check-worktree.py | 36 +- scripts/evidence.py | 4 +- scripts/hooks/post-merge | 4 +- scripts/task.sh | 14 +- tests/test_evidence.py | 73 +++++ tests/test_task.py | 196 +++++++++++ 11 files changed, 921 insertions(+), 23 deletions(-) create mode 100644 .task/reviews/governance-reliability.json create mode 100644 scripts/check-evidence.py diff --git a/.task/feature-governance-reliability.md b/.task/feature-governance-reliability.md index c3e6d4a2..5ea94363 100644 --- a/.task/feature-governance-reliability.md +++ b/.task/feature-governance-reliability.md @@ -415,3 +415,97 @@ "receipt_sha256": "484f8622fcd212fb6f5abca8f41d7d520437634bad537606bcb9422c73c04d21" } ``` + + +```json +{ + "schema": 1, + "source": "SELF", + "timestamp": "2026-10-05T13:03:42.752472+00:00", + "command": "make test-governance", + "command_sha256": "9776a8dfcfb8f4c95abc94c40cae3a2c0e91e8f4b91fe95d98085c290e929158", + "cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-governance-reliability", + "common_dir": "/home/weichen/projects/Agent-System-Dev/.git", + "before": { + "head": "976d2e84434f6a089cb8ccd1da33e151a6cc375d", + "branch": "feature/governance-reliability", + "target_branch": "main", + "target_head": "fd442d933c051fe538b224e067c214c1976f6dd0", + "status": " M Makefile\n M policy/governance.md\n M scripts/check-worktree.py\n M scripts/evidence.py\n M scripts/hooks/post-merge\n M scripts/task.sh\n M tests/test_evidence.py\n M tests/test_task.py\n?? scripts/check-evidence.py\n", + "tracked_diff_sha256": "13d9131729fa404bf237941d1b2cd8ee9538c66f705036ab3cb2793a217ad893", + "untracked": { + "scripts/check-evidence.py": "69a6c4dac0746401295401afcb6b58af6ed612b9a14caf4bdb2693f5a204ed33" + }, + "submodules": " cc1ad7749816afe129f81bcf0732d0ca7c789d10 deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n af199eeaa23c5b39e08b4649f2513d7572dc5274 deps/development-guidelines (heads/main)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/logging-system/deps/development-guidelines (26b562d)\n cb26e4c9473f75ad015a83e3bba8137a08ff56f9 modules/backend (remotes/origin/feature/ext-1-inproc-handler)\n cc1ad7749816afe129f81bcf0732d0ca7c789d10 modules/backend/deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 modules/backend/deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 modules/backend/deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/backend/deps/agent-system-core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n 19e89ae10bd93306400f13a9a1f449cbc5bfaa42 modules/documents (heads/feature/governance-docs)\n 50c724460159171254242ae48e956a80f4eb9c7e modules/frontend (heads/main)\n 2cb1496320dda6e65501ac94318295f067231dd7 modules/ui (heads/feature/governance-docs)\n" + }, + "after": { + "head": "976d2e84434f6a089cb8ccd1da33e151a6cc375d", + "branch": "feature/governance-reliability", + "target_branch": "main", + "target_head": "fd442d933c051fe538b224e067c214c1976f6dd0", + "status": " M Makefile\n M policy/governance.md\n M scripts/check-worktree.py\n M scripts/evidence.py\n M scripts/hooks/post-merge\n M scripts/task.sh\n M tests/test_evidence.py\n M tests/test_task.py\n?? scripts/check-evidence.py\n", + "tracked_diff_sha256": "13d9131729fa404bf237941d1b2cd8ee9538c66f705036ab3cb2793a217ad893", + "untracked": { + "scripts/check-evidence.py": "69a6c4dac0746401295401afcb6b58af6ed612b9a14caf4bdb2693f5a204ed33" + }, + "submodules": " cc1ad7749816afe129f81bcf0732d0ca7c789d10 deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n af199eeaa23c5b39e08b4649f2513d7572dc5274 deps/development-guidelines (heads/main)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/logging-system/deps/development-guidelines (26b562d)\n cb26e4c9473f75ad015a83e3bba8137a08ff56f9 modules/backend (remotes/origin/feature/ext-1-inproc-handler)\n cc1ad7749816afe129f81bcf0732d0ca7c789d10 modules/backend/deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 modules/backend/deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 modules/backend/deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/backend/deps/agent-system-core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n 19e89ae10bd93306400f13a9a1f449cbc5bfaa42 modules/documents (heads/feature/governance-docs)\n 50c724460159171254242ae48e956a80f4eb9c7e modules/frontend (heads/main)\n 2cb1496320dda6e65501ac94318295f067231dd7 modules/ui (heads/feature/governance-docs)\n" + }, + "after_error": null, + "exit_code": 0, + "output": "make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-governance-reliability'\nPYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p 'test_*.py' -v\ntest_candidate_cannot_read_checkout_credentials (test_ci_credentials.CheckoutTests.test_candidate_cannot_read_checkout_credentials) ... ok\ntest_candidate_submodule_update_commands_are_rejected (test_ci_credentials.CheckoutTests.test_candidate_submodule_update_commands_are_rejected) ... ok\ntest_external_or_unlisted_urls_are_rejected_before_component_fetch (test_ci_credentials.CheckoutTests.test_external_or_unlisted_urls_are_rejected_before_component_fetch) ... ok\ntest_inherited_template_hook_does_not_execute_with_credentials (test_ci_credentials.CheckoutTests.test_inherited_template_hook_does_not_execute_with_credentials) ... ok\ntest_nested_external_url_is_rejected_before_authenticated_fetch (test_ci_credentials.CheckoutTests.test_nested_external_url_is_rejected_before_authenticated_fetch) ... ok\ntest_recursive_gitlinks_materialize_exact_sha_without_persisting_credentials (test_ci_credentials.CheckoutTests.test_recursive_gitlinks_materialize_exact_sha_without_persisting_credentials) ... ok\ntest_redirects_do_not_forward_credential_or_fetch_unlisted_target (test_ci_credentials.CheckoutTests.test_redirects_do_not_forward_credential_or_fetch_unlisted_target) ... ok\ntest_after_snapshot_failure_keeps_command_exit_and_output (test_evidence.EvidenceTests.test_after_snapshot_failure_keeps_command_exit_and_output) ... ok\ntest_all_persisted_and_displayed_text_is_sanitized (test_evidence.EvidenceTests.test_all_persisted_and_displayed_text_is_sanitized) ... ok\ntest_authorization_forms_are_redacted_in_capture_console_and_import (test_evidence.EvidenceTests.test_authorization_forms_are_redacted_in_capture_console_and_import) ... ok\ntest_authorization_forms_are_redacted_on_direct_card_capture (test_evidence.EvidenceTests.test_authorization_forms_are_redacted_on_direct_card_capture) ... ok\ntest_before_after_heads_do_not_relabel_changed_command (test_evidence.EvidenceTests.test_before_after_heads_do_not_relabel_changed_command) ... ok\ntest_capture_does_not_overwrite_an_existing_receipt (test_evidence.EvidenceTests.test_capture_does_not_overwrite_an_existing_receipt) ... ok\ntest_capture_without_card_and_import_without_rerun (test_evidence.EvidenceTests.test_capture_without_card_and_import_without_rerun) ... ok\ntest_child_failure_code_is_preserved (test_evidence.EvidenceTests.test_child_failure_code_is_preserved) ... ok\ntest_command_line_token_arguments_are_redacted (test_evidence.EvidenceTests.test_command_line_token_arguments_are_redacted) ... ok\ntest_dirty_and_untracked_contents_have_object_digests (test_evidence.EvidenceTests.test_dirty_and_untracked_contents_have_object_digests) ... ok\ntest_failed_child_exit_survives_receipt_write_failure (test_evidence.EvidenceTests.test_failed_child_exit_survives_receipt_write_failure) ... ok\ntest_full_output_is_preserved_not_only_tail (test_evidence.EvidenceTests.test_full_output_is_preserved_not_only_tail) ... ok\ntest_import_missing_card_fails_without_losing_receipt (test_evidence.EvidenceTests.test_import_missing_card_fails_without_losing_receipt) ... ok\ntest_import_rejects_unredacted_authorization_with_valid_checksums (test_evidence.EvidenceTests.test_import_rejects_unredacted_authorization_with_valid_checksums) ... ok\ntest_import_retry_is_idempotent (test_evidence.EvidenceTests.test_import_retry_is_idempotent) ... ok\ntest_invalid_field_types_and_forged_source_are_rejected (test_evidence.EvidenceTests.test_invalid_field_types_and_forged_source_are_rejected) ... ok\ntest_known_secret_environment_value_is_redacted_without_label (test_evidence.EvidenceTests.test_known_secret_environment_value_is_redacted_without_label) ... ok\ntest_linked_worktree_import_preserves_source_identity (test_evidence.EvidenceTests.test_linked_worktree_import_preserves_source_identity) ... ok\ntest_missing_card_does_not_execute (test_evidence.EvidenceTests.test_missing_card_does_not_execute) ... ok\ntest_missing_required_snapshot_fields_are_rejected (test_evidence.EvidenceTests.test_missing_required_snapshot_fields_are_rejected) ... ok\ntest_nested_cwd_records_untracked_files_from_repository_root (test_evidence.EvidenceTests.test_nested_cwd_records_untracked_files_from_repository_root) ... ok\ntest_output_digest_checked_even_if_receipt_digest_recomputed (test_evidence.EvidenceTests.test_output_digest_checked_even_if_receipt_digest_recomputed) ... ok\ntest_pipeline_failure_is_recorded_and_returned (test_evidence.EvidenceTests.test_pipeline_failure_is_recorded_and_returned) ... ok\ntest_quoted_credentials_with_spaces_are_fully_redacted (test_evidence.EvidenceTests.test_quoted_credentials_with_spaces_are_fully_redacted) ... ok\ntest_receipt_write_failure_cannot_claim_success (test_evidence.EvidenceTests.test_receipt_write_failure_cannot_claim_success) ... ok\ntest_recorder_environment_does_not_leak_into_nested_commands (test_evidence.EvidenceTests.test_recorder_environment_does_not_leak_into_nested_commands) ... ok\ntest_source_cannot_be_promoted_by_environment (test_evidence.EvidenceTests.test_source_cannot_be_promoted_by_environment) ... ok\ntest_tamper_is_rejected_before_card_append (test_evidence.EvidenceTests.test_tamper_is_rejected_before_card_append) ... ok\ntest_unrelated_repo_cannot_import (test_evidence.EvidenceTests.test_unrelated_repo_cannot_import) ... ok\ntest_validate_precheck_checks_result_and_current_base (test_evidence.EvidenceTests.test_validate_precheck_checks_result_and_current_base) ... ok\ntest_validate_precheck_rejects_successful_arbitrary_command (test_evidence.EvidenceTests.test_validate_precheck_rejects_successful_arbitrary_command) ... ok\ntest_finish_abandon_retains_local_remote_tips_and_reason (test_task.TaskLifecycleTests.test_finish_abandon_retains_local_remote_tips_and_reason) ... ok\ntest_finish_abandon_without_reason_preserves_checkout_and_refs (test_task.TaskLifecycleTests.test_finish_abandon_without_reason_preserves_checkout_and_refs) ... ok\ntest_finish_clean_worktree_has_accurate_remote_result (test_task.TaskLifecycleTests.test_finish_clean_worktree_has_accurate_remote_result) ... ok\ntest_finish_deletes_only_merged_remote_branch (test_task.TaskLifecycleTests.test_finish_deletes_only_merged_remote_branch) ... ok\ntest_finish_preserves_component_commits_off_the_pinned_head (test_task.TaskLifecycleTests.test_finish_preserves_component_commits_off_the_pinned_head) ... ok\ntest_finish_preserves_component_untracked_file (test_task.TaskLifecycleTests.test_finish_preserves_component_untracked_file) ... ok\ntest_finish_preserves_linked_component_worktrees_at_the_pinned_head (test_task.TaskLifecycleTests.test_finish_preserves_linked_component_worktrees_at_the_pinned_head) ... ok\ntest_finish_preserves_linked_nested_component_worktree (test_task.TaskLifecycleTests.test_finish_preserves_linked_nested_component_worktree) ... ok\ntest_finish_preserves_locked_worktree (test_task.TaskLifecycleTests.test_finish_preserves_locked_worktree) ... ok\ntest_finish_preserves_main_and_active_index_lock (test_task.TaskLifecycleTests.test_finish_preserves_main_and_active_index_lock) ... ok\ntest_finish_preserves_modified_untracked_and_ignored_files (test_task.TaskLifecycleTests.test_finish_preserves_modified_untracked_and_ignored_files) ... ok\ntest_finish_preserves_remote_unmerged_tip (test_task.TaskLifecycleTests.test_finish_preserves_remote_unmerged_tip) ... ok\ntest_finish_recycles_clean_submodule_without_shared_config_changes (test_task.TaskLifecycleTests.test_finish_recycles_clean_submodule_without_shared_config_changes) ... ok\ntest_finish_rejects_subdirectory_without_deleting_it (test_task.TaskLifecycleTests.test_finish_rejects_subdirectory_without_deleting_it) ... ok\ntest_finish_remote_deletion_lease_preserves_concurrent_update (test_task.TaskLifecycleTests.test_finish_remote_deletion_lease_preserves_concurrent_update) ... ok\ntest_finish_requires_writer_exit_confirmation (test_task.TaskLifecycleTests.test_finish_requires_writer_exit_confirmation) ... ok\ntest_precheck_feature_behind_requires_sync (test_task.TaskLifecycleTests.test_precheck_feature_behind_requires_sync) ... ok\ntest_precheck_rejects_unreachable_authority (test_task.TaskLifecycleTests.test_precheck_rejects_unreachable_authority) ... ok\ntest_start_imports_precheck_and_creates_four_part_commit (test_task.TaskLifecycleTests.test_start_imports_precheck_and_creates_four_part_commit) ... ok\ntest_start_offline_does_not_create_worktree (test_task.TaskLifecycleTests.test_start_offline_does_not_create_worktree) ... ok\ntest_start_rejects_receipt_when_authoritative_base_changed (test_task.TaskLifecycleTests.test_start_rejects_receipt_when_authoritative_base_changed) ... ok\ntest_start_requires_precheck_receipt_before_creating_worktree (test_task.TaskLifecycleTests.test_start_requires_precheck_receipt_before_creating_worktree) ... ok\ntest_start_stacked_branch_records_parent_and_main_baseline (test_task.TaskLifecycleTests.test_start_stacked_branch_records_parent_and_main_baseline) ... ok\ntest_sync_commit_failure_never_reports_synced (test_task.TaskLifecycleTests.test_sync_commit_failure_never_reports_synced) ... ok\ntest_sync_does_not_execute_json_receipt_command (test_task.TaskLifecycleTests.test_sync_does_not_execute_json_receipt_command) ... ok\ntest_sync_keeps_json_evidence_fresh_after_metadata_only_changes (test_task.TaskLifecycleTests.test_sync_keeps_json_evidence_fresh_after_metadata_only_changes) ... ok\ntest_sync_keeps_unchanged_component_branch (test_task.TaskLifecycleTests.test_sync_keeps_unchanged_component_branch) ... ok\ntest_sync_materializes_nested_detached_components (test_task.TaskLifecycleTests.test_sync_materializes_nested_detached_components) ... ok\ntest_sync_materializes_updated_component (test_task.TaskLifecycleTests.test_sync_materializes_updated_component) ... ok\ntest_sync_preserves_component_feature_branch (test_task.TaskLifecycleTests.test_sync_preserves_component_feature_branch) ... ok\ntest_sync_preserves_dirty_child (test_task.TaskLifecycleTests.test_sync_preserves_dirty_child) ... ok\ntest_sync_preserves_nested_feature_branch_when_parent_pin_changes (test_task.TaskLifecycleTests.test_sync_preserves_nested_feature_branch_when_parent_pin_changes) ... ok\ntest_sync_still_warns_for_stale_legacy_table_evidence (test_task.TaskLifecycleTests.test_sync_still_warns_for_stale_legacy_table_evidence) ... ok\ntest_sync_warns_for_malformed_json_evidence (test_task.TaskLifecycleTests.test_sync_warns_for_malformed_json_evidence) ... ok\ntest_sync_warns_for_unresolved_json_evidence_head (test_task.TaskLifecycleTests.test_sync_warns_for_unresolved_json_evidence_head) ... ok\ntest_sync_warns_for_unresolved_legacy_evidence_head (test_task.TaskLifecycleTests.test_sync_warns_for_unresolved_legacy_evidence_head) ... ok\ntest_sync_warns_when_json_after_state_contains_uncommitted_code (test_task.TaskLifecycleTests.test_sync_warns_when_json_after_state_contains_uncommitted_code) ... ok\ntest_sync_warns_when_json_before_state_contains_uncommitted_code (test_task.TaskLifecycleTests.test_sync_warns_when_json_before_state_contains_uncommitted_code) ... ok\ntest_sync_warns_when_json_evidence_predates_noncard_changes (test_task.TaskLifecycleTests.test_sync_warns_when_json_evidence_predates_noncard_changes) ... ok\ntest_verify_rejects_recursive_drift_even_when_root_has_local_edits (test_task.TaskLifecycleTests.test_verify_rejects_recursive_drift_even_when_root_has_local_edits) ... ok\ntest_verify_rejects_uninitialized_component (test_task.TaskLifecycleTests.test_verify_rejects_uninitialized_component) ... ok\ntest_deleting_main_symlink_to_outside_is_denied (test_write_guard.WriteGuardTests.test_deleting_main_symlink_to_outside_is_denied) ... ok\ntest_detached_and_bad_branches_are_denied (test_write_guard.WriteGuardTests.test_detached_and_bad_branches_are_denied) ... ok\ntest_every_patch_file_and_move_destination_is_checked (test_write_guard.WriteGuardTests.test_every_patch_file_and_move_destination_is_checked) ... ok\ntest_feature_missing_parent_is_allowed (test_write_guard.WriteGuardTests.test_feature_missing_parent_is_allowed) ... ok\ntest_invalid_json_is_denied (test_write_guard.WriteGuardTests.test_invalid_json_is_denied) ... ok\ntest_missing_parent_on_main_is_denied (test_write_guard.WriteGuardTests.test_missing_parent_on_main_is_denied) ... ok\ntest_missing_unknown_and_malformed_write_input_are_denied (test_write_guard.WriteGuardTests.test_missing_unknown_and_malformed_write_input_are_denied) ... ok\ntest_non_git_destination_is_explicitly_outside_scope (test_write_guard.WriteGuardTests.test_non_git_destination_is_explicitly_outside_scope) ... ok\ntest_nonwrite_tools_are_outside_scope (test_write_guard.WriteGuardTests.test_nonwrite_tools_are_outside_scope) ... ok\ntest_relative_path_uses_hook_cwd_not_process_cwd (test_write_guard.WriteGuardTests.test_relative_path_uses_hook_cwd_not_process_cwd) ... ok\ntest_symlink_into_main_with_missing_parents_is_denied (test_write_guard.WriteGuardTests.test_symlink_into_main_with_missing_parents_is_denied) ... ok\ntest_valid_multi_file_patch_on_feature_is_allowed (test_write_guard.WriteGuardTests.test_valid_multi_file_patch_on_feature_is_allowed) ... ok\n\n----------------------------------------------------------------------\nRan 91 tests in 18.874s\n\nOK\nmake[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-governance-reliability'\n", + "output_sha256": "ee08a992b6e9f3a269fd50586b78417a634d85da70c7e196b6d529d9e9815274", + "receipt_sha256": "0db3f3798e81f085fe8488b58ed886fe1a2d92b5d6c3ff931bfb89aa3a2eea4c" +} +``` + +## 独立审查与修复跟踪 + +- ce-code-review 收据:`.task/reviews/governance-reliability.json`,run `20261005-123925-a2fa0a6f`;7 个本地审查方向完成,审查对象 c0abfb0。Claude 补充审查超时,无可用结果,不计独立佐证。 +- 审查 #1:子模块额外 worktree 依赖父任务 Git 管理目录。已补递归注册检查及 clean/staged/uncommitted/nested 回归;旧版本同样存在该问题,仍属本次现场保护整改范围。 +- 审查 #2:旧证据扫描器不认识新 JSON。已补新旧格式、前后对象、校验摘要及无法核验时的提示。 +- 审查 #3:带引号的 Authorization 漏脱敏。已补 JSON/Python 字典及赋值形式,覆盖 30 种虚构凭据变体。 +- 审查 #4:已补 abandon 的本地/远端提交、原因记录保留与缺原因拒绝回归。最终修复复验见后续工具收据,不将旧审查直接当新提交通过。 + + +```json +{ + "schema": 1, + "source": "SELF", + "timestamp": "2026-10-05T13:06:18.273553+00:00", + "command": "make test-governance", + "command_sha256": "9776a8dfcfb8f4c95abc94c40cae3a2c0e91e8f4b91fe95d98085c290e929158", + "cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-governance-reliability", + "common_dir": "/home/weichen/projects/Agent-System-Dev/.git", + "before": { + "head": "976d2e84434f6a089cb8ccd1da33e151a6cc375d", + "branch": "feature/governance-reliability", + "target_branch": "main", + "target_head": "fd442d933c051fe538b224e067c214c1976f6dd0", + "status": " M .task/feature-governance-reliability.md\n M Makefile\n M policy/governance.md\n M scripts/check-worktree.py\n M scripts/evidence.py\n M scripts/hooks/post-merge\n M scripts/task.sh\n M tests/test_evidence.py\n M tests/test_task.py\n?? .task/reviews/governance-reliability.json\n?? scripts/check-evidence.py\n", + "tracked_diff_sha256": "27f3040b85f15fad1e186f18c0b80968292d80c3042f55eca86103ab18379646", + "untracked": { + ".task/reviews/governance-reliability.json": "531de62afd17f86cde582d5903a5bd682f9c2866b8aebace516deb692b4a5b69", + "scripts/check-evidence.py": "3323025f3a04d0798b7c76d6a137ad69b4c0b553b58650ed8edaf6b21525d71f" + }, + "submodules": " cc1ad7749816afe129f81bcf0732d0ca7c789d10 deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n af199eeaa23c5b39e08b4649f2513d7572dc5274 deps/development-guidelines (heads/main)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/logging-system/deps/development-guidelines (26b562d)\n cb26e4c9473f75ad015a83e3bba8137a08ff56f9 modules/backend (remotes/origin/feature/ext-1-inproc-handler)\n cc1ad7749816afe129f81bcf0732d0ca7c789d10 modules/backend/deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 modules/backend/deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 modules/backend/deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/backend/deps/agent-system-core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n 19e89ae10bd93306400f13a9a1f449cbc5bfaa42 modules/documents (heads/feature/governance-docs)\n 50c724460159171254242ae48e956a80f4eb9c7e modules/frontend (heads/main)\n 2cb1496320dda6e65501ac94318295f067231dd7 modules/ui (heads/feature/governance-docs)\n" + }, + "after": { + "head": "976d2e84434f6a089cb8ccd1da33e151a6cc375d", + "branch": "feature/governance-reliability", + "target_branch": "main", + "target_head": "fd442d933c051fe538b224e067c214c1976f6dd0", + "status": " M .task/feature-governance-reliability.md\n M Makefile\n M policy/governance.md\n M scripts/check-worktree.py\n M scripts/evidence.py\n M scripts/hooks/post-merge\n M scripts/task.sh\n M tests/test_evidence.py\n M tests/test_task.py\n?? .task/reviews/governance-reliability.json\n?? scripts/check-evidence.py\n", + "tracked_diff_sha256": "27f3040b85f15fad1e186f18c0b80968292d80c3042f55eca86103ab18379646", + "untracked": { + ".task/reviews/governance-reliability.json": "531de62afd17f86cde582d5903a5bd682f9c2866b8aebace516deb692b4a5b69", + "scripts/check-evidence.py": "3323025f3a04d0798b7c76d6a137ad69b4c0b553b58650ed8edaf6b21525d71f" + }, + "submodules": " cc1ad7749816afe129f81bcf0732d0ca7c789d10 deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n af199eeaa23c5b39e08b4649f2513d7572dc5274 deps/development-guidelines (heads/main)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 deps/logging-system/deps/development-guidelines (26b562d)\n cb26e4c9473f75ad015a83e3bba8137a08ff56f9 modules/backend (remotes/origin/feature/ext-1-inproc-handler)\n cc1ad7749816afe129f81bcf0732d0ca7c789d10 modules/backend/deps/agent-command (remotes/origin/feature/core-v0-1-gcc1ad77)\n ed2af3e6048928b1fd0ba6da1f9d0c1bafec82d4 modules/backend/deps/agent-command/deps/development-guidelines (remotes/origin/feature/delivery-mechanism-5-ged2af3e)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 5a57636cc0b8426a86a72bbbdd5b7f30e4fcac88 modules/backend/deps/agent-squad (remotes/origin/feature/agent-harness-p1-27-g5a57636)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 3a110a728cf520cfbbbafc0c4c75f14bf78bec3f modules/backend/deps/agent-squad/deps/agent-native (remotes/origin/feature/agent-harness-p1-27-g3a110a7)\n 65aaebca1ea69ab7d48eda51d33ef1d4eea5a0bf modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent (65aaebc)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/agent-intent/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/agent-native/deps/logging-system/deps/development-guidelines (26b562d)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/development-guidelines (26b562d)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/agent-squad/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/agent-squad/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/agent-squad/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/backend/deps/agent-system-core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n a3ee67bba269e1276c14e22c026171ecf2cf6190 modules/backend/deps/error-code-system (a3ee67b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/error-code-system/deps/development-guidelines (26b562d)\n 49b5d8be604d05e4246dffa0d10fa1c2b7ad45d7 modules/backend/deps/logging-system (49b5d8b)\n 26b562d2e34fbc560711296a309c91c74ffc55b1 modules/backend/deps/logging-system/deps/development-guidelines (26b562d)\n 0b5c7747a3165bf0d0f2219204b7b70ec3ed7645 modules/core (remotes/origin/feature/agent-harness-p3b-12-g0b5c774)\n 19e89ae10bd93306400f13a9a1f449cbc5bfaa42 modules/documents (heads/feature/governance-docs)\n 50c724460159171254242ae48e956a80f4eb9c7e modules/frontend (heads/main)\n 2cb1496320dda6e65501ac94318295f067231dd7 modules/ui (heads/feature/governance-docs)\n" + }, + "after_error": null, + "exit_code": 0, + "output": "make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-governance-reliability'\nPYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p 'test_*.py' -v\ntest_candidate_cannot_read_checkout_credentials (test_ci_credentials.CheckoutTests.test_candidate_cannot_read_checkout_credentials) ... ok\ntest_candidate_submodule_update_commands_are_rejected (test_ci_credentials.CheckoutTests.test_candidate_submodule_update_commands_are_rejected) ... ok\ntest_external_or_unlisted_urls_are_rejected_before_component_fetch (test_ci_credentials.CheckoutTests.test_external_or_unlisted_urls_are_rejected_before_component_fetch) ... ok\ntest_inherited_template_hook_does_not_execute_with_credentials (test_ci_credentials.CheckoutTests.test_inherited_template_hook_does_not_execute_with_credentials) ... ok\ntest_nested_external_url_is_rejected_before_authenticated_fetch (test_ci_credentials.CheckoutTests.test_nested_external_url_is_rejected_before_authenticated_fetch) ... ok\ntest_recursive_gitlinks_materialize_exact_sha_without_persisting_credentials (test_ci_credentials.CheckoutTests.test_recursive_gitlinks_materialize_exact_sha_without_persisting_credentials) ... ok\ntest_redirects_do_not_forward_credential_or_fetch_unlisted_target (test_ci_credentials.CheckoutTests.test_redirects_do_not_forward_credential_or_fetch_unlisted_target) ... ok\ntest_after_snapshot_failure_keeps_command_exit_and_output (test_evidence.EvidenceTests.test_after_snapshot_failure_keeps_command_exit_and_output) ... ok\ntest_all_persisted_and_displayed_text_is_sanitized (test_evidence.EvidenceTests.test_all_persisted_and_displayed_text_is_sanitized) ... ok\ntest_authorization_forms_are_redacted_in_capture_console_and_import (test_evidence.EvidenceTests.test_authorization_forms_are_redacted_in_capture_console_and_import) ... ok\ntest_authorization_forms_are_redacted_on_direct_card_capture (test_evidence.EvidenceTests.test_authorization_forms_are_redacted_on_direct_card_capture) ... ok\ntest_before_after_heads_do_not_relabel_changed_command (test_evidence.EvidenceTests.test_before_after_heads_do_not_relabel_changed_command) ... ok\ntest_capture_does_not_overwrite_an_existing_receipt (test_evidence.EvidenceTests.test_capture_does_not_overwrite_an_existing_receipt) ... ok\ntest_capture_without_card_and_import_without_rerun (test_evidence.EvidenceTests.test_capture_without_card_and_import_without_rerun) ... ok\ntest_child_failure_code_is_preserved (test_evidence.EvidenceTests.test_child_failure_code_is_preserved) ... ok\ntest_command_line_token_arguments_are_redacted (test_evidence.EvidenceTests.test_command_line_token_arguments_are_redacted) ... ok\ntest_dirty_and_untracked_contents_have_object_digests (test_evidence.EvidenceTests.test_dirty_and_untracked_contents_have_object_digests) ... ok\ntest_failed_child_exit_survives_receipt_write_failure (test_evidence.EvidenceTests.test_failed_child_exit_survives_receipt_write_failure) ... ok\ntest_full_output_is_preserved_not_only_tail (test_evidence.EvidenceTests.test_full_output_is_preserved_not_only_tail) ... ok\ntest_import_missing_card_fails_without_losing_receipt (test_evidence.EvidenceTests.test_import_missing_card_fails_without_losing_receipt) ... ok\ntest_import_rejects_unredacted_authorization_with_valid_checksums (test_evidence.EvidenceTests.test_import_rejects_unredacted_authorization_with_valid_checksums) ... ok\ntest_import_retry_is_idempotent (test_evidence.EvidenceTests.test_import_retry_is_idempotent) ... ok\ntest_invalid_field_types_and_forged_source_are_rejected (test_evidence.EvidenceTests.test_invalid_field_types_and_forged_source_are_rejected) ... ok\ntest_known_secret_environment_value_is_redacted_without_label (test_evidence.EvidenceTests.test_known_secret_environment_value_is_redacted_without_label) ... ok\ntest_linked_worktree_import_preserves_source_identity (test_evidence.EvidenceTests.test_linked_worktree_import_preserves_source_identity) ... ok\ntest_missing_card_does_not_execute (test_evidence.EvidenceTests.test_missing_card_does_not_execute) ... ok\ntest_missing_required_snapshot_fields_are_rejected (test_evidence.EvidenceTests.test_missing_required_snapshot_fields_are_rejected) ... ok\ntest_nested_cwd_records_untracked_files_from_repository_root (test_evidence.EvidenceTests.test_nested_cwd_records_untracked_files_from_repository_root) ... ok\ntest_output_digest_checked_even_if_receipt_digest_recomputed (test_evidence.EvidenceTests.test_output_digest_checked_even_if_receipt_digest_recomputed) ... ok\ntest_pipeline_failure_is_recorded_and_returned (test_evidence.EvidenceTests.test_pipeline_failure_is_recorded_and_returned) ... ok\ntest_quoted_credentials_with_spaces_are_fully_redacted (test_evidence.EvidenceTests.test_quoted_credentials_with_spaces_are_fully_redacted) ... ok\ntest_receipt_write_failure_cannot_claim_success (test_evidence.EvidenceTests.test_receipt_write_failure_cannot_claim_success) ... ok\ntest_recorder_environment_does_not_leak_into_nested_commands (test_evidence.EvidenceTests.test_recorder_environment_does_not_leak_into_nested_commands) ... ok\ntest_source_cannot_be_promoted_by_environment (test_evidence.EvidenceTests.test_source_cannot_be_promoted_by_environment) ... ok\ntest_tamper_is_rejected_before_card_append (test_evidence.EvidenceTests.test_tamper_is_rejected_before_card_append) ... ok\ntest_unrelated_repo_cannot_import (test_evidence.EvidenceTests.test_unrelated_repo_cannot_import) ... ok\ntest_validate_precheck_checks_result_and_current_base (test_evidence.EvidenceTests.test_validate_precheck_checks_result_and_current_base) ... ok\ntest_validate_precheck_rejects_successful_arbitrary_command (test_evidence.EvidenceTests.test_validate_precheck_rejects_successful_arbitrary_command) ... ok\ntest_finish_abandon_retains_local_remote_tips_and_reason (test_task.TaskLifecycleTests.test_finish_abandon_retains_local_remote_tips_and_reason) ... ok\ntest_finish_abandon_without_reason_preserves_checkout_and_refs (test_task.TaskLifecycleTests.test_finish_abandon_without_reason_preserves_checkout_and_refs) ... ok\ntest_finish_clean_worktree_has_accurate_remote_result (test_task.TaskLifecycleTests.test_finish_clean_worktree_has_accurate_remote_result) ... ok\ntest_finish_deletes_only_merged_remote_branch (test_task.TaskLifecycleTests.test_finish_deletes_only_merged_remote_branch) ... ok\ntest_finish_preserves_component_commits_off_the_pinned_head (test_task.TaskLifecycleTests.test_finish_preserves_component_commits_off_the_pinned_head) ... ok\ntest_finish_preserves_component_untracked_file (test_task.TaskLifecycleTests.test_finish_preserves_component_untracked_file) ... ok\ntest_finish_preserves_linked_component_worktrees_at_the_pinned_head (test_task.TaskLifecycleTests.test_finish_preserves_linked_component_worktrees_at_the_pinned_head) ... ok\ntest_finish_preserves_linked_nested_component_worktree (test_task.TaskLifecycleTests.test_finish_preserves_linked_nested_component_worktree) ... ok\ntest_finish_preserves_locked_worktree (test_task.TaskLifecycleTests.test_finish_preserves_locked_worktree) ... ok\ntest_finish_preserves_main_and_active_index_lock (test_task.TaskLifecycleTests.test_finish_preserves_main_and_active_index_lock) ... ok\ntest_finish_preserves_modified_untracked_and_ignored_files (test_task.TaskLifecycleTests.test_finish_preserves_modified_untracked_and_ignored_files) ... ok\ntest_finish_preserves_remote_unmerged_tip (test_task.TaskLifecycleTests.test_finish_preserves_remote_unmerged_tip) ... ok\ntest_finish_recycles_clean_submodule_without_shared_config_changes (test_task.TaskLifecycleTests.test_finish_recycles_clean_submodule_without_shared_config_changes) ... ok\ntest_finish_rejects_subdirectory_without_deleting_it (test_task.TaskLifecycleTests.test_finish_rejects_subdirectory_without_deleting_it) ... ok\ntest_finish_remote_deletion_lease_preserves_concurrent_update (test_task.TaskLifecycleTests.test_finish_remote_deletion_lease_preserves_concurrent_update) ... ok\ntest_finish_requires_writer_exit_confirmation (test_task.TaskLifecycleTests.test_finish_requires_writer_exit_confirmation) ... ok\ntest_precheck_feature_behind_requires_sync (test_task.TaskLifecycleTests.test_precheck_feature_behind_requires_sync) ... ok\ntest_precheck_rejects_unreachable_authority (test_task.TaskLifecycleTests.test_precheck_rejects_unreachable_authority) ... ok\ntest_start_imports_precheck_and_creates_four_part_commit (test_task.TaskLifecycleTests.test_start_imports_precheck_and_creates_four_part_commit) ... ok\ntest_start_offline_does_not_create_worktree (test_task.TaskLifecycleTests.test_start_offline_does_not_create_worktree) ... ok\ntest_start_rejects_receipt_when_authoritative_base_changed (test_task.TaskLifecycleTests.test_start_rejects_receipt_when_authoritative_base_changed) ... ok\ntest_start_requires_precheck_receipt_before_creating_worktree (test_task.TaskLifecycleTests.test_start_requires_precheck_receipt_before_creating_worktree) ... ok\ntest_start_stacked_branch_records_parent_and_main_baseline (test_task.TaskLifecycleTests.test_start_stacked_branch_records_parent_and_main_baseline) ... ok\ntest_sync_commit_failure_never_reports_synced (test_task.TaskLifecycleTests.test_sync_commit_failure_never_reports_synced) ... ok\ntest_sync_does_not_execute_json_receipt_command (test_task.TaskLifecycleTests.test_sync_does_not_execute_json_receipt_command) ... ok\ntest_sync_keeps_json_evidence_fresh_after_metadata_only_changes (test_task.TaskLifecycleTests.test_sync_keeps_json_evidence_fresh_after_metadata_only_changes) ... ok\ntest_sync_keeps_unchanged_component_branch (test_task.TaskLifecycleTests.test_sync_keeps_unchanged_component_branch) ... ok\ntest_sync_materializes_nested_detached_components (test_task.TaskLifecycleTests.test_sync_materializes_nested_detached_components) ... ok\ntest_sync_materializes_updated_component (test_task.TaskLifecycleTests.test_sync_materializes_updated_component) ... ok\ntest_sync_preserves_component_feature_branch (test_task.TaskLifecycleTests.test_sync_preserves_component_feature_branch) ... ok\ntest_sync_preserves_dirty_child (test_task.TaskLifecycleTests.test_sync_preserves_dirty_child) ... ok\ntest_sync_preserves_nested_feature_branch_when_parent_pin_changes (test_task.TaskLifecycleTests.test_sync_preserves_nested_feature_branch_when_parent_pin_changes) ... ok\ntest_sync_still_warns_for_stale_legacy_table_evidence (test_task.TaskLifecycleTests.test_sync_still_warns_for_stale_legacy_table_evidence) ... ok\ntest_sync_warns_for_malformed_json_evidence (test_task.TaskLifecycleTests.test_sync_warns_for_malformed_json_evidence) ... ok\ntest_sync_warns_for_missing_json_receipt_fields_even_with_valid_checksum (test_task.TaskLifecycleTests.test_sync_warns_for_missing_json_receipt_fields_even_with_valid_checksum) ... ok\ntest_sync_warns_for_unresolved_json_evidence_head (test_task.TaskLifecycleTests.test_sync_warns_for_unresolved_json_evidence_head) ... ok\ntest_sync_warns_for_unresolved_legacy_evidence_head (test_task.TaskLifecycleTests.test_sync_warns_for_unresolved_legacy_evidence_head) ... ok\ntest_sync_warns_when_json_after_state_contains_uncommitted_code (test_task.TaskLifecycleTests.test_sync_warns_when_json_after_state_contains_uncommitted_code) ... ok\ntest_sync_warns_when_json_before_state_contains_uncommitted_code (test_task.TaskLifecycleTests.test_sync_warns_when_json_before_state_contains_uncommitted_code) ... ok\ntest_sync_warns_when_json_evidence_predates_noncard_changes (test_task.TaskLifecycleTests.test_sync_warns_when_json_evidence_predates_noncard_changes) ... ok\ntest_verify_rejects_recursive_drift_even_when_root_has_local_edits (test_task.TaskLifecycleTests.test_verify_rejects_recursive_drift_even_when_root_has_local_edits) ... ok\ntest_verify_rejects_uninitialized_component (test_task.TaskLifecycleTests.test_verify_rejects_uninitialized_component) ... ok\ntest_deleting_main_symlink_to_outside_is_denied (test_write_guard.WriteGuardTests.test_deleting_main_symlink_to_outside_is_denied) ... ok\ntest_detached_and_bad_branches_are_denied (test_write_guard.WriteGuardTests.test_detached_and_bad_branches_are_denied) ... ok\ntest_every_patch_file_and_move_destination_is_checked (test_write_guard.WriteGuardTests.test_every_patch_file_and_move_destination_is_checked) ... ok\ntest_feature_missing_parent_is_allowed (test_write_guard.WriteGuardTests.test_feature_missing_parent_is_allowed) ... ok\ntest_invalid_json_is_denied (test_write_guard.WriteGuardTests.test_invalid_json_is_denied) ... ok\ntest_missing_parent_on_main_is_denied (test_write_guard.WriteGuardTests.test_missing_parent_on_main_is_denied) ... ok\ntest_missing_unknown_and_malformed_write_input_are_denied (test_write_guard.WriteGuardTests.test_missing_unknown_and_malformed_write_input_are_denied) ... ok\ntest_non_git_destination_is_explicitly_outside_scope (test_write_guard.WriteGuardTests.test_non_git_destination_is_explicitly_outside_scope) ... ok\ntest_nonwrite_tools_are_outside_scope (test_write_guard.WriteGuardTests.test_nonwrite_tools_are_outside_scope) ... ok\ntest_relative_path_uses_hook_cwd_not_process_cwd (test_write_guard.WriteGuardTests.test_relative_path_uses_hook_cwd_not_process_cwd) ... ok\ntest_symlink_into_main_with_missing_parents_is_denied (test_write_guard.WriteGuardTests.test_symlink_into_main_with_missing_parents_is_denied) ... ok\ntest_valid_multi_file_patch_on_feature_is_allowed (test_write_guard.WriteGuardTests.test_valid_multi_file_patch_on_feature_is_allowed) ... ok\n\n----------------------------------------------------------------------\nRan 92 tests in 18.961s\n\nOK\nmake[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-governance-reliability'\n", + "output_sha256": "de8c281371e86f171766ed6ddd635b3fe754cc7d2d736f7e58771822113fea2e", + "receipt_sha256": "1f246ea763bbe40556514f0c0bb62552cd4fcc077c5b0fe12b41bc1e9ca9f67b" +} +``` diff --git a/.task/reviews/governance-reliability.json b/.task/reviews/governance-reliability.json new file mode 100644 index 00000000..8ceee21e --- /dev/null +++ b/.task/reviews/governance-reliability.json @@ -0,0 +1,381 @@ +{ + "status": "complete", + "verdict": "Ready with fixes", + "verdict_reason": "Resolve the P1 cleanup-preservation verification gate (#1), then validate the quoted-credential redaction fix (#3), stale-receipt detection (#2), and abandon lifecycle coverage (#4). Finding #1 remains a blocker despite being excluded from the actionable queue. This verdict covers only c0abfb0, not the root's subsequent repairs.", + "scope": { + "base": "43d33aa4921078bc202393b99cba017d7f731b98", + "branch": "feature/governance-reliability", + "head_sha": "c0abfb0250980af7f1b18c785eb4b55240a8d855", + "pr_url": null, + "files_changed": 24 + }, + "intent": "Implement approved development-governance audit repairs: safe task cleanup and recursive pinned component validation; trustworthy SELF evidence and startup receipt flow; path-specific write guards and bounded CI checkout credentials. Preserve dirty/ignored/unique child history and fail closed without claiming live platform controls.", + "intent_confidence": "explicit", + "reviewers": [ + "correctness", + "project-standards", + "testing", + "maintainability", + "agent-native", + "security", + "reliability" + ], + "findings": [ + { + "#": 1, + "autofix_class": "advisory", + "confidence": 100, + "evidence": [ + "c0abfb0 scripts/task.sh:438-445 rechecks finish safety, adds --force for gitlinks, and removes the parent worktree; scripts/check-worktree.py:51-69 checks the current child checkout and reachable commits but not its additional linked worktrees.", + "SELF scratch reproduction: initialize the pinned component; add an external linked component worktree at HEAD; modify its content; finish returns 0; git status in the external worktree then exits 128 because its common metadata under the removed parent registration is gone.", + "Verified provenance: 43d33aa scripts/task.sh:381-386 already used remove || rm -rf plus prune; source artifact also records originating fdf63e3 and a failing BASE reproduction. The reviewed diff rewrites that removal around new preservation checks." + ], + "file": "scripts/task.sh", + "first_evidence": "scripts/task.sh:443: removal+=(--force)", + "independent_reviewers": [ + "correctness" + ], + "line": 443, + "owner": "human", + "pre_existing": false, + "requires_verification": true, + "reviewers": [ + "correctness" + ], + "severity": "P1", + "suggested_fix": "Before allowing parent removal, recursively inspect each component's worktree registrations/common Git directory. Refuse cleanup when a component owns any additional registered linked worktree whose metadata would be removed, and require the owner to preserve or relocate it explicitly. Add a regression with an external linked component worktree at the same pinned SHA, including staged or uncommitted content, and assert cleanup refuses and the external worktree remains usable.", + "title": "Preserve submodule metadata used by other registered worktrees", + "why_it_matters": "The rewritten forced-removal path trusts finish checks that inspect only each component's current checkout and reachable commits. An initialized submodule can own another linked worktree at the same pinned commit, so all checks pass even when that separate worktree contains staged or uncommitted work. Removing the parent task deletes its embedded submodule common directory and the other worktree's Git index/config/object database. Reproduced: task finish returned 0, while git status in the surviving external component worktree then failed with exit 128. This is secondary to the new guard-dependent deletion path; the older removal implementation also exhibited the defect.", + "protected_subject": "data-loss", + "validation_status": "unresolved", + "validation_reason": "Protected-subject rejection reclassified as unresolved. Base 43d33aa scripts/task.sh:381-386 confirms older destructive behavior, but does not establish unrelatedness or refute the failure at reviewed c0abfb0: task.sh:438-445 expressly makes the new preservation checks the basis for forced removal, while check-worktree.py:51-69 omits linked component worktree ownership. Resolve this gate with a discriminating cleanup regression that preserves an external component worktree and its staged/uncommitted content, or inspected evidence disproving this interaction. Root accepts the remediation scope and reports repairs in progress; those repairs are outside this reviewed commit." + }, + { + "#": 2, + "autofix_class": "gated_auto", + "confidence": 100, + "evidence": [ + "c0abfb0 scripts/evidence.py:227-239 appends fenced JSON receipts; scripts/task.sh:242-251 only scans timestamp-leading Markdown table rows for stale tested HEADs.", + "SELF scratch reproduction: capture a receipt, commit it, advance origin/main with a non-card change, and sync. The recorded before HEAD differs in implementation content, but output contains no [evidence] WARN." + ], + "file": "scripts/evidence.py", + "first_evidence": "scripts/evidence.py:231: + \"```json\\n\" + encoded + \"\\n```\\n\")", + "independent_reviewers": [ + "correctness" + ], + "line": 231, + "owner": "downstream-resolver", + "pre_existing": false, + "requires_verification": true, + "reviewers": [ + "correctness" + ], + "severity": "P2", + "suggested_fix": "Update task-sync's stale-evidence reader to parse the fenced JSON receipts produced by evidence.py and inspect their recorded object SHA/state when deciding whether non-card changes invalidate a check. Retain legacy-table support if historical cards remain supported. Add a regression recording a JSON receipt, advancing main with a non-card change, and checking the stale-evidence warning.", + "title": "Teach stale-evidence checking to read the new receipt format", + "why_it_matters": "Evidence now appends fenced JSON, but task-sync still finds old evidence only by matching timestamped Markdown table rows. Consequently every newly recorded receipt is invisible to the existing stale-object warning. A normal sequence of recording a check, merging changed implementation from main, and syncing now silently retains stale evidence without the warning that previously requested reruns.", + "protected_subject": null, + "validation_status": "confirmed", + "validation_reason": "The reviewed diff adds JSON receipt append_card output in scripts/evidence.py:228-239, while scripts/task.sh:250 still scans only timestamp-leading Markdown table rows, so a recorded JSON receipt is unreachable by the stale-evidence warning after a non-card sync change." + }, + { + "#": 3, + "autofix_class": "gated_auto", + "confidence": 100, + "evidence": [ + "c0abfb0 scripts/evidence.py:44 requires an unquoted Authorization header; lines 117-125 sanitize before receipt construction, lines 193-194 reuse the sanitizer during import, and lines 227-239 append to the task card.", + "SELF synthetic capture/import reproduction at c0abfb0250980af7f1b18c785eb4b55240a8d855: quoted JSON Authorization remains in both receipt and task card; import exits 0; receipt source is SELF. No real credential was used.", + "Reviewer-reported SELF targeted suites: test_ci_credentials.py 7 tests, test_evidence.py 28 tests, and test_write_guard.py 12 tests passed. These suites do not refute the synthetic bypass." + ], + "file": "scripts/evidence.py", + "first_evidence": "scripts/evidence.py:44: value = re.sub(r\"(?i)(\\bAuthorization[ \\t]*:[ \\t]*(?:Bearer|token|Basic)[ \\t]+)[^\\s'\\\";]+\",", + "independent_reviewers": [ + "security" + ], + "line": 44, + "owner": "downstream-resolver", + "pre_existing": false, + "requires_verification": true, + "reviewers": [ + "security" + ], + "severity": "P2", + "suggested_fix": "Extend Authorization redaction to recognize optionally quoted header keys and quoted values used by JSON and Python dictionary dumps while retaining plain-header support. Add capture-and-import regression cases for double-quoted JSON and single-quoted dictionary headers, using a synthetic credential absent from the recorder environment, and assert that command, output, receipt, console, and task card contain no credential.", + "title": "CWE-532: Redact quoted Authorization headers before storing evidence", + "why_it_matters": "A command that logs request headers as JSON or a Python dictionary can persist its bearer/token credential into the receipt and tracked task card. For example, {\"Authorization\": \"Bearer synthetic-json-header-secret\"} bypasses sanitize() because the regex requires an unquoted header name immediately followed by a colon and an unquoted scheme. Known-environment-value replacement cannot help when the credential was read from a protected file or created inside the child command. Import accepts the same unredacted receipt, so subsequent publication of the task card exposes the credential.", + "protected_subject": "secrets-exposure", + "validation_status": "confirmed", + "validation_reason": "At the reviewed revision, sanitize('{\"Authorization\": \"Bearer synthetic-json-header-secret\"}') returned that value unchanged, and the new evidence.py stores sanitize_tree output in receipts and task cards, so a quoted JSON Authorization value can be persisted when such command output occurs." + }, + { + "#": 4, + "autofix_class": "gated_auto", + "confidence": 75, + "evidence": [ + "c0abfb0 scripts/task.sh:420-424 records the abandon reason; lines 449-450 retain the branch and skip remote deletion.", + "Validator AST inspection and report-leaf pinned-source text inspection found no --abandon invocation in reviewed tests/test_task.py." + ], + "file": "scripts/task.sh", + "first_evidence": "scripts/task.sh:420: if [ \"$abandon\" = \"--abandon\" ]; then", + "independent_reviewers": [ + "testing" + ], + "line": 420, + "owner": "downstream-resolver", + "pre_existing": false, + "requires_verification": true, + "reviewers": [ + "testing" + ], + "severity": "P2", + "suggested_fix": "Add a disposable-repository lifecycle test that creates unmerged local and remote task work, runs `finish --abandon ` with `TASK_WRITERS_STOPPED=1`, then asserts the worktree is removed, the local and remote branch tips remain reachable, and `refs/notes/task-abandon` records the reason. Add a companion missing-reason assertion that preserves the worktree.", + "title": "Test the abandon cleanup path", + "why_it_matters": "The new explicit-abandon path removes a worktree while deliberately retaining the local branch and skipping remote deletion. No regression test exercises that lifecycle contract, so a future change can silently recycle unmerged work incorrectly or delete the retained ref without the governance suite detecting it.", + "protected_subject": null, + "validation_status": "confirmed", + "validation_reason": "The reviewed diff's finish --abandon branch records a note and retains the branch, but AST inspection of tests/test_task.py found no invocation with --abandon, leaving that lifecycle contract without regression coverage." + } + ], + "actionable_findings": [ + { + "#": 2, + "autofix_class": "gated_auto", + "confidence": 100, + "evidence": [ + "c0abfb0 scripts/evidence.py:227-239 appends fenced JSON receipts; scripts/task.sh:242-251 only scans timestamp-leading Markdown table rows for stale tested HEADs.", + "SELF scratch reproduction: capture a receipt, commit it, advance origin/main with a non-card change, and sync. The recorded before HEAD differs in implementation content, but output contains no [evidence] WARN." + ], + "file": "scripts/evidence.py", + "first_evidence": "scripts/evidence.py:231: + \"```json\\n\" + encoded + \"\\n```\\n\")", + "independent_reviewers": [ + "correctness" + ], + "line": 231, + "owner": "downstream-resolver", + "pre_existing": false, + "requires_verification": true, + "reviewers": [ + "correctness" + ], + "severity": "P2", + "suggested_fix": "Update task-sync's stale-evidence reader to parse the fenced JSON receipts produced by evidence.py and inspect their recorded object SHA/state when deciding whether non-card changes invalidate a check. Retain legacy-table support if historical cards remain supported. Add a regression recording a JSON receipt, advancing main with a non-card change, and checking the stale-evidence warning.", + "title": "Teach stale-evidence checking to read the new receipt format", + "why_it_matters": "Evidence now appends fenced JSON, but task-sync still finds old evidence only by matching timestamped Markdown table rows. Consequently every newly recorded receipt is invisible to the existing stale-object warning. A normal sequence of recording a check, merging changed implementation from main, and syncing now silently retains stale evidence without the warning that previously requested reruns.", + "protected_subject": null, + "validation_status": "confirmed", + "validation_reason": "The reviewed diff adds JSON receipt append_card output in scripts/evidence.py:228-239, while scripts/task.sh:250 still scans only timestamp-leading Markdown table rows, so a recorded JSON receipt is unreachable by the stale-evidence warning after a non-card sync change." + }, + { + "#": 3, + "autofix_class": "gated_auto", + "confidence": 100, + "evidence": [ + "c0abfb0 scripts/evidence.py:44 requires an unquoted Authorization header; lines 117-125 sanitize before receipt construction, lines 193-194 reuse the sanitizer during import, and lines 227-239 append to the task card.", + "SELF synthetic capture/import reproduction at c0abfb0250980af7f1b18c785eb4b55240a8d855: quoted JSON Authorization remains in both receipt and task card; import exits 0; receipt source is SELF. No real credential was used.", + "Reviewer-reported SELF targeted suites: test_ci_credentials.py 7 tests, test_evidence.py 28 tests, and test_write_guard.py 12 tests passed. These suites do not refute the synthetic bypass." + ], + "file": "scripts/evidence.py", + "first_evidence": "scripts/evidence.py:44: value = re.sub(r\"(?i)(\\bAuthorization[ \\t]*:[ \\t]*(?:Bearer|token|Basic)[ \\t]+)[^\\s'\\\";]+\",", + "independent_reviewers": [ + "security" + ], + "line": 44, + "owner": "downstream-resolver", + "pre_existing": false, + "requires_verification": true, + "reviewers": [ + "security" + ], + "severity": "P2", + "suggested_fix": "Extend Authorization redaction to recognize optionally quoted header keys and quoted values used by JSON and Python dictionary dumps while retaining plain-header support. Add capture-and-import regression cases for double-quoted JSON and single-quoted dictionary headers, using a synthetic credential absent from the recorder environment, and assert that command, output, receipt, console, and task card contain no credential.", + "title": "CWE-532: Redact quoted Authorization headers before storing evidence", + "why_it_matters": "A command that logs request headers as JSON or a Python dictionary can persist its bearer/token credential into the receipt and tracked task card. For example, {\"Authorization\": \"Bearer synthetic-json-header-secret\"} bypasses sanitize() because the regex requires an unquoted header name immediately followed by a colon and an unquoted scheme. Known-environment-value replacement cannot help when the credential was read from a protected file or created inside the child command. Import accepts the same unredacted receipt, so subsequent publication of the task card exposes the credential.", + "protected_subject": "secrets-exposure", + "validation_status": "confirmed", + "validation_reason": "At the reviewed revision, sanitize('{\"Authorization\": \"Bearer synthetic-json-header-secret\"}') returned that value unchanged, and the new evidence.py stores sanitize_tree output in receipts and task cards, so a quoted JSON Authorization value can be persisted when such command output occurs." + }, + { + "#": 4, + "autofix_class": "gated_auto", + "confidence": 75, + "evidence": [ + "c0abfb0 scripts/task.sh:420-424 records the abandon reason; lines 449-450 retain the branch and skip remote deletion.", + "Validator AST inspection and report-leaf pinned-source text inspection found no --abandon invocation in reviewed tests/test_task.py." + ], + "file": "scripts/task.sh", + "first_evidence": "scripts/task.sh:420: if [ \"$abandon\" = \"--abandon\" ]; then", + "independent_reviewers": [ + "testing" + ], + "line": 420, + "owner": "downstream-resolver", + "pre_existing": false, + "requires_verification": true, + "reviewers": [ + "testing" + ], + "severity": "P2", + "suggested_fix": "Add a disposable-repository lifecycle test that creates unmerged local and remote task work, runs `finish --abandon ` with `TASK_WRITERS_STOPPED=1`, then asserts the worktree is removed, the local and remote branch tips remain reachable, and `refs/notes/task-abandon` records the reason. Add a companion missing-reason assertion that preserves the worktree.", + "title": "Test the abandon cleanup path", + "why_it_matters": "The new explicit-abandon path removes a worktree while deliberately retaining the local branch and skipping remote deletion. No regression test exercises that lifecycle contract, so a future change can silently recycle unmerged work incorrectly or delete the retained ref without the governance suite detecting it.", + "protected_subject": null, + "validation_status": "confirmed", + "validation_reason": "The reviewed diff's finish --abandon branch records a note and retains the branch, but AST inspection of tests/test_task.py found no invocation with --abandon, leaving that lifecycle contract without regression coverage." + } + ], + "triage_groups": [ + { + "title": "Task cleanup preservation", + "findings": [ + 1, + 4 + ], + "context": "Task disposal must preserve component metadata and abandoned branch history.", + "preferred_resolution": "Decision-gate: resolve the cleanup-preservation verification gate (#1) before cleanup acceptance; add the independent abandon-retention regression (#4). Only #4 is in the actionable queue.", + "why": "Both concern irreversible checkout disposal and can share disposable Git lifecycle fixtures." + }, + { + "title": "Evidence receipt integrity", + "findings": [ + 2, + 3 + ], + "context": "JSON receipts are newly consumed as tracked evidence and must stay current and sanitized.", + "preferred_resolution": "Apply-queue: close quoted credential redaction (#3), then update stale-receipt detection (#2), each with its discriminating regression.", + "why": "The receipt producer and consumer need to preserve the same confidentiality and tested-object contract." + } + ], + "pre_existing_findings": [], + "requirements_completeness": null, + "learnings": [], + "agent_native_gaps": [], + "deployment_notes": [], + "residual_risks": [ + "Live runner isolation, workflow provenance and checkout-token scope were not replayed; policy/platform-admission.md explicitly leaves those controls to platform validation." + ], + "testing_gaps": [ + "Live CI, runner isolation, workflow provenance, and production incidence of the synthetic Authorization-header exposure were not measured." + ], + "coverage": { + "notes": [ + "Review is pinned to c0abfb0250980af7f1b18c785eb4b55240a8d855 against 43d33aa4921078bc202393b99cba017d7f731b98. Report-stage source reads used git show; ongoing root repairs were not reviewed.", + "All seven selected local reviewers completed. Project standards used the AGENTS.md fallback because no CODING_STANDARDS.md was found.", + "No applicable plan was discovered; requirements completeness and settlement suppression were not evaluated.", + "All local command and reproduction claims remain SELF. Author-reported make test/build results were not promoted to GATE or REPLAY.", + "Synthesis checked all four anchors and surrounding code, merged no semantic duplicates, and omitted the editorial make-help observation under the scope constraint.", + "No repository edits, commits, pushes, branch changes, or local fixes were performed by this review." + ], + "reviewer_selection": [ + { + "reviewer": "correctness", + "tier": "session", + "reason": "logic and state changes in lifecycle and evidence" + }, + { + "reviewer": "project-standards", + "tier": "gpt-5.6-terra", + "reason": "AGENTS.md explicitly governs changed commands and safety contracts" + }, + { + "reviewer": "testing", + "tier": "gpt-5.6-terra", + "reason": "new Git fixture suites and silent-pass test gates" + }, + { + "reviewer": "maintainability", + "tier": "gpt-5.6-terra", + "reason": "1573 executable changed lines and new Python modules" + }, + { + "reviewer": "agent-native", + "tier": "gpt-5.6-terra", + "reason": "agent instructions and tool write authorization changed" + }, + { + "reviewer": "security", + "tier": "session", + "reason": "credentials, evidence redaction and path authorization" + }, + { + "reviewer": "reliability", + "tier": "gpt-5.6-terra", + "reason": "failure propagation and partially completed cleanup/sync" + } + ], + "lite": false, + "suppressed_by_confidence": {}, + "suppressed_findings": 0, + "malformed_findings": 0, + "malformed_returns": 0, + "first_evidence_backfilled": 0, + "quote_demotions": 0, + "mode_aware_demotions": 0, + "semantic_duplicates_merged": 0, + "settlement_suppression_evaluated": false, + "settlement_suppressed": 0, + "failed_reviewers": [], + "bound_exceeded": [], + "cross_model": "Cross-model adversarial peer: timeout, reaped on caller request to bound review latency before completion; no usable artifact. Route=claude; requested model=claude-opus-5; requested effort=high; receipt_supported=unverified; model_actual=unverified; effort_actual=unverified; independence_verified=false. Adversarial lens degraded; no cross-model confidence promotion. No detached job remains.", + "compound_packs": { + "roots": [], + "warnings": [], + "errors": [] + }, + "validation": { + "batch_outcome": "verdicts", + "selected": [ + 1, + 2, + 3, + 4 + ], + "bound_exceeded": false, + "confirmed": 3, + "rejected": 0, + "unresolved": 1, + "malformed": 0, + "failed": 0, + "shortcut_skipped": 0, + "shortcut_basis": "No finding had verified cross-model corroboration; every selected finding entered the single validator batch.", + "raw_verdicts": [ + { + "#": 1, + "status": "rejected", + "protected_subject": "data-loss", + "reason": "Although a scratch fixture reproduced the loss when a clean pinned component has another linked worktree with uncommitted content, base 43d33aa's scripts/task.sh:381-386 already removed the parent with rm -rf plus worktree prune, so this destructive behavior predates rather than being introduced by the reviewed diff." + }, + { + "#": 2, + "status": "confirmed", + "protected_subject": null, + "reason": "The reviewed diff adds JSON receipt append_card output in scripts/evidence.py:228-239, while scripts/task.sh:250 still scans only timestamp-leading Markdown table rows, so a recorded JSON receipt is unreachable by the stale-evidence warning after a non-card sync change." + }, + { + "#": 3, + "status": "confirmed", + "protected_subject": "secrets-exposure", + "reason": "At the reviewed revision, sanitize('{\"Authorization\": \"Bearer synthetic-json-header-secret\"}') returned that value unchanged, and the new evidence.py stores sanitize_tree output in receipts and task cards, so a quoted JSON Authorization value can be persisted when such command output occurs." + }, + { + "#": 4, + "status": "confirmed", + "protected_subject": null, + "reason": "The reviewed diff's finish --abandon branch records a note and retains the branch, but AST inspection of tests/test_task.py found no invocation with --abandon, leaving that lifecycle contract without regression coverage." + } + ], + "protected_subject_reclassifications": [ + { + "#": 1, + "from": "rejected", + "to": "unresolved", + "reason": "Protected-subject rejection reclassified as unresolved. Base 43d33aa scripts/task.sh:381-386 confirms older destructive behavior, but does not establish unrelatedness or refute the failure at reviewed c0abfb0: task.sh:438-445 expressly makes the new preservation checks the basis for forced removal, while check-worktree.py:51-69 omits linked component worktree ownership. Resolve this gate with a discriminating cleanup regression that preserves an external component worktree and its staged/uncommitted content, or inspected evidence disproving this interaction. Root accepts the remediation scope and reports repairs in progress; those repairs are outside this reviewed commit." + } + ], + "degraded_blockers": [ + 1 + ] + } + }, + "artifact_path": "/tmp/compound-engineering-1000/ce-code-review/20261005-123925-a2fa0a6f", + "run_id": "20261005-123925-a2fa0a6f" +} diff --git a/Makefile b/Makefile index fb811663..269c365c 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,7 @@ help: @echo "make sync 物化全部 submodule(递归)" @echo "make build 构建单二进制 bin/agent-system(契约同步→前端构建→embed→静态链接)" @echo "make test 全量测试(boundaries + pins + libs + core + backend + frontend + ui + agent-command)" + @echo "make test-governance 临时真实仓库中的任务、证据、写守卫与 CI 凭据回归" @echo "make svc 服务级操作:make svc ENV= [ACTION=deploy|start|stop|restart|status|logs] [ARGS='--from dev@ --tag ...']" @echo "make svc-list 服务总览:make svc-list [ARGS='--tag core'];数据库运维:scripts/svc.sh db create|dsn|backup|backups|restore|clone|copy|ls|set" @echo "make svc-info 综合信息报告(只读):make svc-info [ARGS='pg1 --reveal']——运行服务/数据库实例与内部库/配置快照" diff --git a/policy/governance.md b/policy/governance.md index e9d88252..07ec5012 100644 --- a/policy/governance.md +++ b/policy/governance.md @@ -52,13 +52,16 @@ GATE 引用受信平台的运行链接、执行身份、完整 SHA 和结果;R 仅在登记的任务 worktree 根目录回收。owner 先确认全部写者已退出、任务成果与证据已保存, 以 `TASK_WRITERS_STOPPED=1 make task-finish` 明确确认; -脚本检查主检出/子目录误用、Git 操作和锁、父子仓修改及未跟踪/ignored 文件。 +脚本检查主检出/子目录误用、Git 操作和锁、父子仓修改及未跟踪/ignored 文件; +子模块另有登记 worktree 时拒绝回收,避免删除其他检出依赖的 Git 管理目录。 可再生缓存由 owner 按已识别路径单独处置;无法确认用途的文件保留。 任务合入需以本次成功获取的权威目标验证。合入提交不能证明未提交文件已经落盘。 Git 对含子模块的工作区需要显式删除选项时,只有全部现场检查通过才允许该路径; 它不豁免任何脏状态、忽略文件、独有提交/引用或锁检查。普通删除失败不转入强删兜底。 保留无法确认安全的目录和分支,输出下一步处理依据。 +子仓 pin 之外的 refs/stash/reflog 历史采取保守拒绝,即使其中部分可能已在远端: +owner 须先独立确认其保存与归属,工具不把缓存的远端引用当作唯一数据已经备份的证据。 远端分支删除与本地回收分别报告,失败不能声明两者全部完成。 回收后由所有者执行 `make task-close` 闭合卡片;回收命令不顺带改写共享主检出。 diff --git a/scripts/check-evidence.py b/scripts/check-evidence.py new file mode 100644 index 00000000..df609348 --- /dev/null +++ b/scripts/check-evidence.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +"""Warn when a task card's recorded objects no longer support current checks. + +Receipt commands and output are data only. This is a freshness check, not an +upgrade of local SELF evidence to reviewer or CI evidence. +""" +import json +from datetime import datetime +from pathlib import Path +import re +import shlex +import subprocess +import sys + +# Reading a receipt must not create ignored files that prevent task-finish. +sys.dont_write_bytecode = True +import evidence + + +def warn(label, reason): + print(f"[evidence] WARN {label}: {reason} ——关键检查须重跑并以 make evidence 重新写入") + + +def check_head(head): + if not isinstance(head, str) or not re.fullmatch(r"[0-9a-f]{4,64}", head): + raise ValueError("invalid recorded HEAD") + resolved = subprocess.run(["git", "rev-parse", "--verify", head + "^{commit}"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if resolved.returncode: + raise ValueError("recorded HEAD is unavailable or ambiguous") + result = subprocess.run(["git", "diff", "--quiet", "--no-ext-diff", + resolved.stdout.decode().strip(), "HEAD", "--", ".", ":(exclude).task"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if result.returncode not in (0, 1): + raise ValueError("recorded HEAD could not be compared") + return result.returncode == 1 + + +def card_path(path): + return path == ".task" or path.startswith(".task/") + + +def check_snapshot(snapshot): + evidence.validate_snapshot(snapshot) + stale = check_head(snapshot["head"]) + for line in snapshot["status"].splitlines(): + if len(line) < 4 or line[2] != " ": + raise ValueError("invalid recorded worktree status") + # Parse quoting as text, never as a shell command. Renames must have + # both paths inside .task to qualify as metadata-only changes. + paths = shlex.split(line[3:]) if line[3:].startswith('"') else [line[3:]] + paths = [part for path in paths for part in path.split(" -> ") if part != "->"] + if not paths or not all(card_path(path) for path in paths): + raise ValueError("recorded object includes uncommitted non-card changes") + if any(not card_path(path) for path in snapshot["untracked"]): + raise ValueError("recorded object includes untracked non-card files") + if any(not line.startswith(" ") for line in snapshot["submodules"].splitlines()): + raise ValueError("recorded component state was not at its pinned SHA") + if not snapshot["status"] and snapshot["tracked_diff_sha256"] != evidence.digest(b""): + raise ValueError("recorded diff cannot be reconstructed from HEAD") + return stale + + +def check_receipt(value): + if not isinstance(value, dict) or type(value.get("schema")) is not int or value["schema"] != evidence.SCHEMA: + raise ValueError("unsupported or malformed receipt") + expected = {"schema", "source", "timestamp", "command", "command_sha256", "cwd", "common_dir", + "before", "after", "after_error", "exit_code", "output", "output_sha256", "receipt_sha256"} + if set(value) not in (expected, expected | {"capture_note"}): + raise ValueError("invalid receipt fields") + for key in ("source", "timestamp", "command", "cwd", "common_dir", "output"): + if not isinstance(value[key], str): + raise ValueError("invalid receipt field: " + key) + for key in ("command_sha256", "output_sha256", "receipt_sha256"): + if not isinstance(value[key], str) or not evidence.SHA256.fullmatch(value[key]): + raise ValueError("invalid receipt digest: " + key) + if value["source"] != "SELF" or type(value["exit_code"]) is not int or not 0 <= value["exit_code"] <= 255: + raise ValueError("invalid receipt source or exit code") + if any(not Path(value[key]).is_absolute() for key in ("cwd", "common_dir")): + raise ValueError("invalid receipt identity paths") + if "capture_note" in value and not isinstance(value["capture_note"], str): + raise ValueError("invalid capture note") + try: + datetime.fromisoformat(value["timestamp"].replace("Z", "+00:00")) + except ValueError: + raise ValueError("invalid receipt timestamp") from None + payload = {key: item for key, item in value.items() if key != "receipt_sha256"} + if evidence.digest(evidence.canonical(payload)) != value.get("receipt_sha256"): + raise ValueError("receipt checksum mismatch") + if not isinstance(value.get("output"), str) or evidence.digest(value["output"]) != value.get("output_sha256"): + raise ValueError("receipt output checksum mismatch") + if value.get("after") is None or value.get("after_error") is not None: + raise ValueError("receipt has no complete after object") + before_stale = check_snapshot(value.get("before")) + after_stale = check_snapshot(value["after"]) + return before_stale or after_stale + + +def records(content): + """Yield fenced JSON and timestamped legacy rows without interpreting text.""" + block = None + start = None + for number, line in enumerate(content.splitlines(), 1): + if block is not None: + if line.strip() == "```": + yield f"JSON receipt line {start}", "json", "\n".join(block) + block = None + else: + block.append(line) + elif line.strip() == "```json": + block, start = [], number + elif re.match(r"^\|\s*\d{4}-\d{2}-\d{2}T[^|]*\|", line): + fields = re.split(r"(? 3 else "" + if block is not None: + yield f"JSON receipt line {start}", "json", "" + + +def main(): + try: + content = Path(sys.argv[1]).read_text(encoding="utf-8") + except (IndexError, OSError, UnicodeError): + warn("task card", "unverified: evidence could not be read") + return + for label, kind, record in records(content): + try: + stale = check_receipt(json.loads(record)) if kind == "json" else check_head(record) + except (ValueError, TypeError, KeyError, OSError, evidence.EvidenceError) as exc: + warn(label, "unverified: " + str(exc)) + continue + if stale: + warn(label, "recorded HEAD predates non-card changes") + + +if __name__ == "__main__": + main() diff --git a/scripts/check-worktree.py b/scripts/check-worktree.py index 283bf86c..8ce1eac6 100644 --- a/scripts/check-worktree.py +++ b/scripts/check-worktree.py @@ -48,7 +48,28 @@ def submodules(repo): yield repo / os.fsdecode(path), sha.decode("ascii") -def check_children(repo, mode): +def worktrees(repo): + records = git(repo, "worktree", "list", "--porcelain", "-z").split(b"\0\0") + parsed = [record.split(b"\0") for record in records if record] + if not parsed or any(not record[0].startswith(b"worktree ") for record in parsed): + raise RuntimeError(f"cannot identify registered worktrees in {repo}") + return parsed + + +def check_component_worktrees(repo, removal_roots): + common = Path(text(repo, "rev-parse", "--path-format=absolute", "--git-common-dir")).resolve() + if not any(common == root or root in common.parents for root in removal_roots): + return + current = Path(text(repo, "rev-parse", "--absolute-git-dir")).resolve() + for index, record in enumerate(worktrees(repo)): + other = Path(os.fsdecode(record[0][9:])).resolve() + # Git may report an absorbed submodule's primary checkout as its common + # directory. It is the current checkout only when no linked gitdir is used. + if other != repo.resolve() and not (index == 0 and current == common): + raise RuntimeError(f"registered component worktree {other} depends on metadata in {common}; preserve or relocate it before removal") + + +def check_children(repo, mode, removal_roots=()): for child, expected in submodules(repo): if child.is_symlink(): raise RuntimeError(f"submodule path is a symbolic link: {child}") @@ -56,6 +77,8 @@ def check_children(repo, mode): if mode in ("verify", "after-sync", "finish"): raise RuntimeError(f"uninitialized submodule: {child}; initialize and inspect it first") continue + if mode == "finish": + check_component_worktrees(child, removal_roots) actual = text(child, "rev-parse", "HEAD") check_operations(child) check_clean(child, ignored=(mode == "finish"), allow_gitlink_drift=(mode == "before-update")) @@ -66,7 +89,7 @@ def check_children(repo, mode): raise RuntimeError(f"submodule SHA drift: {child}: expected {expected}, actual {actual}") if mode == "finish" and git(child, "rev-list", "--all", "--reflog", "--not", expected).strip(): raise RuntimeError(f"submodule has commits outside its pinned history: {child}; preserve branches, stash and reflogs before removal") - check_children(child, mode) + check_children(child, mode, removal_roots) def materialize(repo): @@ -83,10 +106,7 @@ def materialize(repo): def check_finish_root(repo): if Path.cwd().resolve() != repo: raise RuntimeError("task-finish must run at the registered worktree root, not a subdirectory") - records = git(repo, "worktree", "list", "--porcelain", "-z").split(b"\0\0") - parsed = [record.split(b"\0") for record in records if record] - if not parsed or not parsed[0][0].startswith(b"worktree "): - raise RuntimeError("cannot identify the main checkout") + parsed = worktrees(repo) main = Path(os.fsdecode(parsed[0][0][9:])).resolve() if main == repo: raise RuntimeError("task-finish must run in a linked task worktree, never the main checkout") @@ -107,14 +127,16 @@ def main(): raise RuntimeError("usage: check-worktree.py [verify|before-sync|before-update|materialize|after-sync|finish]") repo = Path(text(Path.cwd(), "rev-parse", "--show-toplevel")).resolve() check_operations(repo) + removal_roots = () if mode == "finish": check_finish_root(repo) + removal_roots = (repo, Path(text(repo, "rev-parse", "--absolute-git-dir")).resolve()) if mode in ("before-sync", "after-sync", "finish"): check_clean(repo, ignored=(mode == "finish")) if mode == "materialize": materialize(repo) else: - check_children(repo, mode) + check_children(repo, mode, removal_roots) print(f"[worktree] {mode}: recursive component checks passed") diff --git a/scripts/evidence.py b/scripts/evidence.py index 395d0d1a..644ec39d 100644 --- a/scripts/evidence.py +++ b/scripts/evidence.py @@ -41,8 +41,8 @@ def sanitize(value): value = value.replace(secret, "") value = re.sub(r"-----BEGIN [^-\r\n]*PRIVATE KEY-----.*?-----END [^-\r\n]*PRIVATE KEY-----", "", value, flags=re.S) - value = re.sub(r"(?i)(\bAuthorization[ \t]*:[ \t]*(?:Bearer|token|Basic)[ \t]+)[^\s'\";]+", - r"\1", value) + value = re.sub(r"(?i)(\bAuthorization['\"]?[ \t]*[=:][ \t]*['\"]?" + r"(?:Bearer|token|Basic)[ \t]+)[^\s'\";]+", r"\1", value) value = re.sub(r"(?i)\b(https?|ssh)://[^\s/@:]+:[^\s/@]+@", r"\1://@", value) credential = r"[\w-]*(?:token|password|passwd|secret|api[_-]?key|credential)[\w-]*" prefix = r"(?:\b" + credential + r"['\"]?[ \t]*[=:][ \t]*|--" + credential + r"[ \t]+)" diff --git a/scripts/hooks/post-merge b/scripts/hooks/post-merge index 740e8616..0dafa3f6 100755 --- a/scripts/hooks/post-merge +++ b/scripts/hooks/post-merge @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# 本地钩子(post-merge):merge 型 pull/merge 落地后自动闭合已合入任务卡(ff-only 不触发 -# 本钩子——由 task-finish 收尾与 precheck [cards] 报告兜底)。 +# 本地钩子(post-merge):pull/merge 落地后尝试闭合已合入任务卡;ff-only 也会触发。 +# precheck [cards] 报告欠账,所有者可用 make task-close 手动兜底。 # 触发条件收紧到"主检出 + 集成分支 main"——任务 worktree 里 task-sync 的 merge 不触发, # 防止把卡片闭合混进任务分支现场。失败只警告,绝不阻断 pull。 # 注意:task.sh close 在主检出会另建 feature/card-close-* 分支提交(集成分支不直推), diff --git a/scripts/task.sh b/scripts/task.sh index 5cfc8901..35aee906 100755 --- a/scripts/task.sh +++ b/scripts/task.sh @@ -113,7 +113,7 @@ cmd_precheck() { echo "[verdict] SYNC_REQUIRED — ${branch} 缺少 origin/${TARGET_BRANCH} 的 ${behind} 个提交;主检出 pull --ff-only,任务分支 make task-sync" exit 4 fi - echo "[verdict] READY — 可建任务工作区:make task-start NAME=feature/your-branch" + echo "[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch" } cmd_start() { @@ -239,16 +239,8 @@ cmd_sync() { -m "Why: bind the task validation checkpoint to the latest integration baseline." \ -m "Evidence: SELF recursive component checks; sync_base=${base}; candidate=${head}." \ -m "Impact: task metadata only." -m "Refs: ${card}" - # [evidence] 同步改变了被测对象:卡片证据表中旧 HEAD 的行,其后若有非 .task 变更则失效须重跑。 - local eh stale_ev="" short_head changed - short_head=$(echo "$head" | cut -c1-10) - while IFS='|' read -r _ _ _ eh _ _ _; do - eh=$(echo "$eh" | tr -d ' `') - { [ -n "$eh" ] && [ "$eh" != "$short_head" ]; } || continue - changed=$(git diff --name-only "${eh}" HEAD -- . ':(exclude).task' 2>/dev/null | head -1) - [ -n "$changed" ] && stale_ev="$stale_ev ${eh}" - done < <(grep -E '^\| [0-9]{4}-[0-9]{2}-[0-9]{2}T[^|]*\|' "$card" 2>/dev/null || true) - [ -n "$stale_ev" ] && echo "[evidence] WARN 证据表被测 HEAD 落后且其后有非卡片变更:$(echo $stale_ev | tr ' ' '\n' | sort -u | tr '\n' ' ')(当前 $short_head)——关键检查须重跑并以 make evidence 重新写入" + # JSON receipts carry before/after state; older table rows remain readable. + python3 "${SCRIPT_DIR}/check-evidence.py" "$card" else echo "[warn] 找不到分支 ${branch} 的任务卡,同步记录未写入" >&2 fi diff --git a/tests/test_evidence.py b/tests/test_evidence.py index 249d72e7..2344065f 100644 --- a/tests/test_evidence.py +++ b/tests/test_evidence.py @@ -11,6 +11,36 @@ import unittest SCRIPTS = Path(__file__).resolve().parents[1] / "scripts" +# Literal delimiters exercise header, JSON, repr and assignment boundaries. +AUTHORIZATION_FORMS = ( + 'Authorization: {scheme} {secret}', + '{{"Authorization":"{scheme} {secret}"}}', + "{{'Authorization': '{scheme} {secret}'}}", + 'Authorization: "{scheme} {secret}"', + "Authorization: '{scheme} {secret}'", + 'AUTHORIZATION = {scheme} {secret}', + '"authorization" = "{scheme} {secret}"', + "'aUtHoRiZaTiOn' = '{scheme} {secret}'", + 'authorization={scheme} {secret}', + '{{ "Authorization"\t:\t"{scheme}\t{secret}", "ok": true }}', +) + + +def authorization_cases(): + for scheme in ("Bearer", "tOkEn", "bAsIc"): + for index, form in enumerate(AUTHORIZATION_FORMS): + secret = f"syntheticAuthValue{scheme}{index}" + yield (form.format(scheme=scheme, secret=secret), secret, + form.format(scheme=scheme, secret="")) + + +def authorization_command(headers): + # Use a shell quote that leaves each credential spelling intact in CMD. + args = [('"' + header + '"') if "'" in header else ("'" + header + "'") + for header in headers] + return "printf '%s\\n' " + " ".join(args) + + class EvidenceTests(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() @@ -146,6 +176,49 @@ class EvidenceTests(unittest.TestCase): self.assertEqual(data["output_sha256"], hashlib.sha256(data["output"].encode()).hexdigest()) self.assertEqual(data["command_sha256"], hashlib.sha256(command.encode()).hexdigest()) + def test_authorization_forms_are_redacted_in_capture_console_and_import(self): + cases = list(authorization_cases()) + command = authorization_command([header for header, _, _ in cases]) + result = self.run_evidence(command, RECEIPT=self.receipt) + self.assertEqual(result.returncode, 0, result.stderr) + data = json.loads(self.receipt.read_text()) + imported = self.import_receipt() + self.assertEqual(imported.returncode, 0, imported.stderr) + persisted = self.receipt.read_text() + self.card.read_text() + displayed = result.stdout + result.stderr + imported.stdout + imported.stderr + for header, secret, expected in cases: + with self.subTest(header=header): + self.assertNotIn(secret, persisted + displayed) + self.assertIn(expected, data["output"].splitlines()) + self.assertEqual(data["command_sha256"], hashlib.sha256(command.encode()).hexdigest()) + self.assertEqual(data["output_sha256"], hashlib.sha256(data["output"].encode()).hexdigest()) + self.assertEqual(data["source"], "SELF") + self.assertEqual(data["schema"], 1) + + def test_authorization_forms_are_redacted_on_direct_card_capture(self): + cases = list(authorization_cases()) + command = authorization_command([header for header, _, _ in cases]) + result = self.run_evidence(command) + self.assertEqual(result.returncode, 0, result.stderr) + visible = self.card.read_text() + result.stdout + result.stderr + for header, secret, _ in cases: + with self.subTest(header=header): + self.assertNotIn(secret, visible) + self.assertIn("", visible) + + def test_import_rejects_unredacted_authorization_with_valid_checksums(self): + original = self.capture() + for header, _, _ in authorization_cases(): + with self.subTest(header=header): + self.card.write_text("# Test task\n") + data = dict(original, output=header) + data["output_sha256"] = hashlib.sha256(header.encode()).hexdigest() + self.resign(data) + result = self.import_receipt() + self.assertNotEqual(result.returncode, 0) + self.assertIn("unredacted credential syntax", result.stderr) + self.assertEqual(self.card.read_text(), "# Test task\n") + def test_known_secret_environment_value_is_redacted_without_label(self): data = self.capture("printf %s \"$GITEA_TOKEN\"", GITEA_TOKEN="unlabelledSyntheticCredential") self.assertNotIn("unlabelledSyntheticCredential", self.receipt.read_text()) diff --git a/tests/test_task.py b/tests/test_task.py index 27ccaecf..930b830c 100644 --- a/tests/test_task.py +++ b/tests/test_task.py @@ -1,5 +1,7 @@ """Lifecycle regressions against real disposable Git repositories and remotes.""" import os +import json +import hashlib from pathlib import Path import shutil import shlex @@ -194,6 +196,32 @@ class TaskLifecycleTests(unittest.TestCase): self.assertTrue(wt.exists(), result.stdout) self.assertEqual(self.git(child, "rev-parse", "feature/unique-history").stdout.strip(), unique) + def test_finish_preserves_linked_component_worktrees_at_the_pinned_head(self): + self.add_submodule() + for state in ("clean", "staged", "unstaged"): + with self.subTest(state=state): + wt = self.root / f"worktree-{state}" + self.git(self.repo, "worktree", "add", "-b", f"feature/{state}", str(wt), "origin/main") + self.git(wt, "submodule", "update", "--init", "--recursive") + child = wt / "component" + sibling = self.root / f"component-{state}" + self.git(child, "worktree", "add", "--detach", str(sibling), "HEAD") + head = self.git(sibling, "rev-parse", "HEAD").stdout + if state != "clean": + (sibling / "content").write_text("unique sibling work\n") + if state == "staged": + self.git(sibling, "add", "content") + status = self.git(sibling, "status", "--porcelain").stdout + result = self.task(wt, "finish", check=False) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertTrue(wt.exists(), result.stdout) + self.assertEqual(self.git(child, "rev-parse", "HEAD").stdout, head) + self.assertEqual(self.git(child, "status", "--porcelain").stdout, "") + self.assertEqual(self.git(sibling, "rev-parse", "HEAD").stdout, head) + self.assertEqual(self.git(sibling, "status", "--porcelain").stdout, status) + self.assertEqual((sibling / "content").read_text(), + "v1\n" if state == "clean" else "unique sibling work\n") + def nested_component_update(self, attached): child = self.add_submodule() inner = self.root / "inner" @@ -239,6 +267,19 @@ class TaskLifecycleTests(unittest.TestCase): self.assertEqual(self.git(nested, "rev-parse", "HEAD").stdout.strip(), latest) self.assertEqual((nested / "inner-content").read_text(), "inner v2\n") + def test_finish_preserves_linked_nested_component_worktree(self): + wt, nested, before, _ = self.nested_component_update(attached=False) + sibling = self.root / "nested-sibling" + self.git(nested, "worktree", "add", "--detach", str(sibling), "HEAD") + result = self.task(wt, "finish", check=False) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertTrue(wt.exists(), result.stdout) + self.assertEqual(self.git(nested, "rev-parse", "HEAD").stdout.strip(), before) + self.assertEqual(self.git(sibling, "rev-parse", "HEAD").stdout.strip(), before) + self.assertEqual(self.git(sibling, "status", "--porcelain").stdout, "") + self.assertEqual((nested / "inner-content").read_text(), "inner v1\n") + self.assertEqual((sibling / "inner-content").read_text(), "inner v1\n") + def test_finish_clean_worktree_has_accurate_remote_result(self): wt = self.worktree() # A missing remote branch is not a successful remote deletion. @@ -261,6 +302,37 @@ class TaskLifecycleTests(unittest.TestCase): self.assertNotEqual(result.returncode, 0, result.stdout) self.assertTrue(wt.exists(), result.stdout) + def unmerged_task(self): + wt = self.worktree() + (wt / "tracked").write_text("unmerged task work\n") + self.git(wt, "commit", "-am", "Keep unmerged work") + self.git(wt, "push", "-u", "origin", "HEAD") + return wt, self.git(wt, "rev-parse", "HEAD").stdout.strip() + + def test_finish_abandon_retains_local_remote_tips_and_reason(self): + wt, head = self.unmerged_task() + reason = "superseded by a smaller task" + result = self.task(wt, "finish", "--abandon", reason) + self.assertFalse(wt.exists(), result.stdout) + self.assertEqual(self.git(self.repo, "rev-parse", "refs/heads/feature/test").stdout.strip(), head) + self.assertEqual(self.git(self.remote, "rev-parse", "refs/heads/feature/test").stdout.strip(), head) + note = self.git(self.repo, "notes", "--ref=refs/notes/task-abandon", "show", head).stdout + self.assertIn(reason, note) + self.assertIn("feature/test", note) + self.assertEqual(self.git(self.repo, "show", f"{head}:tracked").stdout, "unmerged task work\n") + + def test_finish_abandon_without_reason_preserves_checkout_and_refs(self): + wt, head = self.unmerged_task() + result = self.task(wt, "finish", "--abandon", check=False) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertTrue(wt.exists(), result.stdout) + self.assertEqual(self.git(wt, "rev-parse", "HEAD").stdout.strip(), head) + self.assertEqual(self.git(self.repo, "rev-parse", "refs/heads/feature/test").stdout.strip(), head) + self.assertEqual(self.git(self.remote, "rev-parse", "refs/heads/feature/test").stdout.strip(), head) + self.assertEqual(self.git(wt, "status", "--porcelain").stdout, "") + self.assertNotEqual(self.git(self.repo, "notes", "--ref=refs/notes/task-abandon", "show", head, + check=False).returncode, 0) + def test_finish_deletes_only_merged_remote_branch(self): wt = self.worktree() self.git(wt, "push", "-u", "origin", "HEAD") @@ -316,6 +388,130 @@ class TaskLifecycleTests(unittest.TestCase): self.assertNotIn("[synced]", result.stdout) self.assertIn(".task/feature-test.md", self.git(wt, "status", "--porcelain").stdout) + def task_card(self, wt): + card = wt / ".task/feature-test.md" + card.parent.mkdir(exist_ok=True) + card.write_text("# Task\n") + self.git(wt, "add", ".task") + self.git(wt, "commit", "-m", "Create task card") + return card + + def capture_evidence(self, wt, command="printf 'checked\\n'"): + card = self.task_card(wt) + self.run_cmd(wt, "bash", "scripts/evidence.sh", env=self.env | {"CMD": command}) + return card + + def commit_evidence(self, wt): + self.git(wt, "add", ".task") + self.git(wt, "commit", "-m", "Record evidence") + + def test_sync_warns_when_json_evidence_predates_noncard_changes(self): + wt = self.worktree() + self.capture_evidence(wt) + self.commit_evidence(wt) + self.advance_remote() + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + self.assertIn("重跑", result.stdout) + + def test_sync_keeps_json_evidence_fresh_after_metadata_only_changes(self): + wt = self.worktree() + self.capture_evidence(wt) + # A second run sees only the first run's uncommitted card receipt. + self.run_cmd(wt, "bash", "scripts/evidence.sh", env=self.env | {"CMD": "true"}) + self.commit_evidence(wt) + (self.repo / ".task").mkdir() + (self.repo / ".task/other.md").write_text("Other task metadata\n") + self.git(self.repo, "add", ".task") + self.git(self.repo, "commit", "-m", "Record other task") + self.git(self.repo, "push", "origin", "main") + result = self.task(wt, "sync") + self.assertNotIn("[evidence] WARN", result.stdout) + + def test_sync_warns_when_json_before_state_contains_uncommitted_code(self): + wt = self.worktree() + (wt / "tracked").write_text("uncommitted code\n") + self.capture_evidence(wt, command="git restore tracked") + self.commit_evidence(wt) + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + self.assertIn("unverified", result.stdout) + + def test_sync_warns_when_json_after_state_contains_uncommitted_code(self): + wt = self.worktree() + self.capture_evidence(wt, command="printf 'uncommitted code\\n' > tracked") + self.git(wt, "restore", "tracked") + self.commit_evidence(wt) + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + self.assertIn("unverified", result.stdout) + + def test_sync_does_not_execute_json_receipt_command(self): + wt = self.worktree() + sentinel = self.root / "command-was-executed" + self.capture_evidence(wt, command="printf ran > " + shlex.quote(str(sentinel))) + self.assertTrue(sentinel.is_file()) + sentinel.unlink() + self.commit_evidence(wt) + self.task(wt, "sync") + self.assertFalse(sentinel.exists()) + + def rewrite_receipt(self, card, change): + prefix, block = card.read_text().split("```json\n", 1) + record, suffix = block.split("\n```", 1) + receipt = json.loads(record) + change(receipt) + receipt.pop("receipt_sha256") + serialized = json.dumps(receipt, sort_keys=True, ensure_ascii=False, separators=(",", ":")) + receipt["receipt_sha256"] = hashlib.sha256(serialized.encode()).hexdigest() + card.write_text(prefix + "```json\n" + json.dumps(receipt) + "\n```" + suffix) + + def test_sync_warns_for_unresolved_json_evidence_head(self): + wt = self.worktree() + card = self.capture_evidence(wt) + self.rewrite_receipt(card, lambda receipt: receipt["before"].update(head="0" * 40)) + self.commit_evidence(wt) + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + self.assertIn("unverified", result.stdout) + + def test_sync_warns_for_missing_json_receipt_fields_even_with_valid_checksum(self): + wt = self.worktree() + card = self.capture_evidence(wt) + self.rewrite_receipt(card, lambda receipt: receipt.pop("command")) + self.commit_evidence(wt) + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + self.assertIn("unverified", result.stdout) + + def test_sync_warns_for_malformed_json_evidence(self): + wt = self.worktree() + card = self.task_card(wt) + card.write_text(card.read_text() + '\n```json\n{"schema": 1, invalid}\n```\n') + self.commit_evidence(wt) + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + self.assertIn("unverified", result.stdout) + + def test_sync_warns_for_unresolved_legacy_evidence_head(self): + wt = self.worktree() + card = self.task_card(wt) + card.write_text(card.read_text() + "\n| 2026-10-05T00:00:00Z | check | `0000000000` | 0 | SELF | abc |\n") + self.commit_evidence(wt) + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + self.assertIn("unverified", result.stdout) + + def test_sync_still_warns_for_stale_legacy_table_evidence(self): + wt = self.worktree() + card = self.task_card(wt) + head = self.git(wt, "rev-parse", "--short=10", "HEAD").stdout.strip() + card.write_text(card.read_text() + f"\n| 2026-10-05T00:00:00Z | check | `{head}` | 0 | SELF | abc |\n") + self.commit_evidence(wt) + self.advance_remote() + result = self.task(wt, "sync") + self.assertIn("[evidence] WARN", result.stdout) + def test_finish_preserves_main_and_active_index_lock(self): result = self.task(self.repo, "finish", check=False) self.assertNotEqual(result.returncode, 0, result.stdout)