A gate binds only a DECLARED act — the ordinary act gets a surface, and the one refusal that would fire on every commit is left out on purpose

Accepted

ontoref
Measured 2026-08-16: of 34 modes, every one covered a product (generate-*, new_*,

Context

Measured 2026-08-16: of 34 modes, every one covered a product (generate-*, new_*, publish-*), a ceremony (governed-delivery, coordinated-delivery), maintenance (sync-*, validate-*) or memory after the fact (coder-workflow). Searching all 34 triggers for fix|bug|task-arrives|triage|intake returned nothing. The most frequent act in the project — "fix this", "build that", "why is this failing" — was the only one with no surface.

The consequence is not that the act went ungoverned in some abstract sense. It is that every gate had to GUESS which act was in progress from a proxy: a glob, a filename, a keyword. Guessing is why they misfire and get skipped — the session hook routed a question about SOWs to a decks howto twice because the words "outreach" and "site" appeared, and markdownlint ran `pass_filenames: false` over the whole tree, failed on every commit regardless of content, and was skipped four times in one session before anyone read it (adr-070, fifth reading).

The heavy path exists and is not the answer to this. `governed-delivery` ran twice — both on the day adr-066 was accepted — and not once in the six weeks after, while `generate-article` accumulated 26 runs. The sixth reading of enforcement-vs-emergence names the difference: an article is wanted at the moment it is made, a guarantee is missed only later by whoever audits. A floor in no chain is indistinguishable from a floor that was never built, and it does not stay neutral — it grows a prose copy of itself, which is what .coder/2026-08-14-pauta-de-sesion.info.md was, confessing its own condition in its last section.

A throwaway prototype (2026-08-16) established by OBSERVED REFUSALS, not by argument, that a pre-commit gate can refuse for six reasons a diff does not contain: act undeclared, act unscoped, scope exceeded, governed surface unconsulted, consultation stale, reversibility unclaimed. Two properties were measured. Forging the consultation record requires PERFORMING the read — it carries a digest producible only by running it. And the cost is negligible at the right hook event: 0.04s per ordinary call. Unplanned, the scope rule stopped a commit from swallowing an unrelated staged file, which is the d3279f0 failure bl-053 describes.

Decision

Give the ordinary act a mode, make the act EXIST AS DATA without inventing a format, and wire a gate that binds only what an act declared.

MODE. `ordinary-act`, three steps, and it does not gate: situate (`governs <path>`), agree the done-condition BEFORE the work with its oracle named or its absence declared, close giving every finding one of three destinations — fixed, confessed as `gateable = false` with a `gate_source`, or deferred with a date. Escalation by reversibility is not restated in it; it points at the `escalation` field of reflection/forms/new_feature_proposal.ncl.

THE ACT IS A RUN. `run start` opens it, `step report` populates it, `mode complete` closes it, in the store every other mode writes to. `vars_required = ["scope", "reversible"]` makes `run start` REFUSE to open without both. And `step report --status skip` is the third verdict `unknown-is-deliverable` had been asking for — the biop that reported UNANSWERED because the delivery record had nowhere to write "could not answer".

THE GATE BINDS FIVE OF THE SIX REFUSALS AND IS SILENT WITHOUT AN ACT. The sixth — act undeclared — would fire on every commit, so it is excluded. Two of the remaining five stopped being refusals and became impossibilities via `vars_required`. What runs at commit time is scope-exceeded, reading run.json and the git index and nothing derived: 0.04s.

CONSULTATION REPORTS AND DOES NOT REFUSE, for two measured reasons. Routing is not obligation: one staged file routes to TEN ADRs and five to FIFTEEN, because the router keeps broad ancestors on purpose — right for orienting, wrong for binding. And `governs` re-derives the 87-ADR corpus per call at ~7s a path, which forbids the position regardless. It lives in `ontoref act consulted`.

Constraints

  • Hard The act gate MUST exit 0 without output-bearing refusal when no `ordinary-act` run is open. It binds only a declared act; it never opines on a commit made without one.
  • Hard `ordinary-act` MUST declare `vars_required = ["scope", "reversible"]`, so an act that exists always carries both and neither can be caught later as a refusal.
  • Soft Any refusal added to the act gate MUST be unable to fire when no act is declared. A check that can refuse an undeclared commit does not belong in this gate.
  • Soft The consultation checks (a routed surface unread, or read before it moved) MUST report and MUST NOT refuse, until a specificity rule is MEASURED and the routing surface stops re-deriving the corpus per call.

Alternatives considered

  • Wire all six refusals, including «no act was declared»rejected: It fires on every commit, which trains the reflex skip. Measured in this repo, not imported: markdownlint ran over the whole tree, failed regardless of content, and was skipped four times in one session before the warning was read. A gate that never discriminates is worse than no gate, because it consumes the attention the discriminating ones need.
  • Wait for evidence that the mode is invoked before wiring anythingrejected: Unsatisfiable by construction: nothing causes the invocation, so the evidence cannot arrive. It is the governed-delivery death restated as a plan. bl-079 keeps the original wording next to this correction because the error is the useful part.
  • A dedicated act record (a `.act/current.json` sidecar, as the prototype used)rejected: The run store already holds exactly this, with a schema, an executor and a DAG that enforces step order. A second file would be a mirror of it, and mirrors here have a measured cost (ADR-070, four incidents).
  • Make consultation binding — refuse a commit whose staged paths route to a surface the act never readrejected: Two independent measurements forbid it. One staged file routes to ten ADRs, five to fifteen: the router keeps broad ancestors on purpose because that is right for ORIENTING, so using its full answer as an obligation demands fifteen reads per commit — the always-firing gate again. And `governs` re-derives the whole corpus per call (~7s a path), so the position is unaffordable regardless. Promoting them needs a MEASURED specificity rule and a router that does not re-derive per call, not a number chosen to make the count comfortable.
  • Give the mode a `verify` on every step so no status is self-reportedrejected: qa:verifiers-bind-to-context-not-to-flow states the rule: a verifier resolves against a slice and a context at operation time, and `verify` is a convenience for the MINORITY of steps machine-checkable when the mode is written. Whether a done-condition is well agreed is a judgement; a command pretending to measure it would be theatre, and the first attempt at exactly that could not even execute.

Anti-patterns

  • A gate that fires on everything — A refusal is added that cannot distinguish the case it cares about from every other commit, so it fires unconditionally. It reads as thoroughness and trains the reflex skip, and it takes the discriminating gates down with it because they share the attention. Measured here: markdownlint with `pass_filenames: false` over the whole tree, skipped four times in one session, and the linter turned out to have been right about something real that nobody read.
  • Waiting for adoption before wiring — A floor is built and its enforcement deferred until there is «evidence it is used». Nothing causes the use, so the evidence never arrives and the floor stays out of every chain — where it is indistinguishable from one that was never built, and where it grows a prose copy of itself. It presents as prudence and is a deadlock the author created. governed-delivery is the measured instance: two runs on the day of acceptance, none in the six weeks after.
  • A verify that cannot be written, then removed instead of narrowed — A mode step is given a `verify` referencing something unknowable at authoring time — here the run directory, which carries the task in its name. It cannot execute. The tempting repair is deletion, which leaves the step self-reported: the position adr-066 exists to refuse, arrived at while appearing to respect the rule that verify is for machine-checkable steps. The honest repair is to NARROW the check to the part that does leave a trace.

Related ADRs

ADR-066 · ADR-070 · ADR-074 · ADR-094 · ADR-029

Was this useful? Rate it
Got something to add? Tell me what you think, what you'd suggest, or whether we should keep exploring this topic.
· reads

We use cookies to help this site function, understand service usage, and support marketing efforts. Cookie Policy for more info.