Skip to content

refactor(types,plugin-designer,i18n)!: retire the unread designer members objectui#11434's ruling settles as RETIRE, on both faces (PR 1 of 3) - #11451

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-11434-designer-members
Oct 2, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-11434-designer-members

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Part of #11434

Clause-②: yes

PR 1 of at most 3 for objectui#11434: every retirement the seat ruling on that card settles (ruling comment 5946170549, option B). The members ruled READ are not touched here and ship in PR 2 and PR 3. So is the onDelete → deleteBehavior respelling. The final PR of the card says it completes the card; this one is Part of.

The ruling this implements

The seat ruled member by member, by the maintainer's criterion for this family: "does the mainstream have it? Yes ⇒ give it a reader. No ⇒ retire it on both faces." Each member below was measured unread before ruling: a non-test grep, plus a runtime probe through the real SchemaRenderer and registry that drew the same markup with the member set and unset. Nothing in this repository or in ObjectStack authors any of them outside test fixtures. The phase-1 report on the card carries the measurement and the citations.

On the TypeScript face each member becomes a ?: never tombstone, so tsc refuses it by name. On the zod face it becomes a retirement tombstone, refused by name with the reason and what to write instead (RETIRED (objectui#11434, ADR-0049) — KEY on OWNER had no reader: … Instead: …). An element type that typed only a retired member leaves both faces and the exports.

Members retired, each with its migration line

Member Faces before Migration (as in the changeset)
DataModelDesignerSchema.autoLayout TS declared; zod unmirrored (UnmirroredDeclared) delete it; auto-layout is an action, use the toolbar's Auto Layout button
ReportDesignerSchema.previewMode TS declared; zod unmirrored (UnmirroredDeclared) delete it; for a chrome-free, non-editable layout author readOnly: true, showToolbar: false, showPropertyPanel: false
DesignerComponent.parentId both, mirrored delete it; nest the child in its parent's children array, the tree's one spelling
DataModelRelationship.onUpdate (seat override: retire) both, mirrored delete it; the platform's relationship contract has no update behaviour
BPMNNode.serviceEndpoint both, mirrored delete it; there is nothing to configure in its place (a service task references an implementation, not a URL)
ObjectDefinition.relationships (+ ObjectDefinitionRelationship: relatedObject, type, label, foreignKey) both, mirrored delete it; declare the relationship on the referencing field: in the designer, a lookup field whose referenceTo names the related object (in @objectstack/spec metadata, a lookup / master_detail field whose reference names it)
DesignerFieldDefinition.validationRules (+ DesignerValidationRule: type, value, message) both, mirrored delete it; put bounds on the field as min / max / minLength / maxLength, other rules in the object's validations

Removed exports. ObjectDefinitionRelationship and DesignerValidationRule leave the @object-ui/types root barrel. ObjectDefinitionRelationshipSchema and DesignerValidationRuleSchema leave @object-ui/types/zod.

The component face agrees. DataModelDesignerProps.autoLayout and ReportDesignerProps.previewMode are removed from @object-ui/plugin-designer; neither was read. The data-model-designer registration no longer publishes autoLayout among its inputs; check:component-surface-parity had reported it as outside (spec ∪ renderer reads). The package README's DataModelDesigner example no longer passes autoLayout.

Renderers are untouched. Every retired member was ignored at render before this change and still is. What moves is the verdict.

Ledger movement (zod-mirror-parity.test.ts, same PR as its members)

Figure Before After Why
UnmirroredDeclared 8 entries / 20 keys 6 entries / 18 keys the DataModelDesignerSchema (autoLayout) and ReportDesignerSchema (previewMode) entries close: each key is now a tombstone on both faces, and a tombstone is a mirrored member
its LOCAL half 5 / 6 3 / 4 the same two entries; the SPEC-DERIVED half (3 / 14) did not move
union of the two unmirrored ledgers 13 pairs (8 + 5) 11 pairs (6 + 5) the closed entries were in UnmirroredDeclared alone
EXPECTED_MIRROR_PAIRS 192 190 the ObjectDefinitionRelationshipSchema and DesignerValidationRuleSchema pairs left the registry with their types

ProcessDesignerSchema's lanes / version entry stays: they are ruled READ, and the reader PR mirrors them and closes it. Each move has its history sentence in the header, as the file's pins require.

Other pins that move with the members:

  • designer-zod-arms-10859.test.ts: the full-document fixture no longer sets the retired members, and the autoLayout / previewMode omission rows become full key-set equality. The removed pairs' rows go.
  • check-designer-field-key-parity.test.ts: the relationships pin now asserts that ObjectDefinition.relationships is the ?: never tombstone. group / sortOrder stay on the UI model and all three stay off every object wire shape. The gate still lists relationships as UI-only, because a tombstone is a property signature.
  • ObjectManager.test.tsx and MetadataService.specKeyObjectPayload.test.ts: the fixtures stop setting relationships. The wire-shape pins keep their strength through a LEGACY value cast from outside the type system, which still proves toObjectPayload's explicit field list keeps the key off the wire.
  • component-docs-retired-handler-keys-7340.test.ts: that census is name-shaped (on*?: never), so it now counts DataModelRelationship.onUpdate, recorded the way objectui#7068's onSuccess / onFailure were (30 total, designer.ts 1). It is a referential action, not a handler.
  • New pin designer-members-retired-11434.test.ts, covering both faces of all seven members, the two removed exports, and lit controls.

i18n census and the decision on the dead editor strings

node scripts/check-i18n-dead-keys.mjs lists appDesigner.fieldDesigner.validationRules and appDesigner.fieldDesigner.addRule as NEEDS-REVIEW. No call site asks for either; their only other footprint is the plugin-designer defaults map. They labelled an editor for the member this PR retires, which was never built. The card that once owned confirming that namespace, objectui#4730, is closed.

Decision: retire both. They are removed from the ten packs and from DESIGNER_DEFAULT_TRANSLATIONS, with a pin, appDesigner-fieldDesigner-validation-rules-retired-11434.test.ts, that checks absence in all ten packs and has a lit neighbour control. The defaults-map half stays held by defaults-maps-mirror-en-pack.test.tsx (objectui#4401). The other six NEEDS-REVIEW keys of that namespace are untouched.

Changesets

  • @object-ui/types minor, with a BREAKING (authoring) banner and one migration line per member (11434-designer-members-retired.md)
  • @object-ui/plugin-designer minor: the removed props and registration input (11434-plugin-designer-retired-props.md)
  • @object-ui/i18n patch: the two labels (11434-i18n-validation-rule-labels.md)
  • @object-ui/app-shell patch: comments only in MetadataService (11434-app-shell-relationships-note.md)
  • Dated notes on two pending changesets this release makes false: 10859-designer-zod-arms.md, whose "four unmirrored members … refused as unrecognized keys" sentence no longer holds for two of them, and 10719-retire-phase35-validation-types.md, whose sentence that "DesignerValidationRule stay[s] exported" no longer holds for it. This follows the dated-note shape objectui#10859 batch 8 landed. check-changeset-overwrite reports both edits, report-only by design.

Evidence (head 91a824298; patch rounds 1 and 2 at 6b5012446 / 97a16bccb below)

  • Patch round 2 (97a16bccb, prose only, contract review 5947291305, seat order 5947305312). The ObjectDefinition.relationships prescription paired a designer-face key with a spec-face type: referenceTo on a master_detail field, which neither face can author. DESIGNER_FIELD_TYPES has no master_detail, and the spec spells the key reference. Fixed in the designer.ts Instead line, the zod refusal message, the changeset migration line and this table row: in the designer, a lookup field with referenceTo; in @objectstack/spec metadata, a lookup / master_detail field with reference. A grep of this PR's diff for other face-mixing prescriptions found two @ts-expect-error descriptions in the new pin, aligned the same way. The docblock's spec sentence and the changeset's TypeScript example are unchanged. Re-run through os-verify-lock: designer-members-retired-11434.test.ts (18 passed) && check:changeset-claims && tsc --noEmit + tsc -p tsconfig.test.json for @object-ui/types, chained, VERDICT command-exit 0.

  • Patch round 1 (6b5012446, prose only, REWORK 5946901058). I measured through the installed @objectstack/spec 17.5.0. ObjectSchema.safeParse with an object-level relationships: [] answers unrecognized_keys: "Unrecognized key(s) on this object: relationships. Until this shape was closed these were dropped silently on the PARSE path …". FieldSchema.safeParse with validationRules: [] answers "Unrecognized key(s) on this field: validationRules. Until this shape was closed these were dropped silently …". Neither carries named guidance. The controls do: object-level validationRules gets "Did you mean validationRules → validations?" and field-level referenceTo gets "→ reference". So every sentence this PR writes about the spec now says "refuses it as an unrecognized key", not "by name". Those sentences are in the designer.ts docblocks, the two designer.zod.ts refusal messages, the MetadataService.ts comments this PR rewrote (including its group / sortOrder sentence, measured the same way), the new pin's header and the two changeset migration lines. The serviceEndpoint prescription is now "delete the key; there is nothing to configure in its place", in the TS docblock, the zod message and the changeset; BPMNNode.properties gets its reader in a later PR. Re-run through os-verify-lock: vitest run packages/types/ packages/app-shell/src/services/MetadataService.specKeyObjectPayload.test.ts → Test Files 329 passed (329), Tests 8767 passed, VERDICT command-exit 0. Then the message pin designer-members-retired-11434.test.ts (18 passed), check:changeset-claims, and tsc --noEmit + tsc -p tsconfig.test.json for @object-ui/types, chained with &&: VERDICT command-exit 0.

  • Test union, root form via os-verify-lock. At a5d1c2693: vitest run packages/types/ packages/plugin-designer/ packages/i18n/ packages/app-shell/src/services/ plus defaults-maps-mirror-en-pack.test.tsx, registered-types-validate-ratchet-10859.test.ts, and the scripts/__tests__ files for designer-field-key-parity, doc-component-types, doc-links, doc-snippet-types, object-metadata-write-doors, readme-exports, doc-version-claims and unit-registry-absence-collision. Result: Test Files 459 passed (459), Tests 10965 passed | 13 skipped, VERDICT command-exit 0. The 13 skips are the pre-existing skipIf in formatting.dateOnlyZone-10866.test.ts. 91a824298 changes only two changeset files, so the ratchet family and every test that reads .changeset/ was re-run on it: packages/types/ + the key-parity pin + those script tests gave Test Files 353 passed (353), Tests 9741 passed, VERDICT command-exit 0.

  • Type-check after a closure build. turbo run build --filter=@object-ui/app-shell^... --filter=@object-ui/plugin-designer^... --filter=@object-ui/plugin-designer passed, then type-check of @object-ui/types, @object-ui/i18n, @object-ui/plugin-designer and @object-ui/app-shell, joined with &&, plus type-check:scripts: VERDICT command-exit 0. tsc -p tsconfig.test.json --listFilesOnly lists the new and edited tests in their packages.

  • Ablation (ablation-replace.mjs with an absolute-path EXIT/INT/TERM trap). Deleting the autoLayout retirement tombstone from DataModelDesignerSchema moved the anchor x1 → x0, blob ff62eaf3 → 04d4fd87. Runtime result: 2 red, both naming the member: "autoLayout is refused on the rendering face, at its own path, with the prescription" and "autoLayout is refused on the strict authoring face, at its own path". tsc -p tsconfig.test.json went red at three rows: the new pin's zod row (Property 'autoLayout' does not exist), the batch-7 arms key-set row (TS2344), and the parity ledger ('designer.zod.ts#DataModelDesignerSchema' not assignable to never). Restored: blob equal to HEAD ff62eaf3, git diff HEAD empty.

  • Gates, each exit 0: check-changeset-presence ("29 source file(s) of 4 released package(s) changed, and this change declares 4 changeset(s)"), changeset:check, check:changeset-claims, census:changeset-polarity, check:pending-changeset-literals, check:designer-field-key-parity (OK), check:handler-key-reads, check:doc-types, check:doc-fences, check:doc-example-readers, docs:check-links, check:i18n-keys, check:i18n-drift, check:i18n-designer-parity, check:new-line-citations (0 new), check:control-bytes, check:test-path-roots, check:unreferenced-sources, check:registry-bare-names, check:prompt-keys, check:element-data-source-declaration, check:metadata-write-doors, check:spec-symbols, check:esm-specifiers, check:self-import, check:phantom-deps, markdown-test-inputs --audit. check:doc-snippets, check:doc-examples and check:readme-exports passed after the scoped build their own --build-filter names; packages that came in with the merge of main were not rebuilt for them. check-governed-queue-guard --test over the diff: NOT GOVERNED.

  • ESLint, narrowed. eslint --no-inline-config --format json over the 30 changed .ts / .tsx files gives, per file, the same error and warning counts as each base blob linted through --stdin. That includes one pre-existing no-restricted-imports error in packages/types/src/index.ts. The two new test files lint 0 / 0. eslint.config.js sets no projectService / parserOptions.project, so the diff cannot move any untouched file's verdict. The full pnpm lint is CI's.

  • NOT MEASURED: check:sdui-registration-pins. Reason: it needs an apps/console build (exit 2, prerequisite not met). The diff adds or removes no registration; it drops one inputs row inside an existing one.

  • NOT MEASURED: type-check:coverage. Reason: it is the whole-repo test compile, which CI runs. Every touched package's tsconfig.test.json is compiled above.

Overlap

packages/plugin-designer/src/index.tsx is shared with objectui#10859 phase 2b. This PR removes only the autoLayout row from the data-model-designer registration's inputs. main was merged before opening (a5d1c2693, after objectui#11446 and objectui#11447 landed). Whichever lands second merges main.

Acceptance notes

  • @object-ui/components' metadata-viewer reads obj?.validations ?? obj?.validationRules, a consumer-side alias of a spelling the spec refuses on objects. It is unreachable through a public door, because the spec refuses validationRules at save. Noted, not filed, and not in this PR.
  • The runtime render probes for PR 2 and PR 3 must not rely only on a gradient-valued style (happy-dom drops radial-gradient from serialized style), as the ruling records.

Generated by Claude Code

claude added 4 commits October 2, 2026 05:52
…the objectui#11434 ruling settles as RETIRE

On both faces: DataModelDesignerSchema.autoLayout, ReportDesignerSchema.previewMode,
DesignerComponent.parentId, DataModelRelationship.onUpdate, BPMNNode.serviceEndpoint,
ObjectDefinition.relationships and DesignerFieldDefinition.validationRules become
`?: never` tombstones on the TypeScript face and retirement tombstones refused by
name on the zod face. ObjectDefinitionRelationship and DesignerValidationRule, and
their zod mirrors, leave the exports. The mirror-parity ledger moves with them
(two UnmirroredDeclared entries close; two pairs leave the registry), the dead
component props and the autoLayout registration input go, and the two
validation-rule labels leave the locale packs and the designer defaults map.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
… DataModelRelationship.onUpdate tombstone

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
… objectui#11434 retirements make false

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

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 27 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/11355-small-p1-sites-r2.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ObjectChartSchema.isAnimationActive?: boolean is declared on the TypeScript face. Code sets it false for a render with no entrance animation: DashboardRenderer and DashboardGridLayout on the object-chart nodes they build, and DatasetWidget and DatasetReportRenderer on the nodes they hand the chart registration. ChartRenderer honours it. The zod mirror declares no member for it, so it is not an authoring key; zod-mirror-parity.test.ts files it as runtime-only.

.changeset/5903-objectgantt-declared-keys.md

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743); the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair — but at that time the ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction, not that nothing was there. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger requires every registered pair's mirrored-but-undeclared key set to equal that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/5928-classname-style-props-rename.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Where the non-pair is recorded now. zod-mirror-parity.test.ts keys its existing EXCLUSIONS entry — the mechanism that accounts for every exported const with no TypeScript declaration to mirror, each with its stated reason — to ClassNameStylePropsSchema. Named for its own two keys, the const leaves no like-named declaration for a name-derived pairing to reach for.

.changeset/6051-gantt-flat-config-declared-keys.md

  • names packages/types/src/index.ts → packages/types/src/index.ts — edited by this change

    GanttConfig itself gains nine members and is a published type, exported by name from packages/types/src/index.ts: lockField, objectField, summaryExtent, defaultCollapsedDepth, borderColorField, dependencyTypes, timeZone, exportFileName, interactions. The entry file's diff is empty only because the export list already named the type — the widening happened at the declaration.

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743) — the same retirement objectui#5903's entry carries, for the same clause and the same reason; the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair, at a time when that ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger reconciles every registered pair's mirrored-but-undeclared key set against that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/6150-undeclared-but-consumed-keys.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ AMENDED, and the amendment ships in this same release. The TreeViewSchema slice (604476d97) gave the key a zod arm after all — a NAMED REFUSAL (handlerKeyRefusal(key, 'runtime-slot', label)), never a shape — because "no mirror entry" is not neutral under BaseSchema.passthrough(): it meant an authored { "type": "tree-view", "onNodeClick": { "action": "toast" } } parsed GREEN, survived the parse, and reached a call site that expects a function. ⇒ the three clauses this bullet used to carry are no longer true of the code shipping beside it. The key is now a MEMBER of TreeViewSchema.shape and an authored value is refused BY NAME at path onNodeClick; it has LEFT zod-mirror-parity.test.ts's RuntimeOnlyDeclared for that file's KnownDrift; and it is no longer "the first pair to sit there without also sitting in UnmirroredDeclared" — draining it emptied that difference, so RuntimeOnlyDeclared is now a SUBSET of UnmirroredDeclared and the union of the two equals UnmirroredDeclared itself. ⛔ objectui#6152's ruling is untouched by any of this: what the key still does not have, and never will, is a z.function() shape — no serialized document could satisfy one.

.changeset/6175-column-state-persistence.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Nothing is retired. Both spellings remain declared on DataTableSchema; onColumnReorder stays declared and stays unwired, exactly as the RuntimeOnlyDeclared ledger in zod-mirror-parity.test.ts records it. Which of the two survives is a declared-surface ruling that stays open and is deliberately not settled here.

.changeset/6237-wizard-step-config-split.md

  • names content/docs/plugins/plugin-form.mdx → content/docs/plugins/plugin-form.mdx — edited by this change

    Documentation repair in the same stroke: the support table in the README and in content/docs/plugins/plugin-form.mdx still said formType: 'tabbed' sections drop the predicate. That stopped being true when the tabbed arm landed — the row now reads Yes, the surrounding prose no longer claims two inert arms or a diagnostic that fires for tabbed, and the wizard row stays No, which is still exactly true.

.changeset/6309-delete-object-fields-bridge.md

  • names types/src/designer.ts → packages/types/src/designer.ts — edited by this change

    Removing it is not the whole change. Three comments — in types/src/designer.ts, types' designer-field-types.test.ts (twice) and fields' richtext-cell-renderer-5452.test.tsx — cited the bridge as a live corroborating source. Left behind, they would have swapped dead code for false documentation: three in-repo pointers telling a future reader that this bridge mediates between the framework field record and FieldDesigner, and nothing telling them it is unreachable. The two that named it as the consumer deriving an editable-subset check from DESIGNER_FIELD_TYPES now name MetadataFieldsPage, which does exactly that with the same idiom and the same objectui#3017 anchor. The third cited the bridge's richtext → html mapping as one of three corroborations that richtext stores HTML; the other two (the showcase seed and the field-type decision tree) are live and carry the point on their own, so that clause is dropped rather than repointed.

.changeset/6310-designer-formula-key-retired.md

  • names packages/plugin-designer/src/hooks/useDesignerTranslation.ts → packages/plugin-designer/src/hooks/useDesignerTranslation.ts — edited by this change

    objectui#6043 retired the Field Designer's formula-expression textarea, which was the key's only call site (FieldDesigner.tsx, the { name: 'formula', label: t('appDesigner.fieldDesigner.formula') } field descriptor). The value outlived it in eleven places: DESIGNER_DEFAULT_TRANSLATIONS in packages/plugin-designer/src/hooks/useDesignerTranslation.ts, and the appDesigner > fieldDesigner > formula leaf of packages/i18n/src/locales/{en,de,es,fr,pt,ru,ja,ko,zh,ar}.ts.

  • names packages/i18n/src/__tests__/appDesigner-fieldDesigner-formula-retired-6310.test.ts → packages/i18n/src/__tests__/appDesigner-fieldDesigner-formula-retired-6310.test.ts — edited by this change

    packages/i18n/src/__tests__/appDesigner-fieldDesigner-formula-retired-6310.test.ts pins the removal by name, following the four prior retirements (objectui#4145, objectui#4392, objectui#4730, objectui#5504). Every i18n gate here runs call site → key, so none of them can see a dead key come BACK into the packs: the reverse sweep that found this one is report-only by design, all-locales-key-parity is fully satisfied by ten packs agreeing on a dead key, and check:i18n-drift only fires when a value changes. Reverse-verified rather than asserted — reviving the row in all ten packs turns exactly that one case red, naming each pack, while the parity gate and the defaults-map mirror stay green.

.changeset/6639-objectgrid-title-mirrored.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The gain is the typed refusal: the mirror's .passthrough() base was already admitting any title unexamined, and it now enforces the declared string. zod-mirror-parity.test.ts's UnmirroredDeclared ledger records the key as worked off — the ledger's first shrink by repair (97 + 1 mirrored + 23 reclassified is what the seeded "121" now means).

.changeset/6661-app-launcher-nav-menu-renderers.md

  • names en.ts → packages/i18n/src/locales/en.ts — edited by this change

    Three new strings — the launcher's and the menu's accessible names, and the menu's empty state — are declared under console.nav in en.ts and its nine sibling packs. An inline defaultValue alone is not a fix: it renders English at one call site and leaves the string untranslatable everywhere (objectui#3517).

.changeset/7344-handler-string-any-mirrors.md

.changeset/7654-floating-chatbot-trigger-icon-tombstone.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Every other tombstone in this package pairs ?: never with a retirementTombstone() refusal on the Zod twin. There is no twin here to carry one: FloatingChatbotConfig has no Zod mirror at all, and floatingConfig sits in the UnmirroredDeclared ledger (zod-mirror-parity.test.ts, complex.zod.ts#ChatbotSchema). BaseSchema is .passthrough(), so the whole floatingConfig object rides through unvalidated — before this change and after it. Minting a mirror to host a refusal would be the declared-but-UNMIRRORED axis (objectui#6152), a different defect: a key can be mirrored and inert, or unmirrored and live, and fixing one says nothing about the other. This change does not widen into it.

.changeset/7694-chart-series-chart-type-alias-refusal.md

  • names zod/index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    • Before: series: [{ name: 'revenue', chartType: 'line' }] validated green through @object-ui/types/zod (safeValidateSchema, objectui check / objectui validate, any pipeline that keeps parse()'s output) — and the key was gone from the output, so a consumer of the parse result drew that series in the chart's own family, precisely what the author was overriding. On the TypeScript face the key was merely an excess property on a fresh literal; a widened object carrying it assigned structurally. - After: the same document REFUSES at series[i].chartType (issue code invalid_type) with one message on both channels — the parse-time issue and the .describe() metadata: Unrecognized key(s) on this chart series: \chartType`. Did you mean `chartType` → `type`? …followed by the reason and the remedy. Writetype: 'bar' | 'line' | 'area'. On the TypeScript face ChartDataSeries.chartTypeis a?: nevertombstone, so both the fresh literal and the widened assignment aretsc errors. - **Both written** ({ type: 'bar', chartType: 'line' }) is refused at chartTypealone — the key is not folded ontotypeand no precedence is minted between the two spellings. - **Which documents to scan.** The narrowing does not stop atChartDataSeriesSchema; it reaches every document through the parents that embed it — ChartSchema.series (zod/data-display.zod.ts, z.array(ChartDataSeriesSchema)) and, one level further out, ReportSectionSchema.chart (zod/reports.zod.ts, ChartSchema.optional()). Authors meet it through safeValidateSchema() (zod/index.zod.ts, which parses AnyComponentSchema) and through the CLI's objectui validate command (packages/cli/src/cli.ts). In practice: every chartnode'sseries[], and every report section whose chart` carries one.

.changeset/7804-tree-view-handler-slot.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The pair moves from zod-mirror-parity.test.ts's RuntimeOnlyDeclared to its KnownDrift, which empties the former of the one entry the latter did not also hold — so the two unmirrored ledgers are now in a containment relation, and the cross-ledger figure that recorded their difference states the containment instead.

.changeset/7917-export-breadcrumb-object-tree-zod-schemas.md

  • names index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    AnyComponentSchema declares 107 node component types. 105 of them could be named on the ./zod barrel — ButtonSchema.safeParse(node), which is what a designer, a form builder or a targeted test needs. The arms declaring type: 'breadcrumb' (navigation.zod.ts) and type: 'object-tree' (objectql.zod.ts) could not: both were already export const in their own module, but index.zod.ts — the package's only zod entry point — did not re-export them, so the schemas existed, were maintained, and were applied by the union while no consumer could name them.

.changeset/8338-retire-toast-action.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The parity ledgers drain with it, every figure re-derived by zod-mirror-parity.test.ts's own AST and mirror instruments rather than stepped by hand: KnownDrift 42 entries / 64 keys → 41 / 63 (the entry's whole content, so the entry went too — the ledger's first loss by RETIRING a key rather than by moving either face toward the other), and WiderThanDeclared 23 / 36 / 47 arms, split 6 / 30 / 0 / 11 → 22 / 35 / 45, split 6 / 29 / 0 / 10. The pair itself stays registered, so EXPECTED_MIRROR_PAIRS does not move.

.changeset/8344-node-recursion-point-redirect.md

  • names zod/index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    Two mechanical notes for anyone editing the wiring. AnyComponentSchema is built in zod/index.zod.ts from all 13 category modules and 14 modules import zod/base.zod.ts, so the arm cannot be an import — z.lazy defers evaluation, not the module graph. It is a written option slot that index.zod.ts fills inside AnyComponentSchema's own initializer, and it is a z.union option rather than a z.lazy holder because z.lazy memoises its getter: a holder would let whichever module graph parsed first decide the accept set for the whole process. Both constraints are measured, and the reasoning lives on defineNodeComponentUnion in zod/base.zod.ts.

  • names index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    Two mechanical notes for anyone editing the wiring. AnyComponentSchema is built in zod/index.zod.ts from all 13 category modules and 14 modules import zod/base.zod.ts, so the arm cannot be an import — z.lazy defers evaluation, not the module graph. It is a written option slot that index.zod.ts fills inside AnyComponentSchema's own initializer, and it is a z.union option rather than a z.lazy holder because z.lazy memoises its getter: a holder would let whichever module graph parsed first decide the accept set for the whole process. Both constraints are measured, and the reasoning lives on defineNodeComponentUnion in zod/base.zod.ts.

.changeset/8499-node-slot-registered-arms.md

  • names zod/index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    Why 49 is acceptable here where 2 was a defect: the 2 were data blocks a consumer had a standing reason to validate on their own, and objectui#7917 (PR feat(types): re-export BreadcrumbSchema and ObjectTreeSchema from the zod barrel (objectui#7917) #8777, open at the time of writing, and the holder of zod/index.zod.ts) exists to export exactly those. The 47 added here are HTML primitives and two input aliases — they have no per-tag consumer to serve, and exporting a SemanticElementSchema / HtmlElementSchema pair would publish a NAMED authoring surface (z.enum families, not per-tag schemas) that this card's ruling does not cover: the ruling is "arm the registered renderers", not "add public exports to @object-ui/types". So the metric is left to move and said out loud instead. ⇒ Whoever next runs that measurement should expect 49, and whoever wants the number back down should treat naming these families as its own decision. If PR feat(types): re-export BreadcrumbSchema and ObjectTreeSchema from the zod barrel (objectui#7917) #8777 lands first, the same movement reads 0 to 47.

.changeset/8572-chatbot-body-retired.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Why this key and not another. It was the ONE place in this vocabulary where body did not mean "what goes inside this component": zod-mirror-parity.test.ts carried the pair under KnownDrift as "two different meanings of one key", and the same collision was the whole reason chatbot was the single arm of the component union whose output was not assignable to SchemaNode. Both ledger rows move with this change, and the two pins that recorded the old state are INVERTED rather than deleted (see below).

.changeset/8598-zod-subpath-single-bundled-module.md

  • names src/zod/index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    The defect. This package declares "sideEffects": false, and src/zod/index.zod.ts fills the node recursion point as the initializer of its AnyComponentSchema const. tsc emitted that barrel as a module whose only other content is re-exports — so a bundler resolving import { CardSchema } from '@object-ui/types/zod' followed the re-export to dist/zod/layout.zod.js, needed nothing from the barrel's own body, and the flag let it drop that body whole. The fill went with it, and every child slot then validated against the pre-spec(types): redirect the node recursion point from BaseSchemaCore to AnyComponentSchema — measured at 9 newly-refused documents, and it drops 118 phantom strict refusals #8344 BaseSchemaCore arm — the ~21 base keys and nothing type-specific — with no error, no warning and no way for the guard inside the dropped code to notice. objectui#8344 shipped that window DECLARED and pointed here to close it.

.changeset/9067-zod-barrel-named-arms.md

  • names packages/types/src/zod/index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    Two new exported symbols, both on packages/types/src/zod/index.zod.ts:

.changeset/9511-record-id-is-a-string.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ The declaration alone would not have been enough, and this is the reusable part. A TypeScript declaration does not run at parse time. The hand-written zod mirror is the only face in this repository that can refuse an authored number, so narrowing the declaration without the mirror would have shipped declared !== enforced on a published surface — and zod-mirror-parity.test.ts would have stayed GREEN through it, because that instrument asserts a mirror accepts everything its declaration declares and a mirror left WIDER passes. Both faces moved together for that reason.

.changeset/9659-node-recursion-point-inert-clause.md

  • names zod/index.zod.ts → packages/types/src/zod/index.zod.ts — edited by this change

    Prose amended where this change falsified it, ⛔ not rewritten. zod/index.zod.ts said defineNodeComponentUnion "wraps it rather than replacing it" — true only while a wrapper existed. zod/base.zod.ts's note on the loose parameter bound still names ChatbotSchema's record body in the present tense; the paragraph is kept for the reason it records and carries an AMENDED note saying the exclusion set that pin reads is now empty.

.changeset/component-meta-converge-and-deprecate-alias-5893.md

  • names packages/types/src/index.ts → packages/types/src/index.ts — edited by this change

    ⚠️ Dated note, 2026-09-29 — the one-occurrence reading above has since moved — objectui#10979. "In-repo, PluginComponentMeta has exactly one occurrence — its own export line" above is the reading of the commit this change landed on (575b71c850), where a whole-tree search for the name returned that one line, in packages/types/src/index.ts. This change then added its own pins and this entry, and later in this same release objectui#5674's retirement of the sibling alias PluginComponentInput (PR objectui#10826) added mentions in its test and its entry. Re-measured on main at 2eaf5be27, the name occurred on 19 lines in 7 files. In non-test source it appeared only on the export line and on one doc-comment line in plugin-scope.ts, and the one file that imported it was this change's own component-meta-single-declaration.test.ts. The text above is kept as the reading of this change.

.changeset/dashboard-config-aria-retired-5852.md

  • names designer.ts → packages/types/src/designer.ts — edited by this change

    Both spellings are named verbatim above so a host can grep its own sources: the retired member is aria, on the TypeScript interface DashboardConfig (@object-ui/types, designer.ts) and on its Zod mirror DashboardConfigSchema (@object-ui/types/zod). It declared { label?: string; description?: string }.

.changeset/object-view-unmirrored-keys-7779.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Who is NOT affected: every correctly typed document, and every document that never wrote these keys — absent stays valid on all nine. No renderer changed. The parity ledger (zod-mirror-parity.test.ts) records the move: UnmirroredDeclared 14 entries / 96 keys to 14 / 87, the ObjectViewSchema entry re-derived into the SPEC-DERIVED half because the mirror now references the spec in code.

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 89cad75d5 (merge-base with origin/main): 33 file(s) changed outside .changeset/, read against 1978 pending declaration(s) that publish a body (2606 pending in total). · run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3553.1 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-YhCwbrXL.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) 570.62KB 136.73KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.34KB 66.32KB
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.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.40KB 11.41KB
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.01KB 3.93KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 141.24KB 37.99KB
plugin-designer (index.js) 217.27KB 44.98KB
plugin-detail (index.js) 245.70KB 64.54KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.14KB 44.58KB
plugin-gantt (index.js) 178.38KB 44.94KB
plugin-grid (index.js) 231.72KB 63.65KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.22KB 22.75KB
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.25KB 2.04KB
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.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
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) 21.42KB 7.05KB
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 (complex.js) 3.19KB 1.62KB
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) 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) 5.07KB 2.39KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
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

…Rules` as unrecognized keys, and `serviceEndpoint` prescribes deletion alone (objectui#11434 patch round 1)

Measured through the installed @objectstack/spec 17.5.0: ObjectSchema and
FieldSchema refuse the two keys with `unrecognized_keys` and no named
guidance, so the prose this change publishes says that instead of "by name".
The serviceEndpoint prescription no longer points at `properties`, which no
renderer reads yet.

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

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3553.1 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-YhCwbrXL.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) 570.62KB 136.73KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.34KB 66.32KB
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.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.40KB 11.41KB
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.01KB 3.93KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 141.24KB 37.99KB
plugin-designer (index.js) 217.27KB 44.98KB
plugin-detail (index.js) 245.70KB 64.54KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.14KB 44.58KB
plugin-gantt (index.js) 178.38KB 44.94KB
plugin-grid (index.js) 231.72KB 63.65KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.22KB 22.75KB
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.25KB 2.04KB
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.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
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) 21.42KB 7.05KB
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 (complex.js) 3.19KB 1.62KB
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) 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) 5.07KB 2.39KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
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: 6b5012446a39cf88a01c34ab7a4566306ed42f04
Local-runs: none

Inputs read: card objectui#11434 (its body and every comment — the claim 5945883001, the phase-1 report 5946109386, the seat ruling 5946170549, the PR-1 report 5946842312, the REWORK 5946901058, the patch-round report 5947109233 and the ACCEPT 5947134117), PR objectui#11451's body and file list, the net diff of the head against origin/main (39 files, +906 / −231, merge-base 990a2d616), and the head's check-runs. Spec claims were checked by reading @objectstack/spec source at objectstack 4e6dc23 (version 17.5.0, the one objectui's lockfile pins). Nothing was built, run or re-run; the check-runs on the head are the gate verdicts.

Check-runs on the head, read at 2026-10-02T07:20Z, every run completed: total_count 43 = 43 returned (one more than the brief's snapshot: the aggregate Test run appeared once its shards finished); 40 success, 3 skipped (the Test (coverage shard …) matrix placeholder, Test (coverage), dependabot), 0 failure, 0 still running. Lint, Type Check, all eight Test shards, Test (dist pins), Spec Main Shape Gate, Governed Surface Queue Guard, Line Citation Gate, the four changeset gates and Bundle Analysis (the job that runs check:sdui-registration-pins, the gate the dev could not run locally) are green. No gate verdict weighs against this head.

① Derived judgments

Accept-set moves on the zod face (@object-ui/types/zod), each through retiredDesignerMember → retirementTombstone, which is z.never({ error }).optional(): refused with invalid_type at the member's own path by safeValidateSchema AND by StrictAnyComponentSchema. The new pin designer-members-retired-11434.test.ts holds both halves (18 tests) with a green control document per node and the two removed mirrors asserted absent beside their carriers present.

  • DataModelDesignerSchema.autoLayout and ReportDesignerSchema.previewMode: from refused-as-unrecognized on the strict face and passed through on the tolerant face, to refused by name on both — right: zero readers by grep and by the runtime probe; auto-layout is an action the toolbar runs on demand, preview is a tool mode; both prescriptions name things that exist (the Auto Layout button; readOnly, showToolbar, showPropertyPanel).
  • DesignerComponentSchema.parentId: accepted string → refused — right: children is the mirror's recursion and the tree's one spelling.
  • DataModelRelationshipSchema.onUpdate: accepted CascadeBehavior → refused — right, the seat override holds: FieldSchema.deleteBehavior is z.enum(['set_null', 'cascade', 'restrict']) and the spec declares no update behaviour; onDelete is untouched for PR 2 / 3 as the ruling says.
  • BPMNNodeSchema.serviceEndpoint: accepted string → refused, prescription "delete the key; there is nothing to configure in its place" — right: the REWORK's pointer at the unread properties is gone from the docblock, the zod message and the changeset.
  • ObjectDefinitionSchema.relationships: accepted array → refused — the accept-set move is right: ObjectSchema is .strict(), declares no relationships, and its UNKNOWN_KEY_GUIDANCE map has no row for it, so "as an unrecognized key" is the measured wording; toObjectPayload's explicit field list keeps it off the wire, re-pinned through the LEGACY cast with a 'relationships' in LEGACY non-vacuity row. Its prescription is wrong in one arm — the paragraph below.
  • DesignerFieldDefinitionSchema.validationRules: accepted array → refused — right: FieldSchema carries min / max / minLength / maxLength and ObjectSchema carries validations; the prescription's "in the field metadata" names the spec face, which is where those keys live (the designer field face has none of the four, and the sentence does not claim it does).
  • ObjectDefinitionRelationshipSchema and DesignerValidationRuleSchema leave the zod barrel — right: each typed only a retired member, and the head tree holds no other reference outside the new pins and the retirement prose.

Public-surface moves on the TypeScript face and the component face:

  • Seven ?: never tombstones (DesignerComponent.parentId, DataModelRelationship.onUpdate, DataModelDesignerSchema.autoLayout, BPMNNode.serviceEndpoint, ReportDesignerSchema.previewMode, ObjectDefinition.relationships, DesignerFieldDefinition.validationRules) — right: the pin's Equal rows separate undefined from the any a deletion would leave behind BaseSchema's index signature, and Type Check is green on the z.ZodType annotation of the recursive DesignerComponentSchema.
  • ObjectDefinitionRelationship and DesignerValidationRule leave the root barrel — right: @ts-expect-error rows on both the barrel and the ../designer path, with resolving controls beside them.
  • @object-ui/plugin-designer: DataModelDesignerProps.autoLayout and ReportDesignerProps.previewMode removed, the data-model-designer registration's inputs loses its autoLayout row, the README example drops the prop — right: neither prop was destructured; the DataModelDesignerSchema children docblock now lists the three remaining inputs, matching index.tsx; check:sdui-registration-pins ran green inside Bundle Analysis on this head.
  • @object-ui/i18n: appDesigner.fieldDesigner.validationRules and .addRule leave the ten packs and DESIGNER_DEFAULT_TRANSLATIONS — right: no t() call site, t(key: string) is string-typed, the absence pin covers all ten packs with three lit neighbours, and defaults-maps-mirror-en-pack holds the map half. TranslationKeys = typeof en narrows by two leaves; see ②.
  • Ledgers: UnmirroredDeclared 8 entries / 20 keys → 6 / 18, its LOCAL half 5 / 6 → 3 / 4, the union 13 → 11, EXPECTED_MIRROR_PAIRS 192 → 190 — right, each matching the two entries closed and the two pairs removed, each with a history sentence; ProcessDesignerSchema (lanes / version) stays, as the ruling requires. The objectui#7340 name-shaped census 29 → 30 with designer.ts: 1 and onUpdate named as a referential action, not a handler — right. designer-zod-arms-10859: the autoLayout / previewMode key-set rows become full equality and the full-document fixture drops the retired members — right. The key-parity pin asserts the relationships?: never; tombstone while the gate itself is unchanged — right.
  • Dated notes on the pending 10719 and 10859 changesets — right: each corrects exactly the sentence this diff falsifies, and the 10859 note's "refused BY NAME on the arms, not as an unrecognized key" is the line the REWORK insisted on.
  • Docs: plugin-form.mdx, zod/README.md, plugin-designer/README.md — right. At the head, apps/, examples/, skills/ and content/ carry no other reference to a retired member or a removed type. (ROADMAP.md's historical [x] rows still name both removed types; not a published surface, not a finding.)
  • Renderers untouched; every retired member was ignored at render before and after — right, and the changeset says so.

Wrong — the ObjectDefinition.relationships prescription names an arm neither face can author. In three published carriers and the PR body — the @object-ui/types changeset's migration line for ObjectDefinition.relationships, the **Instead:** sentence of the relationships?: never docblock in designer.ts, and the instead-string of retiredDesignerMember('ObjectDefinition', 'relationships', …) in designer.zod.ts — the author is told to write "a lookup or master_detail field whose referenceTo names the related object". referenceTo is the designer-face key (DesignerFieldDefinition.referenceTo; FieldDesigner.tsx offers it under visibleWhen: "record.type == 'lookup'" and nowhere else), and DESIGNER_FIELD_TYPES carries no master_detail: DesignerFieldDefinition.type and DesignerFieldDefinitionSchema.type = z.enum(DESIGNER_FIELD_TYPES) both refuse it, and the repo's own pin says so in as many words — "master_detail is a stored type this designer cannot author" (MetadataFieldsPage.carriedThroughReference-8896.test.tsx). On the spec face master_detail exists but referenceTo is refused ("Did you mean referenceTo → reference", the dev's own control in the patch-round report). So the master_detail arm of the prescription is authorable on neither face. The changeset's TypeScript example (type: 'lookup', referenceTo: 'account') is the right arm, and the docblock's earlier sentence about the spec ("a lookup / master_detail field with a reference") is accurate — the defect is the **Instead:** line and its two siblings alone. This is the class the REWORK caught for serviceEndpoint (a prescription pointing at something the face does not deliver), and the changeset text ships to CHANGELOG.md, where a correction afterwards costs a dedicated docs-only PR by rule. Fix: name lookup alone with referenceTo for the designer face (and, if the spec face is meant as well, lookup / master_detail with reference), in the three carriers and the PR body; designer-members-retired-11434.test.ts asserts only the key, the card and Instead: in the message, so it stays green either way; re-run it with check:changeset-claims and record the exits.

② Semver level

  • PR body Clause-②: yes — right: the accept set narrows on seven members and two exports leave, so yes; a yes takes at least minor, and @object-ui/types declares minor with a BREAKING (authoring) banner, the Clause-②: yes line, one migration line per member and the removed-exports paragraph. The arm is optional under the closed pair; (narrowing) would have been the precise one. No major, per this repo's fixed-group rule (Changeset Bump Policy green).
  • @object-ui/plugin-designer minor, BREAKING (TypeScript props), with its migration — right.
  • @object-ui/i18n patch — right by this package's own precedent (its CHANGELOG's "Removed five locale keys that had no call site" entry sits under Patch Changes) and the body states what a host sees; noted for the seat: TranslationKeys = typeof en narrows, and the repo has scored other dead-key removals minor.
  • @object-ui/app-shell patch for comment-only edits — right: the changeset-presence header records that src comment text can reach a published .d.ts, so patch over an empty frontmatter is the conservative declaration, and the body says comments only.
  • No skip-changeset; check-changeset-presence reads 29 source files of 4 released packages against 4 changesets; the two dated notes are report-only under check-changeset-overwrite and follow the batch-8 shape.
  • The @object-ui/types changeset's migration text carries the ① defect, so its level is right and its text is not yet the text that should ship.

③ Boundary flags

  • Phase-1 open_questions (the member rows, the margins sub-keys, the CROSS-CUTTING row): every one ruled member by member in the seat ruling; option C not escalated, with the reason stated (the criterion is the maintainer's standing ruling for this family) — answered.
  • PR-1 report deviations: dated notes on two other cards' pending changesets — accepted by the seat, right; files beyond the order's list — each forced by a pin or by prose made false, right; the parity gate's pin moved while the gate is unchanged — right (teaching the gate to skip never members would be new behaviour); one amend of a never-pushed local merge commit — no shared history rewritten, right; the model-free trailer pair — verified on all five commits of the branch; the --config.engine-strict=false install and two shared-cache hits — local only, CI installed and built fresh and is green; the phase-1 empty-branch-push conflict — closed before the first edit.
  • PR-1 out-of-scope findings: metadata-viewer's validations ?? validationRules alias — noted in the PR's acceptance notes, no reach because the spec refuses the spelling at save, seat ruled no card — answered; the happy-dom gradient caveat — carrier PR 2 / 3 — answered; plugin-designer/src/index.tsx overlap with objectui#10859 phase 2b — carrier objectui#10859, whichever lands second merges main — answered.
  • Patch-round deviations: two extra sites fixed on the same measurement (the new pin's header, the toObjectPayload docblock) — right; one PR-body edit, read back identical — right; earlier reports left as records of their round — right. Its out-of-scope "refuses each of the three keys BY NAME" test name — outside the diff, dropped by the seat — answered.
  • NOT MEASURED items: out-of-repo TypeScript consumers — the changeset's closing paragraph carries the caveat; check:sdui-registration-pins — run by Bundle Analysis on this head, green; type-check:coverage — Type Check on this head, green.
  • Nothing to escalate. The ① defect is new to this review, not a flag the dev or the seat raised.

Shape: draft PR, head repo = base repo, 39 files / 1,137 changed lines, Part of #11434 the only card reference in the body (no closing keyword), needs:contract-review on the PR, no governed path in the file list (Governed Surface Queue Guard green). The code, the accept-set moves, the ledgers, the semver declarations and every gate on this head stand; the verdict turns on the one published prescription above, and a prose-only patch round with a new record on the patched head clears it.

Implemented-by: claude/issue-11434-designer-members
Reviewed-by: session_01YLg8XqWGJ785fwQ5v4pH37

VERDICT: FAIL


Generated by Claude Code

…an author (objectui#11434 patch round 2)

The designer face writes a `lookup` field with `referenceTo` (DESIGNER_FIELD_TYPES
has no `master_detail`); @objectstack/spec metadata writes a `lookup` /
`master_detail` field with `reference`. The docblock's Instead line, the zod
refusal message and the changeset migration line now say which is which.

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

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3553.1 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-YhCwbrXL.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) 570.62KB 136.73KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.34KB 66.32KB
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.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.40KB 11.41KB
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.01KB 3.93KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 141.24KB 37.99KB
plugin-designer (index.js) 217.27KB 44.98KB
plugin-detail (index.js) 245.70KB 64.54KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.14KB 44.58KB
plugin-gantt (index.js) 178.38KB 44.94KB
plugin-grid (index.js) 231.72KB 63.65KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.22KB 22.75KB
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.25KB 2.04KB
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.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
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) 21.42KB 7.05KB
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 (complex.js) 3.19KB 1.62KB
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) 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) 5.07KB 2.39KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
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: 97a16bccbe686c6b6f964ce48cd1e66c80559de5
Local-runs: none

Delta record on the fix-only head that answers the FAIL 5947291305, which this seat rendered on the previous head of the same PR. Inputs read: the card's comments since the ACCEPT (the seat order 5947305312, the patch-round-2 report 5947442034, read as an input), the PR body at this head (one edit since the first review: the ObjectDefinition.relationships table row and a patch-round-2 evidence entry; no closing keyword; Part of #11434 only), the delta from the previous head to this one (one commit, whose only parent is that previous head, no merge of main; 4 files, +8 / −7, prose only), the net diff of this head against origin/main (39 files, +907 / −231, the same merge-base with main as before, unchanged in file list), and this head's check-runs. Nothing was built, run or re-run.

Nothing else moved. The new head's only parent is the reviewed head, so the net diff against main differs from the one judged at the previous head by exactly the delta: the same 39 files, no file entering or leaving, and every differing hunk inside the four delta files. The faces the FAIL measured against — DESIGNER_FIELD_TYPES, DesignerFieldDefinition.type / .referenceTo, DesignerFieldDefinitionSchema.type = z.enum(DESIGNER_FIELD_TYPES), and the installed @objectstack/spec 17.5.0 FieldSchema — are outside the delta and unchanged. Every judgment the first record named right at the previous head therefore carries over untouched; this record re-judges only the four carriers, the two pin descriptions, and the gates on this head.

Check-runs on this head, read at 2026-10-02T07:46Z, every run completed: total_count 43 = 43 returned, all on this head; 40 success, 3 skipped (the Test (coverage shard …) matrix placeholder, Test (coverage), dependabot), 0 failure, 0 still running. Lint, Type Check, all eight Test shards and the aggregate Test, Test (dist pins), Spec Main Shape Gate, Governed Surface Queue Guard, Line Citation Gate, Doc Snippet Type Check, the four changeset gates and Bundle Analysis (which runs check:sdui-registration-pins) are green — the same roster, with the same conclusions, as on the previous head. No gate verdict weighs against this head.

① Derived judgments

The FAIL finding, re-read at each carrier — each now pairs a key with a type the named face can author:

  • packages/types/src/designer.ts, the **Instead:** line of the relationships?: never docblock: "in this designer, a lookup field whose referenceTo names the related object (in @objectstack/spec metadata, a lookup / master_detail field whose reference names it)" — right. Designer face: lookup is in DESIGNER_FIELD_TYPES, DesignerFieldDefinition.referenceTo is declared, and FieldDesigner.tsx offers referenceTo under visibleWhen: "record.type == 'lookup'". Spec face: FieldSchema.type carries lookup and master_detail, and reference is the spec's "target object name for lookup/master_detail fields". The master_detail arm now sits on the one face that has it, with the key that face spells.
  • packages/types/src/zod/designer.zod.ts, the instead-string of retiredDesignerMember('ObjectDefinition', 'relationships', …): the same two-face sentence — right; the rendered refusal still carries Instead: (the helper's template), the key, the owner and the card, which is what designer-members-retired-11434.test.ts asserts on the message.
  • .changeset/11434-designer-members-retired.md, the ObjectDefinition.relationships migration line: "in the designer, a lookup field whose referenceTo names the related object (in @objectstack/spec metadata, a lookup / master_detail field whose reference names it)" — right, and it now agrees with the changeset's own TypeScript example (type: 'lookup', referenceTo: 'account'), which was already the right arm and is untouched.
  • The PR body's ObjectDefinition.relationships table row — right, the same wording; the body's spec-measurement paragraph and the rest of the body are unchanged.
  • designer-members-retired-11434.test.ts, the two edited @ts-expect-error descriptions: the relationships row now reads "declare a lookup field whose referenceTo names the related object" (the literal is an ObjectDefinition, a designer-face document, so the designer-face arm is the right one), and the validationRules row reads "put min / max / minLength / maxLength in the field metadata" (the four keys live on the spec's FieldSchema, not on DesignerFieldDefinition, which the added "in the field metadata" now says) — right; description text only, the directives and the assertions beneath them are unchanged, and Type Check on this head compiles the file.
  • Left as ordered and still accurate: the docblock's earlier spec sentence ("a lookup / master_detail field with a reference"), the validationRules docblock and migration line, the onUpdate lines (spec-face only).

Accept set and public surface: no accept-set move and no public-surface move in the delta. The seven tombstones, the two removed types and mirrors, the plugin-designer props and input row, the i18n keys, the ledgers (UnmirroredDeclared 6 / 18, EXPECTED_MIRROR_PAIRS 190), the 7340 census and the dated notes stand exactly as judged right at the previous head.

② Semver level

Unchanged by the delta and right: PR body Clause-②: yes; @object-ui/types minor with the BREAKING (authoring) banner, the Clause-②: yes line and one migration line per member — the relationships line is now the text that should ship; @object-ui/plugin-designer minor BREAKING (TypeScript props); @object-ui/i18n patch; @object-ui/app-shell patch; no skip-changeset. The four changeset gates (Changeset Declaration, Changeset Claim Re-read, Changeset Bump Policy, Changeset Fixed Group Check) are green on this head. The one caveat the first record attached to the @object-ui/types changeset — its migration text carried the ① defect — is closed.

③ Boundary flags

  • Patch-round-2 report: open_questions empty, out_of_scope_findings empty.
  • Deviations: the two @ts-expect-error descriptions beyond the order's four carriers — the seat order asked for the PR's diff to be grepped for other face-mixing prescriptions and fixed the same way, so this is the order followed, not widened; test-file text only — answered, right. The one PR-body edit, read back identical with the session-URL footer intact — right. The worktree re-created at the remote head and not merged with main — right (the delta is one commit on the reviewed head, which is what keeps this a delta review).
  • The seat order's "⛔ leave them" (the docblock's spec sentence, the changeset's TypeScript example) — honoured.
  • The new commit carries the model-free trailer pair.
  • Nothing to escalate.

Shape: draft PR, head repo = base repo, 39 files / 1,138 changed lines, needs:contract-review on the PR, no governed path in the file list (Governed Surface Queue Guard green on this head).

Implemented-by: claude/issue-11434-designer-members
Reviewed-by: session_01YLg8XqWGJ785fwQ5v4pH37

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 07:49
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 2, 2026 07:49
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit c4ab6d0 Oct 2, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11434-designer-members branch October 2, 2026 08:04
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Oct 7, 2026
…ashboard:metric / metric-card (objectui#10859 batch 8, phase 2b) (objectstack-ai#11453)

Part of objectstack-ai#10859

Clause-②: yes

Phase 2b of batch 8 on the family card. Twelve node type keys leave the
registry: ten are unregistered, and the `metric` / `metric-card` node
keys lose their bare fallback while both dashboard surfaces emit the
namespaced keys. Fourteen keys the ruling also named fail the premise
gate, so they stay registered and are reported as forks with the
evidence. Implemented by `os-dev` for `domain:ui` seat 1, session
`session_01YLg8XqWGJ785fwQ5v4pH37`. It follows the "Phase 2b" section of
seat ruling `5945530142`, as amended by `5945583855`, and the
coordinator's conditional premise gate.

## Premise gate: re-measured on `origin/main` 990a2d6 and later

Each key was searched for producers in source, `examples/**`, the
catalog, docs and the whole objectstack tree at `6c5bef5f`, and for
runtime emission.

| key | producers | runtime emission | disposition |
|:--|:--|:--|:--|
| `scatter-chart` | 0 | 0 | **retired** (unregistered) |
| `dashboard-grid` | 0 (objectstack names it only as a host type in its
own `sdui-parser` lint, which reads it) | 0 | **retired** (unregistered)
|
| `form-analytics`, `import-wizard`, `shared-view-link` | 0 | 0 |
**retired** (unregistered) |
| `app-creation-wizard`, `branding-editor`, `dashboard-editor`,
`navigation-designer` | 0 | 0 | **retired** (unregistered) |
| `related-list` | 0 | 0 | **retired** (unregistered) |
| `metric`, `metric-card` | 0 standalone; the dashboard WIDGET
vocabulary only | `DashboardRenderer`, `DashboardGridLayout` | **emitter
moved** (M3 option A), `skipFallback: true` |
| `pie-chart`, `donut-chart`, `radar-chart` | **1**: see fork 1 | 0 |
**fork**, still registered |
| `page-header` | **objectstack**: see fork 2 | 0 | **fork**, still
registered |
| the ten `sidebar-*` | only the four catalog documents the ruling
orders rewritten | 0 | **fork**, still registered: see fork 3 |

### Fork 1: `pie-chart`, `donut-chart`, `radar-chart` have an in-repo
producer

`packages/plugin-charts/examples/chart-examples.ts` exports
`pieChartExample`, `donutChartExample` and `radarChartExample`, which
author `type: 'pie-chart'`, `'donut-chart'` and `'radar-chart'`.
objectui#7401's describe block "the in-repo examples draw what they say"
renders those three objects (ruling item 3 of that card). The file is
not in the package's `files`, so it does not ship, but it is a producer
pinned by a ruled test. `scatter-chart` has no example there, so it
passed the gate on its own and is retired.

⚠️ Phase 1 counted this file as source without classifying it as a
producer. That miss is why the ruling listed all four chart aliases
together.

### Fork 2: `page-header` is authored by objectstack

On objectstack `origin/main` `6c5bef5f`, the spec conversions registry
carries `PAGE_HEADER_COMPONENT_TYPES = new Set(['page:header',
'page-header'])` and the conversion `page-header-subtitle-alias`
(toMajor 17, "Live window; retires at 18"). Its docblock says the key
"is authorable here because PageComponentSchema.type is deliberately
z.union([PageComponentType, z.string()])". It also says "The alias's
entire reason to exist is out-of-repo consumer schemas" and "That
registration is objectui's to retire, on its own schedule". Its fixtures
author `{ type: 'page-header', properties: {...} }`.

⚠️ Phase 1 did not search objectstack's `packages/spec`. It searched
only examples, apps, content, skills and `packages/studio`.

### Fork 3: the `sidebar-*` family's teaching rewrite has no target

No new producer or emitter turned up. But the ruling ties this
retirement to rewriting the four `components-basic-sidebar` documents
and `sidebar.mdx` "to what the armed `sidebar` both renders and accepts,
measured by a render and a validate". The armed `sidebar` calls
`useSidebar()`, which throws outside a `SidebarProvider`, and the only
authored provider is the `sidebar-provider` primitive this retirement
removes. The measurements below come from a temporary probe test, run
through `SchemaRenderer` with both validator faces and deleted
afterwards:

| node | host | render | tolerant | strict |
|:--|:--|:--|:--|:--|
| bare `sidebar` with `text` children | no provider | throws "useSidebar
must be used within a SidebarProvider." | ok | ok |
| the same | the docs-site wrapper (`InteractiveDemo`: `SidebarProvider`
with `defaultOpen={false}`) | mounts, but `data-state="collapsed"`
`data-collapsible="offcanvas"`: shadcn's offcanvas collapse draws it
off-screen | ok | ok |
| `collapsible: true` | docs-site wrapper | `data-collapsible="true"`,
which no CSS rule matches, so it shows only by accident | ok | ok |
| `collapsible: 'none'` (the in-flow form) | docs-site wrapper | renders
in flow | refused, `invalid_type` at `collapsible` | refused |
| `side` / `variant` / `className` | docs-site wrapper | renders | ok |
refused, `unrecognized_keys` `side` |
| today's `basic-sidebar.json` (`sidebar-provider` root) | docs-site
wrapper | renders expanded | refused at `type` | refused at `type` |

Once `sidebar-provider` is gone, no `sidebar` document both draws
visibly and validates, apart from the `collapsible: true` accident. The
four catalog documents would have nothing honest to be rewritten to.
They cannot keep their retired types either, because `check:doc-types`
admits an exemption only where a retired value appears at a legitimate
position. Forcing it through or quietly picking a fallback were both
ruled out, so the ten stay registered and the teaching is unchanged. The
options are in the report on the card:
- **A.** The `sidebar` registration supplies its own `SidebarProvider`.
Then a bare `sidebar` renders in any host and the teaching rewrite
becomes possible.
- **B.** Arm `sidebar-provider` (declare it) and retire the other nine.
- **C.** Retire as ruled, and teach the bare node as host-provider-only
(it draws collapsed and off-canvas in the docs host).

## What changed

- **Unregistered, each with a tombstone docblock** at its old
registration site (the objectui#10393 / objectui#8760 route). Each
docblock says what was there, why it went, and that the React export
stays where one exists:
- `scatter-chart` (`plugin-charts`), along with its
`CHART_TYPE_KEYWORD_FAMILIES` row;
  - `dashboard-grid` (`plugin-dashboard`);
- `form-analytics` (`plugin-form`), `import-wizard` (`plugin-grid`) and
`shared-view-link` (`plugin-view`);
- `app-creation-wizard`, `branding-editor`, `dashboard-editor` and
`navigation-designer` (`plugin-designer`), under one block;
  - `related-list` (`plugin-detail`).
- **The metric emitter move (M3 option A).**
- `widgetDispatch.ts` gains `DASHBOARD_NODE_TYPES` (`metric` maps to
`plugin-dashboard:metric`, `metric-card` to
`plugin-dashboard:metric-card`) and `toDashboardNodeType`.
  - Both surfaces emit through that table for:
    - the static metric tile;
    - the `metric-card` widget-slot passthrough;
- a `metric` / `metric-card` node in the legacy `component` envelope.
- The two registrations take `skipFallback: true`. The widget vocabulary
and the 2026-08-14 `metric-card` slot ruling are untouched.
- **`dashboardComponents`** loses `dashboard-grid`. Its metric pair is
now keyed by the namespaced type each entry serves, so iterating the map
cannot re-create the retired bare keys.
- **Console.**
  - The `scatter-chart` and `dashboard-grid` lazy stubs are gone.
- The `metric` / `metric-card` stubs, in `register-plugins.ts` and
`preview-gallery.tsx`, pass `skipFallback: true`.
- **Teaching corrected.**
- The key tables in the `plugin-dashboard`, `plugin-form`, `plugin-grid`
and `plugin-view` mdx pages and READMEs: the retired rows are gone, the
metric rows read "none — `skipFallback: true`", and the call counts are
updated.
- The two standalone `metric-card` examples in the dashboard README now
sit in a dashboard's `widgets[]`.
  - The mdx Metric Card block is introduced as that slot entry.
- The `schema-reference.md` sentence about the editable grid no longer
calls it `dashboard-grid`.
- Present-tense comments about the `dashboard-grid` registration are
updated.
- **Doc gate.** Eight per-file `DOC_TYPE_EXEMPTIONS` rows, only at
widget-vocabulary positions:
  - `metric` (a `ChartTypeSchema` widget kind) in four files;
- `metric-card` (a `DASHBOARD_COMPONENT_WIDGET_TYPES` slot entry) in
four files.
- **Regenerated** `packages/cli/src/utils/known-schema-types.ts`: 22
deletions, 12 bare keys and 10 namespaced twins.

### Tests re-pointed (each named a retired key)

- **7401 chart family:** the two `scatter-chart` render cases become
`chart` with `chartType: 'scatter'`, plus an absence row for both
spellings.
- **DOM-leak sweep:**
- the scatter arm is now swept through `plugin-charts:chart` with
`chartType: 'scatter'`;
  - the `dashboard-grid` target is gone;
  - the counts table is now 8 / 7, and 181 targets in all.
- **The `dashboard-grid` tests:**
- Six `DashboardChart` / `seriesLabel` tests and one
`invalidationRefetch` case mount `DashboardGridLayout` directly, as
their `DashboardRenderer` twin already did.
- `DashboardGridLayout.sduiDatasetPath` becomes the retirement pin: a
stored `dashboard-grid` node draws the unknown-type refusal, and
`dashboard` is the control.
- **Metric tests:**
  - the `MetricWidget.domProps` standalone cases use the namespaced key;
- the 11022 strict-face test reads the inputs in the `plugin-dashboard`
namespace;
- the README harness now strips a one-line type alias, so the moved
Metric Card example is judged.
- **cli recogniser:** its unmodelled-type fixture is now
`plugin-dashboard:metric-card`.
- **Console stubs test:** `scatter-chart` joins its `RETIRED` set, and
the list length is 6.
- **`dashboardComponents` parity:** 7 keys, plus a row asserting that
the retired keys stay out of both the map and the registry.

## Ratchet

| pin | before | after | what moved |
|:--|:--|:--|:--|
| `REFUSED_AT_TYPE` (bare) | 36 | **24** | the twelve keys above |
| `NAMESPACED_REFUSED_AT_TYPE` | 389 | **379** | the ten namespaced
twins of the unregistered keys |

The ruling's target was 10. The difference is the 14 forks. The pin's
comment names all 24 remaining keys: the ten the ruling kept
(objectui#11440 and objectui#11441) and the fourteen forks, each with
its reason. A new row pins the refused set to exactly that named list
(`STILL_REFUSED_10859`), so the comment cannot drift. Another new row
asserts that the twelve are out of the population and still refused at
`type`, that the ten twins are gone, and that both namespaced metric
keys are still present. ⛔ Neither pin rises.

## Changesets

There is one `minor` changeset per released package whose code moved.
Each carries a BREAKING (authoring) banner and a migration line per
retired spelling:
- `plugin-charts`, `plugin-dashboard`, `plugin-form`, `plugin-grid`,
`plugin-view`, `plugin-designer` and `plugin-detail`;
- `cli` (the regenerated list);
- `console` (the stubs).

The `plugin-dashboard` entry also covers:
- the `dashboardComponents` re-key;
- the `data-obj-type` change on KPI tiles (`plugin-dashboard:metric`).

`app-shell` changed one test file only, so it has no entry (the
objectui#10393 precedent).

Four pending changesets described a retired key in the present tense:
7401, 10528, 7509 and 7997. Each gains a dated note, and each one's
frontmatter is byte-identical.

## Local runs

All runs are from the worktree root. Heavy runs went through
`os-verify-lock`.

**At the final head `f0d0abe29`:**
- The union of 61 test files, run with `pnpm exec vitest run
--maxWorkers=2` and the listed paths:
  - every test file this PR edits;
- the ratchet, `known-schema-types-derivation-5115`,
`check-known-types`, `registry-bare-name-collisions` and
`check-doc-component-types.test.ts`;
  - `unit-registry-absence-collision`;
- every dashboard / designer / app-shell test that authors a `metric` /
`metric-card` type;
  - the two `@object-ui/types` designer tests that objectstack-ai#11451 touched.
- Result: `Test Files 61 passed (61)`, `Tests 1072 passed (1072)`,
VERDICT command-exit 0.
- Type-check: `pnpm --filter @object-ui/plugin-designer type-check` and
`pnpm --filter @object-ui/cli type-check` both exit 0, after rebuilding
their closures (objectstack-ai#11451 changed `@object-ui/types`).
- Exit 0 for each of:
- `pnpm check:doc-types` (886 registered + 290 exempted type sites; 45
key-table keys judged, 45 registered);
- `pnpm check:doc-snippets` (775 of 775 blocks judged, 0 failed, after
its scoped build);
  - `pnpm check:doc-example-ids` and `pnpm check:doc-fences`;
  - `python3 scripts/regenerate-catalog-index.py --check`;
  - `node scripts/markdown-test-inputs.mjs --audit`;
  - `node scripts/check-doc-links.mjs`;
- `node scripts/check-changeset-presence.mjs` (37 source files of 10
released packages, 9 changesets);
  - `node scripts/regenerate-known-schema-types.mjs --check`;
- `check:registry-bare-names`, `check:prompt-keys`,
`check:readme-exports`, `check:control-bytes`,
`check:new-line-citations` (0 new);
- `changeset:check`, `check:pending-changeset-literals`,
`check:changeset-claims`.

**At `9eb0f580e`** (after the first `main` merge; the code is the same
as the final head apart from objectstack-ai#11451 and one test file):
- Exit 0 for each of:
- `check:doc-examples`, `check:handler-key-reads`, `check:spec-symbols`,
`check:component-surface-parity`, `check:test-path-roots`;
- `check:element-data-source-declaration`, `check:unreferenced-sources`,
`check:doc-example-readers`, `check:self-import`;
- `check:vi-mock-inherit`, `check:vi-mock-specifiers`,
`check:side-effects-array`, `docs:check-links`;
- `check:sdui-registration-pins` (17 of 17 present, after `pnpm --filter
@object-ui/console build`).
- Type-check: `pnpm --filter X type-check` exits 0 for `plugin-charts`,
`plugin-dashboard`, `plugin-form`, `plugin-grid`, `plugin-view`,
`plugin-designer`, `plugin-detail`, `cli`, `app-shell` and `console`.
This ran after `pnpm --filter '@object-ui/console^...' --filter
'@object-ui/cli^...' build`.
- ESLint, narrowed:
- `eslint --no-inline-config --format json` over the 38 changed
ts/tsx/mjs files gives 0 errors.
- Each file's error count equals its base blob's. Warnings are equal or
lower: `plugin-form` index 23 to 22 and `plugin-grid` index 16 to 14,
because the removed renderers carried the `any`.
- The population is the root `eslint.config.js`. It sets no
`projectService` / `parserOptions.project`, so no untouched file's
verdict can move. Full `pnpm lint` is CI's.

**Earlier wide runs**, before the fixes listed:
- `packages/plugin-view/ packages/plugin-designer/
examples/schema-catalog/test/`: 137 files, 3074 tests, all passed.
- The registry-touching tests of `plugin-form`, `plugin-grid` and
`plugin-detail`: 27 files passed.
- 64 dashboard-consumer tests in `app-shell` / `react` / `plugin-report`
/ `components` / `scripts`: all passed.
- `packages/plugin-dashboard/`: 159 of 160 files passed. The
README-harness file was red and was re-run green after its fix.
- `packages/plugin-charts/ packages/cli/`: 109 of 110 files passed. The
recogniser file was red and was re-run green.
- `apps/console/src/__tests__/` plus the sweep plus the doc-types gate
test: 45 of 47 files passed. The stubs test and the exemption-shape pin
were red and were re-run green.

## Reverse verification

The prediction was written to the scratchpad before either leg ran.

**BASE leg.** The thirteen changed source files went back to BASE
`990a2d616`, the new and edited tests stayed, and the five pin files
ran.
- **Predicted:** 13 red. That is 4 ratchet (count, namespaced, phase-2b
row, exact set), 2 map parity, 2 `sduiDatasetPath`, 1 chart-family 7401
and 4 console stubs, with the controls and earlier batch rows green.
- **Observed:** `Tests 13 failed | 49 passed (62)`. The red tests are
exactly those 13, including "refuses 36 registered bare key(s) at
`type`; the pin is 24" and "refuses 389 … the pin is 379".
- **Restored:** 13 blobs equal HEAD, `git diff HEAD` is 0 lines, and
status is 0 lines.

**Ablation.** `skipFallback: true` was dropped from the `metric-card`
registration with `scripts/ablation-replace.mjs`, run from
`../objectstack`. The anchor went from 1 hit to 0, and the blob from
`8a84c9f79e32` to `ea900ba0f0d1`.
- **Leg 1** (source only): `known-schema-types-derivation-5115` went red
("expected [ 'metric-card' ] to deeply equal []", plus the byte-for-byte
regen case), and the map-parity retired row went red (registry key
`metric-card` was `MetricCard`). Result: `Tests 3 failed | 14 passed
(17)`.
- **Leg 2** (list regenerated from the mutated source): the ratchet went
red with "refuses 25 registered bare key(s) at `type`; the pin is 24",
with `metric-card` in the Refused list. The phase-2b row and the
exact-set row were red too. Result: `Tests 3 failed | 21 passed (24)`.
- **Restored:** the tool's restore reports blob equal to HEAD and an
empty `git diff HEAD`. A second trap restored the known-types file, and
its blob `fa94132ef625` equals HEAD.

## Acceptance notes

- `DASHBOARD_WIDGET_HOST_TYPES` in `sdui-parser` still lists
`dashboard-grid`, in both the objectui copy and the objectstack copy. It
is now a reader of a retired key. It is left unchanged so the two copies
stay in step. Carrier: none.
- `ROADMAP.md` still lists the four designer keys under "Registered". It
is a dated progress list, so it is left as is.
- The `plugin-grid` README key-table rows carried line addresses that
were already stale on `main`. The `import-wizard` row is gone, and the
others are untouched.
- The `MetricWidget.domProps` cases (a) to (c) kept passing once their
bare key stopped resolving, because negative assertions over an "Unknown
component type" panel stay green. Pointing them at the namespaced key
makes them bite again.
- `DashboardGridLayout` is no longer swept by the DOM-leak sweep, since
it is not a registered widget any more.
- A legacy report section with `chart.type: 'scatter-chart'` now reaches
the generic `chart` with no derived family. The changeset states this.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants