Skip to content

feat(cli): objectui validate and objectui check judge through the strict authoring face (objectui#5250, slice A) - #11069

Merged
objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-5250-strict-validate-wiring
Oct 9, 2026
Merged

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-5250-strict-validate-wiring

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Part of #5250 — slice A only: objectui validate and objectui check parse through the strict authoring face. objectui#5250 stays open for slice B (the JSON-fence gate), which is priced from the numbers below.
Clause-②: no — narrows the accept set of objectui validate / objectui check to the already-exported StrictAnyComponentSchema; adds no key, export or flag

⏸ Parked as draft by the landing seat (domain:devx seat 2, session_01TdiauJaVCHuj45EzZGUxHh, 2026-09-29T09:00Z; reasons in objectui#5250 5887006513). The code is accepted and the contract review is PASS on a11f73347d (5886974796). The landing waits on the ruling's order, 「declarations repaired … before strict can be switched on」: M3's class (ii) (objectui#11070) and class (iii) (objectui#6152) keys are read or declared, so strict would refuse them wrongly.
Released when objectui#11070 and objectui#6152 are both closed. Then: merge main; re-run M1/M3 on the shipped face (class (ii)/(iii) = 0, or each remaining pair ruled runtime-only); make the un-park step 2 corrections; get a fresh contract-review record on the new head; ready. ⛔ Nobody flips this ready before then.

What changed

  • One door for both commands. packages/cli/src/utils/authoring-face.ts adds validateAuthoredDocument, which runs StrictAnyComponentSchema.safeParse (objectui#8345). validate.ts and check.ts both call it instead of safeValidateSchema, so the two commands cannot drift into two verdicts on one document. No flag chooses the face, in either direction.
  • A refused key is named: the key, its path, and a prescription. findUndeclaredKeys (in union-arm-diagnostics.ts, next to the existing arm selection) reads every unrecognized_keys out of the issue tree, including the ones nested inside union arms. A nested child's refusal is reported only as Invalid input at the child slot, because the slot is SchemaNode | SchemaNode[]. The reader reads only viable arms: an arm whose type mismatched, or that failed on shape alone, is skipped. When several arms are viable, a key counts only if every viable arm refuses it. validate prints a block after the numbered issues:
    Undeclared keys — the strict authoring face refuses them:
       Undeclared key "validation" at (root) (type "input"): no schema declares it there. Remove it, or check its spelling against the keys declared at that position.
    
    check prints the same line under each file it lists, after that file's first-issue line. check stays advisory: it still exits non-zero only on unreadable JSON.
  • Mixed-vocabulary guidance kept reachable. FormFieldSchema.field sits in the UnmirroredDeclared ledger, so strict refuses the 表单字段簇:spec↔runtime 是双层词汇——枢纽补缺、覆盖闸门、边界响亮化(objectstack#4115) #3090 mixed entry (name plus field). Before, validate accepted it with a warning. The same explanation now prints with the refusal.
  • Docs and changeset. The CLI README and utilities/cli.mdx describe the behaviour. Four guide and component pages said, in effect, that nothing refuses an undeclared key, or that objectui validate runs safeValidateSchema. This change made both statements false. The pages are guide/architecture.md, guide/layout.md, components/basic/text.mdx and guide/schema-rendering.md; they now keep the render path and the authoring verdict apart. .changeset/5250-strict-validate-wiring.md declares @object-ui/cli minor, not major, per AGENTS.md's version policy: the fixed group follows the @objectstack major, so a breaking change is marked minor and described in the body. Narrowing a published CLI's accept set is user-visible and breaking for documents that carry an undeclared key, and the body says so.
  • File surface beyond the claim, stated. The claim named validate.ts, check.ts, the utils, the tests and the changeset. The six doc files were added because this change made their statements false. Changed: 15 files, +639 −44. ⛔ Nothing under packages/types/**. ⛔ No scripts/check-doc-snippet-types.mjs or JSON-fence gate. ⛔ The rendering face's .passthrough() is untouched. No catalog or doc document was repaired; the reason is under M3.

M1 — the strict face re-measured on this base

Base f6ae5e22d (origin/main, 2026-09-29). zod 4.4.3. @object-ui/types built first. Instrument: scripts/measure-strict-authoring-face.mjs, whose own report says the corpus is identical to that main commit. No figure is inherited from the card's thread.

corpus items node documents fragments no type unresolved type nodes nodes strict-refused red today strict-only
catalog 432 426 0 0 6 1956 113 13 100
docs 214 160 8 30 16 244 53 26 27
authored 20 2 2 7 9 8 2 1 1

Headline from the script: 588 node documents; 2208 nodes; 168 nodes strict-refused (128 strict-only, 40 already red); 104 component types seen, 76 of them strict-clean. Whole documents: 163 of 588 refused by the script's strict twin, 31 of 588 refused by the face as shipped.

⚠️ The script's walker is behind the shipped face. It has no counterpart of the objectui#11022 registered-input admission (declareRegisteredInputs), so it refuses metric-card widget inputs that StrictAnyComponentSchema accepts. Example: examples/schema-catalog/src/schemas/plugin-dashboard/basic-dashboard.json is accepted by the shipped face. The script still charges its widgets with undeclared value / icon / trend / trendValue (15 to 18 occurrences each in its dashboard row). So M1 is also read through the shipped face, on the same corpora and the same commit, via a scratch copy of the script with one extra reading:

corpus node documents refused by the shipped strict face of which the tolerant face accepts (strict-only)
catalog 426 109 97
docs 160 47 22
authored 2 2 1
total 588 158 120

Script per-component rows with a strict refusal: component · nodes strict-refused · strict-only · red today.

component refused strict-only red today
form 83 79 4
dashboard ⚠ over-reported, see above 13 12 1
button 8 6 2
card 7 7 0
resizable 7 0 7
object-grid 5 1 4
page 5 4 1
carousel 5 0 5
object-form 4 3 1
select 3 0 3
grid, data-table, object-kanban, list-view 2 each 0 2 each
empty, combobox, input-otp, navigation-menu, pagination 2 each 2 each 0
list 2 1 1
label, input, object-view, app, page:tabs 1 each 1 each 0
icon, tabs, detail 1 each 0 1 each

M2 — where this repository itself runs validate / check, and what strict does there

The PM's clue ("no CI step runs bare pnpm check") is falsified. .github/workflows/lint.yml has the step "Verify the CLI's own check command passes on this repository", which runs pnpm check, the root script node packages/cli/dist/cli.js check, after "Build the CLI the self-check runs".

site corpus tolerant face strict face CI effect
lint.yml → pnpm check over the repository every JSON/YAML under the root minus node_modules/dist/.git (633 analysed) 265 validated · 167 recognised-not-validated · 1 did not validate · 46 skipped 172 · 167 · 94 · 46 (measured with the built CLI at the PR head) exit stays 0. 93 files move from validated to "did not validate" and are listed by name with their keys; all 93 are under examples/schema-catalog. 0 files move into "skipped".
same run, structural-arm files (never parsed by check) 167 — 5 of them are strict-refused, which objectui validate would now report none: check does not parse these
the CLI's own tests that run validate/check over fixtures (7 files, plus cli-bin spawning the built binary) 60 documents judged measured by a temporary logging probe, never committed; restore proven by blob hash equal to HEAD; the probe-tainted dist was deleted and rebuilt 0 of 60 change verdict; issue lists identical 60/60 none
registered-types-validate-ratchet-10859 (plugin-ai README document through validate) 1 valid valid none
the CLI's own producers: objectui init (templates simple/form/dashboard) and objectui generate page 4 valid valid none

M3 — every strict refusal, classified

The pairs come from the shipped face over the M1 corpora and M2's extra refusal. Keys are read with the same findUndeclaredKeys this PR ships; its output equals the scratch prototype's over all 158 refused documents. Each of the 120 strict-only refusals names at least one key. The 22 refused documents that name no key are all refused by the tolerant face too, for a value reason.

  • Class (i) — undeclared, and no read site found in the registered renderer. The instrument was a TypeScript-AST scan of property reads, element reads and destructures. ⚠️ Per AGENTS.md this is a candidate grade: SchemaRenderer's prop spread can deliver a key no source names, so none of these is runtime-proven.
  • Class (ii) — a renderer reads the key and no schema declares it (declaration debt, spec lane).
  • Class (iii) — the TypeScript type declares it as a named member and the zod mirror omits it. Measured with the compiler API; an index signature does not count as declaring.
  • Class (iv) — none.
class (component, key-path) pairs document occurrences of them strict-only
(i) 49 70 50
(ii) 32 149 141
(iii) 10 15 13

Class (iii), the UnmirroredDeclared family (objectui#6152):
object-form · formType (3 documents), sections (3), defaultTab (1), showStepIndicator (1); object-grid · operations (1), resizableColumns (1), singleClickEdit (1); pagination · currentPage (2); object-view · form.formType (1), form.drawerSide (1). The validate behaviour change for the mixed-vocabulary FormFieldSchema.field is the same class; no corpus document carries it. The ledger in zod-mirror-parity.test.ts (the UnmirroredDeclared interface) reads 12 entries and 84 keys on this base, counted from the interface itself rather than from its docblock.

Class (ii), by component, with the read site:

  • form · showSubmit in 76 documents. form.tsx destructures showSubmit from schema. This is the single largest group, and all 76 are catalog fields-* fixtures.
  • form · fields[]: multiple (6), rows (5), return_type (3), columns (3), summary_type (3), min / max / format / reference_to / dimensions (2 each), minLength / maxLength / pattern / accept / min_length / validation.message (1 each). Each has a named read in @object-ui/fields widgets or in form.tsx.
  • dashboard · widgets[].options: data (7), xField (6), yField (6), value (5), read explicitly in DashboardGridLayout / DashboardRenderer. Also description and trend (1 each), which reach the child through { ...widget, ...options }. And widgets[].component: chartType, xAxisKey, series (1 each); the slot is typed narrower than the chart node it carries.
  • dataSource on object-grid (2), list-view (2), object-form (1) and object-kanban (1). It reaches the component as a React prop through SchemaRenderer's spread; object-grid also maps the spec binding.
  • page · regions[].children (1) and page:tabs · items (1).

Class (i), by document. The documents are named per the dispatch. Docs fences are cited by file and key, never by line.

  • content/docs/api/schema-reference.md — selection.enabled, selection.mode, pagination.enabled, striped (object-grid)
  • content/docs/blocks/authentication.mdx, forms.mdx, marketing.mdx — action (button)
  • content/docs/blocks/dashboard.mdx, ecommerce.mdx — dataSource (card), action (button)
  • content/docs/guide/dashboard-filters.md — field, optionsFrom (select)
  • content/docs/guide/expressions.md — itemTemplate (list), message (empty), validations (input)
  • content/docs/guide/layout.md — maxWidth, padding (page), tabs (tabs), object (object-grid)
  • content/docs/guide/schema-playground.md — icon (card), title and fields[].defaultValue (form), title / rows / actions / pagination (grid)
  • content/docs/guide/schema-rendering.md — message (empty)
  • content/docs/utilities/runner.mdx — value, change (card)
  • content/docs/utilities/vscode-extension.mdx — dataSource, columns[].key, columns[].title (data-table), pages (app)
  • examples/schema-catalog/src/schemas/:
    • components-basic-navigation-menu/documentation-nav.json and site-navigation.json — items[].items
    • components-basic-pagination/with-item-count.json — pageSize, totalItems
    • components-data-display-list/basic-list.json — items[].type
    • components-form-button/full-width-button.json — fullWidth
    • components-form-combobox/country-selector.json — searchPlaceholder
    • components-form-combobox/searchable-combobox.json — searchPlaceholder, emptyText
    • components-form-form/contact-form.json — submitButton, fields[].columnSpan
    • components-form-form/login-form.json and registration-form.json — submitButton
    • components-form-input-otp/verification-form.json and with-visual-separator.json — separator
    • components-form-label/required-label.json — required
    • fields-currency/euro-currency.json and usd-currency.json — fields[].currency
    • fields-formula/date-calculation.json, numeric-formula.json and text-concatenation.json — fields[].formula
    • fields-number/decimal-numbers.json, fields-percent/required-percent.json and with-decimal-precision.json — fields[].precision; the widgets read scale
    • fields-object/structured-configuration.json — fields[].schema
    • fields-summary/ average-of-field-values, count-of-related-records and sum-of-field-values — fields[].summary_object, fields[].summary_field
  • packages/types/examples/dashboard.ts (dashboardSchema) — content (card)
  • packages/types/examples/login-form.ts (loginFormSchema) — fields[].defaultChecked
  • M2 only: examples/hello-world/schema.json — content on a button (button.tsx reads label; the likely intended key is label, which is a rename, not a deletion)

No class (i) document was repaired in this PR. The dispatch authorises the repair but does not require it. Three reasons:

  1. None of these refusals turns a CI-run check red. pnpm check stays exit 0, no CLI test fixture changes verdict, and no other test runs the strict door over the catalog.
  2. The class (i) grade is a source-read candidate. Deleting on that grade risks deleting a key read through the prop-spread channel.
  3. The catalog fixtures feed rendering pins under examples/schema-catalog/test.

The list is the input for slice B and the repair owners. Classes (ii)/(iii) are not touched; packages/types/** is out of scope for this card. No class (ii)/(iii) site is red in CI.

M4 — root and nested probes

Predicted in writing before the run (2026-09-29T08:14Z):

probe predicted measured
(a) root: the card's input with validation strict refuses, unrecognized_keys at (root), keys validation; tolerant accepts as predicted
(b) nested: div → children[0] input with nonsense strict refuses; top-level invalid_union at children; unrecognized_keys at children → 0 inside an arm; tolerant accepts as predicted. It sits one union deeper than the top: slot union, then the array arm, then the component arm. Depth 2 (children → 0 → children → 0) nests again.
(c) controls: same documents, declared keys only both faces accept as predicted

⇒ StrictAnyComponentSchema judges nested children too, per depth. That is why the wiring needs findUndeclaredKeys: the top-level issue at a child slot names no key.

Tests, reverse verification, gates

New: packages/cli/src/__tests__/validate-strict-authoring-face-5250.test.ts, 12 tests.

Each refusal pin also asserts that the tolerant face accepts the same document.

Pin sweep, repository-wide: no existing test asserted that validate or check accepts an undeclared key. Three CLI pins that stood in for "the parse check/validate runs" now read validateAuthoredDocument: check-first-issue-11007, check-validity-recogniser and the ratchet registered-types-validate-ratchet-10859. The ratchet's counts are unchanged at 73 / 397.

Ablations. Predictions were written before running; each mutation went through objectstack's scripts/ablation-replace.mjs in wrap mode, which checks the anchor hit and the blob change, and proves the restore by blob equal to HEAD with an empty git diff HEAD. The fix and the pins were committed first.

ablation predicted measured
A1 the door reverted to the tolerant AnyComponentSchema 9 red / 3 green 9 red / 3 green
A2 intersection replaced by the union of viable arms 1 red (the metric-card case) 1 red / 11 green
A3 viability filter removed 4 red 4 red / 8 green (the predicted four)
A4 validate.ts alone reverted 6 red. The first draft of this prediction was self-inconsistent and was corrected to 6 before any run 6 red / 6 green

Gates, at HEAD a11f733. The exit code is captured before any pipe, and each tool's own verdict line is quoted.

gate exit verdict
pnpm --filter @object-ui/types build (before M1) 0 dist completeness: 1 package(s) complete
pnpm --filter @object-ui/cli build 0 tsup
pnpm --filter @object-ui/cli test 0 Test Files 23 passed (23) · Tests 314 passed (314) (base: 22 / 302)
pnpm --filter @object-ui/cli type-check 0 tsc --noEmit clean
pnpm --filter @object-ui/cli lint 0 0 errors; 5 warnings, all in untouched files
tests reading the six edited docs (27 files, enumerated by grep) 0 Test Files 27 passed (27) · Tests 1271 passed (1271)
pnpm check (the lint.yml self-check) 0 172 validated, 167 recognised but not validated, 94 did not validate
node scripts/check-changeset-presence.mjs 0 declares .changeset/5250-strict-validate-wiring.md
pnpm changeset:check 0 No changeset declares a major bump
pnpm check:changeset-claims · pnpm check:pending-changeset-literals 0 · 0 report-only, nothing to re-read
pnpm check:control-bytes (objectui's NUL/control-byte gate) 0 OK (scanned 9372 tracked text file(s))
pnpm docs:check-links · pnpm check:doc-fences · pnpm check:doc-types 0 · 0 · 0 links valid across 17 roots · ok · every documented type registered
pnpm check:new-line-citations 0 0 new citation(s)
pnpm check:test-path-roots 0 OK
node scripts/check-governed-queue-guard.mjs --test over the 15 paths 0 NOT GOVERNED

NOT MEASURED locally:

  • pnpm check:doc-snippets exited 2 with PRECONDITION NOT MET, and pnpm check:readme-exports exited 1 with population COLLAPSED. Both need 34 unbuilt packages built, and neither exit is a verdict. The only fence this diff adds is a text block, and the diff adds no import/export line, so neither gate has anything of this PR to judge. Both are declared to CI.
  • The repository-wide lint is CI's.

Acceptance notes

  • scripts/measure-strict-authoring-face.mjs reads redder than the face it measures. Its walker has no counterpart of objectui#11022's registered inputs; see M1 for the measured difference. Its header only warns about the opposite direction (a mirror that falls behind reads cleaner). This matters for slice B's pricing, which reads that script. It is reported to the seat, not filed from here.

  • Some prose in packages/types tests now names the wrong door. Several tests call safeValidateSchema "the door objectui validate / objectui check run", or "the tolerant one objectui validate runs":

    • object-chart-axis-config-10518, twice
    • object-chart-react-tier-node-10770
    • timeline-readme-schema-example-10824
    • form-field-widget-namespace
    • element-number-arm-10872's FACES docblock

    Their assertions stay true. packages/types/** is ⛔ for this card; owner: none.

  • examples/schema-catalog/test/safe-validate-corpus-6318.test.ts pins "stays out of objectui check's bucket" through the tolerant safeValidateSchema. Its seven fixtures are strict-clean, so the pin holds. Its instrument is no longer check's door, though: a fixture that gained an undeclared key would rejoin the bucket with that pin green. Owner: none.

  • AGENTS.md §5 Add default props to all components to prevent collapse in designer #4 and skills/objectui/SKILL.md still say an authored events bag is "kept, judged by nothing". objectui validate now refuses it by name. Both files are governed surface and are not touched here; the natural owner is objectui#8347, which the programme gives the AGENTS.md #0.1 amendment.

  • Nested child-slot refusals list every arm under the numbered issue, including the primitive arms that failed on shape. This is explainUnionIssue's existing capped fallback for undiscriminated unions, and it is not changed here. The "Undeclared keys" block is the readable summary. Pruning shape-mismatch arms from that fallback would be a separate change to ruled arm-selection behaviour.


Generated by Claude Code

… strict authoring face (objectui#5250)

Both commands called `safeValidateSchema` — the tolerant `AnyComponentSchema`,
whose `BaseSchemaCore.passthrough()` kept any undeclared key unjudged. They now
share one door, `validateAuthoredDocument` in `utils/authoring-face.ts`, which
parses through `StrictAnyComponentSchema` (objectui#8345), per the objectui#5250
ruling (option 2): the authoring verdict is strict, the rendering face keeps its
passthrough.

A refused undeclared key is named with its path and a prescription by
`findUndeclaredKeys` (union-arm-diagnostics), which reads keys out of viable
union arms, so a nested child's refusal is named even though the issue list
carries it only inside an `Invalid input` at the child slot.

Part of objectui#5250 (slice A).

Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh
Co-authored-by: Claude <noreply@anthropic.com>
…jectui check` (objectui#5250)

The card's probe (`validation` on an `input`) is refused at the root with its
key, path and prescription; a nested child's undeclared key is named at the
child's path; a key one viable widget arm declares is not named; declared-only
documents stay green. `check` lists a leaf with an undeclared key by name and
names the key under it.

The three CLI pins that stood in for "the parse `check` / `validate` run" now
read `validateAuthoredDocument`, the door both commands call.

Part of objectui#5250 (slice A).

Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh
Co-authored-by: Claude <noreply@anthropic.com>
…or the strict wiring (objectui#5250)

The CLI README and utilities/cli.mdx say what the strict authoring face does
for `validate` and `check`. Four guide/component pages said nothing refuses an
undeclared key, or that `objectui validate` runs `safeValidateSchema`; both
went false with the wiring, so they now name the render path and the
authoring verdict apart.

Changeset: `@object-ui/cli` minor, breaking semantics stated in the body (the
fixed group never declares major).

Part of objectui#5250 (slice A).

Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests package: cli labels Sep 29, 2026
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/11170-node-slot-keys.md

  • names content/docs/utilities/cli.mdx → content/docs/utilities/cli.mdx — edited by this change

    Docs: content/docs/utilities/cli.mdx's "Component nodes only" rule, the gate's own docblock, validateChildren's comment and the parser's header now say the walk follows children and the declared slots; the declaration's header is where the slot list is explained.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with 3c3115e38 (merge-base with origin/main): 18 file(s) changed outside .changeset/, read against 261 pending declaration(s) that publish a body (266 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3106.9 KB 3149.4 KB
Main entry chunk (gzip) 149.3 KB 350 KB
Entry file index-DPkWDRpn.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.33KB 15.01KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.68KB 36.71KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.54KB 61.80KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 168.05KB 43.03KB
plugin-gantt (index.js) 171.12KB 42.43KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.77KB 22.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 19.75KB 6.81KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: a11f73347ddd9f6e95cede76f3ec321516c0a54d
Local-runs: none

Inputs read: card objectui#5250 (body and all 15 comments, the ruling 5534418546 and the director pointer 5572369400 included), PR #11069 (body, 15-file list, net diff against main at 827550193), and the check-runs on this head. Blobs at the head were read with git show only; nothing was built, run or re-run.

① Derived judgments

  1. objectui validate accept set narrows — RIGHT. validate.ts parses through validateAuthoredDocument, which is StrictAnyComponentSchema.safeParse; a document carrying a key no schema declares, at the root or at any child-slot depth, exits 1. This is the devx half the ruling on the card names (「objectui validate and the doc-snippet gates run strict」), and the rendering face is untouched: no path under packages/types/** is in the file list, and BaseSchemaCore still ends .passthrough() at this head.
  2. objectui check's validity arm narrows the same way — RIGHT. recogniseObjectUiSchemaFile calls the same door, so a file with an undeclared key leaves the validated count and is listed by name with the key under it; the exit code is unchanged (read at head: errors increments only on a JSON parse failure). One door by construction is the correct answer to the finding(cli): objectui check never prints the key it refuses, and a nested typo or a root carrying a structural key never reaches its validation step, so a strict map refusal exits 0 as "All checks passed" #11007 ruling that check walks nothing itself, and the lint.yml self-check (Verify the CLI's own check command passes on this repository, run: pnpm check) stays exit 0 — the Lint check-run on this head is green.
  3. No flag in either direction — RIGHT. The ruling names strict as the authoring verdict, not a mode of it; a --strict or --tolerant switch would have been a public-surface widening.
  4. No public surface added — RIGHT. @object-ui/cli's only exports entry is ./dist/index.js, and src/index.ts re-exports serve and init alone; validateAuthoredDocument, describeUndeclaredKey, findUndeclaredKeys, UndeclaredKey and authoredTypeAt sit under src/utils/ and are unreachable from the entry. StrictAnyComponentSchema was already exported from @object-ui/types/zod (index.zod.ts).
  5. Output surface — RIGHT. validate prints an "Undeclared keys" block after the numbered issues; check prints one line per key under each listed file; both go through one function (describeUndeclaredKey) and one reader (findUndeclaredKeys). I read the reader: it walks invalid_union arms rebased onto the union's node (the module's header fact 3), skips an arm whose type mismatched (invalid_value or a discriminated invalid_union at ['type']) or that failed on shape alone, and when several arms are viable names a key only if every viable arm refuses it — the metric-card registered-input case that makes the intersection load-bearing is pinned with its precondition (everyRefusedKeyInTheTree contains widgets.0|value). It reads the issue tree only, never the schema, which keeps the module's existing no-introspection contract.
  6. 表单字段簇:spec↔runtime 是双层词汇——枢纽补缺、覆盖闸门、边界响亮化(objectstack#4115) #3090 mixed-vocabulary note — RIGHT. Strict refuses field on a name-plus-field entry (the UnmirroredDeclared ledger), so the success-branch warning became unreachable for that shape; the same explanation now prints on the failure branch and is pinned (MIXED_FORM).
  7. Six doc files — statements checked against blobs at the head: StrictAnyComponentSchema is exported from @object-ui/types/zod (schema-rendering.md); ButtonSchema declares label and no text (form.zod.ts), so architecture.md and layout.md's "refuses it by name" holds; text.mdx's color was never declared on the text node; cli.mdx's sample line matches formatIssuePath's → spelling and (root). One precision note, not a defect: "at any depth" / "on every nested node" is the ruling's wording and is bounded by the face's own documented limits (opaque custom / function / transform shapes, reported through onOpaqueShape; the spec(types): derive and export the strict authoring twin of the node face — the #5250 strict face itself, no consumer wired #8345 pin measures the published face reporting more than zero of them). The face's header carries that limit; the CLI docs do not restate it, and nothing here claims the bound is wider than the face.
  8. Pending changesets the claim re-read bot names (6320, 6872, 7658, 7926, 8284, 8871, 9308) — re-read against the diff: none of their claims goes false (the glob ignore list in check.ts is untouched; the new #### Undeclared keys heading carries no code span; the actions / breadcrumbs sites in layout.md and the body-channel passages in schema-rendering.md are untouched). Correcting none of them is right.
  9. Test pins — RIGHT. Three CLI pins re-pointed to the door (check-first-issue-11007, check-validity-recogniser, registered-types-validate-ratchet-10859); the new file holds 12 pins, and every refusal pin carries the tolerant-face control, so a red there can only mean the door moved.
  10. Commit trailers — the three commits carry the model-free pair (Claude-Session: plus Co-authored-by: Claude), which is the objectui rule; the PR footer is the session-URL form. RIGHT.

② Semver level

  • .changeset/5250-strict-validate-wiring.md declares @object-ui/cli: minor and states the breaking narrowing in its body with the exact refusal line and "there is no flag to opt out". RIGHT: @object-ui/cli is in the fixed group of .changeset/config.json, and the version policy marks objectui's own breaking changes minor with the breaking semantics in the body (Changeset Bump Policy is green on this head). The only published source in the diff is packages/cli/src/**; content/docs/** publishes from no released package and the README is excluded by the presence rule — one changeset is the right count, and skip-changeset would have been wrong.
  • Migration: nothing an author can write is renamed or removed from a schema, so there is no FROM → TO map to state; the prescription is the refusal line itself (remove the key, or correct its spelling), and it is in the body.
  • Clause-②: no — RIGHT by the criterion (does the change widen the accept set or expand the public surface): the accept set narrows and no key, export or flag is added; the CLI's exports map is unchanged. The line carries no (narrowing) arm; every objectui changeset gate on this head is green (Declaration, Bump Policy, Fixed Group Check, Claim Re-read, Overwrite Report), and the ADR-0087 registration gate is objectstack's packages/spec rule, not this repository's. The narrowing ships to consumers in words through the CHANGELOG body, which is the surface that matters.

③ Boundary flags

Deviations (7, from the os-dev-report):

  1. Six doc files beyond the claimed surface — ACCEPTED. The claim's own rule (a document joins to correct a statement the change falsifies) and AGENTS.md Add automated testing infrastructure and CI/CD workflows #2; each is named in the PR body; none is a governed path (Governed Surface Queue Guard green).
  2. No class (i) document repaired — ACCEPTED. The claim authorised repair only "to delete a key nothing reads"; the class (i) grade is an AST candidate and the prop-spread channel is not ruled out, so a deletion would rest on a source-read grade. Leaving the list on the PR body as slice B's input is the right call. See the open question.
  3. Temporary logging probe for M2, restore proven by blob hash, tainted dist rebuilt — ACCEPTED as reported; nothing was re-run here.
  4. Scratch copy of the measurement script for M1 — ACCEPTED; the divergence it exposed is finding 1 below.
  5. The PM clue "no CI step runs bare pnpm check" is falsified — CONFIRMED at head (lint.yml, step Verify the CLI's own check command passes on this repository).
  6. 表单字段簇:spec↔runtime 是双层词汇——枢纽补缺、覆盖闸门、边界响亮化(objectstack#4115) #3090 note moved to the failure branch — ACCEPTED, pinned (judgment 6).
  7. Attribution deviation from the harness reminder — ACCEPTED; the objectui rule is the model-free pair and the commits carry it (judgment 10).

open_questions (1) — who repairs the 40 class (i) documents, and when. ESCALATED to the dispatching seat on the card; this record does not settle ownership. The reviewer's reading: option A is the one the ruling's sequencing already implies (the fence gate is built on top of the face and surfaces the docs half; the catalog half belongs to the declaration owners, with runtime proof before any deletion). Two documents deserve to be named in the slice B pricing rather than left in the advisory list: examples/hello-world/schema.json (content on a button, where button.tsx reads label — a rename, so outside the authorised repair) is a shipped teaching artifact that the shipped objectui validate now refuses; and the fields-* catalog fixtures feed rendering pins, so their keys are a declaration question (class (ii)-adjacent) before they are a deletion. Option C would leave a shipped example failing the shipped validator.

out_of_scope_findings (5):

  1. scripts/measure-strict-authoring-face.mjs over-reports against the shipped face (no declareRegisteredInputs counterpart) — ESCALATED: slice B is to be priced from that script, so the pricing must read the shipped face's numbers (M1's second table) and the script needs a card (dedupe against finding(scripts): the strict-face measurement script's in-memory twin walks only the in side of a pipe, while the SHIPPED walker walks both #10076).
  2. packages/types tests whose prose names safeValidateSchema as the door validate / check run — carrier none; prose only, assertions hold. ESCALATED for the next authorised packages/types touch.
  3. AGENTS.md §5 Add default props to all components to prevent collapse in designer #4 and skills/objectui/SKILL.md "judged by nothing" — governed Tier H; carrier spec(types)!: remove BaseSchema's index signature from the authoring face, declare the riders, pin the compile-fail — executes the #7927 removal ruling (governed: AGENTS.md #0.1) #8347 is the right routing.
  4. examples/schema-catalog/test/safe-validate-corpus-6318.test.ts pins "stays out of check's bucket" through the tolerant face — carrier none. ESCALATED: the pin is instrument-drifted (a fixture that gains an undeclared key rejoins the bucket with the pin green); a follow-up should re-point it to validateAuthoredDocument or to the built check.
  5. Nested child-slot refusals list every arm under the numbered issue (the existing capped fallback) — ACCEPTED; ruled arm-selection behaviour is untouched.

Not flagged by the dev, found here:

  • packages/types/src/strict-authoring-face.ts's header still reads "Nothing in this repository consumes it yet … the only consumer of these exports today is the pin file" — false at this head, since packages/cli/src/utils/authoring-face.ts consumes it. packages/types/** was ⛔ for this claim, so the edit was not the dev's to make, but the statement belongs with the stale-prose list in the acceptance notes. Carrier none — ESCALATED; the next authorised packages/types touch corrects it.

Check-runs on this head (read 2026-09-29T08:56Z, 43 runs): 40 completed/success, 3 completed/skipped (Test (coverage), the coverage-shard matrix placeholder, and dependabot — skipped by design, not failures), 0 in progress, 0 failed. The runs still in progress when this review began — Type Check, Spec Main Shape Gate and Test (shard 1/8) through Test (shard 8/8) — completed green before this record was written; nothing is NOT MEASURED. The two gates the dev declared to CI as unmeasured locally, Doc Snippet Type Check and README Export Check, are both green on this head, as are Lint, Governed Surface Queue Guard, Line Citation Gate, Control Byte Scan and every changeset gate.

Implemented-by: claude/issue-5250-strict-validate-wiring
Reviewed-by: session_01TdiauJaVCHuj45EzZGUxHh

VERDICT: PASS


Generated by Claude Code

This was referenced Sep 29, 2026
This was referenced Oct 7, 2026
@objectstack-fleet objectstack-fleet Bot assigned os-bill and unassigned huangyiirene Oct 9, 2026
claude added 3 commits October 9, 2026 10:25
…bjectui#5250)

Un-park step 1 of objectui#5250. Two textual conflicts, resolved as the
measurement round priced them:

- packages/cli/src/commands/check.ts imports: both sides kept (the strict
  door's findUndeclaredKeys and objectui#4795's unbindable-text-expression
  readers).
- check-validity-recogniser.test.ts precondition: validateAuthoredDocument,
  the strict door, over main's plugin-dashboard:metric-card fixture.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
… on files the strict face refuses (objectui#5250)

Un-park step 1 of objectui#5250, after merging main:

- check: the objectui#4795 judgement of a `${…}` on a closed text key now
  runs on the registered-type files the strict authoring face refuses, as
  well as on recognised files. On the merged tree a document carrying one
  undeclared key was listed and then skipped, so its expression refusal and
  the exit code it sets disappeared. Both findings are now reported.
- New pin: a file with an undeclared key and a refused expression is listed
  with its key named, refused for the expression, and fails the run.
- The objectui#4795 fixture's test name no longer says the validity arm
  admits it (the strict face refuses its `title`).
- registered-types-validate-ratchet-10859: main's report-wrapper case now
  reads validateAuthoredDocument, the door the PR removed safeValidateSchema
  from.
- validate-strict-authoring-face-5250: the nested probe's issue shape is
  re-pinned: the strict face reports `unrecognized_keys` at `children → 0`,
  and findUndeclaredKeys names it there.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
…tui#5250)

- A nested child's undeclared key is no longer reported only as an
  `Invalid input` at the child slot: a slot only one union arm fits reports
  `unrecognized_keys` at the child. The `Invalid input` that names no key is
  now the shape of a union the node fits more than one arm of, such as a
  dashboard widget. Corrected in the changeset, the findUndeclaredKeys and
  describeUndeclaredKey docblocks, the validate and check comments, and the
  CLI page.
- `objectui check` does not exit non-zero only on unreadable JSON: since
  objectui#4795 a refused expression fails the run, now in a listed file
  too. Corrected in the changeset, the CLI page and the schema-rendering
  guide.
- The changeset states that it supersedes any entry in the release that
  calls `safeValidateSchema` what `objectui validate` runs.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 289 chunks) 3163.6 KB 3204.6 KB
Main entry chunk (gzip) 72.5 KB 350 KB
Entry file index-b9f_J3fn.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 19.52KB 7.19KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 587.83KB 141.44KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 268.74KB 68.04KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.50KB 11.82KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.43KB 15.54KB
plugin-charts (index.js) 84.71KB 23.25KB
plugin-chatbot (index.js) 201.52KB 47.99KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.53KB 49.80KB
plugin-detail (index.js) 248.57KB 65.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.11KB 45.88KB
plugin-gantt (index.js) 179.17KB 45.07KB
plugin-grid (index.js) 249.62KB 69.16KB
plugin-kanban (index.js) 52.77KB 16.56KB
plugin-list (index.js) 120.25KB 30.26KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.10KB 11.81KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.27KB 23.06KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Un-park build round: the body sections this round supersedes

Seat domain:ui#2 · os-bill · session_01MgfduSkFrfM3eorB3UGfAU (take-over claim 6077901503 on objectui#5250). The relay cannot edit a PR body, so this comment lists each body section that no longer holds and what replaces it. The PR stays draft; nobody flips it ready in this round.

Head 101179c62. It is a11f733 plus a merge of main 3c3115e38 and two commits.

1. The park note (the ⏸ blockquote at the top)

  • Superseded. Its release condition is met: objectui#11070 closed on 2026-10-08, and triage 6078650441 dropped Blocked-by: #6152 (the card is pm:dispatched).
  • Un-park step 1 is done:
    • main is merged in (merge commit 091493bfd);
    • the objectui#4795 interaction is resolved (below);
    • the measurement is re-run on the merged head: class (ii) 0, class (iii) 0.
  • Step 2 is prepared but NOT pushed. Its file count is 65, over the 60-file threshold the dispatch set, so the seat splits it first.
  • Step 3 is open as PR objectui#12050 (governed, draft).
  • Step 4 is still owed: a fresh contract-review record on the new head.

2. "What changed": three statements replaced

  • 「A nested child's refusal is reported only as Invalid input at the child slot」 is stale.
    • On main (zod 4.6.5), a child slot that only one union arm fits reports unrecognized_keys at the child, naming the key: children → 0 for the nested probe.
    • An Invalid input that names no key is now the shape of a union the node fits more than one arm of, such as a dashboard widget.
    • findUndeclaredKeys names both shapes. Its docblock, the describeUndeclaredKey docblock, the validate and check comments, the changeset and the CLI page now say this.
  • 「check stays advisory: it still exits non-zero only on unreadable JSON」 is false since objectui#4795: a ${…} refused on a text key its node never evaluates fails the run.
    • New in this round: check runs that judgement on the registered-type files the strict face refuses too.
    • Before this, the merged tree listed such a file and then skipped its expression refusal and the exit code it sets.
    • Being listed for an undeclared key still does not move the exit code.
  • 「Changed: 15 files, +639 −44」 is replaced: against main 3c3115e38 the PR now changes 16 files, +737 −64.
    • The new file is the objectui#4795 test, whose test name said the validity arm admits its fixture. The strict face refuses that fixture's title, so the name now says so.
    • Still nothing under packages/types/**.

3. The M1 tables are replaced

Re-measured on the merged head 101179c62 with the measurement round's instrument (6078291802): the shipped StrictAnyComponentSchema and AnyComponentSchema from the built packages/types/dist, keys read by this PR's own findUndeclaredKeys.

corpus node documents refused by the strict face strict-only red on both faces refused naming no key
catalog 432 23 11 12 12
docs 185 26 13 13 8
authored 6 2 1 1 0
M2 JSON 1 1 1 0 0
total 624 52 26 26 20

The pair list equals the reading on main 47b1f0bb7 in 6078291802. The only difference is one docs fence, which moved down three lines in guide/schema-rendering.md because this PR edits that page.

4. The M2 self-check row is replaced

The built CLI at this head runs check over the repository (the lint.yml self-check):

  • Analyzing 635 files
  • 278 validated, 146 recognised but not validated, 9 did not validate, 47 skipped
  • 0 expression refusals, exit 0

The park-time row read 172 · 167 · 94 · 46.

5. The M3 table is replaced

class pairs document occurrences strict-only occurrences
(i) undeclared, no read site found 32 42 29
(ii) read by a renderer, declared by no schema 0 0 0
(iii) named by the TS type, omitted by the zod mirror 0 0 0
  • Class (iii): the named-member tsc probe re-run on this head gives exactly the 38 TS2322 of the main reading: the 32 pairs, none of them named, plus 5 negative controls and 1 informational probe.
  • Class (ii): carried, not re-derived. The renderer files for the 13 types, and packages/react/src, are byte-identical to the graded base (git diff --quiet exit 0).

6. M4 probe (b) is superseded

The nested probe no longer reports invalid_union at children. It reports one unrecognized_keys at children → 0, keys nonsense, and the pin is re-pinned to that shape. The union-nested shape is still pinned by the two dashboard-widget cases.

7. "Tests, reverse verification, gates" is replaced at head 101179c62

  • New pin (13 now): a file carrying an undeclared key and a refused ${…} is listed with its key named, refused for the expression, and fails the run.
  • Reverse leg for that pin, run through objectstack's ablation-replace with the call in the refused branch deleted:
    • predicted in writing before the run: 2 red;
    • measured: 2 red, 45 green (Tests 2 failed | 45 passed (47));
    • restore proven: blob equal to HEAD, git diff HEAD empty.
    • A first attempt with a replacement already present in the file was refused by the tool as a no-op and restored before anything ran.
  • Tests:
    • CLI suite: Test Files 26 passed (26) · Tests 383 passed (383).
    • The objectui#6318 corpus pin, both repository-wide ratchets and the two touched CLI files: Tests 73 passed (73).
  • Type-check: @object-ui/cli and @object-ui/types exit 0, closure built first.
  • Gates, all exit 0:
    • changeset presence, no-major, fixed, claims (report-only), overwrite;
    • check:new-line-citations (0 new citation(s)), check:control-bytes, docs:check-links, check:spec-symbols;
    • eslint on the 9 touched CLI sources: 0 errors, 0 warnings.

8. "Acceptance notes" bullets superseded

  • Door prose in packages/types tests, and the objectui#6318 pin: prepared as un-park step 2. Not pushed: 65 files, see 1.
  • AGENTS.md section 5 Add default props to all components to prevent collapse in designer #4 and the skills sentence: PR objectui#12050 changes it, in AGENTS.md and in skills/objectui/rules/protocol.md. skills/objectui/SKILL.md says only 「kept and run by nothing」, which stays true.
  • scripts/measure-strict-authoring-face.mjs reading redder than the face: the direction has flipped. On main it reads 2 whole documents cleaner than the shipped face (49 vs 51 of 623, 6078291802).

Generated by Claude Code

…e objectui#6318 pin at check's door (objectui#5250)

Un-park step 2 of objectui#5250, the statements slice A makes false:

- strict-authoring-face.ts and zod/index.zod.ts said nothing in this
  repository consumes the strict face. `objectui validate` and
  `objectui check` consume it now.
- safe-validate-corpus-6318: the pin is about `objectui check`'s bucket, so
  it reads the door `check` reads, validateAuthoredDocument. Its seven
  fixtures are strict-clean, so it stays green. Its counter-probes about
  the union's declarations stay on safeValidateSchema.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 289 chunks) 3163.6 KB 3204.6 KB
Main entry chunk (gzip) 72.5 KB 350 KB
Entry file index-b9f_J3fn.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 19.52KB 7.19KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 587.83KB 141.44KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 268.74KB 68.04KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.50KB 11.82KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.43KB 15.54KB
plugin-charts (index.js) 84.71KB 23.25KB
plugin-chatbot (index.js) 201.52KB 47.99KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.53KB 49.80KB
plugin-detail (index.js) 248.57KB 65.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.11KB 45.88KB
plugin-gantt (index.js) 179.17KB 45.07KB
plugin-grid (index.js) 249.62KB 69.16KB
plugin-kanban (index.js) 52.77KB 16.56KB
plugin-list (index.js) 120.25KB 30.26KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.10KB 11.81KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.27KB 23.06KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract-tier review of record — PR objectui#11069 (objectui#5250, slice A) · PASS on head 3fa762abe

Reviewer: domain:ui seat 2 (os-bill, session_01MgfduSkFrfM3eorB3UGfAU), 2026-10-09T11:11Z. This seat owns the card under the take-over claim 6077901503, which the maintainer directed in this seat's chat: 「11069 什么情况,你负责接手」. The earlier record 5886974796 (PASS on a11f733) does not carry over, as the release 5903643992 said. Read against the PR's diff on GitHub at 3fa762abe, not against the dev reports (6078291802, 6079477577, 6079686158).

Un-park, and its authority:

  • The ruling's condition is met. The maintainer's ruling 5534418546 says 「declarations repaired … before strict can be switched on」. On the merged head, class (ii) and class (iii) both read 0 pairs. The measurement round's instrument, which reproduces this PR's original M1 table exactly at the park base f6ae5e22d, gives the same pair set as main. The class (iii) tsc probe gives the same 38-error set.
  • Triage dropped Blocked-by: #6152 (6078650441), and the maintainer said in this seat's chat, verbatim: 「11069 解封」. objectui#11070 closed on 2026-10-08.
  • Un-park steps 1–3 are done: the merge and repairs; the PR's own stale text; the core statements; the governed companion. Step 2's 62-file sweep is PR objectui#12054. This record is step 4.

Contract reading (Clause-②: no):

  • What narrows. objectui validate and objectui check parse through StrictAnyComponentSchema, which @object-ui/types/zod already exports, via one function, validateAuthoredDocument (packages/cli/src/utils/authoring-face.ts). No key, export, flag or packages/i18n key is added, and nothing under @objectstack/spec changes. The published CLI's accept set narrows: a document carrying a key no schema declares at its position is refused by validate, and named by check.
  • What does not narrow. check stays advisory for an undeclared key. Its exit code still reflects unreadable JSON and the objectui#4795 ${…} refusal, and that refusal now also runs over registered-type files the strict face refuses. That is pinned, and red without the fix. The rendering face's .passthrough() is untouched.
  • No false refusal. The remaining strict-only refusals are all class (i): 32 pairs of keys that nothing reads, across 25 files. The dev's census gives the list. That is the refusal the ruling wants.
  • Changeset: @object-ui/cli minor, with the breaking meaning stated in the body (objectui AGENTS.md §9: never major). It also states that it supersedes any pending entry that calls safeValidateSchema what objectui validate runs. Seven such entries exist; they are not edited, because check-changeset-overwrite guards them and objectui#6152's round 14 is annotating its own two.

Checklist:

  • Shape: draft. First line Part of #5250, so the card stays open for slice B. Clause-②: no is at the start of a line. The assignee is os-bill. Merges from main are merges. Commit trailers carry no model name.
  • Surface: 19 files: packages/cli (the code, tests and README), the changeset, content/docs (5 pages), the 6318 corpus pin, and two packages/types comment blocks. Not governed (the guard reads NOT GOVERNED).
  • Superseded PR body sections are listed in 6079412008. The park note is void as of this record.
  • Evidence on 3fa762abe:
    • the packages/cli suite: 26 files, 383 tests;
    • the corpus pin and both repo-wide ratchets: 3 files, 26 tests;
    • type-checks for @object-ui/cli and @object-ui/types;
    • the changeset checks, check:new-line-citations and check:control-bytes;
    • the repository self-check (objectui check, the lint step), which exits 0.
  • Reverse legs: this PR's 12 original pins each have a tolerant-face control. The new objectui#4795 pin went red with the old continue (2 red, as predicted) and was restored to blob == HEAD.
  • First-load bytes: none. The CLI is not in the console.

Landing order:

  • this PR first;
  • the sweep PR objectui#12054 with it or after it;
  • the governed companion PR objectui#12050 (Tier H) with it or after it, by authorized approval.

This PR lands through the merge queue once every check on 3fa762abe is green.

Noted, not filed: union-arm-diagnostics.ts's header block records its measured facts as of Zod 4.4.3; the tree now runs 4.6.5. Its one false claim, the nested-key one, is corrected. The rest stays dated, not wrong.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 9, 2026 11:19
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 9, 2026 11:20
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit e4c0b54 Oct 9, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-5250-strict-validate-wiring branch October 9, 2026 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants