Checkability is an ordered chain of rungs, and every rung names what no check answers
Accepted
Context
A project's instruments each answer one question about itself, and nothing composes them. `describe project` answers what it declares; `validate ontology` answers whether the graph is well formed; `constraint` answers what binds; `sync audit` answers which membranes are breached; `describe diff` answers what drifted; `positioning sources` answers what was read from outside. Six honest answers, and no surface that asks the question a person actually has: IS THIS PROJECT'S REASON FOR BEING STILL CHECKABLE, AND WHERE DOES IT BREAK.
That question was answered, until now, by assembling six readings in a human head, which means it was answered differently every time and never recorded. It is the same defect adr-080 found at the intake — a judgement paid repeatedly because nothing captured it — one level up.
WHAT WAS BUILT BEFORE THIS DECISION, and it was built deliberately BEFORE rather than after, so the decision would be taken against evidence instead of against a design:
.ontoref/positioning/narratives/the-ladder-that-holds.{es,}.md the argument, seven rungs .ontoref/reflection/schemas/ladder.ncl the contract .ontoref/reflection/ladder.ncl ontoref's own seven .ontoref/reflection/modules/ladder.nu show · rung · audit
The seven, in order, each the condition of the next: reason-for-being · reflection-executes · typed-categories · territory-and-criterion · accreditation · observability · knowledge-lineage.
THREE MEASUREMENTS THAT THE PROSE ALONE COULD NOT HAVE PRODUCED, and that are the reason this is a decision rather than an essay.
1. THE MIDDLE OF THE LADDER IS THE PROTOCOL'S OWN AXIS STRUCTURE, not a rhetorical invention. Rung 3 is `ontology-axis-substance`, rung 2 is `reflection-axis-act`, rung 5 is `witness-as-axis-seam` — the three axes of adr-031, in the order a project has to build them. The other four are what surrounds them: identity, government, observation, descent.
2. THE RUNG THE AUTHOR ASKED FOR IS THE BEST-CORROBORATED ONE IN THE CORPUS. Joining the rungs' anchors against the adr-080 intake (`positioning claims-index`), rung 5 draws 48 external claims from 25 sources — `witness-as-axis-seam` alone carries 30 claims from 20 independent readings, the highest count of any node in the graph. The ladder was not ranked by taste; the corroboration was computed.
3. THE INSTRUMENT PRODUCED TWO FINDINGS IN ITS FIRST RUN, both about ontoref itself and neither reachable before it existed:
· rung 7 is anchored in NO ontology node. 65 nodes in core.ncl and not one names lineage, custody or provenance, while the mechanism (adr-080, refs/, sources/, the assess-signal mode, `validate sources`) has been running for weeks. The project performs the rung and its graph has no concept for it.
· the shared check layer speaks THREE vocabularies that do not agree. The NCL contract (`audit-profile.ncl`) blesses Grep spelled `file` and the tag 'Validator; `check-shape` blesses `path` and 'Cargo and refuses 'Validator; `run-check` implements all of them INCLUDING 'Validator. So a check written against the contract dies at the gate with «This constraint has never been enforced», and a 'Validator check — whose executor branch is written to return `unresolved: true, skipped: true`, i.e. Unknown — is converted by the gate into a decisive Fail, which is `unknown-collapsed-to-reject`. Live uses today: 0 and 0 (76 files use `paths`, none uses `file`; no check declares 'Validator). It is a loaded trap rather than a live defect, and the author of this ADR walked into it within minutes by following the contract.
WHY PROSE WAS NOT ENOUGH, stated as the request that produced this: «que esto no sea sólo una prosa bonita sino un modo y/o eje real de uso del propio protocolo». A narrative can be admired and cannot be run against a project. The corpus already knows what that costs — a rule written as prose with no gate is, to a probabilistic agent biased toward visible progress, a suggestion its sampling is free to skip (adr-063).
AND WHY THE OBVIOUS MECHANISATION IS THE THING TO REFUSE. The moment seven rungs carry checks, the pull is to score them: seven greens, a percentage, a badge. Every rung's real content is a judgement — whether a declaration still matches an intention, whether declared modes are actually RUN, whether categories carve the domain or merely cover it — and none of those is decidable from a static tree. A ladder that reported «7/7» would be the lexical proxy for a judgement this corpus already names as a recurring failure, wearing a new coat.
Decision
A LADDER is an ordered chain of RUNGS declaring what must hold for a project's reason for being to stay checkable. The contract is fixed here in five rules; which rungs a project declares, and how each is evidenced, is the project's own.
1 · A RUNG IS A LINK, NOT AN ITEM
Ordinals are contiguous from 1 in declaration order, and every rung above the first names the one it stands on (`depends_on`). Inserting a rung renumbers the chain, and that cost is intended: «where does this go» becomes a decision somebody takes rather than an append.
2 · `judgement` IS REQUIRED AND NON-EMPTY
It names what the rung asks that NO CHECK CAN ANSWER. The contract refuses an empty one. A rung with no mechanical condition is honest; a rung that pretends the whole claim mechanises is not, and an empty `judgement` is exactly how a satisfied precondition gets read as a satisfied rung.
3 · `verified_by` HOLDS NECESSARY CONDITIONS
Failure is decisive; success is not sufficient. The checks are declared in the shape `checks.nu :: run-check` already executes — no second executor, no fifth dialect.
4 · THE AUDIT'S VERDICT SUBJECT IS `<rung>:conditions`, NEVER `<rung>`
`Pass` on a rung is UNREACHABLE BY CONSTRUCTION, because what would settle it is the judgement and no check reads that. The audit answers with the adr-088 ternary and emits the judgement as `unverified` on EVERY rung including the green ones: verdict.nu's contract is «what was read and what was not», and for a rung the unread half is always present. Dropping it on the clean rungs would lose the residue exactly where it is easiest to forget.
5 · THE AUDIT IS A READING, NEVER A GATE
Unknown leaves the exit code at zero; only a decisively unmet necessary condition fails. If the audit is ever wired into `audit-project`, that mode's steps assert THAT A READING WAS PRODUCED and never that it is clean — adr-084's `deviation-is-reported-never-refused` is Hard and in the negative direction, and a step whose `verify` demanded zero failures would turn a reading into the gate that ADR forbids without anyone editing a constraint.
AND ONE PERMISSION THAT IS PART OF THE CONTRACT: `anchors` MAY BE EMPTY, and an empty one is an OBSERVATION about the ontology — reported 'Soft, exit 0 — never a schema error. Requiring at least one node would force an author to invent a node to satisfy a type, which is buying a green by papering over the finding. Rung 7 is the case that proves it.
THE SEAM (adr-080's, applied again)
'Base the contract: the five rules above, the schema, the ternary, the reader and the audit. Every ontoref-governed project inherits exactly that. 'Project WHICH rungs it declares and HOW each is evidenced. A project with no site, no witness service and no intake corpus is not made to grow them, and the paths in any `verified_by` are that project's own.
Adoption stays opt-in in the strongest sense: a project with no ladder file has no ladder, and the reader says so rather than failing.
THE 'Base HALF IS DECLARED AND NOT YET SHIPPED, and saying so is part of the decision rather than a caveat about it. Everything this ADR governs lives today in ontoref's OWN spine — `.ontoref/reflection/schemas/ladder.ncl`, `ladder.ncl`, `modules/ladder.nu` — and nothing sits in `code/ontology/schemas/` or in the install templates, so NO consumer inherits any of it yet and the migration rule is not triggered. Shipping it is a separate act with its own cost: the schema moves to the data-dir companion, the reader is installed, and a migration accompanies both because that is the moment the consumer-visible surface actually changes. Accepting this ADR binds ONTOREF to the five rules; it does not silently make them everyone's. A reader who took «'Base» to mean «already inherited» would be reading a plan as an inventory — the exact confusion adr-070 names as existing versus participating.
WHAT THIS DECISION DOES NOT TAKE, named so nobody reads them as settled:
· whether ontoref's own seven ship as a DEFAULT SET a consumer inherits pre-filled, or whether a consumer always authors its own. Shipping seven opinionated rungs is a different decision from shipping the contract, and it needs a paid case rather than a plausible one (adr-103). · whether a lineage/provenance node enters core.ncl, closing rung 7's anchor gap. · whether `ladder audit` becomes a step of `audit-project` — which would make it protocol surface and carry its own migration. · what remains of the check-layer divergence. Two thirds of it were repaired the same day this ADR was written, on the operator's decision and not on the ADR's own authority: `check-shape` now admits the 'Validator tag (so its executor branch answers Unknown instead of the gate converting it into a decisive Fail) and the `file` spelling of Grep that the audit contract had always documented, with `tests/test_check_shape_audit_vocabulary.nu` pinning both directions plus three negative controls. WHAT IS STILL OPEN IS THE OTHER INSTANCE, and it is not this ADR's to close: 'ApiCall is declared by the ADR schema and implemented by nobody (bl-098), which is why `tests/test_check_dialects.nu` is red today and should stay red until that is decided. Widening the gate to admit it would let a check through to a branch that does not exist — a green over nothing, which is the failure both suites exist to prevent.
Constraints
- Hard Every rung in a project's ladder declares a non-empty `judgement`.
- Hard Every verdict the ladder audit emits names `<rung>:conditions` as its subject, never a bare rung id.
- Hard The ladder audit runs its checks through `checks.nu :: run-check` and answers with `verdict.nu`; it implements neither.
- Hard A project's ladder exports under its contract: ordinals contiguous from 1, and each rung's `depends_on` naming the one immediately below.
- Soft No gate, hook or mode step refuses on the ladder audit's findings; a step that runs it asserts that a reading was produced, never that it is clean.
Alternatives considered
- Leave the ladder as prose: the narrative, and nothing typed — rejected: It is the state the work started from and the one the request refused: a narrative can be admired and cannot be run against a project. It also loses the joins that produced everything of value here — the corroboration counts, the anchor gap, the conditions — none of which a reader can compute from an essay.
- Express the rungs as an audit profile under `reflection/audit/`, reusing AuditCriterion — rejected: The closest alternative and the one that had to be answered rather than dismissed. A criterion carries id, severity, check and verdict — and has nowhere to put the three fields that make a rung a rung: the ONTOLOGY ANCHORS it joins on, the VERBS that answer it, and above all the JUDGEMENT residue. Adding those to AuditCriterion would push a ladder's shape onto every audit criterion in the corpus to serve one consumer. The two mechanisms do share the check executor and the ternary, and this decision reuses both rather than growing copies.
- Make the ladder a gate: fail CI when a rung's conditions are unmet — rejected: Forbidden by adr-084 for a measured reason — the four defects found off the declared course would all have been refused by such a gate — and it would collapse formalization-vs-adoption by making a protocol opinion a precondition for someone else's commit. It would also make the Unknown verdict unusable: every honest admission of «I could not look» becomes a red gate, and the incentive is to stop admitting.
- Let a rung report Pass when all its necessary conditions are met — rejected: It is one word and it is the entire failure mode. A rung's claim is only ever half-readable, so a green over the readable half, labelled with the rung's name, is a green over the unread half too. The chosen shape keeps the useful signal (the conditions verdict is real and actionable) and removes the ambiguity by naming the subject.
- Fix the scope at 'Base only, or at 'Project only — rejected: 'Base only would export ontoref's seven rungs and its own paths to projects that share neither, which is the localisation adr-080's verdict vocabulary exists to prevent. 'Project only would bury a general contract — ordered chain, required judgement, unreachable Pass — inside one project's self-description, where no consumer could inherit it. The seam is the same one adr-080 declared and it is reused rather than reinvented.
Anti-patterns
- The ladder reported as a score — Rendering the audit as «N of 7 rungs passing», a percentage, or a badge — anything that presents the conditions verdict as a verdict about the rungs.
- A judgement written to satisfy the type — Filling `judgement` with a restatement of the claim, or with «needs human review», so the contract passes while the field carries nothing a reader could act on.
- An anchor invented to clear the observation — Adding an ontology node, or pointing a rung at a loosely related one, so the unanchored-rung observation stops printing.
Related ADRs
ADR-031 · ADR-070 · ADR-072 · ADR-080 · ADR-084 · ADR-088 · ADR-089 · ADR-091 · ADR-103