Skip to content

audit(ui): one-shot CSS class drift audit — surface fork-side references with no CSS definition #2502

@alexey-pelykh

Description

@alexey-pelykh

Problem

The fork-sync regression class documented in remoteclaw/hq#57 (post-mortem) and demonstrated by #2501 (CSS class drift after v2026.3.13-1 sync) likely affects more files than the two surfaces visible so far. The Control UI sidebar nav and topbar were the symptoms a user happened to notice — but every CSS file the fork has synced from upstream could carry similar drift, and there's no evidence other component surfaces are clean.

We need a one-shot audit pass to find ALL existing CSS-class drift across the UI, before fixing anything beyond #2501. Without this, fixes happen reactively as users encounter unstyled components — slow and incomplete.

Goal

Produce a complete inventory of every CSS class referenced from ui/src/**/*.{ts,tsx,html} template strings that has no matching rule in any imported CSS file. Cluster findings by likely sync-wave origin so fixes can be batched.

Scope

In:

  • All ui/src/**/*.ts and ui/src/**/*.tsx files (template-string class references)
  • All ui/src/styles/**/*.css files (class definitions in selectors)
  • ui/src/styles.css import graph (only files actually loaded count)
  • Top-level class="..." and class=${"..."} literals (Lit template syntax)
  • BEM-style classes including double underscores and double hyphens (block__elem, block--mod)

Out (for first pass):

  • Dynamic class composition (e.g., ${cond ? "a" : "b"} template-string interpolation that produces class names) — too many false positives; revisit if the simple pass is clean
  • Classes referenced from :host, attribute selectors, or other non-class="" mechanisms
  • Classes from @create-markdown or other vendored UI (out of fork ownership)

Approach

A standalone script at scripts/audit-css-class-drift.mjs (or .sh if simpler):

  1. Parse class references: regex-match all class="([^"]*)" and class=${"([^"]*)"} literals across ui/src/**/*.{ts,tsx}. Tokenize values on whitespace. Result: a map of class-name → [file:line, file:line, ...] references.

  2. Parse class definitions: scan all ui/src/styles/**/*.css files; extract class names from selectors (handle nested compound selectors like .foo .bar, .foo.bar, .foo > .bar). Result: a set of defined classes.

  3. Compute orphans: references - definitions set difference.

  4. Cluster findings: for each orphan, run git log -p ui/src/styles/<likely-css-file>.css | grep '<orphan>' to find when the rule was last present. Group orphans by the commit that removed them (likely a sync commit).

  5. Output report at .tmp/audit-css-drift.md:

    # CSS Class Drift Audit (YYYY-MM-DD)
    
    **Total orphans**: N
    **Clusters**: K (by removing-commit)
    
    ## Cluster 1: removed in <commit-hash> (sync v2026.3.13-1)
    - `.nav-group` — used at `ui/src/ui/app-render.ts:256, 272, 278`
    - `.nav-label` — used at `ui/src/ui/app-render.ts:258, 279`
    - ... (full enumeration)
    
    ## Cluster 2: removed in <commit-hash> (...)
    ...
    
    ## Recommended actions per cluster
    ...

Acceptance criteria

  • Script committed at scripts/audit-css-class-drift.mjs (or equivalent)
  • Script runs in CI-friendly mode (no interactive prompts; exit 0 on success, exit 1 on findings)
  • Script output saved to .tmp/audit-css-drift.md (gitignored)
  • Triage report posted as a comment on this issue with cluster breakdown
  • Each cluster (other than fix(ui): restore nav-section/topbar class names after v2026.3.13-1 sync — paired call-site update missed #2501's) gets a follow-up fix(ui) issue with the renames table
  • No code fixes applied in this issue's PR — pure audit + report
  • Document the script's known limitations (dynamic class composition not handled, etc.)

Commit message

test(ui): add CSS class drift audit script — surface fork-side references with no CSS definition

Estimated effort

1-2 hours: ~30 min to write the script, ~15 min to run + verify, ~30-60 min to triage + write the report + file follow-up issues per cluster.

References

  • First-instance fix: #2501 (nav-section + topbar drift)
  • Pattern post-mortem: remoteclaw/hq#57
  • Risk model: remoteclaw/hq#59
  • Sync workflow companion check: remoteclaw/hq#58
  • Sync rename detection: remoteclaw/hq#63
  • Build-time gate (depends on this audit succeeding): companion remoteclaw issue

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions