test(morfo): el censo deja de inventar lectores — la guarda de 7(a) en attrs[] y aria[]

Desde que `value` es opcional (decision 7(a), 2026-08-27) el compilador
descarta la entrada declarada sin fuente ANTES de recoger su condicion
(compile.ts:488 y :508, por delante de :496-497 y :516-517). El censo no
lo espejaba: contaba la condicion de una entrada sin value y FABRICABA un
lector. Fallaban LAS DOS ramas, no solo aria[].

Dos consecuencias, las dos medidas:

  - la calibracion («the instrument agrees with the compiler»), que este
    fichero declara condicion de validez de todas sus filas, caia con la
    PRIMERA entrada sin value que llevara condicion. Trampa armada y sin
    detonar: hoy son 0 de 134 attrs y 0 de 860 aria.

  - y la grave: el uso fantasma TAPABA el gate de huerfanas. Medido sobre
    accordion — retirado el value, la registracion viva de
    accordion-provider.svelte.ts:318 que el runtime ya no leeria se
    quedaba VERDE. El gate de componente y el de parte iban
    desincronizados; la guarda los alinea.

La guarda espeja la de data[], que lleva ahi desde siempre.

Anade el NEGATIVO permanente que las dos guardas necesitan: llegan
inertes (cero entradas sin value en el arbol) y un guard que inspecciona
vacio pasa. Se vio ROJO sobre el arbol pre-guarda antes de verse verde
aqui — la mitad del compilador pasaba ya, la del censo era la que
reventaba, que es el eje bajo prueba. Es el detector entero: nada mas en
el fichero cazaria la retirada de las guardas.

Cabecera: la cifra de UNCERTAIN decia SEIS y son TRES. El seis era
honesto cuando se escribio; la caida esta DENTRO de 216ac0116 — la fila
cero retira los 35 espejos de composicion y con ellos las tres refs
espejo de chronos (states.open, props.roleDescription, props.dropEffect).
Verificado midiendo el censo sobre cuatro arboles historicos con
`git show <rev>:<path>`, que es LECTURA. Una cabecera desmentida por su
propia salida es el instrumento mintiendo primero.

NO tocado, y con medida propia que lo defiende: el comentario del escaner
(«3341 candidate files, 108 register») es CORRECTO — 117 pasan el
pre-filtro de texto, 108 producen registraciones, que es lo que el
comentario afirma. Un pase previo pedia cambiarlo y habria corrompido un
comentario bueno.

Censo IDENTICO cifra a cifra: morfos=104 calls=716 keys=763
(75/627/61) unreadable=1 · orphans=20 deadPerPart=0 · advisory 53 =
6/30/17, y las tres UNCERTAIN siguen siendo chronos. Suite: 11 tests en
el fichero (era 10), 19 ficheros / 270 en el scope de morfo, prettier
limpio (--file-info: ignored false).

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

@ -85,9 +85,26 @@ import type { Morfo, MorfoCondition, MorfoPart, MorfoValueSource } from './types
* `SomaRuntimeDirSource<M>` already uses for `dir` — happens after the
* author adjudicates the harvest below, never before. Today the (c) cube
* is 53 rows: demanding a source would be a migration, not a gate. And
* six of those rows are stamped UNCERTAIN — a cube that still hides an
* opaque bag is not an adjudicable harvest yet. (Three at signing; wave 1
* gave chronos three more refs and every one landed on the opaque bag.)
* THREE of those rows are stamped UNCERTAIN — a cube that still hides an
* opaque bag is not an adjudicable harvest yet. All three are chronos',
* all three ride the SAME opaque registration, and the cube prints them as
* `chronosMorfo.props.value` (`components/chronos.ts:464`),
* `chronosMorfo.props.minute` (`:680`) and `chronosMorfo.props.slotLabel`
* (`:684`). This line read SIX until 2026-08-27, when it was measured
* again: a header contradicted by its own output is the instrument lying
* first, so the figure here is the one a run prints — never the one the
* last note remembered. THE SIX WAS HONEST WHEN IT WAS WRITTEN, and the
* cause of the fall is recoverable because history is READABLE
* (`git show <rev>:<path>`): chronos' unregistered refs measure 6 at
* `168a0fba0` and at `3fa4b7954`, 3 at `216ac0116` and 3 ever since. The
* drop is IN `216ac0116` — fila cero, which retired the 35 composition
* mirrors and took 43 lines out of `components/chronos.ts` with them.
* Three of those lines were the three missing rows: `states.open`
* (`aria-expanded`, the composed Popover's), `props.roleDescription` and
* `props.dropEffect` (`aria-roledescription` / `aria-dropeffect`, ×2 and
* ×1). No chronos provider ever registered any of the three, which is
* exactly why they were (c) rows; that commit touched no provider at all,
* so retiring the refs was the whole movement.
* 3. The (c1b) wave — the hand-written attrs that short-circuit the «single
* pipeline of attrs» P0 phase C established — folds into the render bag
* under that law. It is a wave, not a census exception. FIX-2 sharpened
@ -252,10 +269,29 @@ function usesOf(morfo: Morfo): Uses {
// to 4 and from 23 orphans to 27 across that one commit; this loop is why
// the census did not move at all.
for (const entry of part.attrs ?? []) {
// MATCH THE COMPILER, the same law the `data` loop above obeys — and
// for the same reason since decision 7(a) (2026-08-27) made `value`
// OPTIONAL here too: «declared with no source» means the provider owns
// the value, so the entry is a DECLARATION, never a plan. `compile.ts:488`
// `if (!entry.value) continue` runs BEFORE collectConditionDeps
// (`:496-497`), so the compiler collects NEITHER the source NOR the
// condition. Counting the condition here over-reports, and the row it
// invents lands in the CALIBRATION below — the test that declares every
// other row of this file valid. Measured on a minimal synthetic morfo,
// in THIS branch: a `tabindex` with no value and a `prop-truthy`
// condition gave `compiler=[]` / `census=[nested]` ⇒ DISAGREE
// (`tabindex` is the real shape — `float-panel.ts:251`, `:434`).
// Zero entries in the tree carry that shape today (0 of 134
// attrs, 0 of 860 aria), so the trap was armed and undetonated: the
// first one to land would have fired it.
if (!entry.value) continue;
source(entry.value, part.kebab, entry.attr, 'attrs');
condition(entry.condition, part.kebab, entry.attr);
}
for (const aria of part.aria) {
// The twin guard, same law (`compile.ts:508`, its condition deps at
// `:516-517`) — see the `attrs` loop above.
if (!aria.value) continue;
source(aria.value, part.kebab, aria.attr, 'aria');
condition(aria.condition, part.kebab, aria.attr);
}
@ -897,4 +933,33 @@ describe('source census — every registered source has a reader, and every read
'a (c1b) row that cites no site is an unfalsifiable claim'
).toEqual([]);
});
it('the NEGATIVE of 7(a) — a value-less entry contributes NEITHER source NOR condition', () => {
// THE ACTA. The two guards the `attrs[]` / `aria[]` loops carry arrive
// INERT — 0 of 134 attrs and 0 of 860 aria are value-less today — and a
// guard that inspects nothing passes. So the law they obey is pinned HERE,
// on a value-less entry MADE in memory: since decision 7(a) «declared with
// no source» is a DECLARATION, and the compiler collects NEITHER the source
// NOR the condition (`compile.ts:508` runs before its `collectConditionDeps`
// at `:516-517`; `:488` before `:496-497`). The census must drop the same
// pair or it invents a reader, and an invented reader is not cosmetic: the
// phantom use of `cannotCollapse` COVERS the live registration at
// `soma/components/accordion/accordion-provider.svelte.ts:318` that the
// runtime would no longer read, so the orphan GATE above stays green over
// dead code — a false green, measured. Nothing else in this file would
// catch the guards' removal: this negative is the whole detector, and it
// was seen RED on the pre-guard tree before it was seen green here.
const accordion = MORFOS.get('accordionMorfo');
expect(accordion, 'the fixture this negative needs').toBeDefined();
const mutated = structuredClone(accordion) as Morfo;
const trigger = findRawPart(mutated.parts, 'trigger');
const entry = trigger?.aria.find((aria) => aria.attr === 'aria-disabled');
expect(entry?.condition, 'the entry must carry the condition under test').toBeDefined();
delete entry!.value;
const required = compileMorfo(mutated).contracts.requiredSources;
expect([...required.props], 'the compiler drops it').not.toContain('cannotCollapse');
expect([...usesOf(mutated).props.keys()], 'and so must the census').not.toContain(
'cannotCollapse'
);
});
});

Loading…
Cancel
Save

Powered by TurnKey Linux.