diff: settle five over-reports the site pair shows - #1270
Merged
Merged
Conversation
samoht
added this pull request to stack #1271
September 18, 2026 18:48
samoht
removed this pull request from stack #1271
September 19, 2026 11:03
samoht
force-pushed
the
canonical-colour-residues
branch
from
September 19, 2026 11:03
9a82def to
3df9cea
Compare
samoht
added this pull request to stack #1273
September 19, 2026 11:03
samoht
force-pushed
the
canonical-colour-residues
branch
3 times, most recently
from
September 19, 2026 12:32
5d261ff to
176bffe
Compare
diff --diff=canonical reads oklab(0% none none/.5) and #80 as one colour in a colour longhand, since CSS Color 4 sec. 4.4 makes a missing component behave as zero for every purpose but interpolation, and holds the two apart in a custom property. lightningcss writes Tailwind's color-mix(in srgb, rgb(0 0 0) 50%, transparent) mask colour as the OKLab with none chroma axes where tw writes the hex, so every mask utility on tw's site sheet was reported. A colour function in a custom stream is a colour wherever the stream substitutes, so its axes read as the longhand's do, under the same carve-outs: a rule transitioning the property, a keyframe and a @starting-style block keep them as written.
The canonical projection resolved a none axis only for a colour standing as a whole longhand value, on the argument that a custom-property stream may be substituted where sec. 13.3 of CSS Color 4 interpolates it. But the stream's colour function already folds to the hex it is at that same site, and that fold is as blind to where the stream lands as this one; lightningcss writes Tailwind's mask colours as OKLab with none chroma axes, so every mask utility on tw's site sheet reported against the hex tw writes. The custom-property colour fold now takes normalize_color's resolve_missing flag from the pass that owns it, so the stream's axes read as the zeros CSS Color 4 sec. 4.4 makes them, under the same carve-outs as a longhand: a keyframe, a @starting-style block and a rule transitioning the property keep them as written. transition-property never matched a custom property's own name, since the typed table reads one as an unknown property; it now does, by the name CSS Variables 1 sec. 2 makes case-sensitive.
CSS Values 4 sec. 6.1 makes deg, grad, rad and turn units of one dimension, and diff --diff=canonical reports .5turn against 180deg in a custom stream and in rotate, and 1.5rad against the 85.9437deg lightningcss writes, where a quotient already meets its six-significant-figure fold. Tailwind writes a conic mask position in turns and a rotation in radians, and each such utility on tw's site sheet reported. The angle folds to its degrees in rotate, in a transform function and in an unregistered custom property's stream, a radian under the budget a quotient takes, and --lossless keeps the unit as written.
The angle fold picked the shortest of the exactly interconvertible spellings and kept the authored unit on a tie, so .5turn and 180deg never met, and a radian was never converted at all since it goes through pi. CSS Values 4 sec. 6.1 makes deg, grad, rad and turn units of one dimension, and the conversion is Cascade's own digits, the same kind a quotient's fold rounds to six significant figures. Under the budget the canonical projection already sets, normalize_angle now spells every concrete angle in degrees, a converted unit rounded to that budget and an authored degree kept whole, so rotate: 1.5rad meets the 85.9437deg lightningcss writes. rotate and transform hand their calc context down for it, and an unregistered custom property's stream folds its angle tokens beside its time tokens, held off under --lossless as the quotient fold is. The minifier's own spelling is unchanged: it never sets the budget.
CSS Color 5 sec. 6 computes light-dark() to one of its two colours by the element's used colour scheme, so a color-mix() or a relative colour over a light-dark() argument is the light-dark() of that operation over each branch, and a branch mixed with transparent at half is the colour at half alpha, which the projection already folds for a plain colour. Tailwind writes a scheme-aware colour at half alpha as the mix and lightningcss as the light-dark() of the two hexes, and diff --diff=canonical reports the pair. The fold is branch-wise and exact: a mix a branch cannot fold stays as written and still reports, and --lossless keeps the mix.
A color-mix() folds to the colour it names only when both arguments are static, so a light-dark() argument kept the whole mix as written, and diff --diff=canonical reported Tailwind's scheme-aware colour at half alpha against the light-dark() of two hexes lightningcss writes for it. CSS Color 5 sec. 6 computes light-dark() to one of its two colours by the element's used colour scheme, the same scheme at every depth of the value, so a mix or a relative colour over a light-dark() argument is the light-dark() of that operation over each branch, both arguments distributing at once. The fold is exact and stops where a branch cannot fold: such a mix stays as written and still reports, and --lossless holds the fold off as it holds the mix fold. --minify shares the fold and writes the shorter light-dark() form.
Whether what the two readers dropped can still separate two sheets that compare equal was decided in the binary, over the warnings the library hands back, so nothing in test/ could hold it and the cram tests were its only pin. The question is a property of the comparison outcome: Css_compare.unread_separates answers it and the binary reads that answer, with no change in what it does yet.
diff --diff=canonical exits 2 when a declaration the reader refuses is all that separates two sheets, as Tailwind's compiled sheet does against tw's site sheet: Tailwind writes filter: blur(<value>) for a docs placeholder class and tw writes nothing. Parity is rendering, and the reader is held to the browser's accept set by test/spec/browser/accept_set, so a declaration it refuses is one the browser drops from whichever sheet holds it and paints the same. The verdict has to be 0 there, the warning kept as information, and 1 when a real difference stands beside it. A rule the reader dropped is text the comparison never saw, with nothing holding the rule reader to a browser, so it still withholds the verdict unless both sides lost the same run.
cascade diff answered 2 whenever a declaration one reader refused had no twin on the other side, on the argument that the comparison never saw it. But the declaration reader is held to the browser's accept set by test/spec/browser/accept_set, so a declaration it refuses is one every browser drops from whichever sheet holds it, and the two sheets paint the same. Parity is rendering: the verdict is now the one over what remains, the parse warning kept as information since the reader can lag the browser and the warning says where to look, and a difference beside the refused declaration still exits 1. Tailwind's compiled sheet writes filter: blur(<value>) for a docs placeholder class where tw writes nothing, and that pair exited 2 over every comparison of the two. A rule the reader dropped is text the comparison never saw, with nothing holding the rule reader to a browser, so it still withholds the verdict unless both sides lost the same run of text; exit 2 stays for that, for a file that cannot be read at all, a driver failure and no browser.
diff --diff=canonical reports @supports (@media(width>=1px): var(--tw)) { .x { display: flex } } against nothing as a difference, where the browser applies nothing from the block. CSS Conditional 3 sec. 6.1 makes a parenthesised term that is neither a declaration nor a nested condition a general-enclosed whose result is false, and @media(...) is no property name, so the guard is false in every world. Tailwind writes exactly that for supports-[@media(width>=1px)]:flex where tw writes nothing, and the two render alike. The block goes under either reading, --enforce-spec included, since no browser and no reading of the spec answers the guard yes; a guard a browser can answer stays, as does a function form cascade's own feature grammar may have refused.
The reader turns a parenthesised term that is neither a declaration nor a nested condition into a general-enclosed leaf, and the projection kept such a guard open as the optimizer does, so Tailwind's @supports (@media(width>=1px): var(--tw)) block for supports-[@media(width>=1px)] :flex was reported against the nothing tw writes, though the browser applies nothing from it. CSS Conditional 3 sec. 6.1 makes a general-enclosed term's result false, and @media(...) is no property name, so the guard is false however a user agent answers its feature tests. Supports.never_holds reads the term as that constant and the projection drops the block, under --enforce-spec too, since no reading of the spec and no browser answers the guard yes. A function form stays a feature test, since cascade's own grammar may refuse an argument the browser's selector() accepts, and simplify_under keeps the term open for a sheet the optimizer emits, so --minify writes the guard as before.
canonicalize_rule_order's doc enumerates what the comparison-side pass keys alike and names the custom-property stream among the positions a none channel is kept at, which it no longer is. The list now carries the stream, the angle in degrees, and the @supports guard no reading answers yes, beside the keys it already had.
samoht
force-pushed
the
canonical-colour-residues
branch
from
September 19, 2026 12:40
176bffe to
0f12586
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five pairs
--diff=canonicalreported that a browser paints alike, each with its spec section: anonecolour axis in a custom property's stream (CSS Color 4 sec. 4.4), one angle underdeg,radandturn(CSS Values 4 sec. 6.1), acolor-mix()or relative colour overlight-dark()taken branch by branch (CSS Color 5 sec. 6), a declaration the reader refuses withholding no verdict since the browser drops it too (exit 0 when the rest is equivalent), and an@supportswhose guard no reading answers yes dropped (CSS Conditional 3 sec. 6.1). Each pair has a pinned test and an entry.