Case 8/0: the cure that never went home
Eight lines closed the case that opened this series. They exist, they are proven, they serve this page — and they have reached nowhere
🩺 Show the full clinical history → 📋 Session protocol →
Clinical history · Software Pathology Service
Eight lines closed the case that opened this series. They exist: written, proven, and serving this very page right now. And they have reached nowhere — not the commit of their own instance, where someone kept adding kinds BY HAND, one at a time, up to seven, with the cure already written in the file next door; nor the two templates every new site is born from, which are exactly as they were. The patient was cured and the prescription was not. And when the prescription was finally seen to, the architect — with «empirical proof» — recommended deleting the shortcut. It would have broken six of eight routes. Answering 200.
Show clinical picture
- instance / template
- The template is what a site is born from; the instance is the site once born. Fixing the instance cures one patient. Fixing the template cures the ones not yet born. They are not the same, and nothing obliges you to do both.
- optimisation
- A shortcut that answers before the general mechanism does, giving the same result. Its virtue is that it can be deleted without consequence. The catch is that this is only true while the general mechanism covers everything the shortcut covered — and nobody checks, because nobody declared it a shortcut.
- backport
- Taking back to the source a fix that already lives, proven, in something derived from it. It sounds like paperwork. It is the only thing separating curing a case from curing the disease.
- declared debt
- A rule that binds and that nothing verifies, that SAYS SO. Neither green nor red. It is what separates this case file from a promise today: what is not enforced is written as not enforced, with the address of what would settle it.
The protocol to declare, version and verify this → ontoref.dev
The double ledger — what it cost, and what it left
The figures on the left have an easy reading and a hard one. The easy one is the 4, the 7, the 69. The hard one is the zero — «constraints run today by a recipe or CI: 0» — because that zero does not measure a defect: it measures how many of this project’s rules have ever had the chance to say no.
What the crime cost
- Kinds re-listed by hand, per template 4
- …and in the instance's HEAD, which ALREADY had the cure, uncommitted 7 ·
domains,catalog,adradded by hand - Places carrying the hand-written list — not two, three 3 · both templates +
htmx_pages.rs - ADR constraints in rustelo's corpus 23 across 8 ADRs
- …run today by a recipe or CI 0
- The rule forbidding this, written since ADR-002 · «without any hardcoded match arms»
- …pointed at a corpus the defect is not in
crates/foundation/· the defect lives intemplates/ - …with a pattern that would not catch it anyway requires a leading slash; the defect is
"blog" => - Hits of that rule against its own scope 69
- …real violations, once broken down 11 · the other 84 % was its own pattern's noise
- Routes that lost their grid when the shortcut was deleted — answering 200 6 of 8
- Compile errors in the htmx-ssr profile, preexisting 8 · it had never compiled
- Templates under version control 0 of 2 ·
git status→?? - Preexisting defects nobody asked for, found along the way 6
What the case left
- The rule an optimisation is not a redundancy — and one nobody declares reads as the source of truth
- The second fixing the instance is not fixing the product
- The constraint, written and SEEN TO FAIL
adr:002/hardcoded-kind-list-shadows-registry· 9 hits, then 3 - The backport, in both templates the registry resolves; the hand-written list is gone
- The breakdown that turns a number into a diagnosis 69 → 11 real · 15 fixtures · 38 in tests · 4 comments
- The htmx-ssr profile, compiling for the first time
- And what no table records the witness caught the architect, not the other way round
The point of abandonment — what the table doesn't show
The point of abandonment was not a temptation: it was a recommendation, signed, with proof. This case’s architect — the one who wrote the plan, drafted the rules, published the case file about measuring the box next door — said: «the shortcut adds no capability, delete it», and called it empirical proof. They had read the template’s code and curled the instance: two different trees, a demonstration built astride both. Had it been executed, six of eight routes would have lost their grid answering 200 — the failure no smoke test sees. The architect did not stop it. Neither their experience, nor their care, nor having spent the whole day publishing precisely this lesson. What stopped it was one sentence in the task: «curl these eight routes, in both languages, before and after, pasted, not narrated». That is all it took, and it is all there was. The gate caught the architect — and that, not the fix, is the only reason this case file is written in the past tense.
Differential diagnosis — what was ruled out
| Whoever fixed it and did not take it back | “«They forgot to take the fix back.» They did not forget: there was no way back. The fix is intact, with its PAP comment explaining the rule and naming `/recursos` itself. What does not exist is a mechanism that notices the source and the derivative have diverged. There was no oversight: there was no return path.” | ruled out — no oversight, no return path |
| «The template is scaffolding, who cares» | “«The template is scaffolding, who cares.» Every site is born from it. And it gets worse: it is not versioned — `git status` answers `??`. So it is neither disposable scaffolding nor tended product: it is the one tree everything depends on and that nobody declared themselves the owner of.” | ruled out — and something worse appears |
| «ADR-002 did not forbid it» | “«ADR-002 did not forbid it.» It forbids it in letter — «mapping paths to component names without any hardcoded match arms» — over an axiom marked invariant. The rule had been written, accepted and blind for months: its check pointed at `crates/foundation/` while the defect lived in `templates/`, with a pattern requiring a leading slash that would not have caught it anyway.” | ruled out — the rule existed, and was blind |
| «The shortcut is redundant: delete it» | “«The shortcut is redundant: delete it.» ALMOST GUILTY, and of a disaster. The witness refuted it: six of eight routes lost their grid **answering 200** — invisible to any status-code smoke test. The shortcut was not redundancy: it was the only thing translating `/proyectos` into the canonical kind. And the answer was already written in this project's queryable knowledge: «the match arms are an optimisation, not the source of truth». Nobody queried it.” | ALMOST GUILTY — of breaking the site, not of the case |
| Nobody runs the constraints | “«Nobody runs the constraints.» GUILTY, and it is the whole diagnosis. Twenty-three typed constraints across eight ADRs. Zero run by recipe or CI. It is not that this case's rule failed: it is that **no rule in this project has ever been executed**. What nothing executes, nothing can declare sick — not the fix that never went back, not the template that would not compile, not the other four layers underneath.” | GUILTY — and it is nobody's: it is the void's |
Etiology — the cause — shell/htmx.rs — the hand-written list, and how it grew while the cure watched
// templates/website-htmx-ssr/crates/server/src/shell/htmx.rs:423
// (identical in website-leptos/.../shell/htmx.rs:275)
let kind = match base {
"blog" => Some("blog"),
"projects" | "proyectos" => Some("projects"),
"recipes" | "recetas" => Some("recipes"),
"activities" | "actividades" => Some("activities"),
_ => None,
};
// And in the instance's HEAD — with the cure already written, uncommitted,
// in its own working tree — the same pattern, grown BY HAND:
let kind = match base {
"blog" => Some("blog"),
"projects" | "proyectos" => Some("projects"),
"domains" | "dominios" => Some("domains"), // ← by hand
"recipes" | "recetas" => Some("recipes"),
"activities" | "actividades" => Some("activities"),
"catalog" => Some("catalog"), // ← by hand
"adr" => Some("adr"), // ← by hand
_ => None,
};
And it was not two places, but three: htmx_pages.rs:105 has its own list, in its own shape. Nobody looked for it because nobody had a rule that looks — which is exactly what this case is about.
Treatment — A backport that was not designed, and the rule that finally bites
# The fix was not designed: IT ALREADY EXISTED, deployed, serving.
# Verbatim backport from the instance → both templates.
fn render_content_or_grid(path: &str, language: &str) -> String {
use rustelo_core_lib::routing::config::load_routes_config;
let base = /* first segment of the path */;
// PAP: resolve the URL's first segment → content kind from the routes
// registry (site/config/routes.ncl), NOT a hardcoded list. A new content
// kind works with NCL config alone — no code change here.
let kind: Option<String> = load_routes_config().routes.iter().find_map(|r| {
if !r.enabled { return None; }
let seg = r.path.trim_start_matches('/').split('/').next().unwrap_or("");
(seg == base).then(|| r.content_type.clone()).flatten()
});
# And the rule, enforceable at last — SEEN TO FAIL before anything was fixed:
adr-002 · hardcoded-kind-list-shadows-registry · 'Hard
→ 9 hits against today's tree. After the backport: 3.
And the constraint was SEEN TO FAIL before anything was fixed: nine hits, must_be_empty = true. After the backport, three — the third list’s, which stay because they are not this decision’s. A rule only ever seen to pass is not a rule: it is a hope with syntax.
Prognosis
The mechanism was not missing: there was a surplus of it. config-driven-architecture is marked invariant in rustelo’s ontology. ADR-002 says, in letter, «without any hardcoded match arms». And there is more: the exact answer to the question that nearly broke the site — is that match redundant — had been written since 13 July in the project’s queryable knowledge: «the match arms are an optimisation, not the source of truth». It was all there. Written, accepted, dated, queryable. And the defect lived for months, grew to seven hand-written kinds in the very tree that already had the cure, spread into two templates and a third list nobody knew existed. Because between a rule that is written and a rule that bites there is exactly one thing, and it is not the rule’s quality: it is something that executes it. Twenty-three constraints. Eight ADRs. Zero recipes. Zero CI. Case 0/318’s validator at least existed and died on the first file; here not even that — here the rules are perfectly healthy and perfectly silent. And the finish, which is what makes this case unlike every earlier one: the lesson was also written, in a howto, and prevented nothing either — because a howto is read, not executed. Whoever recommended deleting the shortcut never queried it. They could not: nothing obliged them, and nothing told them it was there.
| A fix that cures the instance and not the source | Declared state: nothing declared that the instance and the templates share this resolver, so nothing could notice they had diverged. A fix with no declared drift cures one patient and leaves the disease in the printing press. |
| An optimisation that reads as the source of truth | It gets declared a shortcut. resolve_static_page already had it written — «the match arms are an optimisation, not the source of truth» — in a queryable knowledge entry. Whoever did not query it recommended deleting it, and the shortcut did something: translate /proyectos → projects. |
| A rule forbidding the defect, pointed at another corpus | Review against invariant: a constraint's scope covers the tree where the axiom applies. config-driven-architecture governs sites, and sites are born from templates/ — where the rule was not looking. It is 0/318 again: the rule existed and pointed at the box next door. |
| 23 constraints, 0 executed | gate:just — a recipe that runs them and reports per constraint, even in red. Red seen is worth more than green over nothing. A corpus of rules nobody runs is not governance: it is literature. |
| The template, unversioned | No mechanism covers it, and it is the gravest facet: a fix in templates/ does not survive a git clean. The source every site is born from is not in git — and no ADR says whether that is policy or oversight. |
| Four layers of rot nobody could see | gate:just that instantiates, builds and boots. The htmx-ssr profile had never compiled — 8 errors — and nobody knew, because nothing builds it. What nothing executes, nothing can declare sick. |
The regimen — the session, replayed with protocol
What was asked — reconstructed from .coder/2026-07-16-2a-rustelo-reparacion.done.md · transcript of the rustelo session
render_content_or_grid re-lists 4 kinds by hand in both templates (templates/website-htmx-ssr and website-leptos, shell/htmx.rs), shadowing the registry. ADR-002 already forbids it but its check points at crates/foundation/, where the defect is not. […] 2. Ask me BEFORE choosing between deleting the shortcut or deriving it from config: that is my decision, not yours. […] 4. No-regression witness: curl /blog, /proyectos, /recetas, /actividades in both languages, before and after. Pasted, not narrated.
What should have been asked
Before 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.
Prophylaxis — what enforces the lesson today
- ✓The hand-written list that shadows the registry is forbidden by a typed constraint, seen to fail before anything was fixed
adr:002/hardcoded-kind-list-shadows-registry - ✓The shortcut, backported: the registry resolves the kind in both templates
contract:templates/*/crates/server/src/shell/htmx.rs#render_content_or_grid - ✓That match arms are an optimisation and not the source of truth, queryable instead of rediscoverable
qa:rustelo-static-page-howto
⊘Declared debt: 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.
Discharge and prophylaxis
The discharge is signed with two uncomfortable facts and one good one. The first: the constraint, freshly written, found three places with the hand-written list — and only two were in the task. The rule, the moment it could run, saw before the one who wrote it did. The second: the htmx-ssr profile had never compiled — eight errors from a migration the framework did and the template did not — and nobody knew, because nothing builds it; it surfaced only because a real site was needed for the witness. And the good one: none of this was decided blind. The witness was demanded first, it ran, and it refuted the one who demanded it. A wired contract does not tire or get distracted; but before that, someone has to wire it. Twenty-three constraints are still waiting for their wire, and this page says so instead of keeping quiet.
Glosario
Sin coincidencias.