Skip to content

Fix storage decode policy - #28

Draft
GCdePaula wants to merge 30 commits into
mainfrom
feature/review-ledger-and-tracks
Draft

Fix storage decode policy#28
GCdePaula wants to merge 30 commits into
mainfrom
feature/review-ledger-and-tracks

Conversation

@GCdePaula

Copy link
Copy Markdown
Collaborator

Storage decode policy

convert.rs promised saturating conversions to keep corrupted DB rows from crashing the process, the opposite of docs/invariants.md's fail-loud policy. A 116-call-site audit found every non-test width-conversion site contract-bound, so the width converters now panic on out-of-range values instead of fabricating plausible ones. Deliberate saturation survives only where the full range is legal: clock conversions (F8), the new explicitly-named saturating_query_bound for WS cursors/limits, and the fee-policy clamps in query_batch_policy. Bonus from the audit: two saturating_adds on contract-bound counters became checked_add, and safe_accepted_batches.nonce gained its missing CHECK (nonce >= 0).

Housekeeping

Restore docs/review/. The squash that merged the cockroach branch dropped the review ledger while AGENTS.md/CLAUDE.md kept pointing at it. Restored with statuses updated: F7 (feed invalidation, high) stays open with PR #26 recorded as WP5's field-extension half, and the interim mirror rule (treat any socket drop as a discontinuity, rebuild the soft suffix) is now written down in-tree.

Record the 2026-07 coordination tracks. New docs/plans/ (indexed from CLAUDE.md/AGENTS.md) holding the plan of record for the in-flight efforts: feed & replay protocol redesign (generation id, historical replay endpoints), dump/Application API redesign, the LLM-docs review campaign, and the deferred fee LUT (exact-floor decided, pending a design decision that may retire log-space fees).

@GCdePaula GCdePaula changed the title Review ledger and tracks Fix storage decode policy Jul 30, 2026
@GCdePaula
GCdePaula force-pushed the feature/review-ledger-and-tracks branch from 1f6a8a1 to 9f1a644 Compare August 18, 2026 18:18
…story foundation

One process, one data directory, one way in: this lands the authority
boundary the 2026-08 ADR designed, with admission derived from durable
facts and history given real coordinates.

Process ownership and containment:
- Kernel-enforced one-process-per-data-dir (runtime/process_lock.rs); the
  controller retains the lock through settlement, nested blocking work
  retains clones until it actually stops.
- RuntimeScope: the runtime-lifetime capability (sticky containment
  OnceLock, independent two-second terminal-abort watchdog, best-effort
  fault recorder), constructible only from a held lock.
- The Authorized externalization token: acks, L1 sends, WS frames, and
  snapshot-stream starts require a token minted by consulting containment
  — forgetting the check is a compile error, not a convention.

Commands and the exit-code contract:
- commands/ owns the operator brackets (run + worker supervisor, setup +
  fill, flush); runtime/ is the capability substrate consumed crate-wide.
- One CommandError taxonomy with the R4 exit projection (10 expect
  recovery / 20 transient / 30 terminal, do not restart, page / 40 setup
  needs recovery); terminality declared beside each worker error type.

Fact-derived admission (reviews L2/L3):
- Admission is three facts, each with one owner: the process lock,
  two-sided setup_complete, and the absorbing canonical_divergence marker.
  No lifecycle state machine, no operator acknowledgement; standard
  recovery is automatic and cockroach rebuild is the one manual path.
- The only durable telemetry is the terminal_faults black box: append-only
  terminal-cause rows, written best-effort and verdict-neutrally.
- Boot is prepare -> admit (the same pure reducer re-run over one
  consistent fact set) -> single-use AdmittedRuntime -> non-yielding
  launch.

Startup recovery:
- A pure reducer over one transactionally consistent inspection selects at
  most one phase; every completed phase returns to inspection; flush/sync
  witnesses are boot-local and never persist.
- admission.tla proves terminal dominance, one-phase-per-inspection,
  witness requirements, crash/restart soundness, and capability soundness
  (TLC: 860 generated / 266 distinct / depth 13 / 0 violations).

Durable history foundation:
- (EraId, RecoveryGeneration, K) coordinates, each recorded at the moment
  it happens; the executed_inputs canonical projection; setup completion
  as a synchronous=FULL linearization point; snapshot lifecycle hardening
  (lease reset, GC, orphan sweep, promotion restamp).
- sequencer-core: one shared typed execution boundary writes the consensus
  coordinate; raw hooks are structurally unreachable; app-boundary decode
  and genesis paths return typed refusals.
The documentation practice gains a lifecycle, now recorded in AGENTS.md
("Documentation Practice"): living docs are timeless — present tense,
reasoning inline, no dates, no amendment banners, no review codenames —
while history lives only in docs/review/ and commit messages, and a review
ledger is distilled when it closes. Conclusions with reasoning outlive the
path taken to them. Plus the comment rule: comment the non-obvious, never
restate what the code expresses.

- docs/review/register.md is the new hub: open findings (statuses verified
  against the tree), owed tests with recipes and harness levers, open
  maintainer decisions, settled decisions with each reasoning's current
  home, refuted proposals (do-not-re-propose), and a historical codename
  map so older commit messages stay decodable. CLAUDE.md/AGENTS.md point
  there.
- All eight dated ledgers distilled to stubs or compact decision records
  (docs/review/ 2,392 -> 502 lines); full originals remain in git history.
- The authority-boundary ADR rewritten present-tense (769 -> ~210):
  context, the four mechanisms, rejected alternatives with their
  arguments, revisit conditions; cutover chronology and raw benchmark
  tables reduced to their conclusions. The superseded terminal-containment
  plan is deleted; the coordination-tracks doc is rewritten to current
  truth (Track 5's LUT rationale kept in full).
- Living docs scrubbed of tense leakage; the concepts formerly cited as
  review codes now have real names homed in invariants.md, which also
  gains the do-not-simplify list and I9's content-equal => effect-equal
  argument. ~90 codename citations removed from code comments and the
  schema.
- Adversarial review of the distillation (24 agents, three lenses):
  23 confirmed findings fixed. The lost-content lens restored two real
  casualties with updated homes: cockroach recovery's flush is best-effort
  by construction (no watermark survives the wipe; the fail-safe
  flush-floor option recorded) -> cockroach.md step 2 + register; and the
  supervisor recipes (systemd RestartPreventExitStatus; on Kubernetes the
  crash-loop bound is exit-code alerting, since Deployments cannot honor
  exit codes and there is no boot gate) -> the operator runbook.
L2TxFeedConfig::default() set batch_submitter_address to None — "filter
nothing", the I11-violating value — so the feed a test or future caller
got by default fanned our own batch envelopes out to WS subscribers.
Production was correct only because the runtime glue remembered to
override the default.

The address is now a required constructor argument and the Option is
threaded out end to end: the filter compares plain addresses (matching
the inclusion lane's spelling), and the unfiltered SQL arm in
storage/egress.rs — reachable only through the deleted default — is
gone. Fixtures that seed no own-batch rows pass a sentinel address that
collides with no seeded sender; Address::ZERO is a real fixture sender
and must not be used for that.
…he launch bracket

Simplification pass over the run-command startup glue, adversarially
reviewed: two verification rounds over the proposals and a fidelity
review over the landed diff. Behavior-preserving; operator-visible
deltas are limited to log fields (the "listening" line reports the
resolved bound address; drain warnings carry a structured `phase`).

- L1Config carries the pinned DeploymentIdentity verbatim, built once in
  run(): exactly one route to identity below the gate. The poster's
  start_block round-trip through the reader is gone, and the test
  fixture builds one identity literal instead of hand-copied fields.
- PreparedRuntime is now exactly the launch-argument bundle: config
  structs die in prepare (lane_config, api_config, snapshot_state,
  bound_addr in; run_config, l1_config, db_path, dumps_dir out), and
  launch is six spawns plus the "listening" log.
- The EIP-712 domain is derived in prepare from l1_config.identity —
  one source, now that the identity travels whole.
- ApiConfig owns the deployment-varying ingress values (domain, payload
  bound) via a mandatory constructor; the service limits stay module
  constants, documented as deliberately not operator-tunable.
  start_on_listener drops to six parameters.
- AdmittedRuntime is collapsed into launch(self, RuntimeAdmission): the
  witness is the mechanism, the wrapper was presentation. Vocabulary
  swept through AGENTS.md, the ADR, invariants, the recovery README and
  admission.tla comments; the spec's admittedRuntime state names are
  deliberately kept (TLC unchanged: 860/266/depth 13/0).
- finish's two drain loops merge into one two-phase loop with a single
  precedence match (contained > primary > signal > first drain error).
  The register's drain-merge refutation was scoped to the naive
  re-awaiting sketch ("as sketched" in the 2026-08-18 source); the
  entry is scope-narrowed with the source cited.
- select_first_exit destructures Self exhaustively, closing the one
  per-worker site a seventh worker could silently skip.
- Startup snapshot hygiene moves to commands/run/startup_hygiene.rs;
  its five order-critical steps were mis-documented as four.
- Fee-oracle bootstrap: RunFeeOracleBootstrapError deleted (exit codes
  proven unchanged; double-prefixed misconfig messages fixed); the
  transient connect arm reuses the provider it already built. The
  previously untested Some-limb drain path gets a pin.
- The WORKER_LAUNCH_COUNT probe and its global test mutex are deleted:
  the ProcessLock::acquire assertion is the stronger behavioral
  detector, and the tests it serialized are now independent.
The submitter's signing key rode through three Debug-derived structs
(KeyArgs inside RunConfig/FlushConfig, and L1Config) in plaintext hex —
one future ?config log away from leaking. It now enters the process as
SubmitterKey at the clap value_parser: Debug prints [redacted], no
Display exists (a %key log line is a compile error), and the raw hex is
reachable only through expose_secret(), whose call sites are the
provider builders and address derivation. A test pins that a carrier
struct's derived Debug never prints the secret.

No public-address accessor: the key's public identity is the pinned
identity.batch_submitter_address beside it, already in the startup log.
Closes the register's Debug-derive open finding; the startup log's full
RPC URL (token-bearing per the help-leak test's threat model) is a
recorded, deferred tension.
@GCdePaula
GCdePaula force-pushed the feature/review-ledger-and-tracks branch from a8c23eb to 5233880 Compare August 24, 2026 12:00
GCdePaula and others added 22 commits August 25, 2026 14:19
Require and persist a fresh fee quote during setup, then retain the last price across transient runtime failures.

Keep the process lock through cancellable feed preparation and make E2E mining follow the safe-block clock without synthesizing future L1 time.
Couple stopped-process outage time with L1 progress, update the backward-clock scenario to assert retryable admission denial, and keep the live stuck-Tip injection recoverable after its detector exit.
Add the dated ledger for the pre-merge stock-take of this branch: the
verdict (proportionate; three residue pockets), the facts verified
first-hand, the eight jury-confirmed and ten jury-refuted simplification
proposals with their evidence, and the fifty-four proposals no jury
examined, marked as such. The register gains findings 19–31, two owed-test
entries, a 2026-09-03 refuted block with an evidence line per entry, and
two hygiene fixes the audit found in the register itself: the
fee-price-age refutation is re-homed under the commit that made it, and
the boot-gate refutation's wording is narrowed to the argument it rests on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… the log line

The rollups-e2e job was red on `aging_open_tip_runtime_danger_zone_exit_test`
for a deterministic reason: the assertion grepped the child's log for
`status=TipInDanger(`, but tracing-subscriber styles field names and the
`=` with ANSI escapes whenever `NO_COLOR` is unset (no TTY check), and the
harness passes the parent environment through. It passed only in shells that
export `NO_COLOR`.

Both wallet-sequencer binaries now enable ANSI only when stdout is a
terminal — the production fix: a daemon writing to a pipe, a file, or
journald must not interleave escape codes into its operator log.

The scenario asserts the exit code instead: 10 is the observed-danger class
(`TipInDanger` / `ClosedBatchInDanger`), a clock fallback would exit 20, and
the scenario has no closed batch — the same discrimination the log grep was
reaching for, on a documented contract rather than a rendered line. Verified
locally: the scenario passes and the log file carries no escape bytes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Four independent reviews found the same defect class on this branch: comments
that claim more than the code enforces. In a codebase where comments are the
audit surface, an overstated guarantee is a missing check.

- `authorize()`, the ADR, and the register's settled entry claimed four
  compile-forced externalization primitives; three functions take the token
  (ack, L1 send, WS emit). The snapshot-stream start, the `POST /tx` success
  body, and the lane's two mutation commits are hand-placed consults bounded
  by the exit contract, and now say so.
- `Authorized`'s doc claimed a consult "at this effect boundary"; the token is
  `Copy` and lives for the scope borrow, so it proves a consult at some point
  in that borrow — the ADR's bounded lag, stated where a reader meets it.
- The flush witness was called "non-clone" in the recovery README, the TLA
  header, and a test comment; `RecoveryProgress` derives `Copy`. The property
  is that it is boot-local.
- The process-lock witness comment said a live witness means runtime work
  has not drained; it also covers the controller's own clone through
  settlement.
- Three "journal" sites missed by the black-box rename, one dated rename
  history and a removed "acknowledge" command in the error module's header,
  a module doc arguing with a hypothetical simplifier, and a recovery README
  naming a `DangerDetectorExit` type that does not exist.
- `preparation_outliving_clean_facts_cannot_launch` never calls `launch`; it
  asserts that final admission refuses over aged facts, and is now named so.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
AGENTS.md's documentation practice keeps review-item codenames out of code
comments and living docs; the distillation commit removed ~90 citations and
missed fifteen. Each is replaced by the reason itself or by the invariant id
it stood for (R1a → I14, R2 → I9/I15, "review R4 class 10" → the exit-code
class), or by the plain word "regression" where the code was only a label.
Three of the fifteen were added by this branch (L2, H6, D10); the rest
predate it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Five `Storage` methods were `pub` with only test callers, one of them an
unguarded batch-tree mutation sitting beside its guarded replacement:
`ensure_open_tip` (production opens the Tip through the reducer's guarded
`EnsureOpenTip` phase), `close_frame_and_batch` (production closes through
the pending-snapshot twin, I7), `latest_batch_index`,
`ordered_l2_txs_for_batch`, and `promote_finalized` (production promotes
inside the drain transaction, I6). All five are now `#[cfg(test)] pub(crate)`;
their intra-doc links and the snapshot lifecycle doc name the production
paths instead. Gated rather than deleted: the two index helpers have callers
across three test modules.

This is the benefit the in-crate integration-test move was meant to unlock.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The finality wait timing out and resubmitting is the mempool flush's ordinary
rhythm on a slow chain, not a fault; it was logged at `error!`, so every
healthy recovery boot paged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The comment claimed a `debug_assert` that does not exist. The high limbs are
dropped without a check; that is sound because every caller's inputs are
table entries or partial products for an exponent already bounded by
`MAX_EXPONENT` in `fee_to_linear_fixed`, and partial products never exceed
the final value. The contract half of the fee-determinism finding (the
LSB-first floor order) stays open.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…body

The one `POST /tx` 500 path that still echoed internals — an application
`Internal { reason }` or I/O error during execution — now answers with the
fixed "application internal error" the other internal paths already use.
The reason still travels on the lane's `ExecuteUserOp` error and the log,
which the test now pins alongside the fixed client message.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`ApplicationProgress::new` panicked on an incoherent pair and had only test
callers; its own doc said to use `try_new` on the one path that constructs
a pair from data. `try_new` is now the single constructor (a genesis
instance starts from `Default`), tests use it with `expect`, and the
should-panic test became a direct assertion on the fallible form.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The ledger gains a "Landed" section so a later session resumes from the tree.
The register's findings keep stable numbers: closed entries (4, 5, 17, 21,
25, the comment half of 8, the gating half of 10) are reduced to one-line
closure notes rather than deleted, so the ledger's citations stay valid.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ites the black box once

`RuntimeScope` loses the in-scope fault recorder: the `FaultRecorder`
alias, the `OnceLock` field, `set_fault_recorder`, the recorder call inside
containment, and its installer in `PreparedRuntime::prepare`. Containment is
now three non-blocking steps — CAS-elect the cause, arm the two-second abort
watchdog, request shutdown — and the "arm the watchdog before recording,
either may block" ordering hazard goes with the second SQLite writer that
caused it. The command bracket's settlement write (`record_terminal_fault_best_effort`,
which already existed as the second of two writers) is the black box's one
writer, so a contained run records one row, not two.

The accepted loss, stated in the runbook where an operator reads it: any
death that does not return through its bracket — an abort at the two-second
deadline, a controller panic, SIGKILL — leaves only the process logs, and
the single write has no second attempt. The row is telemetry; restart policy
is the exit code, which is untouched.

`run` gains a verdict-neutral startup read: `warn_on_previous_terminal_fault`
logs the latest black-box row once, ahead of the admission preflight so a
refused boot still says why the last one died; nothing branches on it, and a
missing or unreadable table is a debug line. The black box thereby gets its
first in-product reader.

Tests: the two recorder-only tests are deleted; containment's first-reporter
election is pinned without a callback, and the settlement write is pinned
directly (a transient verdict leaves no row; a terminal one lands the
error's display form). The invariants check policy, AGENTS.md, the ADR, the
recovery README, the admission model's comments, and the runbook are
restated to match. Closes register finding 24.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n-optionally

`acquire_finalized_lease` returns `FinalizedLease { inclusion_block: u64,
dump: LeasedDump }`; `LeasedDump` no longer carries an `Option<u64>` that was
`Some` for one query and `None` for the other. `finalized_state` destructures
the lease, and its branch on an impossible `None` — which escalated a type
artifact to terminal containment, against the check policy's "no
Option-handling for can't-be-None" — is deleted. The column is `NOT NULL`
with a CHECK at the engine, and corrupt-row containment is unchanged (the
persistent-storage classifier and the decode panic, as the existing test
pins). Wire behaviour of `/finalized_state` and `/latest_snapshot` is
unchanged: headers, ETag, the 304 path, the 404, and the guard-after-commit
ordering. Closes register finding 26.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…its postcondition

`ensure_open_tip_for_recovery` guarded two conditions with one disjunction,
so an already-open Tip surfaced as `StaleDecision { expected: Safe, actual:
Safe }` — a line the test pinned as intended. The two checks are now
separate: a non-`Safe` danger is still `StaleDecision`; an already-open Tip
is the payload-free `TipAlreadyOpen`, paired with a retry reason so
`classify_mutation` carries it to the operator (retry, exit 20; a restart
inspects, finds the Tip, and admits).

The same phase is the only edge back into `Repaired` without a Tip, so it
is the reducer's one cycle, and no watchdog exists on the boot path. It now
re-reads `has_valid_open_batch` inside its own transaction after opening and
returns `TipMissingAfterOpen` — classified `refuse`, exit 30 — rather than
commit without one. A typed refuse, not a `debug_assert` (compiles out) and
not a retry (would relocate the spin into the supervisor). `drive_recovery`'s
doc records the termination argument: at most five phases per attempt, the
process lock making this the only writer between them. `admission.tla`'s
`hasOpenTip' = TRUE` is now an enforced postcondition, and says so.

A fault-injection test invalidates the new Tip the moment its first frame
lands (invalidating on the batch insert is caught one step earlier by the
schema), so the opener returns `Ok` with no valid open Tip, and asserts the
refuse plus full rollback. Closes register findings 20 and 23.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…on half

`DangerDetector`, `InputReader`, and the fee-oracle worker used their
`RuntimeScope` for exactly one thing — `wait_for_shutdown` — and each already
holds a construction-required `ProcessLock` clone for its data-directory
work. They now take `ShutdownSignal`, the scope's notification half;
`PreparedRuntime::launch` passes `shutdown.signal()` for the three and the
scope to the lane, HTTP server, and submitter, which externalize or contain.

Nothing the scope carried is lost for them: the lock clone they own is a
clone of the same descriptor the watchdog's weak witness observes, so a hung
one still aborts at the deadline; the signal is a clone of the same
notification state containment pokes, so a contained fault still stops
them; and their terminal exits were always classified by the supervisor,
never by worker-local containment. Their tests construct a bare signal
instead of the default test scope, which leaked one temp-dir lock per use.

The prose that claimed every worker held a scope clone is restated where a
reader meets it: the `ShutdownOnDrop` doc, the launch-boundary test comment,
the process-lock module doc, the scope's own rule, and the ADR's mechanism
1. A pre-existing broken intra-doc link in the shutdown module is fixed
while the file is open. Closes register finding 22.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…failure one verdict

A missing, unreadable, or non-text batch-submitter key file now exits 30
like bad key content one call later, instead of restart-looping at 1;
environmental I/O still exits 1. The read returns a typed
`BootstrapError::KeyFile { path, source }` whose message names the path
and never the contents. Both halves are pinned, including the EIO kind
an operator actually hits.

`RecoveryFailure::Provider(String)` carried two verdicts, decided by its
construction site. It is split into `ProviderUnreachable` (retry) and
`SignerMisconfig` (refuse), classified at birth by
`classify_signer_provider` and pinned, payload and polarity, against the
`BootstrapError` projection it must agree with. `classify_input_reader`
now documents what it can actually receive (only the sync's
`create_provider` produces `Bootstrap` here; discovery-time facts are
`setup`-only) and why `Bootstrap` and `Join` flip polarity between the
startup phases and the live worker.

Register: findings 19 and 27 closed; finding 32 opened (the same L1
misconfiguration exits 1 under `setup` and 30 under `run`; recorded, not
fixed); the flatten-`RecoveryError` refutation annotated now that its
two-verdict premise is gone; drifted cites retargeted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…alues

The five per-class exit-code tests, the verdict test, the two startup-
reader tests, the fee-oracle fatal-math test, and the two app-bootstrap
tests fold into five class functions and one table test that asserts,
for every row, the class and that the black-box verdict agrees with it
(`is_terminal` exactly for class 30). Every shape, reason string, and
rationale comment survives; two rows are new (`ProviderUnreachable`
under retry, `SignerMisconfig` under refuse). A second test pins the
five verdicts to the integers 10/20/30/40/1 through an exhaustive match,
so a renumbered constant or an unnumbered sixth verdict fails here, not
in a runbook.

Two wire-value pins outside the table: `run` on a never-set-up data
directory dispatches to 30 through the real command bracket, offline by
construction (the admission preflight refuses before the key is read or
a provider is built); and the harness gains an opt-in
`stop_expecting_clean_exit` that asserts SIGTERM→0 on a healthy
sequencer, used at the healthy stop of the stale-batches scenario. The
runner's per-scenario shutdown stays lenient on purpose.

Register: the owed exit-code test keeps only its per-variant e2e half;
the `classify_input_reader` polarity pins landed with the previous
commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Wave 4, batch F: no document is restructured yet; sentences the corpus
made that the code does not support are corrected, and a few removal
notices and future-tense clauses retire.

Corrected: README's exit-code list gains 40 (wipe and `setup --recovery`)
and the SIGABRT/134 terminal class; the lifecycle module doc says which
commands preflight `setup_complete` here and which admit through
`commands::setup`, that divergence's only exit is a fresh-directory
rebuild, that the supervisor is expected to honor the exit contract
rather than enforcing it (the ADR and the check policy say the same),
and that `run` reads the black box once at startup; the frontier
writer's comment no longer forecasts a cutover that landed; the lane's
fast-turn doc names the cost it actually avoids (a frontier read) and
its module doc names the lane's divergence refusal point; the reducer
selects at most one phase; the watchdog design notes and I15 say which
half of the freeze is a trigger and which is the frontier writer's own
guard; the threat model's dangling "non-goals" pointer lands on the
lock's stated scope; the check policy no longer implies a pending gap
at the snapshot routes; the calibration rule is quoted with all four
terms.

One home each: I15 owns the clean-exit re-check
(`refuse_divergence_on_clean_exit`) and names `LocalDivergenceFirst`;
I9 owns the accepted false positive the protocol doc now points at; the
ADR's mechanism 1 owns the hand-placed containment-consult inventory,
stated site by site including the poster's per-send and pre-watermark
re-checks, with `runtime/shutdown.rs` and the register pointing at it;
the snapshot routes' gate is `authorize_route`, which gates the cheap
inclusion-block read too.

The stock-take ledger gains landed/withdrawn markers on the entries
later waves resolved. Three read-only refuter passes; the last
amendment was verified against a grep of every production consult site.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…three homes

Wave 4, batch G. The mapping pass found the corpus already elects its
homes: the ADR for mechanisms 1, 2, and 4, docs/recovery/README.md for
the reducer, I15 for the divergence freeze, the register for refuted
proposals. This batch makes the ADR and the register act on that.

The ADR's rejected-alternatives section reduces to six names and a
pointer; their arguments, revisit triggers, and code evidence now live
in the register's refuted list, which gains the durable recovery-phase
ledger it never had, the cost datum the distillation dropped (stated as
its source states it), and a note that the boot-gate carve-out is now
exercised by the startup black-box read. Mechanism 3 reduces to the
decision plus pointers; the recovery README absorbs the loop, the
four-fact inspection, the witness erasure on Retry and Refuse, the
local-before-provider-or-mutation argument, and the phase bound. G3
reduces to the policy sentence plus I15. Mechanism 1, now the token's
home, absorbs the facts the module docs alone carried: containment is
classification-at-birth, the token proves a consult at some point in its
borrow, the lane consults once per effect boundary.

Three read-only refuter passes; the first two each caught my own
restatement of the cost datum overreaching its source.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…r roles

Wave 4, batch H. AGENTS.md's "Hot-Path Invariants" and "Storage
Invariants" restated, at greater length than their owners, what
docs/invariants.md, the ADR, the recovery README, the protocol docs,
README.md, and the schema already own — against the file's own rule.
Both sections are now maps: four pointer bullets and the one rule
nothing else owns (single-lane ordering, no extra concurrency without
approval). The recovery, formal-verification, drain-attribution, and
glossary passages shrink to pointers the same way.

Before cutting, every clause only AGENTS.md carried moved to its owner:
the acknowledgement rule, the no-timer-no-cursor absence, the
catch-up-included range, the loop-return cost, and the reader's
no-cursor seam into ADR mechanism 4 (which also gains the lock's
concurrent-cleanup and watchdog-witness clauses and the snapshot
routes' cancellation caveat from the check policy); the frontier time
gate into I3; the direct-prefix derivability into I2; the replay fee
into I20; the five-block revisit trigger into scheduler-semantics; the
user-op identity rule and the views rule into the schema; batch closure
into README's storage model; the append-oriented rule into the design
principles.

The writer-role table moves into docs/invariants.md as "Writer roles"
and is corrected on the way: one writer role per fact (the old "one
writer per table" was false of `batches`, `frames`, and the watermark);
`deployment_identity`, the initial snapshot registration, and the
batch-tree anchor belong to setup, not the reader; the watermark is
shared by the poster and the flusher under I14; `run`'s startup hygiene
resets leases and, with the lane, collects unreferenced dumps; the
command brackets write the black box.

The check policy's admission bullet points at the ADR and keeps only
what the policy adds; the recovery README's divergence section keeps
the recovery side and points at I15 and I9 for the rest.

Three read-only refuter passes drove the table corrections and the
replay-fee wording.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GCdePaula and others added 3 commits September 5, 2026 04:31
Wave 4, batch I. Six dated ledgers in docs/review/ were 15-20-line stubs
carrying a verdict and pointers; nothing in the tree linked to them by
name, and every fact they held already lived in the register or a living
doc. They become rows of a "Review history" table at the end of the
register (date, scope, verdict, where the content lives), which also
indexes the three ledgers that stay: the two August ledgers and the
stock-take carry measurements and refutation evidence recorded nowhere
else. The originals are recoverable from the distillation commit's
parent, and the table says how.

Two facts only the stubs carried migrate first: the 2026-06 "no
architectural restructure" verdict becomes a settled entry, and the
marker-file containment protocol the 2026-08-01 review hardened and the
cutover later deleted gets its refuted entry, stating what replaced each
half of it. The register header and the pointers in AGENTS.md and the
ADR stop calling the ledgers stubs; the 2026-08-22 ledger stops
restating the register's inclusion-block refutation; the owed tests keep
their freshness stamp; the register's one remaining "two-second" leaves
with the constant's single-home pass.

Three read-only refuter passes over the combined I+J diff drove the
row-1 wording, the stock-take row's method line, the recovery recipe,
and the marker-file supersession.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… name

Wave 4, batch J. The worker supervisor's module doc states the
per-worker plumbing rule and what the compiler rejects, without a count
that drifts or "they are the enforcement"; the exit-code projection
comment keeps the SIGABRT/134 bypass and points at the runbook by path
instead of restating black-box semantics; the shutdown module's "honest
bounds" become the abort bound and a pointer to the exit contract; the
recovery writer's fault model points at the threat model's self-trust
boundary instead of calling itself "not a gap".

The terminal abort bound's number now lives where the constant is
defined (`TERMINAL_ABORT_TIMEOUT` in `runtime/shutdown.rs`) and in the
operator runbook; every other prose site names "the terminal abort
deadline" and, where a reader needs it, where it lives. I15 names the
danger detector's own poll interval, a different constant that happens
to share the value.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The ledger's Landed section gains the wave-4 block, the stock-take's
documentation proposals carry their landed, decided, or partly-landed
markers, and the register settles the single-home rule by naming the
home of each mechanism and the four code-side exceptions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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