Record every UK build attempt in Logbook (#666) - #670
Conversation
The three UK drivers now append exactly one validated, hash-chained Logbook row per non-dry invocation, so discarded intermediate builds stay visible before the P1 calibration work starts generating them. Rows spool beside the build outputs; receipts live under build-scoped logbook-receipts/<build_id>/. Successes record iterating, gate-battery blocks and calibrated-candidate refusals record failed, unexpected exceptions record failed after a pipeline-error receipt, and the named dev-rung SPI singleton abort records discarded while keeping its existing uk_rung_abort_receipt payload. Dry runs are excluded on both success and failure paths. Exit codes, exception types, and stdout payloads are unchanged — the spool notice goes to stderr. Terminal verdicts anchor into durable local receipts rather than host-absolute paths: the national rows carry the schema-4 battery statuses uncollapsed, rung aborts point at the named-edge receipt, and the rowwise and candidate rows point into their manifests. The national pin surface hoists the source digests out of the checkpoint-only path so failure rows carry real input pins, and names the future ledger_facts slot for #622/#623 without inventing a placeholder. Adds microcosm.build.logbook_adoption, a driver-agnostic extraction of the generic US stacked-driver helpers (attempt state, predecessor resolution, git code pins, exportable artifact references, normalized role-pin digests, atomic receipts, record-once terminal write). The US driver keeps its local copy here because its contract suite pins those seams; migrating it is the follow-up. Repoints the Logbook docstring from the merged #616 at #665/#666. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…te setup failures Two findings from the #666 adversarial review, both about failure-path ordering and observability: Chain configuration now resolves before any side effect in all three UK drivers. The national driver used to resolve --logbook-prev-row-digest / POPULACE_LOGBOOK_PREV_ROW_DIGEST after unlinking the prior attempt's evidence, replay, build-record, and rung-abort sidecars, so a malformed or conflicting head destroyed local evidence and then crashed; the rowwise dataset driver had the same ordering against its stale coverage/crosswalk unlinks. A config refusal now aborts with no row, no receipt, and untouched sidecars — the same posture as an argparse refusal — and every recorded row carries the resolved head rather than the raw CLI value, so a failure row can no longer chain to the wrong predecessor. The candidate driver's recording envelope now opens before input verification. Input hashing, frame and ladder loading, cloning, and target binding used to run before the try that records failed attempts, so their failures escaped with no Logbook row despite being real terminal outcomes. main() now seeds the attempt state right after CLI validation and routes dry-runs past recording explicitly; pins promote as soon as both inputs are hashed, and the identity digest waits only on the frame-derived source year. Both regression tests were verified to fail against the unfixed drivers: a malformed env head must leave pre-existing national sidecars intact and spool nothing, and a ladder-load failure must spool exactly one failed candidate row with real input pins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
An adversarial review (Codex, run locally) surfaced two failure-path findings; both are fixed in 206ff6e. [high] Invalid Logbook predecessor could erase national sidecars before aborting. The national driver resolved [medium] Rowwise candidate setup failures escaped unrecorded. Input hashing, frame/ladder loading, cloning, and target binding ran before the candidate's recording envelope opened, so those failures spooled no row — contradicting the one-row-per-non-dry-invocation contract. The envelope now opens right after CLI validation; pins promote as soon as both inputs hash, the identity digest waits only on the frame-derived source year, and dry-runs are routed past recording explicitly. Both regression tests were verified to fail against the unfixed drivers before the fix landed:
Full driver + adoption suites (172), logbook contract/backfill/archive/CLI + untouched US driver suites (204), and ruff all pass locally after the fix. 🤖 Generated with Claude Code |
Closes #666. Workstream A of the UK-migration master epic #665 — this lands before P1 calibration starts generating intermediate builds, since Logbook is the migration's build-attempt memory.
What changed
#628 delivered the append-only Logbook, but adoption is per-tool and only
tools/build_us_multispine_pool.pycalled therecord_build_attemptseam. The three UK drivers now append exactly one validated, hash-chained row per non-dry invocation, so discarded intermediate builds stay visible. Rows spool beside the build outputs; receipts live under build-scopedlogbook-receipts/<build_id>/.Dispositions
iteratingfaileddiscardedThe rung abort keeps its existing
uk_rung_abort_receiptpayload, including its owndisposition: "aborted_with_receipt"field; only the Logbook row saysdiscarded. Exit codes, exception types, and stdout payloads are unchanged — the spool notice goes to stderr.Verdicts and pins.
gate_verdictsanchor into durable local receipts, never host-absolute paths (rows are exported publicly). The national rows carry the schema-4 battery statuses uncollapsed (all five ofpassed/failed/not_applicable/evidence_absent/unreached), read fromerror.report_pathon a block; rung aborts point at the named-edge receipt; rowwise and candidate rows point into their manifests. The national pin surface hoists the source digests out of the checkpoint-only path so failure rows carry real input pins, and names the futureledger_factsslot for #622/#623 without inventing a placeholder.New module.
microcosm.build.logbook_adoptionis a driver-agnostic extraction of the generic US helpers: attempt state, predecessor resolution, git code pins, exportable artifact references, normalized role-pin digests, atomic receipts, and a record-once terminal write. The US driver deliberately keeps its local copy in this PR — its contract suite pins those seams by monkeypatch — so migrating it is a named follow-up. Also repoints the Logbook docstring from the merged #616 at #665/#666.Design notes for review
record_build_attemptcall in one run produces a different row (wall_seconds differs), and two rows chaining the same predecessor make a fork the archive refuses. The national driver's handlers are therefore siblingexceptarms — each records once and then returns or re-raises.GateBatteryBlockedErrorsubclassesRuntimeError, so theexcept ValueErrorarm cannot shadow it; the unrecognized-ValueErrorcase records inline before re-raising, since a re-raise never falls through to a later arm on the sametry. Every driver test assertslen(rows) == 1.input_pins_digestandidentity_digestare required 64-hex, so a placeholder preflight digest is seeded before anything can fail;code_pinkeeps theunresolved-local-git-code-pinsentinel until the real pin resolves. That is what lets a preflight failure still record a valid row.discardedrather thanfailed.Verification
test_logbook_adoption.py+ the four UK driver suites: 169 passedruff check .clean; all 10 changed filesruff formatclean. Full-reporuff format --checkshows 29 pre-existing unrelated diffs, confirmed identical at the base commit and left alone.validates as one 29-row chain, andrenders in the same table beside the US rows —uk-national-staging | f001 | iterating.🤖 Generated with Claude Code