Skip to content

ADR 0106: standards --pin captures a measured gain and carries the gate receipt across it

Amendments.

  • Vocabulary: current spellings are standards (formerly ratchets), done (formerly finish), accept (formerly graduate), and [jobs] / [jobs.<name>] (formerly [capabilities] / [checks.<name>]); the gate-pass artifact became the receipt, and ADR 0245 renames the receipt-family terms to proof; the decision and reasoning are unchanged.
  • ADR 0133 — the gate measures: two premises moved. "done never reads [standards] limits" no longer holds — the gate now verifies every limit and measures each standard — and the alternatives' rejection of "fold standards into done" is reversed for the terminal verb (the inner-loop half of that argument stands: prepare never measures). The pin-commit carry-forward remains sound on its updated footing: a pin only ever TIGHTENS limits, and a tightened limit still passes the never-loosen verification, so the commit remains gate-neutral for the vouch it forwards.
  • ADR 0203 — commit attribution: the standards-pin commit now passes through the shared, pathspec-limited discern commit boundary; it keeps the invoking user's author and committer identity and adds the co-author trailer by default, its identity now discern <[email protected]> (formerly discern-bot). Pinning and receipt carry-forward semantics are unchanged.
  • Complete local Proof: reverses the carry-forward optimization. A reusable Proof is the complete structured Gate result bound to its exact HEAD, declaration evidence, and presentation. A pin commit changes that subject and diff without retaining enough Gate inputs to derive a new Proof, so it leaves the prior marker stale and directs the caller to discern done; acceptance otherwise runs the Gate. Measurement reuse and monotonic pinning are unchanged.

Status: accepted. Extends ADR 0067 (the gate receipt), building on the plan/apply seam, the named-metric standards, and the one result envelope.

Context

§

An agent that improves a metric held by a standard wants to capture the gain — tighten the limit so it can never slide back. Until now that was a hand-edit to discern.toml, committed on its own. That routine is the problem, and it has two faces.

Follow the common success path:

  1. The agent finishes its work; discern done is green, so a gate receipt names the current HEAD.
  2. It runs discern standards (on demand, not part of done) and a metric has improved past its limit.
  3. To lock the gain in, it edits the limit in discern.toml and commits that change on its own.
  4. It accepts — and accept re-runs the whole gate, because the commit in step 3 moved HEAD and the step-1 receipt is now stale.

The step-4 re-run is the most expensive one the tree can trigger (discern.toml is scope-classified as a code change, so the full gate fires), on the most common success path, for a change that cannot alter the gate's outcome: done never reads [standards] limits (standards are deliberately not part of it — ADR 0003). A commit that changes only standard limits is therefore gate-neutral by construction.

The hand-edit is the other face. A raw number typed into discern.toml cannot tell a genuine tightening from a quiet loosening — exactly the "loosening buried in a feature branch" the standard discipline exists to forbid — and it puts the fiddly work of reading the measurement and re-typing the limit on the agent.

Decision

§

Add discern standards --pin: measure, tighten each asked-for limit that improved to the value just measured, commit that change alone, and carry an honored gate receipt forward across the (gate-neutral) commit.

  • Only ever tightens. The pin value is a pure function (pinnedLimit): it moves the limit toward the measurement — a floor up, a ceiling down — and returns "nothing to pin" unless the result is strictly tighter than the current limit, whatever the margin. Pin can never loosen a limit, so it is never the escape hatch the never-loosen rule guards against. A metric that regressed is a failing standard, and pin refuses to run while any standard is red — you cannot capture a good state from a bad tree.
  • A margin for metrics that drift. Pinning to the exact measurement bricks a metric that changes on every unrelated commit: a binary size pinned to its exact bytes fails the next commit, and can't be loosened without tripping the never-loosen guard. The optional per-standard margin (default 0) is the headroom pin leaves — floor measured − margin, ceiling measured + margin — and doubles as the threshold below which a gain is too small to bother pinning. A deterministic metric (coverage on a fixed tree) keeps margin 0; a drifting one gets headroom.
  • Carries the receipt forward, fail-closed. Pin captures the receipt status before it changes anything; after committing it re-stamps the vouch onto the new clean HEAD only when the prior receipt was honored — reusing done's own receipt-write path. With no honored prior vouch it does nothing, leaving the now stale receipt for accept to re-validate. It only ever forwards a vouch that genuinely held a moment ago, across a commit it authored and so knows touched nothing but standard limits.
  • The carry-forward belongs to the mutator, not to accept. Scope classification is path-based; it cannot see that only [standards] limits moved inside discern.toml (the same file also holds [jobs], which the gate does read). Only the operation that authored the commit has that knowledge, so the vouch is re-stamped where it is known safe — never inferred from a diff after the fact.
  • A mode of the standards verb, on the existing seams. Pin runs through the same plan/apply core and returns the one standards result envelope; the CLI flag and the discern_standards MCP pin parameter share it. It needs a clean worktree, so the commit carries the limit change and nothing else.

Consequences

§
  • The success path stops paying for a redundant gate. The donestandards --pinaccept path re-runs the gate zero times: the pin commit inherits the done vouch, so accept takes its fast path. The one expensive, common, provably-pointless re-run is gone.
  • Re-pinning is a first-class operation, not a hand-edit. The tedious read-the-number-and-retype step disappears, and because pin structurally cannot loosen, the "capture a gain" path can no longer be confused with a quiet loosening. The hand-edit survives only for its legitimate remaining use — loosening a mis-set limit, a deliberate decision recorded in its own commit.
  • Structural neutrality, not a heuristic. The "only standard limits changed" half of the safety argument is guaranteed — pin authored the commit. The "done ignores those limits" half is the single assumption, true for discern (verified: the gate's codegen documents the [standards] schema, never a project's live limit values) and for any project whose gate does not read discern's own config namespace. It is the same best-effort posture as ADR 0067's environment-drift residual, and fail-closed: a pin that cannot confirm a clean prior vouch simply carries none, and accept re-runs.
  • margin is backward-compatible. Its default of 0 leaves every existing standard pinning to the exact measurement; a project opts a drifting metric into headroom only when it wants to.

Alternatives considered

§
  • Reorder the workflow — standard before the final done run. Guidance only, no engine change. It fights the grain: standards are on-demand and you don't learn a metric improved until you run them, which needs a clean tree, which means you've usually already finished. A discipline patch for a structural gap — brittle, and it doesn't survive any further post-done commit.
  • A content-keyed receipt, or accept honoring a stale receipt when the diff is gate-neutral. Covers the whole class of gate-neutral post-done commits, but makes accept infer neutrality from a diff it didn't author — parse both discern.tomls, prove only [standards] moved — a weaker guarantee than the mutator that knows, with more surface, and it dilutes ADR 0067's clean identity model. Deferred until a second expensive instance of the class actually appears; the standard re-pin is the only common, full-gate member today, and it admits the stronger fix.
  • Fold standards into done (or a done --pin-standards). Reintroduces the slow measurement into the inner loop the standards/done split deliberately keeps it out of.
  • Pin to the exact measured value always, no margin. Simpler, but bricks any metric that drifts on unrelated commits — the pinned ceiling fails the next commit and can't be loosened without tripping the never-loosen guard. margin is the guard that makes pin safe to reach for.
choose openEsc close