Uh oh!
There was an error while loading. Please reload this page.
test(scripts): pin @object-ui/fields' published stylesheet as a third subject - #7043
Merged
Merged
Conversation
… subject `plugin-published-stylesheet.test.ts` ran its per-package assertions over `plugin-grid` and `plugin-kanban` only. `@object-ui/fields` — the package whose sheet has actually been shipping to consumers since objectui#4059, the very defect the test's header cites as the reason the shape exists — was covered by the builder's four write-time assertions and by nothing in the suite, since CI runs the tests on an unbuilt worktree. objectui#6405 re-pointed fields at the shared `createPluginStylesheetBuilder`, so it now exports the same module shape the plugins do and the assertions apply unchanged. The `CARD_THEMED` entry is derived from the emitted sheet — surviving classes whose declarations resolve a `--color-*` token from components' unpublished `@theme` block — not read back off fields' own `MUST_SURVIVE`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GgDDqh6YnkXqsnVTCa7wHk
This was referenced Aug 31, 2026
zhuangjianguo
marked this pull request as ready for review
August 31, 2026 15:41
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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.
Fixes#6438
scripts/__tests__/plugin-published-stylesheet.test.tsran its per-packageassertions over exactly two subjects,
plugin-gridandplugin-kanban.@object-ui/fieldswas not one of them — and it is the package whose stylesheethas actually been shipping to consumers since #4059, the very defect the test's
own header cites as the reason the shape exists. Its
dist/index.csswasguarded by the four write-time assertions inside the shared builder, which run
only during a build; CI runs this suite on an unbuilt worktree, so nothing in
the test run inspected it.
This adds
fieldsas a third subject. The suite goes from 14 tests to 20(three subjects times six per-package assertions, plus two standalone).
Premise re-verified on the merged ref
Re-read on
main=e33b44796, item for item, rather than inherited:packages/fields/scripts/build-css.mjs(notbuild-stylesheet.mjs) importscreatePluginStylesheetBuilderat line 94 and exportsPACKAGE_ROOT/PACKAGE_NAME(96/97),
MUST_SURVIVE/CLASS_CEILING(114/132),builder/buildOptions(161/163) behind the
isEntrypointguard (171) — the same shape the two pluginsexport.
SUBJECTSwas at test line 91.How the
CARD_THEMEDentry was derivedIndependently, from the sheet the build actually emits — not read back off
fields' own
MUST_SURVIVE, which would have looked identical while pinningnothing.
Method: build fields' sheet through the shared builder, then keep every
surviving class whose own declarations resolve a
--color-*token declared inpackages/components/src/index.css's@themeblock (35 tokens) — the file thatpackage does not publish, which is exactly what makes an in-monorepo build the
only possible producer of these utilities.
That yields 17 surviving themed classes out of 163 surviving total. Two
independent corroborations:
packages/fields/scripts/build-css.mjsrecords, from @object-ui/fields declares a./style.cssexport but nothing buildsdist/index.cssfor it — the subpath quick-start teaches looks unresolvable #4059, that "17 of thosedepend on the ObjectUI
@themeblock" — the same count, reached by adifferent method.
./style.cssexport but nothing buildsdist/index.cssfor it — the subpath quick-start teaches looks unresolvable #4059 names (bg-primary/20,hover:bg-accent/30,ring-destructive/50) are 3 of the 17, confirming they were the startingcorpus and not the answer. The other 14 are ones a literal-grep method could
not see.
Only 3 of the 17 appear in
MUST_SURVIVE, so the list is demonstrably not thatlist read back.
Banner: taken from
buildOptions, and why nothing changedfields passes a per-package
header(HEADER, line 147, intobuildOptionsatline 168);
plugin-grid'sbuildOptionshas noheaderkey and inherits theshared
defaultHeader. The emitted sheet isheaderplus the sheet, so anyassertion reading the banner from the shared default would judge fields wrongly.
Surveyed before writing: no assertion in the suite reads the emitted banner,
so the caveat is preventive here, not corrective. The one assertion that
inspects the whole
cssstring — "carries utilities only" — was checked againstfields' actual
HEADERbytes and none of its three patterns can match it. Themodule header now records the rule for anything added later. A banner pin is
not added here, for a reason recorded as a follow-up below.
Proof the new assertions have teeth
"The suite is green after I added it" is not evidence — a green assertion that
inspects nothing is precisely the defect this card records. Two ablations, each
proving the mutation reached disk before measuring, and each proving the restore
by blob hash rather than by exit code:
1. A themed utility stops being produced.
hover:bg-primary/10is in thederived list and deliberately not in
MUST_SURVIVE, so the builder'swrite-time throw does not fire and mask the result. Its single usage site in
RecordPickerDialog.tsxwas retargeted tohover:bg-primary/15.1e9d341dto3e0a4915Tests 1 failed | 19 passed, the failure beingfields > emits the themed utilities only this build can producewithAssertionError: expected [ 'hover:bg-primary/10' ] to deeply equal []1e9d341d,git diff HEADempty2. The manifest declaration breaks. fields'
exports['./style.css']waspointed at
./dist/nope.css, which also proves the subject name resolves topackages/fields.5e442f18to98eeea6fTests 1 failed | 19 passed, the failure beingfields > declares the export AND the step that produces it5e442f18,git diff HEADemptyIn both runs exactly one assertion went red and it was a
fieldsone, withplugin-gridandplugin-kanbanstill green — so the red is subject-specific,not a global break.
The finding that justifies the per-package coverage
Under ablation 1 the union assertion, "gives every themed utility the card
measured a producer", stayed green. Measured cause:
plugin-gridalso emitshover:bg-primary/10, so the union was satisfied by another subject whilefields' own sheet had genuinely regressed. Adding fields to
SUBJECTSis whatbuys the coverage; adding it only to
CARD_THEMEDwould have reproduced thedefect this card records.
Verification
Union run on the final commit,
git rev-parse --short HEAD=1219b8d88, tree clean:npx vitest run scripts/__tests__/plugin-published-stylesheet.test.ts --maxWorkers=2—Tests 20 passed (20), exit 0pnpm type-check:scripts— exit 0. Load-bearing: the shared builder's own comment records that this reads the options types through this test file, and fields is the first subject to passheader.pnpm type-check:coverage—45/46 via type-check,41/41 packages compile their testspnpm check:control-bytes—OK (scanned 5850 tracked text file(s))pnpm changeset:check— no major, fixed group OKnode scripts/check-changeset-presence.mjs— "no changeset is owed"; the changeset is an explicit no-release declaration in the empty-frontmatter shape this repo uses for test-only changesLint was narrowed to the changed file rather than run farm-wide, and the
narrowing is measured, not assumed: the file count comes from eslint's own
--format jsonoutput (1 file), and type-aware linting is not enabled ineslint.config.js(noprojectService,project:orparserOptions;control term
ruleshits 10 times in the same file, so the query was live), sothis diff cannot move the verdict on any untouched file. CI runs the full farm
regardless.
Follow-up, filed not ridden along
The emitted banner is pinned by nothing, and it cannot be pinned cleanly today:
the shared builder does not export its
defaultHeader, so an assertion coveringall three subjects would need a tolerant fallback in the test for the two
packages that declare no header — the consumer-side leniency this repo's
contract-first rule says to fix at the producer instead. That is a
producer-side change with its own review, so it is recorded rather than ridden
along here.
Generated by Claude Code