Repository navigation
[AI:claude] feat(gate): M1 slice 2 - holds on the gate ledger, single writer (Refs STORY-B6B1278890774EF993D2EBC327862470-080) - #3106
Conversation
… gate ledger only (Refs STORY-B6B1278890774EF993D2EBC327862470-080) Work in progress, not ready for review. The library compiles. About 119 lib tests still assert legacy files and need updating. - Holds, releases, label sync and auto-release authorization/withdrawal are now hold-family events on the ledger (gate/ledger/hold.rs). - Legacy markers are read through. - The verdict funnel writes to the ledger only. A spec with no change has an unbound by-spec ledger. - The archive and sidecar-migration writers are deleted. - The writer ratchet is now 0, with an atomic-writer allowlist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…seat (Refs STORY-B6B1278890774EF993D2EBC327862470-080) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dger state; fail-closed legacy history checks (Refs STORY-B6B1278890774EF993D2EBC327862470-080) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… writer (Refs STORY-B6B1278890774EF993D2EBC327862470-080) Finish slice 2: a placement through merge_hold_core supersedes a pending auto-release authorization with an explicit release-withdrawn event instead of the fold voiding it on every hold event, so a raw hold change is refused and withdrawn on the PR (TASK-1757). Register gate/hold_collect.rs as a gate kernel, and retarget the remaining tests that read legacy verdict files to the ledger. Fail-closed expectations are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review: PR-3106 — round 1, RequestChanges at
|
| Spec | Verdict | Evidence |
|---|---|---|
| STORY-…-080 (M1 slice 2) | Holds and verdicts are on the ledger as briefed. CI is red, an uncontained reviewer's verdict is not collected, and the new launcher-armed refusal hold has no test. |
Acceptance status (slice 2 scope)
- AC1 ledger events:
holdandhold-releasecarry the head and patch identity. Verified bya_release_appends_and_keeps_the_hold_as_evidence. The mandate-cover and carry-over events are not applicable here because they belong to slice 3. - AC2 change as the only key / spec index: verified by
a_pr_keyed_verdict_write_lands_on_the_change_and_a_spec_keyed_one_on_the_spec. Unbound by-spec entries are accepted under ruling (a). - AC3 a release appends and never deletes; the mandate and awaiting read the ledger: verified by
a_release_appends_and_keeps_the_hold_as_evidenceanda_cleared_hold_is_read_from_the_ledger_without_a_marker. - AC4 carry-over: not applicable because it is slice 3.
- AC5 only uncontained writers append: partial. The contained refusal is tested (
a_contained_writer_is_refused_and_leaves_nothing_in_its_worktree). An uncontained standalone reviewer's verdict is no longer collected, and the hand-off file stays in the seat clone. - AC6 read-through, old writers deleted, ratchet: verified by
legacy_markers_are_read_through_until_the_ledger_answers,verdict_and_hold_writers_write_no_legacy_file, the writer ratchet with its baselines at 0, and themerge-holds/merge-hold-clearancesliteral baselines at 0. Integration tests and agent templates still read the legacy files. - AC7 lives in
gate/:hold_collectis registered in GATE_KERNELS. Unverified until CI's gates shard finishes. - Brief item 1 (hold readers on the ledger, rework release through the projection): verified in the code and by the retargeted story_1687 and bug_2186 tests.
- Brief item 2 (single writer; collect and adopt append to the ledger only): verified by the code, with the collection gap below.
- Brief item 3 (ledger tie-break; spec-only verdicts on the ledger): verified by
the_ledger_answers_a_read_only_where_the_file_knows_less. - Brief item 4 (ratchets at 0): verified.
- Brief item 5 (fail-closed expectations unchanged): the bug_775 phase-3 and TASK-1801 expectations are untouched in the diff. Their pass/fail is unverified because the lib shards are red.
- Ruling (d) (a collected untyped marker becomes a typed Rework hold): verified by
a_collected_untyped_marker_becomes_a_typed_rework_hold.
Findings (complete list; all are in the verdict record)
- [major][CI] CI (cli-0), CI (lib-0) and CI (lib-1) failed in run 40964841522. These shards were green on main. The job logs cannot be read from the reviewer seat. The likely cli-0 cause is
aida-cli/tests/bug_2187_reviewer_record_identity.rs:199andbug_2201_outside_project_reviewer.rs:332, which read the legacy.aida/review-verdicts/PR-N.jsonthat slice 2 no longer writes. - [major]
collect_standalone_verdict(gate/review_verdict.rs:2372) collects only from files. An uncontained reviewer'saida review recordnow writes only to the ledger, so the launcher reports NoReviewVerdict and skipsarm_collected_refusal. - [major][strict-tier] No test covers
arm_collected_refusal, which is the contained reviewer's refusal path now. The tests for the old fallback were deleted. The source-order test still pins onlyadopt_worktree_hold. - [major][templates] Two prompts still read the legacy files:
templates/dispatch/take-prompt.md:3(a rework implementer readsreview-verdicts/PR-N*) and aida-review step 6a ("Read back AIDA_REVIEW_VERDICT_FILE"). Stale discipline docs:workflow-patterns.md:2186,git-sync-and-review.md:565/577,machinery-glossary.md:279/312anddocs/autonomous-drain.md:115. - [minor]
verdicts_for_shakeeps the last event per key in key-sorted order, not the newest by(at, seq). - [minor]
mandate_ship.rs:542: when the release fails, the code still posts the "released" comment and emits aplaced:falseevent, while the ledger hold stays open. - [minor]
record_label_stateappends alabel-syncevent even when the state is unchanged, so the ledger grows without bound. - [minor] The new contained checks use
aida_contained_env().unwrap_or(false), so a malformedAIDA_CONTAINEDis treated as uncontained (contrary to BUG-2146). - [minor][AC5] The contained hand-off verdict file is left in the seat clone after collection.
- [cosmetic] The hold lock path moved (
merge-hold-locks/PR-N.lock→<ledger>/PR-N.hold.lock). An older binary and this one do not lock each other out during rollout.
Recommendation: fix 1–4 in one rework push. 5–10 are small and can be bundled with them.
…uns uncontained, ledger-only verdicts collected (Refs STORY-B6B1278890774EF993D2EBC327862470-080)
PR-3106 round-1 ruling, all items in one push:
6 (blocking) aida queue work resolves containment from the [agents]
contained knob and exported AIDA_CONTAINED=1 on its OWN process for the
reviewer child, so its in-process collect refused ("a contained seat
cannot collect"). session::set_contained_env_for_children keeps the
inherited value; the ledger asks session::process_contained(), which
answers for this process. Test:
the_launchers_export_for_its_reviewer_does_not_contain_its_own_collection.
2 collect_standalone_verdict also takes an uncontained reviewer's
ledger-only record written after the launch (same PR/head/grant checks)
and the caller arms the refusal hold from it. Test:
an_uncontained_reviewers_ledger_only_refusal_is_collected_and_holds_the_pr.
3 arm_collected_refusal split into place_collected_refusal (ledger) + label
sync. Test: a_contained_reviewers_refusal_is_armed_by_the_launcher_and_its_hand_off_removed.
4 take-prompt, aida-review step 6a, discipline docs, autonomous-drain and
the generated glossary read verdicts via `aida review verdict --json` /
the ledger.
5 failed mandate release posts nothing; malformed AIDA_CONTAINED is
contained (process_contained fails closed); the seat hand-off file is
removed after collection; verdicts_for_sha orders by ledger (at, seq).
1 CI: bug_2187 asserts the ledger; bug_1452, story_1417, story_1655,
task_1458 and orchestrator_leases forge-seam fixtures retargeted to
ledger state (no assertion weakened). In the test binary,
process_contained reads AIDA_CONTAINED only under the env lock, so tests
without an env guard no longer race a sibling's contained window
(story_1687 auto_release_* flaked on it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round-1 rework (ec65dd9): all ruling items in one push
Local runs (this seat cannot read CI logs):
Accepted per ruling: item 7 (label-sync growth) and item 10 (hold-lock path during rollout). |
…fusal tests read ledger state (Refs STORY-B6B1278890774EF993D2EBC327862470-080) Both CI failures at ec65dd9 were the tests opening the legacy .aida/review-verdicts/<KEY>.json file, which slice 2 no longer writes: - story_078 node_alias_review_record_keys_the_verdict_under_the_canonical_id panicked "no verdict under the canonical id: []" because the legacy dir is empty. It now looks for the canonical id's gate-ledger by-spec index entry. Every other assertion is unchanged: no file names the alias, and the alias read-back still works. - queue_work_tests closed_refusal_does_not_count_as_outstanding panicked at the read_to_string(verdict_path).unwrap() in its fixture setup. It now closes the refusal through close_verdict_on_merge (the BUG-1529 path, ledger-appended). The AwaitingMerge assertion is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round-2 rework (5fb1323): both red tests fixedRoot cause. The ruling suspected alias keying and the refusal projection. Neither caused these failures. CI run 40976271233 shows both tests failing where they open the legacy
Deviation from the literal ruling. Keeping these tests byte-identical would mean writing the legacy file again. Slice-2 acceptance forbids that ("the story cannot complete with dual writes"). So I applied the 13:40 rule instead: retarget to the equivalent ledger state, and weaken nothing.
No production code changed. Validation limits in this seat. This sandbox mounts the cargo build-slot lock directory ( |
|
Update: the first targeted run eventually got a build slot and finished. |
Review: PR-3106 (round 3, head
|
| Spec | Verdict | Evidence |
|---|---|---|
| STORY-…-080 (M1 slice 2, Refs) | ✅ PASS | All slice-2 acceptance items and every round-1 and round-2 ruling item are verified (detail below) |
Slice-2 acceptance
- Holds are on the ledger, and releasing a hold appends an event. Verified by
merge_hold_core/story_1687/bug_2186tests.rework_hold_releasenow reads throughledger::project(rework_hold_release.rs:146,654). - There is one writer. The ratchet
legacy_gate_writers_do_not_gain_call_sites(gate/ledger/tests.rs:1402) checks that every writer in the GONE list (includinglocal_hold_pathandlocal_clearance_path) has 0 call sites.verdict_and_hold_writers_write_no_legacy_fileproves it at runtime. newer_ofgives a same-round tie to the ledger (review_verdict.rs:967-992). Spec-only records use theby-specindex;story_078covers this.- Writer baselines are 0.
write_verdict_atomicis allowed in two places, each with a stated reason: the contained hand-off and backfill-shas. Carry-over moves in slice 3. - The fail-closed expectations for TASK-1801 and bug_775 phase-3 are unchanged.
Round-1 items: CI is retargeted. The launcher collect now runs uncontained via session::process_contained and set_contained_env_for_children. A malformed AIDA_CONTAINED value is treated as contained (fail closed). A failed mandate release posts nothing. The hand-off file is removed after collection. verdicts_for_sha orders by ledger (at, seq). Templates and docs now use aida review verdict --json.
Round-2 items: The two red tests failed while reading the legacy fixture file in their own setup. The product was not at fault: the panic at queue_work_tests.rs:3684:47 was read_to_string(verdict_path).unwrap(). They now use ledger state: the by-spec index, and the real close_verdict_on_merge path. The assertions are unchanged. The alias still appears in no file, and reading back by alias still works.
AC4 (carry-over), AC7 subsumes: these belong to slice 3 (final slice) and are not applicable here.
CI: run 40981230917 passed at 5fb1323 (cli-0/1, lib-0/1, contracts, rest, gates). merge-hold-gate is red only because of the round-1 hold label, which this approval addresses. Because the spec is keystone-class, a human must clear the hold.
Non-blocking note: read_verdict_for_sha no longer lazily archives the embedded rounds of pre-TASK-1460 legacy files, because the migration was deleted. This repo already ran it (.archive-migrated is present), so nothing is lost here.
|
Finding filing pending (the contained reviewer seat cannot write the AIDA store): minor: legacy verdict files that still hold un-archived embedded |
M1 slice 2: holds on the gate ledger, single writer (Refs STORY-B6B1278890774EF993D2EBC327862470-080)
Slice 2 of 3 of the M1 gate ledger. Slice 1 (verdicts on the ledger, with dual write) shipped as #3090. This slice puts holds on the ledger and removes the dual write. Carry-over proof events (AC4) and superseding TASK-1992/TASK-1316/STORY-1375/TASK-2008/STORY-1683 are slice 3, the final slice.
What changes
hold,hold-release,release-authorized,release-withdrawnandlabel-syncevents (gate/ledger/hold.rs) replace the.aida/merge-holds/PR-Nmarkers and the.aida/merge-hold-clearances/files. A release appends an event and never deletes evidence. The ship-held mandate,aida awaiting, the merge-hold-gate label sync and rework auto-release read holds through the ledger fold, with read-through of existing legacy markers.write_verdict_object_for_spec,close_verdict_on_merge, the archive writer) are ledger-only. The per-commit archive write and the sidecar migration are deleted.local_hold_path,local_clearance_path,clear_holdandsuperseded_clearance_pathare deleted.collect_standalone_verdictandadopt_direct_writestay. They append ledger events only.by-spec/<SPEC>.jsonl(ruling (a) accepts this for slice 2).legacy_gate_writers_do_not_gain_call_sitesare 0, and themerge-holds/merge-hold-clearancesliteral baselines are 0.legacy=false).For the reviewer
gate/hold_collect.rs: the reviewer-worktree cleanup ingate/dispatch_*reaches hold collection only through this module. It is registered as a gate kernel instory_1888_gate_paths_tests::GATE_KERNELS, since it reaches outsidegate/only through gate paths.merge_hold_core(append_hold_record) now appends an explicitrelease-withdrawnbefore itsholdwhen an auto-release authorization is pending. This is the legacy "placement removes the clearance file" behavior.holdevent no longer voids the authorization inledger::hold::fold. The release path's second pass refuses the changed hold and posts "authorization withdrawn" on the PR (TASK-1757).prfield changed was appended to the other PR's ledger, so PR 37's hold looked unchanged. The fixture now appends that raw replacement to PR 37's ledger, as the legacy fixture rewrote PR 37's marker.task1801_record_refuses_to_rewrite_a_refused_archive_entry: one retained-history read moved fromRetainedHistory::besidetoRetainedHistory::projected.same_sha_recorded_twice_is_idempotent: the original assertions are kept: one commit in the per-sha view, and no manufacturedrounds. An "exactly one ledger event" count, added during retargeting, was dropped. A re-record stays its own event, because the phase-3 handshake counts only records written during the review session, so deduplicating re-records would fail a fresh review closed.current_verdict_body,verdict_events_at,ledger::hold::state). The fail-closed expectations (TASK-1801, bug_775 phase-3) are unchanged. Fixtures that hand-write a legacy file now create its directory first.Tests run in this seat
env -u AIDA_CONTAINED cargo test --profile agent -p aida-cli-lib --lib -- gate:: drain_gate pr_merge_gategave 1063 passed. All remaining failures are listed below. Follow-up targeted runs covered the fixed tests (rework_hold_release,gate::ledger,review_verdict,gate::mandate,story_1888,bug_775,task_1460,review_verdict_display), plus wider filters (phase_gates,human::,status_awaiting,pr_claim,lane_liveness,doctor,merge_hold).make check-ci-fastpassed.Not runnable in this sandboxed seat (CI is the gate for these):
test_env.rs:93("BUG-1642: could not install the hermetic test HOME: Read-only file system"):drain_gate::bug_2139…unresolved_root_refuses_before_queue_or_phase_mutationstory_1917_dispatch_flow_schedule_tests(native_pr_ship_*,native_train_held_member…,r5_dispatch_tick…)story_1698_mandate_tests::{bug_2179_…, task_1790_exclusion_special_files…, task_1951_store_history_walk…}task1801_replacing_validated_verdict_with_fifo_reads_open_inodebug_2123_tests::production_auto_release_reads_the_forge_hold_verdict_and_storesolo_reviewtestsphase_gates::real_phase_driver_wiring_testsdoctor_cmdteststask_2344_q1_failed_rollback_is_fenced…: a dispatch tick lock held by another process in this seat.bug_1749_doctor_toon_tests::*: needs a builtaida-clibinary.a_fresh_refusal_after_a_close_is_not_closed: passed in the first run. It failed in one later run because another test in the same process setAIDA_CONTAINED=1at the same time. That is a pre-existing race: 46 tests on main set that variable in-process, and slice 1 shipped green with them.🤖 Generated with Claude Code