Keep fixed-candidate evidence outside the measured checkout

Why: recording checks in a frozen task card can change the candidate and invalidate current-head CI.

Evidence: SELF fixed-candidate capture regression and all 33 evidence tests passed; actual output and object digests are preserved by make evidence.

Impact: document preparation, external receipts and post-phase import using existing schema 1; no filesystem freeze or trust upgrade is introduced.

Refs: U3; policy/governance.md; .task/feature-merge-queue-policy-draft.md
This commit is contained in:
2026-10-13 07:53:47 +00:00
parent eb46bbb296
commit 1024c389f6
2 changed files with 50 additions and 2 deletions
+34 -2
View File
@@ -20,10 +20,23 @@ make task-start NAME=feature/my-task PRECHECK_RECEIPT=/tmp/my-task-precheck.json
同一收据不可覆盖。首次检查失败时处理原因,使用新路径重新启动。主干在两步间前进时,
重新确认新的启动基线,不能把旧收据移花接木到新对象。
恢复已有任务仍先捕获本次启动检查,再在原任务工作区用
`IMPORT_RECEIPT=/tmp/my-task-resume.json make evidence` 导入;不重新建分支。
恢复已有登记任务先捕获本次启动检查,再在原任务 worktree 用
`make task-resume PRECHECK_RECEIPT=/tmp/my-task-resume.json` 验证并原样导入;不重新建分支。
默认 `TASK_WORK_MODE=delivery`,继续要求严格 READY 和当前目标一致。
工作区忙或落后时先由 owner 保存现场并同步;远端不可达时只继续不依赖新鲜基线的阅读和分析。
局部恢复接口已具备,流程启用仍以 [合入调度](merge-queue.md#采纳顺序与停止条件) 的采纳条件为准。
启用后,既有任务可以显式选择 local,保持原 R0,标记落后,继续已授权局部工作:
```bash
TASK_WORK_MODE=local RECEIPT=/tmp/my-local-resume.json CMD="make precheck" make evidence
TASK_WORK_MODE=local make task-resume PRECHECK_RECEIPT=/tmp/my-local-resume.json
```
LOCAL_READY 只用于局部恢复;新任务入口始终校验严格 READY,正式验收与合入另行同步。
恢复核验实际 worktree/卡片/分支、R0 祖先关系及源码外原始收据;脏现场、Git 操作、组件漂移和未知远端仍拒绝。
旧收据允许作为历史证据原样导入,不自动成为当前恢复或交付准入;格式继续为 schema 1。
堆叠任务使用 `PARENT=feature/parent PARENT_PR=<父PR链接>`。父分支须包含本批主干 R0;
卡片同时记录父分支、父 SHA 和父 PR。父先合入,子同步最新 main 并改回 main 为 PR base。
@@ -37,6 +50,9 @@ make task-start NAME=feature/my-task PRECHECK_RECEIPT=/tmp/my-task-precheck.json
它是组合测试和构建的前置检查。父仓未提交改动可以局部测试,但证据必须记录实际对象状态;
正式验收使用已提交的固定对象,不能仅写一个与工作树不同的 HEAD。
`task-sync` 对同一基线重复调用只核验,保留 HEAD、索引和卡片;实际合并新目标才追加一次记录。
输出完整 sync_base、记录完成后的 tested_head、checked_at 及 changed;changed 表示是否实际纳入新目标,组件仍须核对。
## 本地记录与独立证据
本地 `make evidence` 一律生成 SELF。`SRC=GATE/REPLAY` 不可把本地执行升级为权威来源。
@@ -51,6 +67,22 @@ PR 合入由智能体执行:先完成有效 Review,再同步并解决冲突
命令含敏感值时展示脱敏形式,并记录原命令摘要。执行前后对象分别记录;命令改变 HEAD
时不把执行前 SHA 冒充执行后对象。不能读取执行后状态时明确记录缺项。
### 候选固定前后
固定前,完成同步、必要检查、任务卡及本地收据提交,核对干净的组件组合,再读取和推送最终 HEAD。
将这个 head、base、完整组件及相关配置引用到调度尝试;任务卡表内“记录前对象”不当作最终候选。
固定后,本地命令使用源码外唯一 RECEIPT 保存完整输出,平台 CI/Review/合入结果写调度记录:
```bash
RECEIPT=/tmp/my-attempt-worktree-check.json CMD="make test-worktree" make evidence
```
执行者选择位于当前 checkout 和 Git 元数据之外的未用绝对路径,工具保留 before/after、原命令退出码和 SELF 来源。
这是 manual 流程,工具不提供工作树冻结或路径范围的 OS 强制隔离。命令改变源码、组件或相关配置时,
保留实际记录,重新建立尝试及受影响验证;新增提交必须核验新 HEAD 的必需 CI。
后续实际合入/清理后按授权闭合任务,再原样导入已保存收据;不向仍冻结的候选追加记录提交或补写未来结果。
凭据从环境或受保护文件引用,避免出现在命令字面量。脱敏是补充防护,不是允许输出秘密。
执行脚本不通过 shell tracing 暴露环境;管道任何一段失败应传回非零退出码。
工具写入失败本身也必须报错,不能只保留一个看似成功的退出状态。
+16
View File
@@ -109,6 +109,22 @@ class EvidenceTests(unittest.TestCase):
VALIDATE_RECEIPT_PURPOSE="resume-local")
self.assertEqual(data["output"], "unset")
def test_fixed_candidate_capture_preserves_checkout(self):
self.git("add", ".task/main.md")
self.git("commit", "-qm", "Save fixture card before validation")
head = self.git("rev-parse", "HEAD")
card = self.card.read_bytes()
index = self.git("ls-files", "--stage")
data = self.capture("printf 'fixed candidate check\\n'")
self.assertEqual(data["before"]["head"], head)
self.assertEqual(data["after"]["head"], head)
self.assertEqual(data["output"], "fixed candidate check\n")
self.assertEqual(self.git("rev-parse", "HEAD"), head)
self.assertEqual(self.git("ls-files", "--stage"), index)
self.assertEqual(self.card.read_bytes(), card)
self.assertEqual(self.git("status", "--porcelain"), "")
self.assertEqual(self.receipt.stat().st_mode & 0o777, 0o600)
def test_capture_without_card_and_import_without_rerun(self):
self.card.unlink()
data = self.capture("printf 'once\\n' >> invocation; cat invocation")