C4 fix - five undefined token names rendered surfaces transparent

The T9.9 token sweep pointed seven files (help.js, auth-guard.js, wp-format.js,
project-data.js, index.html, field.html, wp-creation-app.js) at Carbon names
the theme never defined: --cds-layer-01/-02, --cds-border-subtle-01/-strong-01,
--cds-layer-hover-01. theme-light.css carries no -01 suffixes. An undefined
var() invalidates the whole declaration, so the help-centre modal, the
change-password and language dialogs, the print popup's inlined values, the
creator nav drawer and the sync badge all rendered TRANSPARENT backgrounds -
reported by Nick against the help menu, 2026-08-20.

Renamed every consumer to the canonical tokens (--cds-layer, --cds-layer-accent,
--cds-layer-hover, --cds-border-subtle, --cds-border-strong), matched to the
hex each replacement originally stood in for. color_check gains check 3: every
var() consumed anywhere must resolve to a definition somewhere - the class of
this bug, pinned. Verified live: the modal computes rgb(255,255,255) over an
opaque gray nav, and the language dialog is opaque too. BL-025 logged for the
one wrong-base-colour rgba tint noticed in passing.

Item: C4 (regression in its own enforcement). Probe: color_check 5/5.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 11:27:12 -07:00
parent 454bfa0fe1
commit 2a5f6b3549
9 changed files with 77 additions and 32 deletions

View File

@@ -67,6 +67,34 @@ def main():
others.append(name)
chk("...and no consumer still references either", not others, others)
print("\n3. every token consumed is a token defined")
# The bug this pins: help.js (and six other files) shipped consuming
# --cds-layer-01/-02 and --cds-border-subtle-01/-strong-01 - names the theme
# never defined (its names carry no -01 suffix). An undefined var() makes
# the whole declaration invalid, so the help centre modal, the password and
# language dialogs, and the print popup all rendered TRANSPARENT
# backgrounds. Found by the user, 2026-08-20. Definitions are collected
# from every file (page aliases are legal); consumption of a name nobody
# defines is the defect.
defined, consumed = set(), {}
for name in sorted(os.listdir(HTML)):
if not name.endswith((".js", ".html", ".css")):
continue
src = io.open(os.path.join(HTML, name), encoding="utf-8").read()
for m in re.finditer(r"(--[a-zA-Z0-9-]+)\s*:", src):
defined.add(m.group(1))
for m in re.finditer(r"setProperty\(\s*['\"](--[a-zA-Z0-9-]+)", src):
defined.add(m.group(1))
for m in re.finditer(r"var\(\s*(--[a-zA-Z0-9-]+)", src):
consumed.setdefault(m.group(1), set()).add(name)
# --wp-chart- is the creator's JS-concatenated fallback ('--wp-chart-'+k);
# the numbered names it builds are all defined, the fragment is not a name.
unresolved = ["%s (%s)" % (t, ", ".join(sorted(fs)))
for t, fs in sorted(consumed.items())
if t not in defined and t != "--wp-chart-"]
chk("no var() anywhere names a token that nothing defines",
not unresolved, unresolved[:8])
print("\n" + "-" * 54)
print("%d/%d checks passed." % (len(_PASS), len(_PASS) + len(_FAIL)))
for f in _FAIL: