fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(design-system): stop the radius scanner from skipping wrapped values - #1520

Merged
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7
Jul 27, 2026
Merged

fix(design-system): stop the radius scanner from skipping wrapped values#1520
jackwener merged 2 commits into
mainfrom
claude/modest-spence-135ff7

Conversation

@jackwener

Copy link
Copy Markdown
Member

The gap

radius-converge-contract.test.ts scans renderer CSS for border-radius declarations that violate the radius token contract. Both scanner regexes matched the value with [^;}\n]+.

Excluding \n meant a declaration whose value wraps onto a second line matched nothing at all — the scanner skipped it silently instead of reporting it. Any radius could escape governance just by being formatted across two lines:

border-radius:10px12px; /* never scanned */

Prettier/biome will not reflow a long value back onto one line, so a four-corner shorthand or a long calc() reaches this state on its own.

One nuance worth recording

A newline directly after the colon was always fine — the \s* there already spans it. Only a newline inside the value, after the first token, was affected:

snippetbeforeafter
border-radius:⏎ 10px;✅ matched
border-radius: 10px⏎ 12px;skipped
border-radius: 10px 12px⏎ 14px 16px;skipped
border-radius: calc(var(--radius-modal)⏎ - 8px);skipped

The obvious minimal repro (border-radius:⏎ 10px;) is not a repro. A regression test written around it would have been green against the buggy regex and guarded nothing.

The fix

[^;}\n]+[^;}]+ on RADIUS_DECL_RE and RADIUS_LONGHAND_RE.

Greediness stays bounded regardless: ; and } are still excluded, so a match cannot outrun its own declaration or rule body. splitCorners() already tokenizes on any whitespace at paren depth 0, newlines included, so wrapped values tokenize correctly once matched at all.

Tests

Two cases added next to the existing scanner tests:

  • reads values that wrap onto a second line — five offenders that must be flagged (incl. a longhand, and a wrapped + 8px proving the shrink-only rule still applies across the break), plus three valid multi-line values that must pass.
  • stops each match at its own declaration boundary — three declarations across three rules must capture separately and not bleed, i.e. the widened class did not become a false-positive machine.

Verified the first test fails against the old regex and passes with the fix. The second passes both ways by design — it is an over-reach guard, not a bug repro.

Gate

  • npm run build:main — clean
  • node --test "dist/main/**/*.test.js"2878 pass, 0 fail (2876 baseline + 2)
  • node scripts/check-dead-css.mjs --check — no dead classes ✓
  • biome check on the changed file — clean

Context

Found while reviewing #1514, which fixed a separate bug in this same contract (it mandated invalid unspaced calc()). That fix already landed; this is the remaining scanner gap.

The CSS governance scanner matched `border-radius` values with the class
`[^;}\n]+`. Excluding `\n` meant a declaration whose VALUE wrapped onto a
second line matched nothing at all — the scanner skipped it in silence
rather than reporting it, so any radius could escape the token contract
just by being formatted across two lines:
border-radius: 10px
12px; /* never scanned */
Neither prettier nor biome reflows such a value back onto one line, so a
long four-corner shorthand or calc() reaches this state on its own.
(A newline directly after the colon was always fine — the `\s*` there
already spans it. Only a newline *inside* the value was affected, which
is narrower than it first looks.)
Widening the class to `[^;}]+` cannot make a match outrun its own
declaration: `;` and `}` are still excluded, so it stops at the first
declaration terminator or the end of the rule body either way. The
regression test covering that is asserted alongside the fix.
Found while reviewing #1514, which fixed a separate bug in the same
contract (it accepted only invalid unspaced calc()). This is the
remaining scanner gap.
`main` has been red since 17362dc (#1515); 0e80fe1 (#1359) inherited it.
All three jobs failed, none of it visible in that PR's own checks because
the earliest failure short-circuits the rest of the job.
typecheck job
- `format:check`: scripts/build-cursor-overlay.mjs was committed
unformatted. Reapplied `biome format`; purely mechanical.
- `knip`: #1515 added a second overlay entry point pair
(permission-overlay{,-preload}.ts) but registered only the cursor
overlay in knip.json, so both files read as unused. Registered them
beside their cursor-overlay twins — they are loaded by path at
runtime (loadFile / preload), never imported.
- `knip`: asOsPermissionId was exported and referenced nowhere in the
repo. It is an identity function (`return id`), so nothing is lost by
dropping it — git history holds it if Stage 2 wants it back. Its sole
import (OsPermissionId) went with it.
test job
- `check-console`: three console.warn sites in
permission-overlay-main.ts (locale fallback, missing .app bundle, the
controller log sink). These are main-process diagnostics that expose
paths, not secrets — the same category as the daily-review and
settings-runtime entries — so they are allow-listed with a reason
per the script's own documented convention.
e2e job
- `settings.spec.ts:141` asserted a permission row draws exactly two
grant buttons. #1515 added a third (拖拽授权) to precisely the row
the fixture aims at — screen_recording is requestable, openable AND
drag-grantable — so the `=== 2` filter matched nothing and the guard
silently measured no rows. Relaxed to `>= 2`, which is what the
contract was always about: a row whose actions track competes with
the body. A wider actions track only makes the squeeze worse, so the
three-button row is strictly the better subject.
Verified locally: lint, format:check, build, typecheck, knip (both
workspaces), check-console, and the full test:dist suite.
@jackwener
jackwenerforce-pushed the claude/modest-spence-135ff7 branch from 717931f to 6e97744CompareJuly 27, 2026 08:52
@jackwener
jackwener merged commit 96ea7c7 into mainJul 27, 2026
3 checks passed
@jackwener
jackwener deleted the claude/modest-spence-135ff7 branch July 27, 2026 08:58
jackwener added a commit that referenced this pull request Jul 27, 2026
…name (#1537)
The CSS scanner matched the property name as a bare substring, so
`--os-track-border-radius: …` in base.css was scanned as though it were
a plain `border-radius` declaration. Both such properties currently hold
whitelisted tokens, so nothing failed — but the moment one held a raw px
the offender would have read
renderer CSS: border-radius: 4px;
naming a declaration that does not exist anywhere in the stylesheet, and
sending whoever has to fix it looking for the wrong thing.
Keeping these in scope is deliberate, not merely tolerated. `.os-theme-maka`
is OverlayScrollbars' theming API: the library's own CSS consumes those
properties and renders a real scrollbar corner. A radius that reaches the
screen is governed no matter which declaration spells it. So the fix is to
capture the whole property name rather than to anchor the match and drop
the coverage.
The lookbehind is load-bearing: without it a prefixed property also matches
at its inner `border-radius` and is reported twice. `\b` cannot do this job
— `-` is a non-word character, so a word boundary already exists between
`-` and `border`.
Found while reviewing #1520; deliberately left out of that PR and #1535 as
pre-existing and orthogonal.
Verified: lint, format:check, typecheck, check-dead-css, and 2891
main-process tests. The new assertion fails against the old regex.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener