Uh oh!
There was an error while loading. Please reload this page.
fix(cli): objectui check judges only files that are recognisable as ObjectUI schemas, and reports what it skipped - #5334
Conversation
…ObjectUI schemas (#5127) A root `type` is not evidence that a file is a UI schema — `type` heads at least seven unrelated JSON vocabularies, the commonest being `package.json`'s `"type": "module"`. Measured at this repo's root: 46 warnings, 45 of them package manifests, and the first line a user saw in their own project. A file now enters type judgement only on a positive marker: `$schema` pointing at an objectui.org host, or a structural key declared on `BaseSchema`. An exclusion list of filenames was rejected — that is a second hand-maintained list of the shape #5115 had just finished deleting. Option D lands with it: the command reports how many eligible files carried no marker, so the narrowed judgement surface is never silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
…posed (#5127) Reverse-verification predicted 8 red and observed 7. The miss was the `.eslintrc.json` case: `globSync` does not match dot-prefixed names without `dot: true`, so that file was never scanned and its assertion of silence held whatever the marker did — green in both directions, measuring nothing. It is replaced by a deployment-resource descriptor, which is scanned and whose root `type` is unregistered, plus an explicit test that pins the dotfile scope itself with a scanned sibling as counter-probe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-support-ai
commented
Aug 19, 2026
PM review: technically ACCEPTED, and deliberately NOT merged. Round 17. ⛔ This PR is not queued and I will not queue it. The 2026-08-19 ruling reserves one thing to the maintainer: "The URL proposal goes in the implementing PR for the maintainer to confirm at merge (it is a permanent public URL)." Clause-② is Everything else checks out:
What makes the marker defensibleThe structural set is read out of The The card's own baseline was stale and was re-measured rather than inherited — today's Option D ships with it and goes one better than the ruling asked: The verification I want on the recordThe ablation caught two phantom fixtures in this PR's own new suite — green in both directions, therefore measuring nothing:
Both surfaced because the first ablation round predicted 8 red and observed 7, and the one-test gap was chased instead of rounded off. Replaced with a scanned deployment-resource descriptor and a Filed out of it: #5335 — Stated plainly, and it is in the PR body tooThis PR does not close the coverage gap. Until #5329's corpus migration lands, this is the A+D interim the ruling permits, and 258 real schema files leave the judgement surface. Recorded as a debt, not as a fix. Generated by Claude Code |
…inted (#5127) Maintainer ruling 2026-08-20 (verbatim 「C」) supersedes the `$schema` half of the 2026-08-19 「全部接受」 ruling. The structural arm and the option-D skip count are unaffected and stand. `pointsAtObjectUi()` and `OBJECTUI_SCHEMA_URL` are removed, and the skip hint now names the structural keys by rendering the gate's own array — so it cannot advertise a way in that the build does not honour. The fixtures in `check-known-types.test.ts` and `check-jsonc-parse.test.ts` declared that URL to stay judged; they now carry a structural key instead. Each silence assertion among them gains a counter-probe, because a fixture that is no longer admitted leaves those assertions green while measuring nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
The note advertised a `$schema` URL as one of two ways a file opts into type judgement. The maintainer's 2026-08-20 ruling removed that arm, so the structural key is the only marker, and a release note describing a way in that does not exist is a defect in its own right. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
objectui check judges only files that declare themselves ObjectUI schemas, and reports what it skippedobjectui check judges only files that are recognisable as ObjectUI schemas, and reports what it skipped✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#5127
Implements the maintainer's 2026-08-20 ruling (verbatim 「C」):
objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped — with no public$schemaURL minted.That ruling supersedes the
$schemahalf of the 2026-08-19 「全部接受」 ruling. The structural arm and the option-D skip count are unaffected and stand.⛔ No permanent public identifier is proposed any more. The URL this PR previously proposed for confirmation is not adopted and appears nowhere in the code, the skip hint, the tests, the changeset or the docs — verified by grep over
packages/cli/srcand.changeset. The hold this PR carried (clause-②, "proposes a permanent public identifier") is therefore discharged: there is nothing left for the maintainer to confirm.⛔ This PR does not close the coverage gap. It is the interim the ruling permits, and the debt is stated below, unchanged.
What changed since the last revision
pointsAtObjectUi()and theOBJECTUI_SCHEMA_URLconstant are gone, along with the branch that called them. What remains is one arm.The skip hint was rewritten. It used to print the URL and tell the reader to declare
$schema— advice for a capability the build would no longer have, which is the "comment claims, code does not enforce" shape this repo treats as a defect in its own right. It now names the structural keys, and it does so by rendering the gate's own array rather than a sentence maintained beside it, so it cannot drift from what the gate honours:A test reads that sentence back and feeds every key it advertises to the command on its own file; if the hint ever names a key the gate does not honour, the file is skipped and the test goes red.
The gate as it now stands
A file enters type judgement only when its root carries a key declared on
BaseSchema(packages/types/src/base.ts) that is distinctive to a UI node:children,body,className,style,placeholder,visible,visibleWhen,visibleOn,hidden,hiddenOn,disabled,disabledOn,testId,ariaLabel.Everything else with a root
typeis simply not judged. No exclusion list of filenames — the rejected direction B from the original ballot, of the shape #5115 had just finished deleting.Only the
.jsonarm is affected. The glob also matches.yaml/.yml, and those files are read by neither the parse arm nor the judgement arm, before this change or after it.Why the structural set is drawn from
BaseSchema, and why it stops short of itThe set is read out of the node contract rather than invented, and it is closed: it grows only when
BaseSchemagrows.BaseSchema's remaining keys are held out because their names head foreign root vocabularies. Measured over this repository:nameappears at the root of 45 of the 46 foreign judged files anddescriptionat 44 — bothpackage.jsonkeys — so admittingBaseSchemawholesale takes foreign retention from 0 files to all 46, re-creating the exact defect.id,labelanddataare held out on the same reasoning;itemsis held out because it is a JSON Schema key.The arm is drawn for precision over recall on purpose. A foreign file wrongly judged is this card's defect reappearing in a user's project; a real schema wrongly skipped is a coverage debt that the corpus migration repays and that the printed count keeps visible meanwhile.
Why there is no
$schemaarmRecorded in the code beside the gate, so the next reader does not re-propose it. In short: a
$schemaURL is a permanent identifier living in users' files, which no sweep can reach, and minting the address before the document exists is backwards. The only consumer that needs a URL rather than any agreed marker is an editor resolving it over HTTP; an agent authoring schemas instead needs a contract it can read before writing and a good error after writing, and the latter is this command. Because the matching was host-based rather than literal, the arm can be added later without invalidating a single file — most soundly once@object-ui/typesships a generated JSON Schema, which the ruling files separately for the decision inbox.Re-measured after the change
Measured first-hand at
9f118b934, both columns produced in this worktree — thebeforecolumn by buildingmain'scheck.tsin the same tree, not inherited from the earlier report.package.json"module"The skipped figure did not move — 304 before this revision and 304 after — and that is a measured result, not a stale number. Removing the
$schemaarm released nothing, because the arm matched nothing: of the 470 files a roottypestring makes eligible in this repository, exactly 1 declares any$schemaat all (a draft-07 JSON Schema document) and 0 point at anobjectui.orghost. The ruling states this; it is confirmed here rather than taken on trust.Of the 470 eligible files, 46 are foreign (45 package manifests + one draft-07 JSON Schema) and 424 are real in-repo ObjectUI schema files (423 under
examples/schema-catalog/src/schemas, plusexamples/hello-world/schema.json). Under the marker as shipped, 166 of those 424 are retained and 258 leave the judgement surface (60.8%). 258 real + 46 foreign = the 304 skipped above.The catalog's own deliberate
examples/schema-catalog/src/schemas/core-schema-renderer/unknown-component-type.jsonfixture goes quiet. It was the single genuine warning the command emitted, and its root is{type, someData}— no marker. This is the cost the ruling names, and it is why option A alone was rejected and why D ships alongside.The debt is repaid by the corpus migration, which is its own card and is not touched here —
examples/schema-catalog/**is untouched in this diff.Option D — the shrink is never silent
The count covers files that a root
typestring made eligible and no marker admitted — files that were never eligible do not inflate it, since they are not lost coverage. It is a report, not a failure: exit codes are untouched, and a JSON parse failure remains the only thing that fails the run.Verification
All at
9f118b934, the final commit on this branch.pnpm exec vitest run packages/cli/src/__tests__/from the repo root (the canonical invocation —assertCanonicalVitestInvocationrefuses a package-cwd run): 10 files, 202 tests, all passing. 203 previously; the two tests that pinned the$schemaarm are gone and one hint test is new.pnpm --filter @object-ui/cli type-check→ clean (tsc --noEmit, and the run echoed the script name, so it is not a zero-match silent pass).pnpm --filter @object-ui/cli lint→ 0 errors, 11 warnings, none in any file this PR touches (grepped by filename).node scripts/check-control-bytes.mjs→ OK, 4723 tracked text files; the touched files also self-scanned clean for raw control bytes.node scripts/check-changeset-no-major.mjs,node scripts/check-changeset-fixed.mjs→ OK (changeset isminor).node scripts/check-package-self-import.mjs,node scripts/check-phantom-dependencies.mjs→ OK.pnpm --filter @object-ui/types build && pnpm --filter @object-ui/cli build, thennode packages/cli/dist/cli.js checkat the repo root — the table above.Build artifacts, per leg
packages/cli/dist/was deleted outright, and the threecheck-*files then ran 34 passed with nodist/present at all. The imports are relative (../commands/check.js), and no root vitest alias covers them, so Vitest resolves tosrc/commands/check.ts.dist/, so it was rebuilt. Confirmed in both directions before each measurement: the new hint sentence is present indist/cli.jsfor theafterrun and absent from the pre-change build used for thebeforerun, and the removed URL greps to 0 in the shipped bundle.cli-bin.test.tsself-builds the CLI only whendist/is absent. A staledist/is not refreshed by running the tests, so an end-to-end reading taken without an explicit rebuild can silently describe old code.Reverse verification
Three ablations, each with the count predicted before running. The fix was committed first, so every restore was a
git checkoutback to the commit, confirmed byte-identical by an emptygit status --porcelain.1. Revert
check.tstomain(the gate itself removed) — predicted 8 red, observed 8, the same set name for name: the package-manifest case, the JSON Schema case, the deployment-descriptor case, the foreign-file-whose-type-names-a-real-component case, the new$schema-is-not-a-marker case, and all three option-D assertions. The tests asserting a schema is still judged stay green under this ablation by design — the old code judged everything — which is why they are paired with the ones above rather than standing alone.2. The fixture trap, which this revision exists to defuse. The pre-existing fixtures in
check-known-types.test.tsandcheck-jsonc-parse.test.tsdeclared the$schemaURL in order to stay judged. Deleting those lines and taking the green run would have put every one of them back into the state the previous revision of this body warned about: the warning assertions fail, and — worse — the silence assertions keep passing while measuring nothing. Each fixture is therefore given a structural key (className, the least semantically loaded key in the set) instead, and each silence assertion is paired with a counter-probe — a file with the same marker and an unregistered type — so the silence is a verdict rather than a judgement that never ran.Measured, not asserted. Dropping the marker injection from
check-known-types.test.ts: predicted 5 red, observed 5. Then the counterfactual, same ablation but with the counter-probe and the added warning assertion removed — i.e. the tests in their original shape: predicted 3 red, observed 3, with 2 passing while measuring nothing. Those two are exactlyis silent for registered types...andreports an unknown type as a warning, never as a failure, over fixtures the gate never admitted.3. Dropping the markers from
check-jsonc-parse.test.ts— predicted 4, observed 3 on the first run. The miss was in the ablation, not the suite: the pattern used to strip the markers required a trailing space, and thecommented.jsonfixture spells the marker with a newline after the comma, so that one fixture was never actually ablated and its test stayed green for a correct reason. Completing the ablation gave 4 red, as predicted. Recorded because the previous rounds on this card turned up two genuine phantom fixtures the same way, and the difference between "my probe missed" and "my fixture is phantom" is only visible if you go and look.The changeset
Updated in the same push: it described the
$schemaURL as one of two ways a file opts in. It now describes the structural key as the only marker and records that no public$schemaURL is introduced. Stillminor.Generated by Claude Code