Skip to content

The validator sees the rule after an @import, and dark rules fail - #529

Merged
yayashuxue merged 1 commit into
mainfrom
fix/validator-at-rule-bypass
Sep 11, 2026
Merged

The validator sees the rule after an @import, and dark rules fail#529
yayashuxue merged 1 commit into
mainfrom
fix/validator-at-rule-bypass

Conversation

@yayashuxue

@yayashuxue yayashuxue commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Three faults in bin/tdoc-validate-template, ordered by how much they matter. The first one is why the other two are worth fixing now: until it is closed, any rule added to this file can be stepped around with a single line.

1. One @import hid the rule after it from every check

A statement at-rule ends at its semicolon and leaves no block behind, so the rule written after it lands in the same [^{}]+ run. Two of the three CSS loops judged that run by its first character, read the whole thing as one @-prefixed selector, and skipped it — taking the following rule with it.

.wrap{padding:99px}                          /* error, as it should be */
@import url("x.css"); .wrap{padding:99px}    /* silently passed */

So one @import line was a general-purpose way to hide CSS from this file, including from whatever checks get added to it later. The fix keeps only what follows the last ;, which leaves an ordinary selector to judge. The third loop already read _unconditional_css, which delimits at-rules properly, and was never affected.

_unconditional_css is deliberately left alone. It strips at-rule blocks on purpose — a size inside @media is a different layout, not a second size in the same one — so making the parser recurse into at-rules generally would break responsive layouts that are entitled to differ.

2. An error that named the wrong property

body{background:#fff;margin:0} reported "body background does not match the house style" — but #fff is the house ground, and margin is the fault. One message stood for both halves of allowed and white, so it named a property that was correct. That reads as a bug in the validator rather than a fault in the document, and it is how an author learns to work around the tool instead of the rule. It now names the properties that actually broke it.

A body that sets no background at all is left to the structural error below it, rather than called a house-style mismatch as well.

3. Dark rules were only taste notes

tdoc has no per-document dark palette. The frame paints dark with filter: invert(1) hue-rotate(180deg) over whatever the document painted, so a hand-built dark rule is inverted along with everything else and renders light — the failure authoring/style/technical.md records against a page that shipped its own dark palette and came out white. The reader sees it, so it is an error, not taste.

All three spellings are caught:

  • @media (prefers-color-scheme: dark){…}
  • html[data-tdoc-theme="dark"] …
  • a body simply painted dark, which wears no dark marker at all

A ground given as var(--x) is left alone — only a renderer can resolve it, and guessing would be worse than staying quiet. That case is what a render-time check would still be needed for.

Checking

Ran old and new against every HTML document in the repo (59):

  • the parsing fix on its own changes no verdict on any of them
  • with all three fixes, the only verdict that changes is test/fixtures/tdocs/copy-doc/v1/index.html

That fixture carries a real html[data-tdoc-theme="dark"] body{background:#111} rule, so it is an instance of the mistake rather than a false positive. I left it as it is — it is not a validator fixture, and its tests only read the theme attribute — but it should probably be fixed in its own change.

New tests cover all of it; each new assertion was checked to fail on main and pass here.

The full suite passes: npm test — 80 suites green, locally and on CI. The 8 playwright/network suites are gated off in both, as usual.

test/fixtures/tdocs/copy-doc/v1/index.html is used by two of those gated suites, and neither invokes the validator, so this change does not affect them either way. The dark rule in that fixture is vestigial: the test that cares about dark reads the data-tdoc-default-theme="dark" attribute, not the CSS. Read, not run — playwright is not installed here.

Found by @ops, who hit the dark-mode bug while authoring and then traced it.

🤖 Generated with Claude Code

Three faults in bin/tdoc-validate-template, in the order they matter.

A statement at-rule ends at its semicolon and leaves no block behind, so
the rule written after it shared one `[^{}]+` run with it. Two of the
three CSS loops judged that run by its first character, read the whole
thing as one `@`-prefixed selector and skipped it, carrying the following
rule out of every check. `@import url("x.css"); .wrap{padding:99px}`
passed silently where `.wrap{padding:99px}` alone is an error, so one
`@import` line was a general way to hide CSS from this file -- including
from whatever rules get added to it later. Keeping only what follows the
last `;` leaves an ordinary selector to judge. The third loop already
read `_unconditional_css`, which delimits at-rules properly, so it was
never affected.

The body check reported "body background does not match the house style"
for `body{background:#fff;margin:0}`, where #fff *is* the house ground
and `margin` is the fault. One message stood for both halves of
`allowed and white`, so it named the wrong property and read as a bug in
the validator rather than a fault in the document -- which is how an
author learns to work around the tool instead of the rule. It now names
the properties that broke it, and a body with no background at all is
left to the structural error below rather than called a mismatch twice.

Dark rules were only taste notes. tdoc has no per-document dark palette:
the frame paints dark with `filter: invert(1) hue-rotate(180deg)` over
whatever the document painted, so a hand-built dark rule is inverted with
everything else and renders *light* -- the failure technical.md records
against a page that shipped its own dark palette and came out white. A
reader sees it, so it is an error. All three spellings are caught: the
`prefers-color-scheme: dark` block, the `html[data-tdoc-theme="dark"]`
selector, and a body simply painted dark, which wears no dark marker at
all. A ground given as `var(--x)` is left alone -- only a renderer can
resolve it, and guessing would be worse than staying quiet.

Checked against every HTML document in the repo: the parsing fix changes
no verdict on any of them, and the only verdict it changes at all is
test/fixtures/tdocs/copy-doc/v1/index.html, which carries a real
`html[data-tdoc-theme="dark"] body{background:#111}` rule. That fixture
is left as it is -- it is not a validator fixture and its tests only read
the theme attribute -- but it is an instance of the mistake, not a false
positive.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 10, 2026 21:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown

Preview

Open this: https://pr-529-tdoc-preview.jyshi1107.workers.dev/ — the homepage, this PR's code
carrying the landing version in this PR's checkout.
Or a document: https://pr-529-tdoc-preview.jyshi1107.workers.dev/d/conway-life/v/2

This link is unique to this PR. New commits update the same URL. It is not tdoc.dev.

Preview has no Durable Object — concurrent comments use the KV fallback. Data expires in 14 days.

@yayashuxue
yayashuxue merged commit c004e47 into main Sep 11, 2026
5 checks passed
@yayashuxue
yayashuxue deleted the fix/validator-at-rule-bypass branch September 11, 2026 07:30
Sign up for free to 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.

2 participants