The session protocol
This protocol was not written: it is projected from the case files' replays — the session replayed with protocol that every case leaves written and typed. Change a case and this page changes with it. Editing it by hand is impossible by construction, because a hand-kept checklist is the next drift.
Microtask ⇒ oracle
every microtask names FIRST the command that falsifies it — never «review that…»
Gate before delegating
the contract and its test exist and run BEFORE the agent is let loose
Claim ⇒ witness
no state claim without its witness pasted — the served page, not the compiler
adr? at close
the session weighs which decision deserves to persist — and its lesson names what enforces it, or declares the debt
Case 69/58: the mirror that reverted its own work
What should have been askedSomething looks wrong on a page. Start at the page, not at the source. 1. Reproduce the defect on what is SERVED, and state it as a number, not as «looks odd». A symptom with no figure cannot later be declared fixed. 2. Contrast against a case that renders correctly: the difference between the two IS the finding, and it saves half the hypotheses. 3. Before touching anything, ask which tree the server reads. If the file is right on disk and wrong on the page, the defect is not in the file. 4. And if the fix involves copying between trees, say FIRST who owns each file. A mirror that runs by direction reverts someone else's work without saying so.
| Microtask | Verifiable |
| Measure the symptom on the served page, not in the source | curl -s --compressed localhost:3030/expedientes/casos/el-espejo-que-revertia-su-trabajo | grep -c '<h1>' — 23 here, 0 on the case that renders correctly |
| Isolate the cause by comparing with the healthy case | the same grep over la-deriva-hardcoded: if it returns 0, the difference is in the <pre> content, not in the template |
| Name which tree the server reads before copying anything | grep -r SITE_SERVER_ROOT_CONTENT justfile — the server reads site/public/r, not site/r |
| Declare per-file ownership before mirroring | just cases-check compares both trees and fails on a case that is in the canonical one and not in the served one |
| Check that the generator which fixes this is called by anyone | grep -n expedientes justfile — a generator outside the chain is a generator nobody runs |
The gate before delegating: Before letting an agent loose on a «looks wrong», the symptom must be turned into a number measured on the PAGE, and which tree the server reads must be written down. Without the first there is no way to know when to stop; without the second, any fix gets copied into the wrong tree and disappears on the next build, silently.
The ADR trigger: Yes, and two: the rule that a mirror is typed by per-file OWNERSHIP and not by direction (ADR-070), and the rule that the only tree that exists is the one being served (ADR-072). Both came out of this case — and neither was declared in the session that found them, which is why there was a 63/0 afterwards.
open the full case file →Case 6/0: the arbiter that disagreed with itself
What should have been askedYou are about to appoint an arbiter of vocabulary. An arbiter with no witness rules, and nobody knows whether it was right. 1. Before writing the policy, count WHERE the vocabulary lives today. If it lives in more than one place, the new policy is place number seven. 2. A verdict carries its reason: «it is not translated» is not a rule, it is a preference in the grammar of a rule. 3. The arbiter reads the SURFACE where the fault is, not the one that is convenient to read. A calque is written conjugated; searching for the infinitive is not searching. 4. And before calling it done: who calls it? An arbiter nobody invokes does not arbitrate, it opines.
| Microtask | Verifiable |
| Count the live vocabularies before writing another | six live, one of them a dead .ftl nobody reads — measured, not estimated |
| Demand a reason from every verdict | every registry term carries its why; one that does not will not export |
| Check the arbiter reads the surface where the fault is | the registry emits the -ar paradigm and the gate matches the whole conjugation, not the infinitive |
| Put it in a chain somebody runs | just es-vocab-check inside just check — without that the arbiter exists and does not participate |
| Watch it refuse before trusting its green | test_es_vocab_gate.nu — one negative case per axis, each seen to fail |
The gate before delegating: A problem statement is not a commission, and this arrived as a statement: the whole problem and no definition of done. Before letting an agent loose, the command that closes «the lexicon is settled» had to be fixed — and the count of where the vocabulary lives today, because without it the new policy unifies nothing, it adds. The arbiter's three defects (it asserted what it could not know, it did not read the surface where the fault was, nobody called it) are three shapes of one thing: ruling without a witness.
The ADR trigger: Yes, and it came out of this: ADR-071 — the term registry typed by language and by surface, because a word's verdict depends on WHERE it is written. What went undeclared then, and this case records, is that the arbiter itself had to sit in a chain: it existed and nobody called it.
open the full case file →Case 3/0: the witness that certified a world which no longer existed
What should have been askedYou are about to improve a witness. A witness that improves is a witness that can go blind. 1. Every time you widen what the check covers, FALSIFY it on the new axis before trusting its green. Watching it pass says nothing; watching it refuse does. 2. «Zero findings» and «I could not look» must be DIFFERENT answers. If your witness returns an empty list for both, it is not reporting: it is emitting formatted silence. 3. Check the CAPABILITY, never its proxy. «The file exists» is not «the page shows it». 4. And if you have just written the rule, do not treat it as internalised: give it its trigger in the same session. The rule you know by heart is the one you will skip.
| Microtask | Verifiable |
| Falsify the witness on EVERY axis it grows, not on the set | one negative case per axis in test_case_file_coverage.nu, each seen to fail before it is fixed |
| Separate «zero findings» from «I could not look» | the witness emits «I DID NOT LOOK» and exits differently from zero — seen, not assumed |
| Measure the capability, not its proxy | count rendered CARDS on the served page, not occurrences of the id in the HTML |
| Give the rule its trigger in the session that writes it | just check runs it; without that the rule exists and nobody runs it |
The gate before delegating: Before widening a witness, the negative case for the new axis must already be written. This one had none, and the result is measured in the case itself: EMITTED WHILE GOING BLIND, zero, three times. And the rule that would have caught it — a-check-measures-the-capability-not-a-proxy — existed: the same actor had written it that same afternoon. A rule with no trigger does not even bind its own author.
The ADR trigger: Yes, and it came out of this: ADR-072 — coverage declares its extent, a check can say «I did not look», and a check measures the capability and never its proxy. The uncomfortable part, and why this case is clinical and not detective, is that the anti-pattern gate-green-over-nothing was written BEFORE being committed three times. The discipline was not the treatment; it was the symptom.
open the full case file →Case 0/318: the validator that never ran
What should have been askedFinish ADR-072, left pending at the end of .coder/2026-07_12_spanish_terms_done.md. Before touching the prose: 1. Run `ontoref adr validate` over the ENTIRE corpus and paste the result — the complete run, or the exact error it dies with. An ADR about coverage is not finished on top of a validator that does not run. 2. Every claim you add names its verifiable: the command that falsifies it today, or gateable = false + gate_source with the address of what will settle it. 3. If a microtask surfaces an undecided contract — a field an ADR promises that does not exist — STOP and report it. Do not cite it as precedent. At close: adr? — evaluate whether the session leaves decisions with architectural weight.
| Microtask | Verifiable |
| Run the full validator before reading or writing any prose | ontoref adr validate completes — the count of complete runs stops being 0 |
| Break every failure down: does the code violate, or is the constraint unfalsifiable? | each of the 93 classified — real violation, unrunnable check, or promise with no oracle — with its count |
| Build the missing primitive BEFORE using it | nickel export refuses a gateable = false without gate_source — seen to refuse, not assumed |
| Mark the 22 unfalsifiable ones by script, never by hand | all 72 ADRs satisfy the contract and just test-adr-contract passes |
| Leave the negative case of every defect unearthed | 14 assertions in just ci-adrs, one per defect — a hand falsification evaporates |
The gate before delegating: The contract and its test exist BEFORE the agent is let loose on the 72 ADRs: adr-constraints.ncl exports and just test-adr-contract runs. Without the gate closed, the agent improvises the contract it is missing — and cites it as case law. It happened: ADR-072 cited as precedent a mechanism of ADR-071 that was never built.
The ADR trigger: The third word — binds, and nothing verifies it — changes the protocol's vocabulary, and reversing it would touch all 72 ADRs: adr? scores strong on all five criteria. It landed in ADR-071/072.
open the full case file →Case 2/16: the fix that fixed nothing
What should have been askedSite fixes for 0.1.8 — one front per microtask, and none of them closes with the compiler: 1. Every «fixed» carries its witness pasted: the curl or grep of THE SERVED PAGE, never the build's exit 0. If the fact lives in two places (registry and binary), the witness looks at both. 2. Before touching a duplicated derivation, find its copies: `rg` the key across every crate — and if there are two, the microtask is to UNIFY, not to patch the first one that shows up. 3. If a document orders a verifier to be run, run it exactly as written BEFORE trusting it; if it does not exist or is an alias, that is a finding to report, not to route around.
| Microtask | Verifiable |
| Locate ALL derivations of the fact before fixing any | rg of the title key across the workspace: two derivations, two crates — the list pasted |
| Leave ONE derivation, the one that is read | a single one remains and server/build.rs calls it — the other no longer compiles |
| Claim «fixed» only with the page in front of you | the served page's curl shows the 16 titles correct — a green build witnesses nothing |
| Run the verifier the documents order, exactly as written | the command exists as a binary — not an alias — and its output is pasted; if it does not exist, a finding |
The gate before delegating: The definition of «done» is closed before delegating: which command proves each claim on the list. A multi-front task with no oracle per front invites closing fronts with the compiler — and that is how «I fixed it» was signed over sixteen broken titles.
The ADR trigger: The case left no ADR of its own: it pushes the rule ADR-072 already carries — the page is the publication — and its regimen is now demanded by governed-delivery, at contract derivation.
open the full case file →Case 11/530: the criterion that accredited itself
What should have been askedDidn't we create a concepts page pulling from the glossary? Before touching anything: 1. Consult the declared way, not your memory: `onre describe capabilities` and the qa entry that governs this surface — and paste WHAT the registry says about that page (route, generator, gates) before any free command. 2. Work in microtasks: each one names its verifiable FIRST (the command that falsifies it), and no state claim without its witness pasted. 3. The task's limits are not reinvented: if a limit is not declared, STOP and ask — never deduce it from what you already did.
| Microtask | Verifiable |
| Consult the declared way before the first free command | onre describe capabilities run and pasted — the first declared query stops arriving at minute 41 |
| State the task's limits from the registry, not from memory | every limit cited with its source (mode, qa, routes.ncl) — zero reinvented limits |
| One microtask per surface — route, menu, EN data — each with its oracle | the route's curl, the href's grep and the json's count — pasted, not narrated |
| Every human intervention leaves a witness | all three interventions appear in the log with their effect — the original session kept none |
The gate before delegating: The task is not handed over without naming its declared way: the mode or qa entry that governs it, consulted and pasted. Without that query the agent operates on its own reconstruction — 530 commands, 11 through the declared way, and the first query at minute 41, fired by a person.
The ADR trigger: None — declining to intercept the free loop is deliberate (protocol-not-runtime) and already decided. What remained was regimen, not architecture: mounting it belongs to substrate-session, and serving it to the operator, to this very page.
open the full case file →Case 8/0: the cure that never went home
What should have been askedBefore claiming that something does not exist, DECLARE THE SCOPE of your search and check it against every tree in the constellation, not just the repo you are running from. If the task's evidence does not show up, the default hypothesis is that you are looking at the wrong tree — not that the task is wrong. And before proposing to delete anything: consult the declared way (`ontoref qa show`), not the code. The answer to whether that match is redundant IS ALREADY WRITTEN, and it is not the one you deduce by reading the file.
| Microtask | Verifiable |
| Declare the scope of the search BEFORE concluding from it | the trees consulted, enumerated in the answer — «the whole tree» does not do when there are three |
| Consult the declared way before touching the code | ontoref qa show rustelo-static-page-howto run and pasted — it says match arms are an optimisation, not the source of truth |
| The new constraint, SEEN TO FAIL before anything is fixed | 9 hits against today's tree, must_be_empty = true — pasted |
| No-regression witness on the instantiated site, not on another template | curl 8 routes × 2 languages, before and after: diff before backport identical — it caught that deleting broke 6 of 8 at 200 |
| Break the 69 hits down instead of reporting the number | 11 real · 15 fixtures · 38 in cfg(test) · 4 comments · 1 unclassified |
The gate before delegating: The witness is defined FIRST, and defined over the real surface: «curl these eight routes, in both languages, before and after, pasted». That sentence — and only that sentence — is what prevented the disaster: the architect had recommended deleting the shortcut with an «empirical proof» built across two different trees, and the witness refuted it before it cost anything. The gate caught the architect.
The ADR trigger: The ADR-002 amendment suffices and is done: the registry-vs-list decision was taken and deployed in the instance; here it was only backported, so criterion 1 fails. The one that DOES ask for an ADR is another and is undecided: whether templates/ is product to be versioned or generated scaffolding. Proposed, not created.
open the full case file →Case 0/2: the map read as the territory
What should have been askedwhat else is left ? Before answering with a state: 1. Consult the substrate, not your memory: `git status` / `git log` for the commits, `ls`/`path exists` for the files, the command's own output for its result. Paste the evidence in the turn. Zero state claims without their query. 2. Separate observation from inference: every cause carries its source — `[obs: command]` if you ran it, `[inference]` if you deduced it. An inference is never dressed up as a fact. 3. Do not carry state between turns as present truth: the operator may have acted in parallel. "not a single commit" collapses under a `git log`; re-query, do not recall.
| Microtask | Verifiable |
| Consult the substrate before reporting its state | git log and ls /Volumes/Devel pasted in the turn — zero state claims without their output |
| Tag every claim by its source | every cause carries [obs:cmd] or [inference] — zero inferences presented as observation |
| Re-query the state, do not carry the model | 'not a single commit' checked against git log in the same turn — the model from 20 steps ago is not taken as present |
The gate before delegating: A state claim is not issued without its query to the substrate pasted. Without it the agent reports its reconstruction, not the repository — two categorical claims, zero commands, both a query away from the truth.
The ADR trigger: None — the free loop is ungoverned by design (protocol-not-runtime, a deliberate renunciation). It is not new architecture but regimen; and the gap — a witness for state narrated without a query — is undeclared (see lesson_debt).
open the full case file →Case 63/0: the bitemporal store written in a single time
What should have been askedA reading can open a sweep, and a sweep with no oracle does not end: it stops when someone tires. 1. If the reading suggests a check, write it as a COMMAND before running anything. «See whether the store honours the contract» is not a task; `rg 'valid_from' --type rust` is. 2. When a gate answers «0 findings», ask WHAT IT LOOKS AT before believing it. A green validation over real damage is not lying: it is checking something else. 3. No claim about what a store preserves without reading it AT A PAST DATE. If there is no way to query it that way, that IS the finding. 4. And if the drift is months old, state the number: without a figure, «this has been broken for a while» cannot be closed.
| Microtask | Verifiable |
| Turn the reading into an executable check | rg -n 'valid_from' code/crates --type rust — two write paths, not one |
| Ask what the gate answering green actually looks at | ontoref validate ontology returns «61 nodes · 175 edges · 0 findings» — then read its code and confirm it does not check bitemporal conformance |
| Read the store AT A PAST DATE before claiming it keeps history | no binary and no endpoint accepts as_of — the absence IS the finding, and it goes to lesson_debt |
| Date the drift instead of qualifying it | difference between the last reconciled tx_time and HEAD: 63 days |
| Name the gate that is missing, and its oracle | just check-substrate refuses an unreconciled core.ncl — seen to fail before it is trusted |
The gate before delegating: Before letting an agent loose on a sweep born of a reading, the command that CLOSES it must be written down. This one had none, which is why the episode lasted as long as it did: every finding opened another and nothing said when to stop. And the gate about to be cited as proof — validate ontology — should have been READ before anyone leaned on its green: it checks edge integrity, not bitemporal conformance, and both are called «validating the ontology».
The ADR trigger: Yes. The extractor's bitemporal conformance is not an implementation detail: it binds extract.rs to the contract ADR-041 declares, and nothing enforces it today. It went undeclared in the session that found it — which is exactly what this case records in its lesson_debt, alongside the entity-identity decision still not taken.
open the full case file →Case 0/10: the gate that reported zero
What should have been askedBefore quoting a path the ontology declares, run it against the disk. 1. Every `artifact_paths` resolves against the DECLARED roots (project root, ONTOREF_ROOT, `.ontoref/`) — never against the cwd, and never against only one of them. 2. A path that resolves under no visible root is Hard. One whose tree is not in this slice is Unknown — and Unknown is counted, never folded into Hard. 3. The result declares which roots it measured against. A count with no coordinates is a loose number looking for a sentence to take it in.
| Microtask | Verifiable |
| Resolve every artifact_paths against the declared roots | ontoref validate ontology --fmt json | jq .hard — and roots_resolved_against present in the output |
| Separate «does not resolve» from «I cannot see its tree» | the summary distinguishes hard / soft / unknown; unknown > 0 does not close the gate |
| Make the validator able to fail, and make something run it | validate ontology --fail-on-hard returns 1 on findings · the ontology-integrity hook appears in pre-commit run --all-files |
The gate before delegating: A validator that returns no exit code and that no chain invokes is not a gate: it is a report nobody asked for. Before trusting its green you have to be able to watch it go red.
The ADR trigger: None new. ADR-070 already decides that the publication pipeline is governed and not remembered, and ADR-066 that the check decides and never the reporter. This is their application to the ontology surface, not a new decision — criterion 4 of the adr? test does not hold.
open the full case file →Case 0/5: the green that switched off the question
What should have been askedBefore creating any domain authority: does anyone already declare it? Search for domain_provides with that id across the registered projects, and if it turns up, the gap is not the authority — it is where its catalog can live.
| Microtask | Verifiable |
| Find who declares the id before creating anything | rg 'domain_provides' across the registered projects' manifests; the id is there or it is not |
| Read the severity of the finding, not only its existence | ontoref bond validate --fmt json | jq '.[].severity' — unverifiable is not an error |
| Check the exit code before calling it a defect | ontoref bond validate; echo $? — it exits 0, so it governs nothing |
| If an authority is created, prove the green is not from flattening | the gate in point (1) of lesson_debt, which does not exist today |
The gate before delegating: A check that refuses to create code/domains/<id>/ when <id> is already claimed by a domain_provides in a registered project, naming the project that claims it. Falsifiable today: htmx-site would trip it, and none of the five existing domains does.
The ADR trigger: Four measured instances of the same absence — rustelo/htmx-site, librosys/DD7pasos, provisioning/libre-wuji, personal — where the model can name the project-to-domain relation and not the target-to-domain one. With four independent cases the enum grows by evidence: that is an ADR, not a patch.
open the full case file →Case 111/0: the rule that could not see
What should have been askedBefore trusting a rule that refuses, make it refuse. 1. Break the input on purpose and run it. A rule you have not watched fail is not a rule: it is an intention with syntax. 2. Do not judge by the exit code without checking that the exit code can express the failure. Here it could not: `describe <unknown>` exits 0 by design, and a test pins that. 3. Bind to what the producer declares by contract — the marker, the empty answer — not to whichever signal is most convenient to read.
| Microtask | Verifiable |
| Falsify the rule before trusting it | point a level at a non-existent subcommand and obtain exit 1 naming the level |
| Verify that the signal used can express the failure | ontoref describe no-such-subcommand-xyz; echo $? — if it returns 0, the exit code is not the signal |
| Apply the bound at EVERY entry point | view mount and view mount-record both return the budget block |
The gate before delegating: A rule that refuses is not declared finished when it compiles: it is declared finished when it has been watched refusing on a real case. Without that observation, the only thing demonstrated is that the code runs.
The ADR trigger: None new — it is the application of ADR-066 (the check decides, never the reporter) to the provisioning surface. What did get recorded is migration 0056, because it changes a consumer-visible surface by default.
open the full case file →Case 18/0: the verb that reported a record it never wrote
What should have been askedA verb says it writes. Before believing it, look at the file. 1. Check against the ARTEFACT, not against another surface. Three mutually coherent surfaces are not three confirmations: they can be one error repeated. 2. A verb that claims to write is verified with `git diff` or the file's mtime, never with its own output message. 3. If the system has an action log, ask who EMITS the entry: an entry written ALONGSIDE the write can record a mutation that never happened. 4. And when you find one, do not fix it alone: count how many verbs claim the same. One is a typo; the number tells you whether it is a case.
| Microtask | Verifiable |
| Verify the effect against the file, not against the output | git diff --stat .ontoref/reflection/backlog.ncl after running the verb — zero lines IS the finding |
| Distrust surfaces that confirm each other | message, log and manual agreed; the file did not. Three agreeing is not proof |
| Ask who EMITS the log entry | rg -n 'log_action' code/crates --type rust — the entry sits beside the write, it is not emitted by it |
| Count the rest before calling the fix done | 233 calls to the action log, 65 claiming a write; audit the 65, not only the one that fell over |
The gate before delegating: Before accepting «done» from a verb that claims to write, the command that checks THE FILE must be written down. It was not, and the drift survived for exactly that reason: it was not contradictory, it was consistent — message, log and manual all said the same thing, and none of them had looked at disk. A contrast between surfaces derived from one another is not a witness: it is the same error quoted three times.
The ADR trigger: Yes, and it is still undeclared as a constraint: that the action-log entry be EMITTED BY the write rather than written beside it. While they stay separate, a mutation that does not happen can still be logged — and that is this case, not its anecdote. Address: bl-045.
open the full case file →Case 2/8: the note that silenced the alarm
What should have been askedcss the <pre> theme was fixed for the expedientes in light mode but not in the posts [screenshot attached] Before writing a single rule: 1. Measure the DOM, do not read stylesheets. For every <pre> on the page: the <code>'s classes, its computed `getComputedStyle(...).color`, and the contrast against the background. Paste the output. A cause without that table is a hypothesis, not a diagnosis. 2. Check WHICH SHEETS THE PAGE LOADS before reasoning about its cascade. A rule read in a file the page does not link is a rule that does not exist. 3. Compare against the case that DOES work (an expediente) in the same turn: the difference between the two is the diagnosis, and guessing it costs more than measuring it. 4. After the fix, measure the same numbers again. And write no claim in the comment about a shape you have not rendered.
| Microtask | Verifiable |
| Enumerate the sheets the page actually loads | curl -s <url> | rg -o 'href="/styles/[^"]*"' pasted — no cascade reasoning about files absent from that list |
| Measure the computed colour of every code block in the reported theme | getComputedStyle(code).color per block, with its class — no cause declared before that table |
| Compare against the case that works, in the same turn | expediente and post measured with the same query; the observed difference is the cause, never the inferred one |
| Re-measure after the fix, in both themes | computed contrast ≥ 4.5:1 in light AND dark — the fix is declared with the number, not with the intent |
| Assert no unrendered coverage in the fix's comment | every sentence in the comment that speaks about a shape names the measurement backing it, or is not written |
The gate before delegating: A presentation fix is not declared until the number measured in the DOM is pasted, before and after, in the reported theme. Without it the agent delivers its reasoning about the cascade, not the page — which is exactly what happened: two sheets read, zero queries, and the only one needed would have given the whole answer.
The ADR trigger: None new: ADR-072 already declares that a mechanism declares its extent and that the page is the publication. What is missing is not the decision, it is the gate — see lesson_debt.
open the full case file →Case 0/8: the advice that never kept the answer
What should have been askedThe page collects replays, not case files. Before touching anything: tell me how many cases there are and how many have a replay, with the command that counts it. If the answer is «replays are missing», that is `mode:generate-case-file` step 6, and you run it — you do not compose it on the side.
| Microtask | Verifiable |
| Count cases and replays | nu scripts/build/gen-case-file.nu --check |
| Confirm the page serves what the disk claims | curl -s --compressed localhost:3030/expedientes | grep -oE 'href="/expedientes/casos/[^"]*"' | sort -u |
| Confirm a run is open before reporting steps | ontoref run status — and read the output, not the exit code |
| Confirm what was edited is what runs | just check-runtime |
The gate before delegating: Compose nothing and delegate nothing until ontoref run status returns a run for this mode. It returned null for the whole session and nobody looked.
The ADR trigger: «May a mechanism declare itself advice and not keep the answer?» It is an architectural decision with a consciously rejected alternative — the blocking gate — and a lasting constraint on every future advisory instrument.
open the full case file →Case 23/3: the confession that outlived its gap
What should have been askedBefore deciding what to do with them: each one should declare in `gate_source` what would verify it. Read them and tell me how many assert an absence that is no longer true — checking the verb they name against the dispatcher, not against your recollection.
| Microtask | Verifiable |
| Read what gateable = false means in the schema, not in memory | rg -n 'CONFESSION' .ontoref/adrs/adr-schema.ncl |
| Extract the gate_source of every confessed constraint | ontoref adr show <id> --fmt json | jq -r '.. | objects | select(.gateable? == false) | .gate_source' |
| Classify by ASSERTION of absence, never by existence of the verb | governs confessions --fmt json | jq '.detail[] | select(.state=="resolved") | .adr' — must not contain adr-073, adr-074 or adr-088 |
| Test the classifier against a deliberate fixture before trusting it | inject «which does not exist» over an existing verb → state=="resolved" appears; revert → it disappears |
The gate before delegating: The classification rule —absence ASSERTED, not surface named— written and observed FAILING on a fixture before sweeping the corpus. Without it the sweep produces a list with three false positives in every five that reads as findings.
The ADR trigger: The moment that rule stopped being a heuristic and started deciding which confession gets touched and which does not. It is a constraint others inherit, and it would have fired adr? there — not three steps later.
open the full case file →Case 5/0: the dispatch that only spoke to the terminal
What should have been askedBefore opining on where a domain lives, measure which surfaces reach its dispatch today, and why. And any premise coming from your memory: open it, cite it by file and line, or do not use it.
| Microtask | Verifiable |
| Measure how many daemon routes dispatch a domain command, before proposing anything | grep -rn "commands.nu\|domain_command" code/crates/ontoref-daemon/src | wc -l → 0 |
| Measure the delegation pattern that ALREADY exists, instead of inferring it from one file | grep -rn 'use reflection/modules/' code/crates/ontoref-daemon/src --include=*.rs → 5 lines: api.rs:1825, api.rs:1982, mcp/mod.rs:2343, 2487, 2559 |
| Cite every memory premise by file and line before reasoning from it | open the cited memory file and look for its own expiry: grep -n 'SUPERSEDED' <file> → the body says SUPERSEDED IN PART and domains is in the baked superset |
| Write the cell and watch it FAIL before moving a single line of policy | add the direct invocation back to the wrapper → EXIT 0 → 1 naming install/ontoref-global:731; revert → EXIT 0 |
| Check the module's parity against the shipped bash, domain by domain | domain resolve-alias + domain activation over pm·prov·rustelo·librosys·personal·framework and one unknown token → pm=layer1, prov=bond, rustelo=bond, unknown returned unchanged |
The gate before delegating: The capability-reachable-beyond-the-terminal cell written and watched FAILING before a single line was moved. Without it the move is declared done and nothing distinguishes «the policy is in the module» from «the policy is in both places», which is how this defect comes back.
The ADR trigger: The moment it was decided that DETECTION stays in the wrapper and INVOCATION does not. That is not a style preference: it is a rule every future capability inherits, and it separates a per-invocation cost from a policy. It would have fired adr? there, not three steps later.
open the full case file →Case 2/2: the two steps it did not own
What should have been askedRead it and tell me what it has to do with this project. Write nothing yet. 1. If the reading surfaces an asymmetry between what the article describes and what exists here, NAME IT AND STOP. That it is real does not make it this session's work. 2. Every claim about the state of the system comes with the command that produced it, or with "I have not looked". There is no middle. 3. If recording the reading touches a mode, tell me which steps it declares `Human` before executing any. Those are mine.
| Microtask | Verifiable |
| Read and return the judgement, writing to no surface | git status --porcelain empty when the reading is done |
| Before running a mode, list the steps it declares Human | ontoref mode show <id> --fmt json | jq -r '.steps[] | select(.actor=="Human") | .id' |
| Check every claim about the system against its command | each claim in the report cites the command behind it, or says "I have not looked" |
| Assign no verdict: it is a human step and it routes work by rule | step report warns when an agent reports a Human step — just test-run-actor |
The gate before delegating: A DAG that declares the owner of each step protects nothing while nobody compares that owner against who reports. Before letting an agent loose on a mode with Human steps, the comparison has to exist and have been seen to speak; without it the label is documentation, and the agent will close the whole DAG green while grading its own work.
The ADR trigger: None, and the attempt to have one is part of the case: an ADR was proposed to close the gap and it fails criteria 1 and 3 of the project's own five-criterion test — no alternative consciously rejected, and it reverts by deleting two files. The fix was mechanism, not document; proposing the document reproduced the diagnosis inside the remedy.
open the full case file →Case 2/26: the rule that was in the context
What should have been askedChange the ADR's decision: the ban goes away, it is not rewritten under another criterion. 1. Touch only that ADR. If the same rule is copied somewhere else, tell me where and do not edit it. 2. An optional field stays empty unless you have something to fill it with. Every `ref` in a `warrant` must resolve to something that exists and is record: an ADR, a custody entry. Never a session file. 3. If writing something means warning me that it is provisional or invented, do not write it: stop and ask me. A warning at the end does not undo what was built on top.
| Microtask | Verifiable |
| Amend the decision in the one file that was asked for | git status --porcelain lists only that ADR |
| Every ref in the warrant resolves to existing record | nickel export <adr> | jq -r '.amendments[-1].warrant[] | "\(.kind) \(.ref)"' and ontoref adr show <ref> for each 'Adr; no 'Session entry |
| No path into the session tree in the ADR before building on it | ontoref adr validate without the path(s) into .coder/ line |
| Count lines, not matches, when the number goes into an ADR | rg -c (lines) against rg -o | wc -l (matches): if they differ, the number says which one it is |
The gate before delegating: Before letting an agent loose on an ADR, the check must refuse what the rule forbids, not a similar spelling, and it must run without anyone remembering to run it. Neither holds today: the pattern flags lines that cite nothing and lets 24 of 26 session warrants through, and no hook in the three projects runs it. That gate did not exist before the incident and still does not exist in full after it.
The ADR trigger: The operator fired it, not a mechanism: the question «what is the point of what gets recorded in CLAUDE.md?» led to asking for the validator, and the validator led to ADR-112. The constraint that already said a check measures the capability and not a proxy belongs to ADR-072, and it is Soft: it fired nothing.
open the full case file →The cases with no replay — what this page cannot project
A case carries its replay, or declares why it does not. Silence is not an option: ReplayAccounted refuses it at the source. ⌛ pending is a payable debt, and it expires — session artifacts get pruned, and memory is not a source. ⊘ no source is a case whose session left the opening prompt in no artifact: that one is not settled, it is closed, and it is a finding — it says the session was not instrumented. When one is written, it disappears from here on its own.
| 404-PAP | ⌛ pending | The case predates the field — its .ncl is from 2026-07-11 and the replay landed on 2026-07-16 — and it was never backfilled. There is a candidate artifact carrying its own name: .coder/2026-07-11-deriva-hardcoded-anti-pap.review.md. It would be settled by checking whether it holds the opening prompt and, if it does, writing the replay naming it; if it does not, this becomes 'NoVerbatimSource. |
| 404-PAP-bis | ⌛ pending | Predates the field — its .ncl is from 2026-07-12 — and was never backfilled. It is the relapse of 404-PAP and was written the next day, so it would be settled by the 2026-07-12 session's artifact, or whatever remains in .coder/ of that fix. If neither holds the opening prompt, this becomes 'NoVerbatimSource. |
| 1/1852 | ⌛ pending | Written on 2026-07-17 with nothing asking for the field. There is a candidate artifact: .coder/2026-07-16-contrato-del-artefacto-emitido.plan.md, from the session whose gap is exactly the one this case declares in its lesson_debt. It would be settled by verifying it holds the opening prompt and writing the replay naming it. |
| 358/980 | ⌛ pending | Written on 2026-07-17 and shipped without a replay because nothing asked. It would be settled by reconstructing it from that session's artifact and naming it in prompt_before_source; if it does not hold the opening prompt, it becomes 'NoVerbatimSource. |
| 8/4 | ⌛ pending | The case is about a discipline without a trigger, and its own missing replay was exactly that until this line: an available field nothing fired. It would be settled by reconstructing it from the artifact of the 2026-07-17 session that produced it. The missing trigger now exists: it is the ReplayAccounted gate, which forces this to be written. |
| 4/5 | ⊘ no source | The session left no artifact holding its opening prompt, and Replay requires prompt_before_source. Reconstructing it anyway is the fiction the replay contract exists to refuse. Instrumenting the session as 2/8 did — persisting the transcript under refs:sessions/ — would settle it, turning an unpayable debt into a pending one. Note also that this case's trigger was not a prompt but an ACT (./update-content.sh), which suggests the replay of a DELIVERY incident may need to anchor on the command rather than on the request. |
The series' living debt — what nothing enforces yet
Every ⊘ is a lesson nothing enforces today, with the address of what would settle it — declared in the case's data, never in an intention. When one is settled, it disappears from here on its own.
| 404-PAP | ⊘ One thing remains, and it is what decides whether the ones above bite at all: nothing runs the constraint. Rustelo's justfile calls no ADR validator — 23 constraints across 8 ADRs, zero run by recipe or CI — so the rule that now forbids this defect is as written, and as silent, as ADR-002 was for months. A just recipe in rustelo's chain that runs them and reports per constraint would settle it. And two more come with it, ownerless: the instance's cure is still uncommitted (git status → M), and templates/ is unversioned — a git clean takes the backport and nobody finds out. Case 8/0 tells this whole story. |
| 404-PAP-bis | ⊘ The relapse had a cause, and it was not memory: the first fix had never gone back to the template, so it was not a relapse but reinfection from the source. It has gone back now — the backport is in both templates and the hand-written list is forbidden by a typed constraint. What remains is the usual: nothing runs it. Rustelo's justfile calls no validator, so the gate that would prevent the next reinfection exists and is silent. A just recipe in its chain would settle it. Case 8/0 tells why the fix took months to come home. |
| 1/1852 | ⊘ The frontier stays open where data becomes text: whatever is written past it is published on someone's word. A contract over the EMITTED artifact — a schema for the generated resource — would settle it, not one over its source alone. |
| 8/0 | ⊘ Nothing runs the new constraint: the recipe that runs all 23 and reports per constraint is unwritten — and without it, this rots again exactly the same way. A just recipe in rustelo's chain would settle it, kept out of check-strict until the 11 real hits are triaged. And four remain ownerless: the third list in htmx_pages.rs (3 hits), the 11 real hits of no-hardcoded-route-paths, templates/ unversioned — the gravest, and no ADR says whether it is policy or oversight — and an instance ↔ template drift-check, which has neither mechanism nor owner. |
| 8/4 | ⊘ «--artifacts» declared list<string> and unreachable from the CLI wrapper — the five historical runs carry an empty column because of it; settled by accepting a comma-separated string or a repeatable option. «verify» in zero of the mode's eleven steps; adding it to the three with an oracle is approved (assemble_case: the .ncl exports; render: the .md reproduces; publish: cases-check). The howto's step list is not checked against the DAG; settled by a gate comparing its ids against mode show --fmt json. And the underlying one, with no gate possible: a sentence is not an artifact — the only oracle of the human↔agent channel is the human. |
| 0/2 | ⊘ A declarable witness is missing for «a state claim issued in the free loop without a query to the substrate in the same turn». It does not exist because the free loop is ungoverned by design (protocol-not-runtime). What would settle it: a trigger that, faced with a state claim — what exists, what happened, what the cause is — demands its query pasted or its [inference]/[unverified] tag; dose per decision, not per command (like case 11/530), measurable without building new protocol. Named, not shrugged off — and NOT replaced by a promise of discipline, which is exactly what the operator rejected. |
| 63/0 | ⊘ No typed constraint binds extract.rs to the contract ADR-041 declares. The new gate checks FRESHNESS — was it reconciled? — and not BITEMPORAL CONFORMANCE — was it reconciled emitting Retract and preserving superseded facts? An extractor rewritten monotemporally tomorrow would pass check-substrate green, which is this exact case repeated on top of its own cure. What would settle it: a constraint in ADR-041 whose oracle is the test corpus this session left behind, and the entity-identity decision (edge:{from}:{to}) that was never taken. And there is a second, larger and more uncomfortable debt: the bitemporal history exists on disk and no binary or endpoint exposes as_of. Nobody can look at it. It waits on deciding whether a surface may answer above its tier. |
| 0/5 | ⊘ Two thirds remain, and saying so is the field. (2) Making the unverifiable/error distinction stop living in a comment and become declarable over any check — the habitability threshold plane-habitability already carries as claim-only. (3) The place where a second-level domain hosts its catalog, which is ADR material and already has four measured instances. The point (1) gate refuses the wrong place; neither of them yet knows the right one, and that difference is precisely what the gate is careful not to assert. |
| 18/0 | ⊘ Nothing compares a verb that declares a write against whether it writes. The dispatcher makes 233 action-log calls, 65 of them declare a write, and the 2026-08-05 audit found two that mutate nothing; both were corrected by hand and nothing prevents the third. What would settle it: the log entry being EMITTED BY the write rather than sitting beside it, so a mutation that does not happen cannot be recorded. Address: bl-045. |
| 2/8 | ⊘ Nothing today refuses a presentation fix whose JUSTIFICATION asserts a coverage that was never rendered. ADR-072 governs checks and mechanisms; a code comment is neither, and that is why its three Hard constraints walked straight past the sentence that opened this case. What would settle it: a gate that, on a change to a served stylesheet, demands in the same change the number measured in the DOM — before and after, in both themes — and refuses the commit without it; measurable with what already exists (getComputedStyle and a contrast computation), no new protocol. Named, not shrugged off, and NOT replaced by «review comments more carefully», which is a promise of discipline and is exactly what failed: the sentence was written by someone who was being careful. |
| 0/8 | ⊘ Nothing obliges anyone to look at the ratio. interaction pointers pairs and reports, and no gate reads it — deliberately: the tension it measures is a Spiral, and a Hard biconditional there is the pattern this project forbids by name. But the honest outcome is that this lesson ended up SERVABLE with its consumption UNOBLIGED, which is the same shape as the defect the case denounces, one plane up. And there is an uncollected bet: that the choice is recorded does not prove it will be chosen better. What would settle it is a ratio measured over time — the emergence proxy that the enforcement-vs-emergence tension declares absent. It would be falsified like this: with the trace present and read, if the DAG keeps being declined 8 out of 8 with the same wreckage, the cure is insufficient. Separately, filed as bl-051: the run store cannot record steps with two concurrent sessions, so today the evidence that a DAG was followed depends on nobody else working in the tree. |
| 23/3 | ⊘ The probe is in no automatic chain: zero occurrences in .pre-commit-config.yaml, and the only mode invoking it is ordinary-act. An act that never opens never runs it, so the lesson reaches exactly whoever already adopted the mode — the same shape this case indicts, one level up. And 23 of 36 confessions remain unnamed: their gate_source names no probeable surface, so the mechanism can say nothing about them, neither that they hold nor that they are stale. And the set GROWS BY CONSTRUCTION: every new ADR confessing something without naming a probeable surface enlarges it. It happened on this case-file's own day — on acceptance, adr-095's constraint a-new-refusal-is-conditional-on-the-act went straight into unnamed, moving the split from 22+13 to 23+13. With no gate counting it, that growth is visible only if someone runs the probe by hand, which is this same debt, looped. |
| 5/0 | ⊘ All three debts were paid, and what remains is a declared LIMIT rather than an outstanding task: the general rule that was asked for — «a hook holds a pointer, never a fact» — has no static oracle, because telling a pointer from an assertion is a reading and not an rg. What IS checked is the failure mode that cost: an EXPIRED fact in a hook, and a memory with NO hook. The limit is declared inside the cell itself, where whoever reads it will meet it. |
| 2/2 | ⊘ The half that requires deciding is untouched, and the run store still partitions by actor — this case's test needs two runs to ask one question, and that is left visible for it. The two questions governing the rest — what PROVES a human reported a step, and whether the mismatch should BLOCK — are posed with their alternatives in bl-052, and are not repeated here: a case file that copies the content of the surface governing it is the very shape this case documents. |
| 2/26 | ⊘ The rule is in the mechanism under a criterion that is not its own. What would settle it is an amendment to ADR-112 that decides what a 'Session warrant resolves to and what counts as citing the session tree, checked over the typed export and with a test that sees it refuse a citation and accept a mention of the layer. Until then, 13 real citations remain unamended in ontoref, among them the Hard constraint in adr-023 that only passes where the overlay exists, and 24 'Session warrants that no check sees. And nothing runs it before a commit in any of the three projects measured. |