Skip to content

Complete selector matching, specificity, and dependency invalidation coverage #237

Description

@wieslawsoltes

Current selector and invalidation checkpoint — 20 September 2026

Exact merged heads: WebScene a46b62e14eb197603f7e227c1558afb9088633b0; AppScene 97702daeb9ad71341ced7226f0aa966dc77ea53c; unchanged Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c; local vscode-demo e4b98e5470cd7856aff3dfd6843c8e125d7db933 (clean, intentionally unpushed). Open consolidations remain WebScene #76 085bba760fa571c8f08ea866dc5dd1ec27c4d376, AppScene #65 ce66ef6ceb776b3f14e129f853bfc08b5c5e608c, and vscode-demo #1; do not merge them. One-agent mode is active.

Focused selector, structural mutation, pseudo-element, state, scoped selection/highlight, scrollbar state, placeholder/details and compiled-selector work recorded by this tracker is merged. The later pointer stack adds generated non-inherited touch-action without reopening selector ownership.

No focused selector branch is active. Continue source work only from a newly reduced current-main selector or invalidation defect. Authored WPT/native/performance and unchanged-product pixel/package gates remain deferred and are not claimed.

Parent tracker: #235

Problem

Dynamic applications depend on exact selector matching and invalidation across class/attribute/state changes. Existing coverage does not yet systematically prove specificity, structural/state pseudo classes, pseudo elements, combinators, ancestor dependencies, detached subtrees, and shadow-related boundaries.

Proposed work

  • Inventory selector forms used by unchanged VS Code and product-neutral WPT fixtures.
  • Add parser/matcher contracts for combinators, attribute operators, structural/state pseudo classes, pseudo elements, :is(), :where(), :not(), and specificity edge cases.
  • Compile dependency metadata needed for targeted invalidation.
  • Prove mutations invalidate the necessary descendant/ancestor/sibling scope without forcing unrelated full-tree work.
  • Add semantic counters and a bounded mutation benchmark.

Acceptance

Activity

  1. danwalmsley commented on Sep 17, 2026

    @danwalmsley
    Collaborator

    Coordination: PR #245 is the existing structural-invalidation implementation under this issue, continuing merged #148 and integrating #234. Head ba468ff covers compiled child-list routes, structural DOM/style checkpoints and directly related scaling/regressions (40/40 WebScene/Chrome; 44-case native matrix). Please consume or coordinate with this implementation instead of creating a second structural invalidation path. Its remaining lane is disconnected/remaining DOM checkpoints, positional sibling-scan costs and unrelated structural-rule scaling. This does not claim ownership or completion of the broader specificity/matching inventory, CSSOM #239, cascade #238, layout #240, responsive #242, or VS Code profiling #243. #235 now records the boundary and evidence.

  2. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Installed SDK gate: compiled attribute mutation is not restyled

    The exact macOS ARM64 SDK consumer gate reproduces a remaining attribute-invalidation gap on clean main sources:

    The installed Kestrel parity consumer creates independent parsed and compiled engines. Both initially agree in dark mode. It then executes:

    kestrel.theme = "light";
    kestrel.applyTheme();

    Both engines report:

    kestrel.theme == "light"
    document.documentElement.dataset.theme == "light"
    document.documentElement.matches('[data-theme="light"]') == true
    

    The parsed engine updates #ribbon to light computed styles:

    background rgb(243, 246, 249); color rgb(35, 55, 74)
    

    The compiled engine retains the original dark computed styles:

    background rgb(33, 44, 58); color rgb(220, 228, 237)
    

    A subsequent root class mutation does not refresh the compiled result. This causes the installed hybrid_kestrel_parity.py third snapshot (1440x900, light, Drafting) to fail while parsed/compiled node counts and geometry still agree.

    All preceding installed qualifier gates pass: manifest verification; producer source denial; independent hybrid builds; all installed samples; runtime HTML/WebScene contracts; native dependency isolation; incremental CSS/worker/asset/C++ rebuilds; read-only relocated SDK integrity; actual presentation, lifecycle, callback cancellation, and GPU retirement. A repeat with Node 24 removes the earlier npm engine warning but produces the same style mismatch, so Node is not causal.

    This fits #237's existing attribute-mutation acceptance scope. It is separate from #245's currently documented structural child-list lane; no draft code was included or modified for this SDK build.

  3. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    P0 release gate dependency: draft #245 resolves exact installed parity repro

    Read-only validation against the current draft #245 head confirms this release blocker is already fixed by that implementation, so no duplicate invalidation patch should be created.

    Exact inputs:

    • AppScene 9f434e0deea632fe28962ce32e2f4ddede4aa14c
    • WebScene PR Optimize structural CSS invalidation and DOM mutation checkpoints #245 05aa8f12466bebd8e10ceb7c10915f1f61f2110f (clean detached source)
    • macOS ARM64 SDK producer/runtime profile passed; 2,859-file manifest verified after the consumer run with zero missing or mismatched files
    • SDK was recursively read-only during the independent Kestrel compiled/parsed consumer build and headless execution
    • LLVM 22.1.8 and Node 24.18.1

    Reduced result:

    initial parsed/compiled: data-theme=dark; #ribbon background rgb(33, 44, 58), color rgb(220, 228, 237)
    after dataset mutation parsed/compiled: data-theme=light; matches([data-theme=light])=true;
      #ribbon background rgb(243, 246, 249), color rgb(35, 55, 74)
    after unrelated root class mutation: both engines remain identical and light
    

    The same probe fails on clean WebScene main b81f594c: the compiled engine reports data-theme=light and selector matching succeeds, but its computed style remains dark. Draft #245 therefore supplies the missing compiled attribute/style checkpoint needed by the exact AppScene SDK qualification gate.

    Dependency: the macOS ARM64 SDK release qualification for #237 must be rerun from WebScene main after #245 is ready and merged. #237 remains open for its broader selector/specificity matrix; this P0 installed-theme blocker should be considered owned by #245.

    Evidence SHA-256:

  4. danwalmsley commented on Sep 17, 2026

    @danwalmsley
    Collaborator

    Coordination: #245 is now pushed at 14ca683, with main b81f594 integrated via bc16392. The generated-binding conflict was resolved by regeneration from the merged manifest, retaining HTMLAnchorElement and corrected character-data setters. Cumulative local production/certification validation passes 140 route cases, four stable-text cases, twelve native child-vector cases, 410 related WPT checks, ten focused native groups and parser/generated-binding checks. The new work only bounds safe sibling-vector removal; it does not implement #257 form-state behavior. The exact installed Kestrel parsed/compiled theme probe is still verified only for 05aa8f1 and should be rerun against this cumulative head; no claim of current-head installed qualification or remote CI is made.

  5. danwalmsley commented on Sep 17, 2026

    @danwalmsley
    Collaborator

    Follow-up: WebScene 6da8c56 + AppScene 3b00e895 passes the normal packaged producer, all 16 native AppScene tests, relocated read-only/source-denied consumer qualification, and installed Kestrel smoke plus existing three-snapshot parsed/compiled parity (376/298/311 nodes, zero differences). Optional GPU presentation suite not run. Correct integration uses AppScene #84’s existing codec-enabled renderer/Skia lock; no hash validation weakened. Native Spotify now shows album art/circular artists, but its header remains clipped. Engine source is unchanged by documentation head 33c174c. The user reports excellent ordinary resize with a narrow→wide breakpoint pause; I am profiling that specific transition under #242, not duplicating other CSS lanes. Details: https://github.com/SceneTech/WebScene/blob/33c174c8/docs/validation/spotify-messageport-startup-20260917.md

  6. danwalmsley commented on Sep 17, 2026

    @danwalmsley
    Collaborator

    CharacterData editing checkpoints — 4f9c3ba

    Pushed #245 at 4f9c3ba3. This completes the five CharacterData editing/query methods and UTF-16 length exposure in the existing #237 structural-checkpoint lane. appendData, insertData, deleteData, replaceData, and substringData share the text-setter checkpoint, preserving conversion order/errors, reentrant reparenting/data changes, lone surrogates, node identity, empty/relational selectors, connected stylesheet text and textarea default/dirty values. Stable nonempty edits avoid structural CSS work without suppressing layout.

    The initial contract passed Chrome and failed native 0/20 before implementation; the final expanded contract passes 23/23 in each engine, plus the existing setter contract 47/47 in each (70/70 combined). Native adjacent verification totals 329 subtests across ten documents, including a passing pseudo-layout reftest. Cumulative scaling passes 172 route cases; all 32 new method-transition cases retain identical eight-counter results as unrelated nodes/rules grow 32→1,024. Eight stable-text cases pass, with up to 102,400 nonempty method edits and zero work across all eight CSS counters. These are deterministic CSS-work assertions, not a wall-clock or Spotify-presentation speedup.

    Default generated bindings (24 interfaces/191 members), certification and production builds, and five adjacent runtime groups pass. An optional legacy syntax check fails at generated-only attr_template/node_template references in unchanged files; legacy build/runtime qualification is not claimed. Existing detached-GC tests passing does not resolve the separate #258 retained-subtree oracle failure.

    No changes to other agents' #257/#286 implementations, no new SDK/manual app replacement, and no CI monitoring. The open demo remains the media-index qualified package. Remaining splitText/normalize, complete Range/MutationObserver semantics, #258 owner reconciliation, cascade/layout dependencies and physical/native/Chrome resize acceptance keep the full CSS goal open.

    Implementation boundaries, checks and exact machine-readable evidence.

  7. danwalmsley commented on Sep 17, 2026

    @danwalmsley
    Collaborator

    Text topology follow-up — PR #292 at 7a8fffb9

    The structural checkpoint lane now includes browser-compatible Text.splitText() and Node.normalize(). The parent concatenated text and element-child structure are invariant, so this path dirties layout/paint but deliberately performs no selector invalidation or cascade.

    The new contract failed native 0/6 before implementation and passes 6/6 Chrome and native after it; adjacent CharacterData remains 70/70. A four-case native gate varies 8/128 affected parents independently of 32/1,024 unrelated nodes/rules and runs 100 split/normalize cycles per parent. All nine selector/cascade/positional/detached-root counter deltas are zero.

    The gate also exposed quadratic detached-leaf registration: 12,800 pairs initially took about 307–308 ms because each removed suffix scanned historical roots. An indexed leaf path reduces the same local diagnostic to 23.6–28.7 ms with zero containment comparisons. This timing identifies the algorithmic fix; it is not a cross-machine release benchmark.

    Generated bindings, detached-DOM GC, certification and production runtime builds pass. Range boundary adjustment and MutationObserver delivery remain outside this tranche. The original #258 oracle still requires owner requalification. IndexedDB and the independently owned #246/#256/#257/#286 work are unchanged. CI was not monitored.

    Evidence: https://github.com/SceneTech/WebScene/blob/7a8fffb9/docs/validation/css-text-topology-20260917.md

  8. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Ownership boundary for the next focused slice from exact main dbdf02c75fa8efcab2eaa145106b985c95feba48:

    Audit found a product-neutral nested functional-selector gap. Servo parsing and specificity metadata already accept nested :is() / :where() / :not(), but the native matcher divides each argument with a raw find(','). A comma inside a nested function is therefore mistaken for an outer-list separator. The bounded fix will reuse the existing depth-aware CSS component-list splitter for functional selector arguments, then add Chromium/native computed-style and mutation coverage plus native invalidation-count, lifecycle, heap/RSS, and timing gates.

    Planned paths: webscene_v8_runtime_css_parsing.inc, a dedicated WebPlatformSubset contract/profile entry, and a focused native test source/registration as needed. This has zero changed-path overlap with open #348 (grid/layout), #350 (input/tasks/surfaces), draft #76, and active #248/#270. It will not alter structural child-list routing from merged #245 or cascade behavior from closed #238.

  9. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Merged focused nested functional selector-list slice via #356 at 615c10bc9dde326a66de730c9d6e8c63576fcf54 (exact PR head 8d1d715e450db8a00967f17baf17dacdf5c87694, rebased on e3fb0ee20430f7d49350298056a6f1b4b13d1ac6). Chromium 153 passed 5/5; native before the fix passed 4/5 and retained styles after the nested [hidden] dependency changed; native after passed 5/5. Exact-head portable V8 and native Linux document contracts passed. The 128-node/1,000-transition gate held identical targeted counters at 32 and 1,024 unrelated rules/nodes (4,000 plan lookups, 256,000 candidate visits, zero fallback visits, 384,000 rule checks, 129,000 cascade applications), completed in 434.131 ms / 687.716 ms, kept heap flat in each run, and returned detach/low-memory/final lifecycle metrics to baseline. This closes only the nested :is()/:where()/:not() list-tokenization gap; #237 remains open for the remaining selector/invalidation matrix.

  10. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Coordination for #81 follow-up: I am reducing a query-bearing same-origin iframe document-fetch -> nested Worker -> transferred MessagePort failure from main eb3cfe38. This lane will not touch selector parsing/matching, specificity, invalidation, CSS state, or #237 tests. Planned files are iframe/Worker resource tests, a dedicated WebPlatformSubset contract/profile, and only generic iframe hydration runtime code if required. Please flag any new overlap before merge.

  11. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Nested :has() selector-list matching — merged #420

    PR #420 merged to main at 19ad3eb229d6c93240f9898c44c70df5cc97ce0b from exact tested head 4f2b45094fe78ed333ce2703710c6cb961472aec, rebased on eb3cfe38 after #418.

    This closes the smallest residual functional-list gap after #356: unchanged Code OSS 645f29cc uses .monaco-list-row:has(.monaco-icon-label:is(.monaco-decoration-itemColor, .monaco-decoration-badge)), while native still split :has() on every comma. Matching now reuses the existing allocation-free depth-aware list traversal. Parser/specificity and #148/#245 compiled invalidation routes were already correct and remain unchanged.

    Evidence:

    • Chrome 153.0.8010.50: 6/6.
    • Native exact Match nested functional selector lists #356 head 8d1d715e: 1/6; candidate: 6/6.
    • Adjacent native contracts: 5/5 nested functional, 10/10 routed nested selector, 19/19 attribute invalidation, 73/73 child-list.
    • Exact-head hosted gates passed: portable V8 run 35364489926, Linux build/test job in 35364490038, and native Linux document/compiler run 35364489831 including the independent native-only SDK.
    • The 128-node/1,000-transition gate has identical counters at 32 and 1,024 unrelated rules/nodes: 6,000 plan lookups, 518,000 candidates, zero fallbacks, 37,664,000 compound checks, 1,024,000 rule checks, 258,000 cascades, 1,024,000 candidate checks. Isolated runtime is 1,539.88/1,777.78 ms; V8 heap returns byte-exactly after detach/low-memory and RSS remains inside +64 MiB.

    Detailed retained evidence: https://github.com/SceneTech/WebScene/blob/19ad3eb229d6c93240f9898c44c70df5cc97ce0b/docs/validation/css-nested-has-selector-lists-20260918.md

    #237 remains open. The next inventory must cover relative sibling :has(+ ...)/:has(~ ...) matching and reverse invalidation (also present in unchanged Code OSS), remaining structural/state/specificity cases not yet browser/native proved, shadow selector boundaries, and cumulative exact-package acceptance. This merge does not close broader CSSOM/layout/paint/scheduling or product gates.

  12. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Relative sibling :has() — merged #426

    PR #426 merged to main at f034e70563934b401bf9e0c88d0f29c089366ae8 from exact tested head a23325b5d23c4c8b8b72d2ca9bf6135c61b28a8a, rebased on e523daa11ae3ac4d06a9cbba64561ec06bd271f3.

    This closes the next selector slice after #420. Unchanged Code OSS 645f29cc uses .monaco-list-row:has(+ .monaco-list-row.selected) and p:has(+ [data-code] > .chat-codeblock-pill-widget). Native now anchors relative arms at :scope, searches only their descendant or following-sibling region, and reuses the ordinary compiled selector matcher. Existing previous_sibling/preceding_siblings dependency routes handle class and attribute changes; a bounded surviving-child route covers final-sibling removal.

    Evidence:

    • Chrome 153: 7/7.
    • Native pre-fix control: 1/7; exact-head candidate: 7/7.
    • Servo selector/parser and dependency-plan executable: pass.
    • Adjacent nested-functional, attribute-invalidation, and structural-scaling filters: pass.
    • Exact-head portable V8 passed in run 35367883880; unrelated hosted tails were canceled under the fast-merge policy.
    • The 128-group/1,000-transition gate has identical counters at 32 and 1,024 unrelated rules/nodes: 512,000 plan lookups, 9,664,000 candidate visits, zero fallbacks, 21,312,000 compound checks, 768,000 rule checks, 512,000 cascades, and 768,000 candidate checks. Runtime was 3,097.37/3,355.65 ms; settled V8 heap returned byte-exactly and native node/RSS bounds passed.

    Detailed evidence: https://github.com/SceneTech/WebScene/blob/f034e70563934b401bf9e0c88d0f29c089366ae8/docs/validation/css-relative-sibling-has-20260918.md

    #237 remains open for the remaining structural/state/specificity matrix, shadow selector boundaries, and cumulative exact-package acceptance.

  13. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Implemented and merged in PR #479 as 4d1a13e281fefa2e168c8506a6e4dd0769dc767c.

    The runtime now exposes pointer-driven :active state for the pressed target and its inclusive ancestor chain, maintains a dedicated dependency index separate from :hover, and recascades only affected subject/descendant/sibling/custom-property scopes. State becomes observable before down-event handlers and clears before up-event handlers while click targeting remains independent. Cascade switching, navigation, teardown, low-memory compaction, and memory accounting carry the new state/index.

    Per the implementation-throughput directive, native/browser/WPT, performance, memory, lifecycle, exact-package, and CI validation remain explicit debt before release promotion.

  14. wieslawsoltes commented on Sep 19, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Ownership: CSS Custom Highlight API

    Focused child #740 now owns the next one-agent implementation lane from exact WebScene main 6ec61c77d08c11d99229877e840ed3b7fd144a41.

    The slice covers only the unchanged Code OSS chat-find and Markdown inner-diff paths: retained Range boundary points, Highlight, CSS.highlights, functional ::highlight(<custom-ident>) color/background paint, mutation-safe teardown, bounded work, and zero idle demand. It will not modify the merged structural invalidation routes, details-content implementation, form-state work, or broader Selection/Range editing APIs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    vscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions