feat: extractors for UI files (CSS/HTML) and JS linkage - #3067
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a webui extractor that graphs frontend classes, IDs, and CSS custom-property tokens as shared nodes so a single selector like .tp-canvas links its CSS rule, its HTML element, and the JS code that touches it. extract_css/extract_html are dispatched for .css/.scss/.html/.htm, JS extraction is wrapped by _extract_js_with_ui to append selector_edges (failing silently if that raises), and those extensions are now classified as code rather than docs so they skip the AI doc pass. These type="ui" nodes are exempted from the file-stem prefix remap and from collision disambiguation so the shared identity survives across files; parsing is capped at 4 MB and 4000 nodes per file with oversized files returning an error result.
Worth a look
- Buffer reset on overflow loses selector, mis-associating following body —
graphify/extractors/webui.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- CSS extraction can amplify a small stylesheet into unbounded edges —
graphify/extractors/webui.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- classList arguments are split on whitespace instead of parsed as string literals —
graphify/extractors/webui.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Attribute selector literals are reported as real CSS classes/IDs —
graphify/extractors/webui.py:187· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- classList.replace only links the removed class —
graphify/extractors/webui.py:258· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 2365 functions depend on the 484 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 495 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
detect()— 108 callers, 15 callees - new:
save_manifest()— 40 callers, 11 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_files_direct()— 17 callers, 20 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_corpus_parallel()— 26 callers, 11 callees - …and 58 more — each is listed as a finding
Verification — 2365 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 2138 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify extract.
The verifier did not have enough to check extract, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `cache_root` is annotated `Path | None` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_disambiguate\_colliding\_node\_ids.
The verifier did not have enough to check \_disambiguate\_colliding\_node\_ids, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set
· 1 grounded finding(s) anchored inline below; 65 more finding(s) on lines outside this diff (see the check run).
| i += 1 | ||
|
|
||
|
|
||
| def extract_css(path: Path) -> dict: |
There was a problem hiding this comment.
extract_css()
fans out to 6 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
What this adds
This PR introduces extractors for UI files (CSS, SCSS, HTML) and adds a wrapper around the JS extractor to link code to interface elements.
New nodes and edges
.tp-canvas), IDs (e.g.#main), and CSS variables (e.g.--t).styles(from CSS file to class/ID)markup(from HTML file to class/ID)defines_token/uses_token(for CSS variables)touches_ui(from a JS function to a class/ID it manipulates)Why map nodes to classes instead of CSS rules?
A single class node is created rather than mapping every individual CSS rule. In a large project, there can be tens of thousands of CSS rules, which makes the graph unreadable and bloated. Developers reason about the interface in terms of classes, so treating a class as a shared
uinode keeps the graph clean and semantic.Before and After
.tp-canvasclass?", the graph had no concept of markup or styles, and could not answer..tp-canvasis shared across CSS, HTML, and JS, the same query instantly returns the rule in the stylesheet, the element in the markup, and all the JavaScript functions that manipulate it.