The article was a projection; the informe was not. Same cases, two hands, and
they drifted: deriva's ledger carried 6 rows in the .md and 8 in the viewer,
recaida had no typed source at all, and espejo never made it into the informe —
so its own article linked to an anchor that did not exist. The English tree was
two hand-written .md nobody regenerated and a third case that was simply absent.
Three fixes, one shape:
- The <pre> was killing the render. `<section class="exp">` opens a CommonMark
HTML block of type 6, closed by the first blank line — and weapon.code has
blank lines. Joined with "\n" the whole body was ONE block that died inside
the snippet, so every `#` comment re-parsed as an ATX heading: 23 spurious
<h1> in espejo, `</pre>` swallowed by the last one. Chunks are now separated
by blank lines, so <pre> opens a type-1 block that only closes on `</pre>`.
The editorial prose stops being buried in raw HTML and renders as Markdown.
- The skin becomes a dimension of the contract. The informe carries prose per
case AND per skin; the old Expediente held one flattened skin, so the viewer
could never be projected from it. `skins.<skin>` now holds what the genre owns
(loglines, alibis, headings, stamps); the numbers, the code, the technical
names of the suspects and the closing stay neutral. A datum that changed with
the skin would be fiction, not genre.
- The locale becomes a dimension of the build. Both trees project from .ncl,
the renderer's vocabulary lives in scripts/ (not among the instances it types
— `contract-in-the-instance-tree`), and expedientes-parity fails when a case
exists in one locale and not the other.
Gates: expedientes-check · informe-check · expedientes-parity, all in the chain.
A projection nobody re-derives is not a projection, it is a copy you trust.