Representation and sequencing correction — 2026-08-27
Follow #41 and isomorphisms/idric-arm-thumb#31 before implementation. "Attached to each DOM node" below means associated with a stable logical node identity. It does not decide between an embedded field, parallel style table, immutable projection, or another reviewed layout, and it does not require a permanently live standards-complete DOM. This remains an issue-only future design while the Idriç data/text/tree contracts are open.
Goal
Treat CSS as something IB can parse and compile once, rather than repeatedly interpreting selector text while rendering.
The basic pipeline should be:
CSS text
→ parse once
→ normalized rules/selectors
→ compiled selector match plans / indexes
→ match affected DOM nodes
→ cascade + inheritance
→ computed style record attached to each node
This should make style resolution an explicit compiled phase and give the renderer something cheap and concrete to consume.
Selector compilation
Do not require one representation for every selector. Explore representations appropriate to the selector family, including:
- direct predicate sequences for simple tag/class/id/attribute selectors;
- indexes keyed by ID, class, tag, attribute, or the selector's rightmost discriminating component;
- decision tables / jump-friendly dispatch where a selector set has finite alternatives;
- compact automata or state-machine-like matchers where that actually fits;
- explicit tree-walk plans for descendant, child, sibling,
:has(), and other relational selectors.
The important boundary is that selector syntax is parsed once. Runtime matching should execute a prepared representation rather than continually re-reading and re-interpreting CSS syntax.
Computed style records
After matching, resolve the cascade and inheritance into a concrete computed-style record associated with each DOM node.
The record should be suitable for later layout/paint work without re-running the entire stylesheet. Preserve enough provenance/debug information to answer why a property won when useful, but keep the hot rendering representation small.
Things the representation must eventually account for include:
- specificity;
- source order;
- inheritance;
- initial/default values;
- inline styles;
- important declarations;
- pseudo-classes / state-dependent rules;
- stylesheet and DOM mutation invalidation.
Invalidation is a separate problem
Do not make a full dynamic invalidation engine a prerequisite for the first implementation.
Start with a static DOM + stylesheet oracle. Then add dirty-node / dependency invalidation so a DOM mutation, class change, state change, or stylesheet edit only recompiles/rematches the affected region when possible.
:has() and other relational selectors are especially useful later because they force us to record upward or cross-tree dependencies instead of blindly rescanning the whole document.
First experiment
Use the selector fixture already being developed in #35 as the semantic oracle. Extend it with a small stylesheet whose final computed property values are known exactly.
For the first narrow benchmark, compare:
- straightforward parsed-selector interpretation;
- parsed-once compiled matching;
- indexed candidate selection + compiled matching;
- cached computed styles reused by a mock layout/paint pass.
Measure selector tests / nodes visited as well as wall time so we can distinguish algorithmic wins from backend noise.
Acceptance criteria
- stylesheet text is parsed once for the fixture;
- selectors have an explicit compiled runtime representation;
- matching does not depend on reparsing selector text;
- computed style values for the fixture are deterministic and oracle-checked;
- a second mock render can consume cached computed-style records without re-running unchanged CSS matching;
- mutation/invalidation work is documented separately rather than hidden inside the first static implementation.
Related
Representation and sequencing correction — 2026-08-27
Follow #41 and isomorphisms/idric-arm-thumb#31 before implementation. "Attached to each DOM node" below means associated with a stable logical node identity. It does not decide between an embedded field, parallel style table, immutable projection, or another reviewed layout, and it does not require a permanently live standards-complete DOM. This remains an issue-only future design while the Idriç data/text/tree contracts are open.
Goal
Treat CSS as something IB can parse and compile once, rather than repeatedly interpreting selector text while rendering.
The basic pipeline should be:
This should make style resolution an explicit compiled phase and give the renderer something cheap and concrete to consume.
Selector compilation
Do not require one representation for every selector. Explore representations appropriate to the selector family, including:
:has(), and other relational selectors.The important boundary is that selector syntax is parsed once. Runtime matching should execute a prepared representation rather than continually re-reading and re-interpreting CSS syntax.
Computed style records
After matching, resolve the cascade and inheritance into a concrete computed-style record associated with each DOM node.
The record should be suitable for later layout/paint work without re-running the entire stylesheet. Preserve enough provenance/debug information to answer why a property won when useful, but keep the hot rendering representation small.
Things the representation must eventually account for include:
Invalidation is a separate problem
Do not make a full dynamic invalidation engine a prerequisite for the first implementation.
Start with a static DOM + stylesheet oracle. Then add dirty-node / dependency invalidation so a DOM mutation, class change, state change, or stylesheet edit only recompiles/rematches the affected region when possible.
:has()and other relational selectors are especially useful later because they force us to record upward or cross-tree dependencies instead of blindly rescanning the whole document.First experiment
Use the selector fixture already being developed in #35 as the semantic oracle. Extend it with a small stylesheet whose final computed property values are known exactly.
For the first narrow benchmark, compare:
Measure selector tests / nodes visited as well as wall time so we can distinguish algorithmic wins from backend noise.
Acceptance criteria
Related