@ -36,15 +36,26 @@ import type { Morfo, MorfoCondition, MorfoPart, MorfoValueSource } from './types
* provider writes the attr by hand ( inert declaration , correct DOM ) , 20
* naming - only ( ` consumerWins ` ) refs , and 1 per - part dead source .
*
* WHAT THIS TREE MEASURES TODAY ( 2026 - 08 - 27 , re - run ) : 729 keys in 716
* registrations across the same 104 morfos ( 66 states / 602 props / 61 parts ) ,
* 1 of them unreadable ⇒ 20 orphans , 0 per - part dead sources , advisory cube 78
* = 22 ( c1a ) / 36 ( c1b ) / 20 ( c2 ) . Both gated numbers fell below the founding
* WHAT THIS TREE MEASURES TODAY ( 2026 - 08 - 27 at ` f48acab37 ` , after wave 1 of the
* ARIA harvest and FIX - 2 of the classifier ) : 729 keys in 716 registrations
* across the same 104 morfos ( 66 states / 602 props / 61 parts ) , 1 of them
* unreadable ⇒ 20 orphans , 0 per - part dead sources , advisory cube 89
* = 17 ( c1a ) / 55 ( c1b ) / 17 ( c2 ) . Both gated numbers fell below the founding
* measure because wave C2 FIXED four defects at the source , not because the
* census looked away ; the key count moved TWICE and in opposite directions —
* − 4 for those retreats ( 725 → 721 ) and + 8 when the dynamic - part blind spot
* closed ( 721 → 729 , see ` DYNAMIC_LEVEL ` ) .
*
* THE CUBE HAS MOVED THREE TIMES SINCE SIGNING , and only one movement is a
* cure . Wave 1 ( ` 338c49d67 ` ) FABRICATED 12 rows ( 10 c1a + 2 c1b ) and
* reclassified 3 ( c2 → c1b ) by giving refs to attrs no provider registers :
* 78 ( 22 / 36 / 20 ) → 90 ( 32 / 41 / 17 ) . Its hotfix ( ` f48acab37 ` ) retired ONE of those
* fabricated rows — ` chatMessage.states.open ` , a mirrored ` stateRef ` that
* clobbered the composed Popover ' s live ` aria-expanded ` — for 89 ( 31 / 41 / 17 ) .
* Then FIX - 2 ( 2026 - 08 - 27 ) moved 14 rows c1a → c1b because the PARTITION was
* lying , not because anything got fixed : the same 89 rows , cut where the
* evidence actually falls ( see ` handWriteOf ` ) .
*
* THE THREE COMMITMENTS OF SIGNATURE C , so this file is read for what it is :
*
* 1 . Generifying the builders is ITS OWN AXIS , not this one . ` v.stateRef ` /
@ -56,12 +67,17 @@ import type { Morfo, MorfoCondition, MorfoPart, MorfoValueSource } from './types
* 2 . The flip to a BIDIRECTIONAL gate — also REQUIRING the source , the shape
* ` SomaRuntimeDirSource<M> ` already uses for ` dir ` — happens after the
* author adjudicates the harvest below , never before . Today the ( c ) cube
* is 78 rows : demanding a source would be a migration , not a gate . And
* three of those rows are stamped UNCERTAIN — a cube that still hides an
* opaque bag is not an adjudicable harvest yet .
* 3 . The ( c1b ) wave — the 36 hand - written attrs that short - circuit the
* is 89 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 . )
* 3 . The ( c1b ) wave — the 55 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 .
* render bag under that law . It is a wave , not a census exception . FIX - 2
* sharpened what it is a wave OF : 14 of the 55 are written by an EIDOS
* template , not by the provider — 7 of them in a file that registers
* nothing at all ( ` field-langs-switcher.svelte ` × 5 , ` dialog-close.svelte ` ,
* ` metrics-delta.svelte ` ) , where the bag governs no attr of that part .
*
* WHAT THIS FILE GATES ( red the day it grows ) : new orphans , and new per - part
* dead sources . Both are dead code by construction , and both are measured
@ -408,7 +424,11 @@ interface Census {
readonly deadPerPart : CensusRow [ ] ;
/** ADVISORY: ref with no source and no hand-written attr — the attr is NOT in the DOM. */
readonly c1a : CensusRow [ ] ;
/** ADVISORY: ref with no source, but the provider writes the attr by hand. */
/ * *
* ADVISORY : ref with no source , but SOMEONE writes the attr by hand — the
* provider , or a template of the component that registers nothing . The row
* cites the site , because the two cases carry different debts .
* /
readonly c1b : CensusRow [ ] ;
/** ADVISORY: ref with no source, naming attrs only — the consumer may supply it. */
readonly c2 : CensusRow [ ] ;
@ -435,6 +455,62 @@ function textOf(file: string): string {
return text ;
}
/ * *
* The files that may write an attr BY HAND for a component : soma ' s providers
* and eidos ' templates / wrappers , at the kebab the morfo declares . ` .css ` is
* excluded ON PURPOSE — a rule SELECTS the attr , it does not write it , and
* counting it would erase the sharpest finding of the ( c1a ) cube : ` tooltip.css `
* and ` time-range-picker.css ` select attrs that never reach the DOM ( dead
* rules ) . A component whose directory is not its kebab simply finds nothing ,
* and its rows stay in ( c1a ) — the conservative side of the cut .
* /
const dirFiles = new Map < string , string [ ] > ( ) ;
function componentDirFiles ( kebab : string ) : string [ ] {
const cached = dirFiles . get ( kebab ) ;
if ( cached ) return cached ;
const files : string [ ] = [ ] ;
const walk = ( dir : string ) = > {
if ( ! existsSync ( dir ) ) return ;
for ( const entry of readdirSync ( dir , { withFileTypes : true } ) ) {
const full = join ( dir , entry . name ) ;
if ( entry . isDirectory ( ) ) walk ( full ) ;
else if ( /\.(svelte|ts)$/ . test ( entry . name ) && ! entry . name . includes ( '.test.' ) )
files . push ( full ) ;
}
} ;
for ( const root of SOURCE_ROOTS ) walk ( join ( root , kebab ) ) ;
dirFiles . set ( kebab , files ) ;
return files ;
}
/ * *
* The two shapes in which a component actually writes an attr by hand : a QUOTED
* KEY in a props bag ( ` 'aria-level': depth.current + 1 ` ) and a TEMPLATE
* ATTRIBUTE ( ` data-mode="segmented" ` ) . The whitespace before the ` = ` is
* load - bearing : without it the probe also swallows CSS attribute selectors
* inside strings — measured , ` chronos-provider.svelte.ts:580 ` queries
* ` [data-minute=" ${ minute } "] ` , which is a READ , and the loose form moved that
* row into ( c1b ) as if someone had written it .
* /
function writesAttr ( text : string , attr : string ) : boolean {
return (
text . includes ( ` ' ${ attr } ' ` ) ||
text . includes ( ` " ${ attr } " ` ) ||
new RegExp ( ` (^| \\ s) ${ attr . replace ( /[.*+?^${}()|[\]\\]/g , '\\$&' ) } = ` ) . test ( text )
) ;
}
/** Where `attr` is written by hand, `path:line`, or undefined if nowhere. */
function handWriteOf ( files : readonly string [ ] , attr : string ) : string | undefined {
for ( const file of files ) {
const text = textOf ( file ) ;
if ( ! writesAttr ( text , attr ) ) continue ;
const line = text . split ( /\r?\n/ ) . findIndex ( ( entry ) = > writesAttr ( entry , attr ) ) + 1 ;
return ` ${ relative ( ROOT , file ) . replace ( /\\/g , '/' ) } : ${ line } ` ;
}
return undefined ;
}
/ * *
* Pure over its input , so the negative can mutate a registration in memory and
* watch the classifier bite .
@ -467,10 +543,26 @@ function classify(registrations: readonly Registration[]): Census {
if ( ! morfo ) continue ;
const uses = usesOf ( morfo ) ;
const compiled = compileMorfo ( morfo ) ;
// Every file that registers for this morfo, so an inert DECLARATION can be
// told from a DEAD attr: tree-view is the annotated archetype — its
// provider writes `'aria-level': depth.current + 1` by hand.
const providerText = [ . . . new Set ( regs . map ( ( reg ) = > reg . file ) ) ] . map ( textOf ) . join ( '\n' ) ;
// Where an inert DECLARATION can be told from a DEAD attr. Tree-view is the
// annotated archetype — its provider writes `'aria-level': depth.current + 1`
// by hand — but the registering files are NOT the whole surface, and the
// narrow version of this line was the second blocker of the flip.
//
// FIX-2 (2026-08-27, unified dossier §2.2 + ledger L2): the probe used to
// read ONLY the files that REGISTER, and only for a quoted object key. It
// missed both real shapes of the hand: the attr written as a TEMPLATE
// attribute (`data-mode="segmented"`), and the file that WRITES BUT NEVER
// REGISTERS — an eidos painting a part it does not declare. 14 of the 31
// (c1a) rows were (c1b) in disguise (32 in the dossier, before `f48acab37`
// retired one), and (c1a) is the class that says «THE ATTR IS NOT IN THE
// DOM»: five of them are field-langs, whose switcher and lang-option are
// painted by `field-langs-switcher.svelte`, a file that registers nothing
// and names no morfo — while 13 rules of `field-langs.css` live off exactly
// those attrs. The debt is the same either way; what was false was the NAME
// on the rows, and the flip to a gate had its second blocker right here.
const handFiles = [
. . . new Set ( [ . . . regs . map ( ( reg ) = > reg . file ) , . . . componentDirFiles ( morfo . kebab ) ] )
] ;
census . calls += regs . length ;
const registered : Record < Bucket , Map < string , string > > = {
@ -510,23 +602,25 @@ function classify(registrations: readonly Registration[]): Census {
// from the LIVE registry before any map overwrites it.
if ( bucket === 'parts' ) continue ;
const id = ` ${ name } . ${ bucket } . ${ key } ` ;
const row = {
id ,
label :
` ${ id } ← ${ sites . map ( ( use ) = > ` ${ use . part } . ${ use . attr } ( ${ use . how } ) ` ) . join ( ' ' ) } ` +
( opaque
? ` ⚠ UNCERTAIN — ${ opaque } opaque registration(s) on this morfo may already feed it `
: '' )
} ;
const attrs = [ . . . new Set ( sites . map ( ( use ) = > use . attr ) ) ] ;
if ( sites . every ( ( use ) = > use . consumerWins ) ) census . c2 . push ( row ) ;
else if (
attrs . every (
( attr ) = > providerText . includes ( ` ' ${ attr } ' ` ) || providerText . includes ( ` " ${ attr } " ` )
)
)
census . c1b . push ( row ) ;
else census . c1a . push ( row ) ;
const base = ` ${ id } ← ${ sites . map ( ( use ) = > ` ${ use . part } . ${ use . attr } ( ${ use . how } ) ` ) . join ( ' ' ) } ` ;
const uncertain = opaque
? ` ⚠ UNCERTAIN — ${ opaque } opaque registration(s) on this morfo may already feed it `
: '' ;
if ( sites . every ( ( use ) = > use . consumerWins ) ) {
census . c2 . push ( { id , label : base + uncertain } ) ;
continue ;
}
// EVERY attr of the row must be hand-written for the declaration to be
// merely inert: one attr left to the bag is one attr missing from the DOM.
const written = [ . . . new Set ( sites . map ( ( use ) = > use . attr ) ) ] . map ( ( attr ) = >
handWriteOf ( handFiles , attr )
) ;
if ( written . every ( ( site ) = > site !== undefined ) )
census . c1b . push ( {
id ,
label : ` ${ base } — written by hand at ${ [ . . . new Set ( written ) ] . join ( ' ' ) } ${ uncertain } `
} ) ;
else census . c1a . push ( { id , label : base + uncertain } ) ;
}
}
@ -670,7 +764,11 @@ describe('source census — every registered source has a reader, and every read
` \ n[source-census] ${ title } — ${ rows . length } \ n ${ rows . map ( ( row ) = > ` ${ row . label } ` ) . join ( '\n' ) } `
) ;
show ( '(c1a) NO source, NO hand-written attr — THE ATTR IS NOT IN THE DOM' , census . c1a ) ;
show ( '(c1b) NO source, the provider writes the attr by hand — inert declaration' , census . c1b ) ;
show (
'(c1b) NO source, the attr is written BY HAND (provider, or a template that ' +
'registers nothing) — inert declaration' ,
census . c1b
) ;
show (
'(c2) NO source, naming attrs only (consumerWins) — the consumer may supply it' ,
census . c2
@ -682,7 +780,7 @@ describe('source census — every registered source has a reader, and every read
` gated: orphans= ${ census . orphans . length } deadPerPart= ${ census . deadPerPart . length } · ` +
` advisory (c)= ${ census . c1a . length + census . c1b . length + census . c2 . length } `
) ;
// Lax pin, anti-empty only: the harvest is 22/36/20 on 2026-08-27 and
// Lax pin, anti-empty only: the harvest is 17/55/17 on 2026-08-27 and
// shrinking it is the POINT. A zero here means the cross-reference broke,
// not that the cube was cleared — that day the number becomes a gate.
expect ( census . c1a . length + census . c1b . length + census . c2 . length ) . toBeGreaterThan ( 0 ) ;
@ -741,4 +839,35 @@ describe('source census — every registered source has a reader, and every read
) ;
expect ( census . orphans . map ( ( row ) = > row . id ) ) . not . toContain ( 'chronosMorfo.props.redonly' ) ;
} ) ;
it ( 'the NEGATIVE of FIX-2 — an attr written in a TEMPLATE is a hand, a SELECTOR is not' , ( ) = > {
// The old probe, reconstructed in memory: a quoted object key, nothing else.
// It is what put 14 rows in (c1a) — «THE ATTR IS NOT IN THE DOM» — while the
// attr was in the DOM, painted by a template. Both halves matter: without the
// first the widening is unproven, without the second it is unbounded, and an
// unbounded probe would have quietly absolved `tooltip` and `chronos`.
const old = ( text : string , attr : string ) = >
text . includes ( ` ' ${ attr } ' ` ) || text . includes ( ` " ${ attr } " ` ) ;
const template = '<div data-field-langs-switcher data-mode="segmented" role="radiogroup">' ;
expect ( old ( template , 'data-mode' ) , 'the OLD probe misses the template attr' ) . toBe ( false ) ;
expect ( writesAttr ( template , 'data-mode' ) , 'the WIDENED probe sees it' ) . toBe ( true ) ;
// The counterfactual, taken from the shape that actually exists in the tree:
// a CSS attribute selector inside a query string is a READ of the attr, and
// crediting it as a write moved `chronos.props.minute` — a live (c1a) row —
// into (c1b) while the loose form was in place.
const query = 'root.querySelector(`[data-chronos-time-slot][data-minute="${minute}"]`)' ;
expect ( old ( query , 'data-minute' ) , 'the old probe was right about this one' ) . toBe ( false ) ;
expect ( writesAttr ( query , 'data-minute' ) , 'a selector is not a hand-write' ) . toBe ( false ) ;
// And the consequence the cube must carry: a (c1b) row NAMES its site, so the
// class can be adjudicated without re-deriving it. It holds at 55 rows and at 0.
expect (
census . c1b
. filter ( ( row ) = > ! row . label . includes ( ' — written by hand at ' ) )
. map ( ( row ) = > row . id ) ,
'a (c1b) row that cites no site is an unfalsifiable claim'
) . toEqual ( [ ] ) ;
} ) ;
} ) ;