Repository navigation
Ticket 0009: anchor reconcile, the first consumer of anchors (+ P2 remediation from #318/#319) - #320
Conversation
cog anchor reconcile: scan a tree for sealed bundles, fold the anchor log into an AnchorSet projection (BTreeSet, exhaustive Payload match), and anchor exactly the sealed-but-unanchored remainder. Idempotent by construction; a tampered log refuses reconciliation. Detection keys on the four witness manifest filenames and reuses the emitters' per-kind AnchorRequest builders; roots are re-validated (64 lowercase hex) because reconcile, unlike the live emitters, anchors bundles it did not verify. Reviewer fix: reconcile-side kernel profile gate — the kernel request builder debug-asserts a profile that untrusted on-disk manifests can violate. P2 remediation (codex bot review of #318/#319): - complete --anchor-key/--anchor-log flags no longer consult deadbolt-anchor.toml, so a malformed config cannot veto explicit paths - anchor init preflights the log path before minting a key, and removes the freshly minted key if the log open still fails - no stranded keys - the kernel anchor gate runs the CLI verifier's source-artifact preflight, refusing symlinked sources the library verifier would follow - pending-anchor markers moved beside the run directory (<run>.pending-anchor.json): anchoring debt is operational state, not evidence, and the observation verifier rightly refuses foreign files inside sealed bundles Implemented by Codex (gpt-5.5) from the 0009 ticket; review, P2 fixes, and validation by Claude. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4dcca9793c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| pub(crate) fn pending_anchor_marker_path(run: &Path) -> PathBuf { | ||
| match (run.parent(), run.file_name().and_then(|name| name.to_str())) { | ||
| (Some(parent), Some(name)) => parent.join(format!("{name}.{PENDING_ANCHOR_FILE}")), |
There was a problem hiding this comment.
Clear sibling pending markers after successful seals
When the marker is moved beside the run directory, rerunning a previously failed observation/codelet/transaction seal with a valid anchor configuration no longer overwrites or removes the old <run>.pending-anchor.json; those success paths return Anchored without calling delete_pending_anchor_marker_if_present (kernel has a separate stale-marker cleanup). This leaves operational debt visible even though the bundle has just been anchored, so the non-kernel seal paths should clear the sibling marker on successful anchoring as reconcile does.
Useful? React with 👍 / 👎.
| } | ||
| }; | ||
|
|
||
| if !is_lower_hex_64(&request.witness_root) { |
There was a problem hiding this comment.
Verify bundles before anchoring them
For a scanned bundle whose evidence was tampered after sealing, this path builds an AnchorRequest and only checks that the requested root is lowercase hex before appending it. For example, changing witness_root.txt in an observation/codelet/transaction bundle to any other 64-character lowercase hex value is caught by the normal bundle verifiers as witness_root_mismatch, but reconcile will still anchor that false root because it never runs those verifiers before this format check. Reconcile should gate each candidate with the same per-kind verification used by the live seal paths before writing an anchor.
Useful? React with 👍 / 👎.
P1 (codex bot, PR #320 review): reconcile built an AnchorRequest from what the bundle claimed and only shape-checked the root, so evidence tampered after sealing - e.g. witness_root.txt rewritten to a different 64-hex value - would be anchored even though every live seal path re-verifies before anchoring. Reconcile now gates each candidate with the same per-kind verifier the emitters use (kernel via a shared verify_kernel_witness_for_anchor so the two gates cannot drift). New verify_failed summary count; verification failures force nonzero exit - tampered evidence must be loud. Already-anchored roots skip verification: their anchor was recorded at a verified moment. Reconcile tests now seal REAL observation/kernel bundles instead of hand-built manifests, plus a tamper test proving a re-rooted bundle is refused while valid bundles still anchor. P2 (codex bot): a successful anchor now pays off the run's stale sibling pending-anchor marker in all four emitters (shared anchored_outcome), not just via kernel's build-time stale cleanup. Also drops the per-anchor full-log replay: same-root dedupe within a run now uses a local BTreeSet of newly anchored roots. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ticket 0009:
cog anchor reconcileScans a directory tree for sealed bundles, folds the anchor log into an
AnchorSetprojection, and anchors exactly the sealed-but-unanchored remainder. Idempotent by construction: the second run anchors nothing. Deliberately the first consumer of anchors — it validates the seam by using it.AnchorSet(cog-anchor):BTreeSetfold overLogReader::replay; exhaustivePayloadmatch (no_ => {}); replay verifies the chain first, so a tampered log refuses to reconcile.read_verifying_key(cog-anchor): read-side companion togenerate_key_file, same 64-lowercase-hex rules.AnchorRequestbuilders (visibility bump only) — single source of truth for manifest→request. Roots are re-validated reconcile-side (64 lowercase hex) because reconcile anchors bundles it did not just verify.P2 remediation (codex bot review of #318/#319)
--anchor-key/--anchor-logno longer consultdeadbolt-anchor.toml, so a malformed config cannot veto explicit paths.cog verify kernel-witness.<run>.pending-anchor.json. Anchoring debt is operational state, not evidence; the observation verifier'"'"'s strictuncommitted_artifact_presentno longer fails a sealed bundle whose anchor attempt failed. Kernel stale-artifact clearing follows the marker.Validation (run on Windows by the reviewer)
cargo test -p cog-anchor: 9/9 pass (incl. tamper-refusal)cargo test -p cog-cli: 545 pass / 7 fail — the 7 are the known pre-existingstyle_plansnapshot failures on native Windows, identical on clean maincargo tree -i magpie-log:cog-anchorremains the sole direct dependent (pin7c7f043unchanged)Codex (gpt-5.5) implemented ticket 0009 (
.agent-runs/20260705T093018Z-1991177716); Claude reviewed, applied the reviewer fix and P2 remediations, and ran validation. Merge is George'"'"'s call, as always.🤖 Generated with Claude Code