LearnNewsExamplesServices
Frontmatter
id18162
titleThe Workstation theme guard runs in CI with no unit coverage, and its deleted spec describes a guard that no longer exists
stateClosed
labels
bugaitestingregressionbuild
assigneesneo-opus-grace
createdAtSep 3, 2026, 8:56 AM
updatedAtSep 3, 2026, 11:29 AM
githubUrlhttps://github.com/neomjs/neo/issues/18162
authorneo-opus-grace
commentsCount0
parentIssue17922
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 3, 2026, 11:29 AM

The Workstation theme guard runs in CI with no unit coverage, and its deleted spec describes a guard that no longer exists

Closed v13.2.0/archive-v13-2-0-chunk-18 bugaitestingregressionbuild
neo-opus-grace
neo-opus-grace commented on Sep 3, 2026, 8:56 AM

Sub of #17922 · sibling of #17924, #17964, #17968, #18052

Context

c623b2f63c (#17791 via #17806) deleted 804 unit spec files. #17922 censused the ones whose subject never left this repository. #18052 took the first of the remaining owed set; this ticket takes check-theme-surfaces.

Measured at dev@3b19d7dca7, the owed set is now four: this one, WorkflowConcurrency, PublishReleaseNoteOrphan, and RebuildContentIndexesAndSeo.

The Problem

buildScripts/util/check-theme-surfaces.mjs has two live callers and zero unit coverage since 2026-08-27:

caller trigger
.github/workflows/check-theme-surfaces.yml PRs touching the guard or the theme surface
package.json → npm run check-theme-surfaces local + manual

It enforces three contracts nobody is asserting: dark/light parity for every --workstation-* / --agent-dock-* token, token-only color consumption across the Workstation SCSS tree, and completeness of every consumed non-local token in both skins.

A guard with no spec fails in one direction silently. If its detection quietly stops matching — a regex narrowed, a branch inverted — the workflow keeps reporting green and the theme surface it protects drifts unobserved. That is the same shape as #17230 ("a theme surface whose token pattern matches nothing reads as clean"), which was filed against this very guard and is now unguarded again.

Why this is a rewrite, not a restoration

The deleted spec is 618 lines and must not be restored verbatim. Verified mechanically rather than inherited:

$ git show c623b2f63c^:…/check-theme-surfaces.mjs | wc -l   → 734
$ wc -l buildScripts/util/check-theme-surfaces.mjs          → 217

The subject's own header records why: "The application-specific Institution token language and drawer-frame contract left with the Institution product." Three of the five checks the deleted spec asserts — the --fm-* cockpit skin parity, the text-safe-ink contrast floor, and the drawer shell/pane frame seam — no longer exist in the guard. A verbatim restore would red on the majority of its arms for reasons that say nothing about whether the surviving guard works.

What survives is one export, collectThemeSurfaceFailures(surface), whose injectable surface argument makes the guard testable against fixtures without touching the repository's own theme files.

The Fix

  1. Author test/playwright/unit/buildScripts/util/check-theme-surfaces.spec.mjs, beside the surviving sibling tree — not the old unit/ai/ prefix, which is what classified it as extracted substrate and would re-arm the same deletion at the next boundary change.
  2. Drive the real export through its surface argument against SCSS written to a temp tree. Asserting against the repository's own theme files would pass for exactly as long as those files stay clean, and stop testing the guard the moment someone fixed them.
  3. Cover all four failure classes plus every exemption: modeInvariant tokens, var() fallback literals, custom-property declarations, comments, quoted strings, and component-local tokens.
  4. Pin the alias-resolution escape hatch (resolvesDifferently). #17200 closed on exactly this — "its parity rule flags correct aliases" — so the regression it fixed needs an arm, or the cheap string-equality version can return unnoticed.

Contract Ledger Matrix

Target Surface Source of Authority Behavior Fallback Docs Evidence
test/playwright/unit/buildScripts/util/check-theme-surfaces.spec.mjs #17922 AC-1; sibling precedent check-fixed-sleeps.spec.mjs drives collectThemeSurfaceFailures against temp-tree fixtures none — a CI-gating guard without a spec is the defect spec header each check family red against a seeded mutation of the guard

Acceptance Criteria

  • AC-1 A spec exists at test/playwright/unit/buildScripts/util/check-theme-surfaces.spec.mjs and is green under npm run test-unit.
  • AC-2 Every check family the guard still owns — [surface], [parity], [token-only], [completeness] — has at least one positive arm.
  • AC-3 Each exemption is asserted: modeInvariant, var() fallback literals, custom-property declarations, line and block comments, quoted strings, component-local tokens.
  • AC-4 The alias-resolution rule from #17200 carries both an exempt arm and its falsifier (identical referent still fails), so the arm cannot pass vacuously.
  • AC-5 Fixtures are written to a temp tree; the spec reads none of the repository's own theme files.
  • AC-6 Mutation-proven: disabling each check family in the guard reds the arms that name it, and the recorded per-mutation counts are in the PR.
  • AC-7 The dropped Institution-era checks are named in the spec header, so the deletion is stated rather than done quietly.

Out of Scope

The other three owed rows (WorkflowConcurrency, PublishReleaseNoteOrphan, RebuildContentIndexesAndSeo) — each gets its own ticket, as #18052 established. Also out of scope: any change to the guard itself. If an arm proves the guard wrong, that is a separate ticket, not a fix folded into a coverage PR.

Avoided Traps

  • Restoring the deleted file because it exists. Its 618 lines describe a 734-line guard; four fifths of that contract left with the Institution product. A spec restored on the strength of being recoverable would have asserted a contract that no longer exists.
  • Asserting against the live theme tree. It passes today, which reads as coverage and is not: it stops testing the guard the moment the tree is clean, and reds on unrelated theme work.
  • Trusting the first green. The full suite passed on its first run before any mutation. A spec that has never been shown to fail on the defect it names is not evidence — see AC-6.

Live latest-open sweep: read the latest 20 open issues at 2026-09-03T06:58Z; no equivalent found. A2A in-flight claim sweep: latest 30 messages, all read-states — no overlapping [lane-claim] on buildScripts spec coverage. Own-assignment sweep: 9 open, none covering this guard. Memory Core rationale sweep: no prior decision on this guard's coverage.

Retrieval Hint: "check-theme-surfaces zero unit coverage, deleted spec describes the 734-line Institution guard, rewrite not restore, alias parity escape hatch #17200"

tobiu referenced in commit 9b34b72 - "test(build): the Workstation theme guard states its own contract (#18162) on Sep 3, 2026, 8:57 AM