fix(theming): lo que el adversarial del cierre midio - numeros de prosa y el exit de --debt

La verificacion adversarial del cierre (11 confirmados, 2 refutaciones de
NARRACION, 7 mutaciones con arbol restaurado byte a byte) dejo cuatro
correcciones, ninguna de mecanismo:

- El "114" de palabras eran 117 nombres --palabras-* consumidos (103 con
  fallback + 14 sin, los 117 bajo --palabras-scheme-*): el punto doctrinal
  sale REFORZADO - todo el canal es proyeccion del scheme. Corregido en el
  README y en la cabecera del ledger.
- Los "18 sin contrato" de recipe-contract SS4 son 23: el titulo dejaba
  fuera a los cinco estructurales que su propia enumeracion lista dentro.
  Renumerado con el desglose recontado.
- --debt no fijaba exit code: un modo de chequeo que no puede fallar es
  medio guard. Ahora process.exitCode=1 con deuda nueva o STALE (verificado
  por mutacion: HEAD exit 0, con literal inyectado exit 1, restaurado).
- El 5o test del suelo se llamaba "mutation probe" y no muta nada: renombrado
  a lo que es (canario de cordura del scanner), con la historia de donde SI
  se vio el rojo por mutacion.

Hallazgos del adversarial que quedan registrados sin ejecutar: las fichas de
docs/audit/theming estan OBSOLETAS respecto a la clase structural (--report
sin re-correr; tarea aparte con supervision por ficha) - el desglose "Knobs
de apariencia" de la ficha no suma (preexistente) - el suelo de reach tiene
~0,5pp de holgura por redondeo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alpha-0.1-background
dev 1 month ago
parent 69d69d43c6
commit 1ba518fcc2

@ -210,13 +210,16 @@ key. The old coarse ceilings of `theming-reach-floor.test.ts` (`maxLiteral`
564 / `maxGlobal` 1156) are RETIRED by it: a total only sees a net move, so
five regressions under five fixes read green.
**R-5.2 is the contract half**, and its 18 contract-less recipes were
adjudicated one by one rather than waived: eight paint nothing; the
typographic primitives (`heading`, `text`, `display`) and the calendar-layer
consumers are all-`system`, and their theming surface IS the layer they
consume (D-TH.2-b); five are `structural`; the WIP tracks sit outside the
audited catalogue; and the real debt (`field-langs`, 31 raw globals with no
contract) is covered BY the ledger — the entry IS its written registry. What
**R-5.2 is the contract half**, and its **23** contract-less recipes were
adjudicated one by one rather than waived (recounted by the adversarial pass
of the same day — an earlier draft said 18 by leaving the structural five out
of its own total): eight paint nothing; the typographic primitives
(`heading`, `text`, `display`) are all-`system` and their theming surface IS
the layer they consume (D-TH.2-b); five are `structural`; the three
calendar-layer consumers keep bridge privates and their raw knobs in the
ledger; `palabras` is a WIP track outside the audited catalogue; and the real
debt (`field-langs`, 31 raw globals with no contract) is covered BY the
ledger — the entry IS its written registry. What
the rule does NOT adjudicate, and says so in its own PASS note, is the
`var(--{c}-x, fallback)` reference that no `base.ts` entry declares (`mockup`
×11, `text-scramble` ×2): `recipe-css-contract.test.ts` sanctions that idiom

@ -67,8 +67,9 @@
* tokenizes, not by a commit of this axis.
* ⚠ ONE CAVEAT, MEASURED AND WRITTEN DOWN (2026-08-25, adversarial review
* of the debt-B axis): for `palabras` the census's classification is IN
* QUESTION. Its two recipes consume 114 distinct `--palabras-*` names with
* `var(…, fallback)` and declare ZERO of them; those names are not a theme
* QUESTION. Its two recipes consume 117 distinct `--palabras-*` names (103
* with a `var(…, fallback)`, 14 without — all 117 under `--palabras-scheme-*`,
* recounted by the adversarial pass) and declare ZERO of them; they are not a theme
* contract but the live projection of the document's `scheme-style`,
* written per instance as `--palabras-scheme-*` by `schemeCssVars`
* (`palabras-scheme.ts`). That is a VALUE channel, another axis — so the

@ -647,6 +647,9 @@ async function writeDebtBaseline() {
function reportDebt(only?: string, asJson = false) {
const { debt } = censusAudit(only);
// A check mode that cannot fail is half a guard: red findings set the exit
// code so `--debt` can gate a script or a hook, not only a human reader.
if (debt.newDebt.length > 0 || debt.stale.length > 0) process.exitCode = 1;
if (asJson) {
process.stdout.write(
JSON.stringify({ newDebt: debt.newDebt, stale: debt.stale }, null, '\t') + '\n'

@ -29,9 +29,10 @@ Lo que sí está medido es el tamaño de la deuda. El censo del eje
knobs** de apariencia con un alcance nominal del **22,2 %**: 103 leen nombres
`--palabras-*`, 272 primitivos globales y 87 son literales. Pero ese 22 % **no
es superficie de tema**: las dos recetas no declaran ni una sola de esas
propiedades (114 nombres distintos consumidos con `var(…, fallback)`, cero
declaraciones), porque son la **proyección en vivo del `scheme-style` del
documento** — `palabras-scheme.ts` las escribe por instancia como
propiedades (117 nombres distintos consumidos — 103 con `var(…, fallback)` y
14 sin él, los 117 bajo `--palabras-scheme-*`; recontado por la pasada
adversarial —, cero declaraciones), porque son la **proyección en vivo del
`scheme-style` del documento** — `palabras-scheme.ts` las escribe por instancia como
`--palabras-scheme-*`. Ese canal pertenece al esquema del documento, no al tema.
La deuda, por tanto, no se salda aquí: se salda declarando el bloque `palabras`

@ -122,13 +122,15 @@ describe('theming reach — the floor only moves up', () => {
});
/**
* The mutation test the plan demands (memory
* `a-guard-that-inspects-nothing-passes`): a guard is only trustworthy once
* you have SEEN it go red. This one proves the classifier still reacts —
* without it, a broken scanner would report a perfect catalogue and every
* assertion above would pass over nothing.
* A SANITY CANARY on the scanner, not a mutation (memory
* `a-guard-that-inspects-nothing-passes`): it proves the classifier still
* returns sane values for a known-clean subject, so a broken scanner cannot
* report a perfect catalogue and let every assertion above pass over
* nothing. The real red was SEEN by mutation on 2026-08-25 (a literal
* injected into `mark`, then into `avatar` by the adversarial pass) — a
* test file cannot mutate the recipes it guards.
*/
it('the classifier still reacts to a literal (mutation probe)', () => {
it('the classifier still reacts to a literal (scanner sanity canary)', () => {
const scan = scanComponent('mark');
expect(scan, 'mark should scan').not.toBeNull();
const before = scan!.row.literal;

Loading…
Cancel
Save

Powered by TurnKey Linux.