ADR 0106: standards --pin captures a measured gain and carries the gate receipt across it
Amendments.
- Vocabulary: current spellings are
standards(formerlyratchets),done(formerlyfinish),accept(formerlygraduate), 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. "
donenever reads[standards]limits" no longer holds — the gate now verifies every limit and measures each standard — and the alternatives' rejection of "fold standards intodone" is reversed for the terminal verb (the inner-loop half of that argument stands:preparenever 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]>(formerlydiscern-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 todiscern 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:
- The agent finishes its work;
discern doneis green, so a gate receipt names the current HEAD. - It runs
discern standards(on demand, not part ofdone) and a metric has improved past its limit. - To lock the gain in, it edits the
limitindiscern.tomland commits that change on its own. - It accepts — and
acceptre-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
marginfor 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-standardmargin(default 0) is the headroom pin leaves — floormeasured − margin, ceilingmeasured + 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 foracceptto 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 insidediscern.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_standardsMCPpinparameter 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
done→standards --pin→acceptpath re-runs the gate zero times: the pin commit inherits thedonevouch, 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 "
doneignores 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. marginis 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
donerun. 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-donecommit. - A content-keyed receipt, or accept honoring a stale receipt when the diff is gate-neutral. Covers the whole class of gate-neutral post-
donecommits, but makesacceptinfer neutrality from a diff it didn't author — parse bothdiscern.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 adone --pin-standards). Reintroduces the slow measurement into the inner loop the standards/donesplit 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.
marginis the guard that makes pin safe to reach for.