Case 2/16: the fix that fixed nothing
Sixteen broken titles, one fix, a green build — and the sixteen titles untouched, because the key was computed in two places and I changed the one nobody reads
🕵️ Show the full case file → 📋 Session protocol →
Case file · Code Homicide Dept.
Sixteen of twenty pages were serving the name of a broken key as their title, at 200, including the privacy policy and the legal notice. I found the guilty derivation, fixed it, rebuilt, and the build came out green. The sixteen titles stayed exactly as they were. The key is computed in TWO places, in two different crates, and I had fixed the one the head does not read. And that is only half the case: while chasing it I found that the project's own stored answer — verified, dated, written so that nobody would have to guess — asserted that a mechanism did not exist. It existed. It was applied. With its env var exported and the consumer's route files already written. I was one command away from reimplementing it.
Show glossary
- derivation
- The rule that turns one datum into another: from `OntorefPage` to the key `ontoref-page-title`. A derivation is a COMPUTED FACT, and a fact computed in two places is two facts that will eventually disagree. The question is never whether they diverge. It is when.
- seam
- The point where a consumer adds something of its own WITHOUT touching the implementation: here, its own routes, merged at startup over the ones the shared image ships. A seam that exists and that nobody knows exists is worse than no seam at all — because whoever looks for it and does not find it builds a second one.
- howto
- An answer stored in the project's knowledge registry, with its date and its verified flag. It exists so that nobody has to guess. And that is exactly why, when it stops being true, it is more dangerous than nothing at all: with documentation, you stop looking.
- Fluent key
- Every text on a static page lives in a key. And there are TWO ways to kill the whole file: repeat a key, or write one with no value. The second was committed by the very generator this author had already armoured against the first.
The protocol to declare, version and verify this → ontoref.dev
The double ledger — what it cost, and what it left
Look at the proportion presiding over the table: two derivations, sixteen titles. It is not a big error. It is a duplicated one, which is a different animal: a defect that survives its own repair and, meanwhile, spends the confidence of whoever repaired it. And look at the zero near the bottom: «times the verification command two documents tell you to run exists». Zero. That is not a broken net. That is a net painted on the floor.
What the crime cost
- Routes the site declares 24
- Titles serving the name of a broken key, at 200 16 of 20
- Derivations of that key, in two different crates 2
- The one I fixed first the one the head does NOT read
- Titles still broken AFTER rebuilding with that fix 16 · the same ones
- How long the duplicate derivation had been alive (git) since 2026-07-10
- The howto I consulted: date and flag 2026-07-13 · verified: true
- …and what it asserts «a consumer CANNOT declare its own routes»
- The mechanism it says does not exist exists, applied, with its env var exported
- Consumer route files already written 2 · es.ncl and en.ncl
- The verifier that howto tells you to run
ore rustelo routes --check - Times that command exists 0 · neither the alias nor the subcommand
- Invocations of
ore—an alias that NO LONGER EXISTS— in the knowledge base 355 - Files invoking it 83 · 21 of them ADRs
- Invocations of
onre(today's alias, same defect, not yet broken) 126 - The real command, which neither of them names
ontoref - Times case 0/318 already convicted this 1 · «aliases, not binaries»
- Executable checks that case fixed 33
- Invocations in PROSE it left untouched 481
- Pages that LOOKED cured, by coincidence 1 of 2
- Fluent keys my own generator deleted with an empty value 9 · while 1861 survived
- Locks I had written against that 1 · the duplicate one. Two were needed.
- Broken titles at the end 0 of 20
What the case left behind
- The rule fixing one of two derivations changes nothing, and looks like it changed everything
- The derivation one, public, and the head's generator CALLS it instead of copying it
- The head reads the route registry, like the body — no more half a page
- The declared route beats the URL segment; no more being cured by coincidence
- The other edge of the knife the generator also refuses to emit a key with NO VALUE
- The howto corrected, with the date of its lie written inside it
The point of abandonment — what the table doesn't show
The point of abandonment came right after the first fix, and I walked through it feeling like the job was done. I had found the derivation, changed it, written three tests, the build had gone green and the logic was flawless. The only thing I did not do was ask the server for the page. I wrote «the sixteen titles are fixed, it just needs a restart» — a sentence that sounds like diligence and is a prediction dressed as a finding. And it was false. One curl would have done it. What saved the case was not my rigour: it was that the next measurement was unavoidable, because the restart had to happen anyway.
The suspects — the false leads
| «The route was in the wrong file» | “«The route was in the wrong file.» True: I declared it in `routes.ncl` and the page 404'd; the site's seam (`site/config/routes/ | ruled out — the symptom, and it was warned about |
| «The howto was stale» | “«The howto was stale.» It was, and it is the weapon. Verified on 13 July, carrying `verified: true`, it asserts that a consumer CANNOT declare its own routes and that «the fix is small and localised». The fix was already done: `merge_site_routes` is applied, `run.sh` exports its env var, and both consumer route files exist. But a document does not maintain itself. Blaming the howto is blaming the gun.” | ruled out — the weapon, not the culprit |
| «The mechanism for a site to contribute routes was missing» | “«The mechanism for a site to contribute routes was missing.» This is what I believed, and I went as far as proposing a plan to implement it. It is ruled out by reading twelve lines of Rust: the mechanism exists, and it exists EXACTLY where it had to — the code's own comment says why it sits in the embedded branch and not the filesystem one: «a fix that only lived there would be a fix nobody could run». Whoever wrote it thought of this. I did not read it.” | ruled out — the mechanism existed, and explained itself |
| «I fixed it» — said in front of a green build | “«I fixed it.» GUILTY, and it is nobody's: it is the sentence everyone says. I said it after changing the code and seeing a green build — that is, after confirming the compiler was happy, which is a statement about the CODE and not about the PAGE. And the page, which was the only thing that mattered, went on serving sixteen broken titles. A green build does not say the fix landed: it says it compiles. A whole case fits between those two sentences.” | GUILTY — and it is everyone's sentence |
The weapon — Two crates, one key, and the one that is read is not the one I fixed
// crates/server/build.rs ← the derivation the <head> USES
fn component_to_key_prefix(component: &str) -> String {
format!("{}-page", component.to_lowercase()) // OntorefPage -> ontorefpage-page
}
// crates/build-config/src/site_config.rs ← the derivation I FIXED
pub fn ftl_page_prefix(component: &str) -> String {
// strips the Page suffix, kebab-cases OntorefPage -> ontoref
}
// The site's .ftl files, always and forever:
// ontoref-page-title = ...
//
// One of the two agrees with the data. The other is the one that is read.
// I changed the one that agrees. I rebuilt. The build came out GREEN.
// And the sixteen titles went on serving `[ontorefpage-page-title]`.
And there is a detail that turns this from anecdote into case: one of the two pages looked cured. /conceptos served its title correctly, not because the fix worked, but because its URL segment — «conceptos» — happens to equal its page id, and the branch that derives the title from the segment got it right by luck. If both new pages had had that luck, I would have closed the case with the defect alive. It was /sobre-el-idioma that gave it away, whose key is lenguaje-page-title and whose segment looks nothing like it. A coincidence very nearly signed the discharge papers.
The turn — Fuse the two into one, and let the head read what the body reads
# 1. ONE derivation. And the other crate CALLS it instead of copying it.
fn component_to_key_prefix(component: &str) -> String {
format!("{}-page", build_config::ftl_page_prefix(component))
}
# 2. The <head> reads the REGISTRY, not the baked enum. A page the site
# contributes at startup does not exist in the enum — and it was serving
# a perfect body with a broken title.
let registry_title = load_routes_config().routes.iter()
.find(|r| r.path == path && r.language == language)
.map(|r| r.title_key);
# 3. And the declared route BEATS the URL segment. Without this, /conceptos
# looked cured — because its segment happens to equal its page id.
if registry_title.is_none() && (component == NotFound) { ...derive from segment... }
# Two functions that must agree are two functions that will eventually disagree.
One confession is left, and it is the one that stings. While fixing all of this, my own generator for the new page emitted a Fluent key with no value — a syntax error in Fluent — and deleted its page’s nine keys while the other one thousand eight hundred and sixty-one carried on undisturbed. Weeks earlier I had written a lock in another generator against duplicate keys, and published an entire case file about it. It never occurred to me that the same knife had two edges. A lock against half a defect is a lock against nothing.
The verdict
The series asks: with ontoref, would it not have gone like this? And this case is the most uncomfortable one to answer, because the protocol was in place and working, and nothing of its own failed. The answer was in the knowledge registry, one command away, and I ran that command. The mechanism was implemented, documented inside itself, with its reasoning written into the code. The gates were green. Everything ontoref promises was there, and the sixteen titles stayed broken anyway — because the failure was not in the system: it was at the frontier between the system and the person asking it. I did three things, and all three are the same thing. I trusted a document over the code — and the document carried verified: true, which is precisely what makes you stop looking. I trusted a diff over the page — I changed one derivation believing it was the derivation, never once asking whether there might be two. And I trusted a green build over a curl — which is trusting that the compiler is happy when the question was whether a reader sees a title. All three times I measured the thing next to it. What this case file adds to the series is not a new mechanism: it is a warning about the ones already there. A verified: true does not expire on its own. A verification command nobody has ever run may not exist at all — and here it did not, and two separate documents told you to run it. And a fact computed in two places is a fact that, the day somebody fixes one of them, will lie to their face with a smile and a green build.
| A fact computed in two places | They are fused into one. Not made to «agree»: made to BE the same. build-config was already a build dependency of the other crate — the function was made public and the <head>'s generator now calls it. Two functions that must agree are two functions that will eventually disagree. |
| Half a page from the registry, half from the binary | The <head> reads the route registry, like the body. A site contributes its routes at startup and resolve_static_page serves their content with no rebuild — but the title came from the enum generated at build time, which cannot know a route added afterwards. Perfect content and a broken <title>, at 200, in the one element Google reads. |
| A coincidence that makes the unfixed look fixed | The declared route beats the URL segment. Without that guard the title was derived from the segment whenever the component was not compiled — and on /conceptos that happened to equal the correct key BY COINCIDENCE. One of the two pages looked cured. The other one gave both away. |
| A verified answer that stopped being true | It is corrected, and the date of its lie is written inside it. A howto carries verified: true and a date — and neither expires on its own. This one asserted that a consumer cannot declare routes, and the mechanism already existed, applied, with its env var exported. I read it, I believed it, and I was one command away from reimplementing what was already done. |
| A verifier that does not exist, ordered by two documents | ore rustelo routes --check. Named by the howto AND by the site's own routes file. It does not exist twice over: ore is an alias renamed to onre that today resolves to nothing, and the rustelo subcommand does not exist under the real command, ontoref, either. A verification step nobody can run is worse than none: whoever reads it believes there is a net. |
| A knowledge base that tells you to run an alias | An ADR, a howto and a comment are not executed: they are read. That is how 355 invocations of ore — an alias that no longer exists — survived across 83 files, 21 of them ADRs, plus 126 of onre, the same defect not yet broken. An alias lives in one person's shell profile; the binary is called ontoref and exists for everyone. A document names the COMMAND, never its author's shortcut. |
| The same defect, convicted and still alive | Case 0/318 already ruled on this: «ore and onre are aliases, not binaries… a constraint that can only pass on its author's laptop is not a constraint». And it fixed the 33 checks that EXECUTE. It left 481 invocations in the prose — because prose does not execute, nothing failed, and the defect stayed alive exactly where the project explains how it works. It is caught where it runs; it survives where it is only read. |
| A generator that emits a key with no value | The other edge of case 1/1852's knife. There a generator wrote a DUPLICATE key and took the whole language down; I locked it. Here the same generator — written by the same author, after publishing that case — emitted a key with NO VALUE, a Fluent syntax error, and deleted its page's 9 keys while the other 1861 carried on. A lock against half a defect is a lock against nothing. |
The reconstruction — the session, replayed with protocol
What was asked — reconstructed from outreach/.coder/2026-07-14_site_slides_updates_done.md
fixes on the ontoref website version 0.1.8 the Architecture diagram on the home page says v0.1.7 does anything need updating in it for 0.1.8 ? why doesn't a click on it zoom in lightbox mode like the images in posts do ? - the ontology slides need reviewing and verifying against the ontoref lexicon - make a Spanish version of rustikon.md with the lexicon and term verification
What should have been asked
Site 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.
Case law — what enforces the lesson today
- ✓The page is the publication: verify what is served, never the compiler
adr:072/the-page-is-the-publication - ✓The live witness counts the card on the page, not the string in the HTML
test:scripts/build/check-served-live.nu - ✓The contract's oracle reads the SERVED surface when the deliverable is a page — never the compiler
mode:governed-delivery/derive-contracts
One thing remains, and it is not comfortable. This case file is written by the same person who published 1/1852 — «the generator that reported success» — a few hours earlier, whose moral, in capitals, was verify the page, not the file. And he did it again: he verified the diff, not the page. He wrote a lock against duplicate keys and his next generator died of an empty one. That does not invalidate the lesson; it confirms it. A lesson learned is not a mechanism, and that is exactly why this project insists that the mechanism has to refuse — because the one who learned the lesson is going to forget it again, and the lock will not.
Glosario
Sin coincidencias.