Skip to content

fix(bin): support pipeline-owned rebase restamps in receipt sealing - #111

Merged
dnth merged 7 commits into
mainfrom
fm/fm-receipt-rebase-restamp-completion
Sep 5, 2026
Merged

dnth merged 7 commits into
mainfrom
fm/fm-receipt-rebase-restamp-completion

Conversation

@dnth

@dnth dnth commented Sep 5, 2026 •

Copy link
Copy Markdown
Owner

Intent

Fix bin/fm-receipt-check.sh so --bind-run and --complete can seal a genuinely-passed full-no-mistakes run when the no-mistakes pipeline's rebase step RE-STAMPS the entire commit chain (same trees, new committer stamps, therefore new SHAs), which the already-merged PR #105 does not cover.

Context: PR #105 handles only the head advancing by NEW commits landed ON TOP of the validated head, permitting current_head != validated_head when validated_head is still an ancestor of current_head. This distinct facet: the rebase step re-commits every branch commit with the same tree and a new committer stamp, producing new SHAs for the whole chain, so validated_head is no longer an ancestor of current_head at all, the descendant check fails, and --bind-run also fails earlier because the run's observed head no longer resolves to the planned validated head. Hit live on task port-3690-3614-e2e-test: run 01M1RW6JNH5C5VN15PPRYDW3J0 reported head bd8aaff5 while the planned head was 874ce334; both carry tree f7d8fa3a and git merge-base --is-ancestor 874ce334 bd8aaff5 exits 1.

Required behavior: recognize a PIPELINE-OWNED rebase-restamp as authoritative. When the bound, genuinely-passed run reports a rewritten head whose CONTENT is identical to the validated chain, accept it for both bind and complete.

CRITICAL safety invariant that must be preserved and tested: still REFUSE when the rewritten or advanced chain's content is NOT identical to the validated content (any foreign change), when the run did not genuinely pass, or when the rewrite is not owned by the bound pipeline run. This must not become a hole that lets unvalidated content complete. Do NOT weaken PR #105's existing on-top-descendant path; add the rewrite case alongside it.

Acceptance criteria:

  • AC1: --bind-run and --complete seal a genuinely-passed full-no-mistakes run whose branch head was rewritten by the pipeline's rebase (same trees, new SHAs, validated_head no longer an ancestor), WITHOUT a fresh no-mistakes run. Reproduce the exact rebase-restamp scenario in a colocated test and show bind plus complete now succeed.
  • AC2: The safety invariant is preserved and tested. Colocated tests cover both the accept case (content-identical pipeline rewrite) and the refuse cases (any content difference, a run that did not pass, a rewrite the bound run does not own).
  • AC3: PR fix(bin): seal terminal runs after pipeline-owned head advances #105's existing on-top-descendant completion path is unchanged and still works, existing fm-receipt-check tests pass, and touched bin/ scripts are shellcheck-clean.
  • AC4: A short reconciliation note records what changed vs PR fix(bin): seal terminal runs after pipeline-owned head advances #105, the exact checks relaxed (--bind-run head-match, --complete descendant), and the content-identity mechanism chosen to keep foreign drift refused.

Constraints: this edits firstmate's shared tracked bin/, so the firstmate-coding-guidelines apply (shellcheck-clean bin scripts via bin/fm-lint.sh, colocated tests in tests/ extending the existing runner, one sentence per line in tracked Markdown, plain dash, no agent commit co-author, maintainer-verification evidence under docs/verification/).

Firstmate-Validation-Generation: 4a06de7b3bb4869c8c688896b75f1033

What Changed

  • Added faithful chain restamp detection that compares validation-base ancestry, commit count, and per-commit trees.
  • Updated receipt binding and completion to accept pipeline-owned, content-identical rebase restamps while preserving pass, branch ownership, and foreign-drift checks.
  • Added comprehensive restamp acceptance/refusal coverage and documented reconciliation with the existing descendant-advance behavior.

Risk Assessment

⚠️ Medium: The change is substantively bounded and preserves the existing descendant path, but introduces complex shell-based chain provenance and ownership logic in a security-sensitive completion boundary.

Testing

Ran the focused fm-receipt-check behavioral suite, including accepted pipeline restamps, provenance/foreign-content refusals, ownership refusals, non-passed runs, and existing descendant paths; all completed successfully with exit code 0. CLI transcript saved as evidence.

Evidence: Receipt-check behavioral test transcript
ok - fm-receipt-check help renders an executable generation-bound bind command
ok - fm-receipt-check reports required, evidenced, and missing ids deterministically
ok - fm-receipt-check distinguishes complete evidence from invalid JSONL
ok - structured success and negative outcomes control criterion evidence
ok - pinned brief and metadata delivery modes must match exactly
ok - pinned metadata owner rejects hard-linked validation records
ok - invalid ship briefs fail and scout/report behavior stays unchanged
ok - early snapshot failures release cleanup without a FIFO reader
ok - snapshot readiness publication failures terminate without waiting
ok - fm-receipt-check pins task evidence and rejects hard-linked ledgers
ok - receipt append and check consume one criterion grammar
ok - exact bound runs complete from the shared current CI-log readiness predicate
ok - finding-to-criterion invalidations remain inspectable in task metadata
ok - run binding resolves abbreviated heads and rejects non-planned commits
ok - binding and completion work against the real agent-supplied intent-log shape while wrong runs fail closed
ok - completion accepts only active pipeline-owned descendant heads
ok - terminal passed runs seal their own pipeline advance and refuse foreign drift
ok - pipeline rebase restamps bind and seal their validated content
ok - restamped chains enforce provenance and ownership
ok - low-risk mechanical changes can skip a full No-Mistakes run
ok - low risk requires safe changelog prose and file-bound mechanical evidence
ok - implementation completion refreshes per head and remains idempotent
ok - plan publication holds the pinned ledger boundary against concurrent receipts
ok - diff summary errors fail closed before risk classification
ok - successful terminal runs bind while failed runs remain rejected
ok - No-Mistakes status and CI-log observations are bounded
ok - authoritative documentation remains high
ok - terminal delivery paths record one completion timestamp at their boundary
ok - completion signals release the validation lock for retry
ok - replanning invalidates prior run and completion bindings
ok - dirty worktrees cannot be planned or completed
ok - git status errors fail implementation, planning, and completion cleanliness gates
ok - shared cleanliness inspects ignored submodules
ok - direct and local plans never invoke No-Mistakes
ok - local completion requires fast-forward readiness
ok - local readiness and landing share one fail-closed default resolver
ok - security and uncertain changes retain full No-Mistakes validation
ok - direct-PR and local-only retain evidence gates without invoking No-Mistakes
EXIT:0

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed (3) ✅
  • 🚨 bin/fm-receipt-check.sh:833 - The new tree-equality fallback does not prove that a rewritten head is the bound pipeline run's restamped chain. For example, create an unrelated commit from another parent with the same tip tree as validated_head, bind a passed run reporting that commit, and leave the worktree at it: lines 832-834 accept it because fm_nm_head_content_identical passes, then the same-branch/terminal checks complete it even though the run does not own that rewrite. The same tip-tree check also permits foreign changes that are later reverted. This contradicts the required safety invariant: “still REFUSE ... when the rewrite is not owned by the bound pipeline run” and “any foreign change.” The rewrite path needs provenance/chain-content validation at the earliest shared boundary, not only final-tip tree identity.

🔧 Fix: Enforce faithful chain provenance for restamped heads
1 error still open:

  • 🚨 bin/fm-receipt-check.sh:827 - The rewrite ownership checks are skipped whenever current_head == validated_head (lines 827-854). A bound run can report a faithful restamped head, while custody has returned the worktree to the validated head, and run_out.branch can name another branch (or an active run can have non-pipeline_owned sync); the accounting predicate passes and the branch/ownership checks are never reached, so --complete seals a rewrite the bound pipeline run does not own. This contradicts the required safety invariant to refuse “when the rewrite is not owned by the bound pipeline run.” Apply the ownership/branch checks to the restamp case even when the current head equals the validated head, or otherwise establish an equivalent shared ownership proof.

🔧 Fix: Enforce ownership checks for custody-returned restamps
2 issues (1 error, 1 warning) still open:

  • 🚨 bin/fm-nm-run-lib.sh:114 - fm_nm_head_is_faithful_restamp populates arrays with Bash mapfile, which is unavailable in the stock macOS Bash 3.2 supported by this repository. Any genuine restamp bind/complete on macOS therefore fails closed despite valid input; replace this with a Bash-3.2-compatible read loop.
  • ⚠️ tests/fm-receipt-check.test.sh:1116 - The required regression coverage is incomplete: the new tests do not exercise refusal of (1) an unrelated same-tree tip from a different parent, (2) a foreign commit later reverted so the tip tree matches, or (3) a rebase onto a newer base with changed trees. These cases are specifically required to validate the chain-provenance invariant beyond the single foreign-tip edit covered here.

🔧 Fix: Ensure Bash 3.2 compatibility and adversarial restamp coverage
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-receipt-check.test.sh
✅ **Document** - passed

✅ No issues found.

🔧 **Lint** - 1 issue found → auto-fixed ✅
  • ⚠️ linter found issues (exit code 1)

🔧 Fix: Replaced unsafe cherry-pick command substitution with Bash-compatible loop
✅ Re-checked - no issues remain.

✅ **Push** - passed

✅ No issues found.

dnth added 7 commits September 5, 2026 22:44
The no-mistakes rebase step re-commits every branch commit with a fresh
committer stamp. Every tree stays byte-identical, but the whole chain gets
new object ids, so the planned implementation head stops being an ancestor
of anything the run reports. `--bind-run` then refused the run because its
head no longer resolved to the planned head, and `--complete` refused it
because the current head was not a descendant of the planned head. A
genuinely passed run could not seal without a replan and a fresh run.

Accept that shape through content identity. `fm_nm_head_content_identical`
compares the tree object Git already computes for each commit: it holds for
a pure restamp and breaks on any change to any tracked file. `--bind-run`
now accepts a run head recording the planned head's tree and records that
restamped head; `--complete` accepts a run head recording the current head's
tree, and a current head recording the planned head's tree.

Every other requirement is unchanged. The run must still be the bound run at
the current generation, still be genuinely passed or checks-green, still
report the current worktree branch with pipeline ownership while active, and
still be terminal PASSED otherwise. The descendant-advance path added for
commits landed on top of the validated head keeps its exact behavior.

Claude-Session: https://claude.ai/code/session_01WGckfiJn9GAx7n4jCJYntc
…base only for full-no-mistakes completion, preserving direct-PR/local completion paths that legitimately lack it. Verified with fm-pr-check-security, fm-receipt-check, bin/fm-lint.sh, and git diff --check
@dnth
dnth merged commit 61923ed into main Sep 5, 2026
16 checks passed
@dnth
dnth deleted the fm/fm-receipt-rebase-restamp-completion branch September 5, 2026 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant