Skip to content

ADR 0300: Checkpoint observation is drained metadata, never a verdict

Status: accepted; fills the observation seam of ADR 0299 under the Logbook charter of ADR 0160, the follow-through framework of ADR 0207, the counting rules of ADR 0229 and ADR 0256, and the recommendation bar of ADR 0276

Context

§

The checkpoint contract records judgments, but nothing recorded how the mechanism itself behaves: which checkpoints fire and how often, whether declarations follow relevant revisions or land on unchanged subjects, how long a question waits for its conclusion, which land under owner-authorized variances, and which open questions an effort simply ends on. Without that memory an owner cannot tell a checkpoint earning its tax from one taxing every change, and the external design review fixed the interpretive line early: a declaration on an unchanged subject does not prove rubber-stamping — the agent may have reviewed before invoking the gate — so the record must observe without judging.

Three constraints shaped where the record could live. The done and accept envelopes are published contracts, and the observation facts (reconcile outcomes, subject-revision flags, elapsed times) are Logbook material, not caller material. The refusal that serves a question — the firing moment — must record even though no gate ran. And the unmet rationale, durable Proof evidence, is prose that must never enter the metadata-only Logbook.

Decision

§

One additive checkpoints block on the verb event carries the open question and variance lifecycle as metadata, collected where each fact becomes true and drained at the recording points; every reader of it observes checkpoint fit and none can gate anything.

  • The vocabulary. Servings (fired, reopened, and advise — advise checkpoints have no open questions, so the serving itself is the record), declared entries carrying the conclusion, the definition hash and subject fingerprint, a revised flag, and elapsed_ms, plus variances and abandoned on the landing's event. Ids, outcomes, fingerprints, and timing only: no field for the rationale exists, so the metadata bar is structural. Older events without the block stay readable; readers censor what is missing.
  • Mechanical honesty for the unchanged/revised split. revised is true exactly when the declaring invocation's own reconciliation reopened the subject — a relevant in-scope revision separated the serving from the conclusion. Elapsed time runs from the serving the agent actually answered: on a same-invocation reopen, the replaced subject's serving time, which reconcileEpisode now reports.
  • Collection by accumulator, drain at the recording points. The gate pre-flight and the acceptance transition observe into a process-local accumulator (result_capture.ts, beside the observed-result mailbox); the CLI wrapper and the MCP completion boundary drain it into the event (the drain-parity guard already forces every mailbox through those two recording points), and the recorder's fallback take clears any remainder. Both surfaces therefore record equivalently, refusals record their firings, and a refused landing observes no variance — the landing's observations are recorded only after the trunk transition completes.
  • The follow-through family is stream-walked, so checkpoints auto-enrol. checkpoint-declare declares a new rule kind in the ADR 0207 framework: its follow-through episodes are enumerated per (branch, checkpoint id) from the recorded blocks rather than per delivered hint — a serving opens one, a reopen while pending folds into it, the resolving declaration's revised flag decides followed or not followed, and a missing block, missing flag, or history's end censors. Any checkpoint id that ever appears in observations is measured; no registry names checkpoints anywhere.
  • One economics reader, three consumers. A single tally (checkpoint_economics.ts) feeds the practice-stats card, the checkpoints verb's observed-history section, and the hygiene detectors, so the numbers cannot disagree. Rows are plain counts beside their denominators, bounded to the most-served 16 with the remainder counted — the wire scales with configuration, never history.
  • Hygiene advisories judge configuration, never agents. checkpoint-dead (configured, never fired) and checkpoint-noisy (served on ≥80% of efforts) count gate-run efforts since the newest recorded [checkpoints] config change — the epoch machinery's own attribution, so a revised definition earns fresh evidence — and speak only after 8; checkpoint-varied speaks once at least 3 variance-carrying landed efforts where the checkpoint fired exist and they cover at least half of such landings. Each recommends reviewing the trigger, question, or mode, with its counts.
  • The boundary is a guard, not a convention. An import-graph test walks every checkpoint decision module (the package minus the always-ok report.ts, plus the acceptance interlock) and fails if any path reaches the Logbook; black-box tests prove the rationale never lands in a Logbook byte while the same invocations serve it as Proof evidence.

Consequences

§
  • The owner's questions become answerable from counts: which checkpoints fire, on what share of efforts, how conclusions arrive, and which routinely need a variance — while no number claims anything about the agent's diligence.
  • The verb-event schema gains one optional field for the life of the feature; every existing reader tolerates it, and every new reader must censor its absence.
  • Abandonment is observed only where an effort observably ends (a completed landing). A worktree deleted by hand ends unobserved — accepted: the Logbook records verbs, and no verb ran.
  • Advise servings record once per gate run, so their fires measure served context, not distinct occasions; the per-effort share carries the deduplicated view.
  • The dead/noisy denominator resets on any [checkpoints] edit, since the section hashes as one unit — conservative in the delaying direction.

Alternatives considered

§
  • Lift observations from the result envelopes by shape, like consent and landing state. Rejected: the facts (reconcile outcomes, revision flags, elapsed times) would have to join the published done/accept contracts first, growing caller-facing surface for reader-only material — and the accept envelope's variances carry the rationale, which a shape-lift would have to deliberately strip forever.
  • Dedicated event kinds (checkpoint-fired, checkpoint-declared, …). Rejected: the lifecycle is per-invocation context, exactly what the verb event exists to carry; new kinds would multiply the compatibility surface and orphan the begin/completion pairing.
  • Count a declaration on an unchanged subject as not-followed evidence of neglect. Rejected on the review's correction: the revision flag records what happened to the subject, not what the agent read; interpretation stays with the owner.
  • Enrol checkpoints in follow-through by id, mirroring the hint-id tables. Rejected: a registry of checkpoint ids would let project-authored checkpoints escape measurement — the observation block already names every id.
  • Let the noisy detector read live config thresholds to suggest exact replacement trigger values. Rejected under the recommendation bar: the counts justify a review, not a computed configuration change.
choose openEsc close