fix: verify archived captain decisions after retention#905
Open
codenum137 wants to merge 11 commits into
Open
Conversation
added 11 commits
July 23, 2026 15:44
Open
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
complete,verify, and identicalresolveretries work after a captain decision is retained, whileholdcannot recreate an archived resolution.Risk Assessment
✅ Low: Captain, the CR rejection now closes the parser-normalization gap without changing writer or lifecycle semantics, and no remaining material source defect was substantiated.
Testing
已核对目标 SHA,聚焦回归通过;真实 CLI 流程完成 retention 后的三条调用路径,持久化证据与篡改负控符合预期,并用 base commit 在同一状态复现原失败。测试残留已清理;按要求未运行 lint、formatter 或静态分析,此 CLI 变更无 UI 截图适用。
Evidence: 目标提交端到端 CLI 记录
active_lookup_exit=1 complete: sample-archive-review decision inventory reviewed (route) verified: sample-archive-review unresolved-decision inventory resolved: sample-archive-review-decision-route archive SHA-256 unchanged tampered_verify_exit=1 E2E_RESULT=PASSEvidence: 基线提交反事实
Base commit reports the archived decision absent from backlog.md and exits 1 on the same retained state.Evidence: Retention 后的持久化 archive
Evidence: Retention 后的 active backlog
Pipeline
Updates from git push no-mistakes
⏭️ **intent** - skipped
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 4 issues found → auto-fixed (3) ✅
bin/fm-decision-hold.sh:327-active_identity_counttreats every non-regular backlog path as an empty store because[ -f ]is also false for directories, FIFOs, and broken symlinks. Archived verification can therefore succeed and permit scout cleanup while the active backlog is invalid and was never checked for collisions. Return zero only when the path is genuinely absent; reject unsafe or unreadable active-store paths.bin/fm-decision-hold.sh:396-hold_reasonis still TOON-encoded. A malformed archived header containing(hold: ) (hold-kind: captain)yields an empty reason rendered as""; both shell predicates pass, so the record is accepted. Decode the field or explicitly reject the encoded empty value.bin/fm-decision-hold.sh:280- The extractor accepts non-empty whitespace-only raw lines, which tasks-axi normalizes to empty lines before digest validation. Changing a canonical blank decision line to spaces therefore produces a stable archive that still verifies, contradicting the lossless canonical-record contract. Reject whitespace-only raw lines or validate the extracted record before parsing.bin/fm-decision-hold.sh:505- The active identity is rechecked beforeverify_archived_resolution, but that validation invokes another hash subprocess and the final pass checks only the archive. A concurrent insertion of the same active ID during that window can leave an active/archive collision while lookup returns success. Repeat the active check after final structured/archive validation or use a coherent store lock.🔧 Fix: Harden archive-aware decision verification
1 error still open:
bin/fm-decision-hold.sh:403- The new decode loses the distinction between TOON's missing sentinel-and the valid quoted value"-". Bothcommand_holdand tasks-axi accept--reason -; after retention, this block decodes"-"to-and line 408 rejects it, making a writer-created decision unusable by complete, verify, resolve retry, and scout teardown. Check the raw unquoted sentinel before decoding, then reject only a decoded empty string.🔧 Fix: Preserve quoted dash hold reasons
1 error still open:
bin/fm-decision-hold.sh:249-semanticLinestrips trailing carriage returns whileextractRecordaccepts and copies CR-terminated nonblank lines into the parser view. Because tasks-axi also strips those carriage returns, changing an archived decision line from LF to CRLF leaves the parsed decision and digest unchanged, allowing a byte-corrupted archive to verify. Reject carriage returns anywhere in the extracted record before parsing.🔧 Fix: Reject carriage returns in archived decisions
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
git status --short --branch && git rev-parse HEAD && git branch --show-currentgit diff --name-status bd43c73fc956af2c7dfddd8ba74bab214a3012c0 c7314195f61e05cbce6fa7cba54df6bd71349aecbin/fm-test-run.sh tests/fm-decision-hold-lifecycle.test.shbash .tmp-archive-aware-evidence.sh(临时驱动已删除;使用真实tasks-axi 0.2.3完成 hold、resolve、retention、归档后重试及篡改负控)FM_HOME=<baseline-counterfactual-home> bash <base-code>/fm-decision-hold.sh verify sample-archive-review证据完整性检查:身份计数、archive SHA-256、关键 transcript 行及最终git status --short✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.