Repository navigation
docs: stop teaching keys the strict authoring face refuses (objectui#12131, phase 1) - #12134
Merged
objectstack-fleet[bot] merged 5 commits intoOct 11, 2026
Merged
Conversation
…12131)
Interface blocks (content/docs/components/form):
- button.mdx: drop `fullWidth` and `href`; neither is declared on
ButtonSchema and the button renders byte-identically with either. The
full-width spelling the page's own fixture uses, `className: "w-full"`,
is now named on the `className` line.
- form.mdx: `submitButton` -> `submitLabel` (the declared key the form
renderer reads for its submit text); FormField `defaultValue` (undeclared,
renders identically) -> FormSchema `defaultValues`, the key the renderer
seeds react-hook-form from.
- label.mdx: drop `required`; LabelSchema declares no indicator key and
the renderer only leaks it as a stray `required` attribute.
Catalog fixture: components-form-label/required-label.json is renamed
password-label.json (a label paired with a password input, which is what
it shows); the generated index is regenerated and the objectui#8761 pin
and the label page follow the new id.
READMEs (outside the JSON-fence gate's scan surface):
- README.md form: drop the undeclared root `title` (it only reached the
DOM as a native tooltip on the form element).
- README.md dashboard: rewrite onto declared keys: `metric-card` entries
with `title`/`trendValue` and literal values (metric-card does not
evaluate `${...}`), dataset-bound `line`/`pie` chart widgets, and the
flat `w`/`h` moved into `layout` boxes; drop the undeclared root `title`.
- packages/plugin-dashboard/README.md: the object-bound table example is
an `object-data-table` node; a bare `table` is the static component and
declares neither `objectName` nor a column `format`.
Claude-Session: https://claude.ai/code/session_01DwLS3LzXyNmyTunMGbpc8W
Co-authored-by: Claude <noreply@anthropic.com>
…ulary (objectui#12131) The root README's "Dashboard" copy-paste schema passed check:doc-types only because it taught registered COMPONENT keys (`statistic`, `chart`) in a dashboard's `widgets[]`, which the strict authoring face refused. Rewritten onto the slot's own vocabulary, its `type` values are `metric-card`, `line` and `pie`: widget-slot / widget-kind values that are not bare registry keys. They are declared in DOC_TYPE_EXEMPTIONS under `README.md`, worded after the `packages/plugin-dashboard/README.md` entries that already declare the same three values; the gate's stale-exemption check keeps the entries tied to the sites. Claude-Session: https://claude.ai/code/session_01DwLS3LzXyNmyTunMGbpc8W Co-authored-by: Claude <noreply@anthropic.com>
…ot vocabulary (objectui#12131)" This reverts commit dfda40f. The root README's dashboard example is re-shaped in the next commit onto registered node types only (`grid`, `statistic`), so the three `README.md` exemptions would fail as `stale-exemption`. Claude-Session: https://claude.ai/code/session_01DwLS3LzXyNmyTunMGbpc8W Co-authored-by: Claude <noreply@anthropic.com>
…face accepts (objectui#12131)
The 2026-09-01 ruling on objectui#7115 (maintainer-approved) set this
example's content to four `statistic` tiles whose `${stats.*}` values
evaluate, and rejected spelling the numbers out. Since then the
dashboard's `widgets[]` slot has closed: the strict authoring face
refuses a `statistic` entry there, and measured through the real
`SchemaRenderer` on main the example drew six "chart type is not
supported yet" panels, with no tile drawn and no expression evaluated.
The previous commit moved it onto `metric-card` entries with literal
values, which reverses that ruling (`metric-card` has no carriage row).
This keeps the four ruled tiles byte-for-byte (`label`, `${stats.*}`
`value`, `trend`, `description`) and changes only their container to a
`grid` with `columns: 4`: strict-valid, and measured, each tile draws
its evaluated value. Dropped: the undeclared root `title`, the flat
`w`/`h`, and the two charts, which carried no data and drew only the
"not supported" panel. A one-line lead-in points at the
plugin-dashboard README for the `dashboard` node and dataset charts.
Claude-Session: https://claude.ai/code/session_01DwLS3LzXyNmyTunMGbpc8W
Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
…objectui#12131) objectui#12130 is open on exactly this key (declare it, or rule it runtime-only), so the docs do not pre-empt it: the `// Default value` line and `defaultValue?: any;` are restored byte-for-byte as main has them, as the last member of `interface FormField`. The FormSchema `defaultValues` and `submitLabel` lines stay. Claude-Session: https://claude.ai/code/session_01DwLS3LzXyNmyTunMGbpc8W Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contributor
Author
|
Head
|
objectstack-fleet
Bot
deleted the
claude/issue-12131-refused-teaching-surfaces
branch
October 11, 2026 11:13
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.
Part of #12131
Clause-②: no
Phase 1 only. Phase 2, widening the scan surface of
scripts/check-doc-json-fences.mjsto the published READMEs, has not started: that script arrives with PR objectui#12127, which is still open and unmerged.git ls-treeon freshorigin/main(c9fc10b1) lists nothing for it (control legscripts/check-doc-links.mjs: 1 entry). This branch neither stacks on #12127 nor creates the script.What changed
Interface blocks (
content/docs/components/form). Each block now lists only keys the node schema declares. Every removal was measured through the realSchemaRendererplus the registry at the base commit10713937, by rendering with and without the key:button.mdxfullWidthclassNamecomment now names"w-full", the spelling the page's ownfull-width-buttonfixture usesbutton.mdxhrefaction:buttonnode, which the block'sonClickcomment already saysform.mdxsubmitButtonsubmitbuttonDOM attributesubmitLabel(submit text measured "Send it")form.mdxdefaultValuedefaultValues(input value measured "PRESET-VALUE")label.mdxrequiredrequiredattribute on the label element, no indicatorhrefand FormFielddefaultValuewere not in the card's list. They sit in the same blocks and are the same defect (undeclared and unread), so they are fixed here under the bounded in-place rule: same defect class, a mechanical removal, files already in this claim, and the same gates. All three edited blocks still compile on their own undertsc --strict(a control with a deliberate type error fails).Catalog fixture.
components-form-label/required-label.jsonis nowpassword-label.json, because it shows a label paired with a password input and draws no required indicator. The generated index was regenerated withpnpm --filter @object-ui/example-schema-catalog regenerate. The objectui#8761 pin and the label page follow the new id, and the page's "Required Field" heading becomes "With a Password Input" so the page stops making the same promise.git grep required-labelnow returns nothing.README examples. All three are repaired, so none is a declared fragment:
README.md, Contact Formtitle(at runtime only a native tooltip on the form element)titledropped. Measured: 4 fields (text, email, select, textarea), required markers, submit "Send Message"README.md, Dashboardstatistic/chartare not widget types inwidgets[];label,value,trend,w,h,chartTypeundeclared there; undeclared roottitlepackages/plugin-dashboard/README.md, object-bound tabletableis the static component:datarequired,objectNameundeclared, columnformatnot on the static surface"type": "object-data-table", the node the dashboard renders an object-bound table as, plus one lead-in sentence saying why a baretabledoes not fitThe Dashboard example: two rulings, one shape
The 2026-09-01 ruling on objectui#7115 (maintainer-approved, comment
5494799307) set this example's content to fourstatistictiles whose${stats.*}values evaluate, and it rejected spelling the numbers out. A pin inscripts/__tests__/check-doc-component-types.test.tsholds that ruling ("the flagship dashboard example teachesstatistic, and keeps its expressions"). Since then the dashboard'swidgets[]slot has closed, and the strict face refuses astatisticentry there. Measured on main: the example as written renders six "chart type is not supported yet" panels. No tile draws and no expression evaluates.This PR keeps the four ruled tiles byte-for-byte (
label, the${stats.*}value,trend,description) and changes only their container, fromdashboardtogridwithcolumns: 4. That shape passes strict, each tile draws its evaluated value (measured:EVAL-REVdrawn from aPredicateScopeProviderscope), and the #7115 pin stays unchanged and green. It drops three things: the undeclared roottitle, the flatw/h, and the two charts, which had no data and drew only the "not supported" panel. A one-line lead-in points readers to the plugin-dashboard README for thedashboardnode and dataset charts.7ba0fe0afirst rewrote the example as adashboardwithmetric-cardentries holding literal values, dataset-boundline/piewidgets andlayoutboxes, anddfda40fadeclared those three values inDOC_TYPE_EXEMPTIONS. That variant reverses the #7115 ruling:metric-cardhas no carriage row, which was measured (a${stats.revenue}value renders literally). It was therefore reverted (74a3bead) and replaced (e7d0ebce). The net diff touches no script. If the seat wants this example to use thedashboardnode, that reversal needs a ruling first.Premise re-derivation (the card's enumeration)
content/docs": falsified as stated. I applied feat(scripts): judge JSON doc fences through the strict authoring face (objectui#5250 slice B) #12127's gate predicate (json/jsonc fence, parses, plain object with a stringtype,typenames an arm, blockquoted fences read) to every tracked.md/.mdxoutsidecontent/docs. At base it found 19 refused documents. Three are the in-scope README fences and one is thedocs/auditsrecord, which was left untouched as triage ruled. The other 15 are 5 historical records (CHANGELOGs and a changeset), 9 fences in the publishedskills/tree (all but one are labelled counter-examples), and 1 deliberate counter-example inpackages/components/src/renderers/complex/README-KANBAN.md, which is not in that package'sfiles. After this PR the count is 16, and none of the 16 is in this claim's surface.className: "w-full",submitLabel, no indicator key onlabel): verified against the schema and through the renderer.fullWidth×1 inbutton.mdx,submitButton×1 inform.mdx,required×2 inlabel.mdx. Of the last two, one is in the interface block and one is the fixture id, and both changed.Verification, at
e7d0ebceEvery exit code was captured by redirecting output first and reading the code after, never through a pipe. Each verdict below is the gate's own printed line.
node scripts/check-doc-links.mjsnode scripts/check-doc-component-types.mjsnode scripts/check-prompt-component-keys.mjsnode scripts/check-doc-fence-languages.mjs --self-testand plain runnode scripts/check-doc-example-ids.mjsnode scripts/check-new-cross-file-line-citations.mjsnode scripts/check-control-bytes.mjsnode scripts/check-shell-escape-residue.mjsnode scripts/check-changeset-presence.mjspython3 scripts/regenerate-catalog-index.py --checkpnpm exec vitest run scripts/__tests__/pnpm exec vitest run packages/types/pnpm exec vitest run examples/schema-catalog/pnpm exec vitest run packages/plugin-dashboard/tsc --noEmit -p examples/schema-catalog/tsconfig.json --listFilespassword-label.jsonandindex.tsin the program.ts/.tsxfilesOn an earlier head,
scripts/__tests__/was red on exactly one test: the #7115 pin, against themetric-cardvariant. That red is what surfaced the ruling.Lint narrowing: eslint answers "File ignored because no matching configuration was supplied" for the changed
.md,.mdxand.jsonfiles, so its population is the two.ts/.tsxfiles. The--format jsonoutput counts 2 files. The resolved config sets neitherparserOptions.projectnorprojectService, so this diff cannot move eslint's verdict on any file it does not touch.NOT MEASURED locally, left to CI:
check:doc-snippetsas a whole. Its--build-filterclosure is nearly every package, too heavy for the foreground limit. The threetsinterface blocks it reads in this diff were compiled on their own (see above).tsconfig.test.json, which resolves about 15 unbuilt workspace packages. The only change it sees is one string in anas constid tuple.check-links. This diff adds one relative link, whichcheck-doc-linksresolves.check:readme-exports, which needs the full package build. This diff adds no import to any README.Acceptance notes
customdashboard widget. Thecomponentarm for any other registered node accepts only base keys under strict.{ "type": "dashboard", "widgets": [{ "id": "w", "type": "custom", "component": { "type": "text", "content": "hi" } }] }has strict=false and tolerant=true, while the TypeScript face typescomponentas anySchemaNode. This is reported to the seat, not fixed here.skills/objectui/rules/protocol.md. The fence labelled "✅ CORRECT" (adata-tablewithcolumnsand nodata) is refused by both faces.skills/**is a governed surface, so this is reported to the seat.README-KANBAN.md's refused-by-nameonCardMovedocument is a deliberate counter-example and would need the gate's fragment marker, if that file is in the surface at all. It is not shipped.check-changeset-presencesays none is owed (package READMEs are excluded from the published-source rule).Generated by Claude Code