Repository navigation
feat(types): TypeScript node types for the authored properties-bag carriers (flex and the eight object-* blocks), by reference, joined into AuthoringNode (objectui#11468) - #11477
Conversation
…carrier outside the public blocks, by reference, joined into AuthoringNode (objectui#11468) The eight ObjectQLPublicBlockComponentSchema arms and FlexBlockSchema had a zod arm and no TypeScript node type. Each is now its arm's own authoring input, derived as PublicBlockNode is: ObjectQLPublicBlockNode (one member per arm), the eight ObjectXBlockNode aliases picked from it, and FlexBlockNode. All of them join AuthoringNode, so SchemaRenderer's schema prop accepts them. The derivation now reads a bag's shape the way it reads the arm's. flex and object-chart have no spec row, so their bags are the flat mirrors' own .passthrough() members; reading the arm's shape alone left each bag open. A spec-row bag is already closed, and the 27 public blocks are typed exactly as before (pinned). Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…lexBlockNode; changeset (objectui#11468) The example annotated its root flex node BaseSchema and checked each bag with satisfies FlexLayoutProps, which typed the nested flex node's bag against SchemaNode. Both flex nodes are now FlexBlockNode, the arm's own input. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…ode types, not BaseSchema (objectui#11468) Each doc block that authors an object-grid, object-form, object-map, object-gantt or flex node in its properties bag now annotates the arm's node type (ObjectGridBlockNode, ObjectFormBlockNode, ObjectMapBlockNode, ObjectGanttBlockNode, FlexBlockNode). The bag is checked against the arm, and the block keeps compiling once BaseSchema's index signature goes. The types README lists the new node types; its nested flex example names each inline child's type with satisfies, because the flex bag's child list is unknown[] as the arm declares it. Five plugin-map.mdx blocks keep BaseSchema: each also writes onMarkerClick on the node, a key the object-map arm does not declare and its node type refuses. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
… structural fit (objectui#11468) A typed FlexBlockNode constant fits BaseSchema-without-its-index-signature structurally whether or not AuthoringNode includes the carriers, so that assertion could not fail. An inline flex literal where SchemaRenderer takes a schema compiles only through AuthoringNode. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Inputs: card #11468 (body and both comments: the claim 5954372420 and the os-dev-report 5955478276), PR #11477 (body, the 16-file list, the net diff against ① Derived judgments
② Semver level
Clause-②: yes. The card's claim and the PR body both say yes, and the diff publishes ten new exported types on ③ Boundary flagsThe report's
Check-runs on the head: read 2026-10-02T15:20:46Z, 30 completed (success, or skipped for the coverage and dependabot jobs) and 11 in progress; read 2026-10-02T15:26:23Z, 33 success, 3 skipped, 6 in progress (Type Check, Test shards 2, 3, 4, 5, 8); final read 2026-10-02T15:27:48Z, just before this post: 37 success, 3 skipped, 2 in progress (Test shards 2/8 and 4/8), nothing red. Bearing on the contract: Type Check, the gate for every type-level pin and for the read-side consequence in ① 2, completed success at 15:26:36Z; Doc Snippet Type Check, Doc Component Type Check, README Export Check, Build Docs, Lint, Spec Main Shape Gate and the four changeset checks are success. The two pending shards can only carry the one runtime premise test (every carrier arm and both mirror bags are zod objects), whose premises I read directly off the head's sources above; six of the eight shards and Test (dist pins) are already success. No red or pending run bears on this verdict. Implemented-by: VERDICT: PASS |
Fixes #11468
Clause-②: yes
F3 of objectui#8347 (that card stays open and waits on this one and its two siblings). Dispatched by the
domain:spec @ objectuiseat (objectui#10217) and implemented by an os-dev subagent of sessionhttps://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC. Generic parameters below are spelled in words (for example "a record of string to never"), because GitHub strips tag-shaped text from a body.What changes on the published face
@object-ui/typesadds ten exported types. Each is derived by reference from its zod arm, and none is restated:ObjectQLPublicBlockNodeObjectQLPublicBlockComponentSchema, each the arm's own input: the derivationPublicBlockNodeusesObjectMetricBlockNode,ObjectMasterDetailFormBlockNode,ObjectTimelineBlockNode,ObjectFormBlockNode,ObjectMapBlockNode,ObjectChartBlockNode,ObjectGanttBlockNode,ObjectGridBlockNodeObjectQLPublicBlockNodefor eachtypeFlexBlockNodeFlexBlockSchemaarm's inputAuthoringNodegains two members: it is nowPublicBlockNode | ObjectQLPublicBlockNode | FlexBlockNode | ElementTextInputNode | ElementRecordPickerNode | PageDocumentNode. The type expression ofSchemaRenderer'sschemaprop does not change (BaseSchema | AuthoringNode | string | null | undefined), and the prop accepts the nine carriers throughAuthoringNode. No zod schema, renderer or runtime code changes.Accept set, before and after (TypeScript face only)
object-map,object-gridor other carrier node, or aflexnode, had no TypeScript type. The docs annotated itBaseSchema, whose index signature accepts any key, so a misspelled bag key compiled.childrenorbody, as the zod arm and the strict authoring face do.The one derivation change: the bag is read closed, like the arm
ClosedArmInputread an arm's shape with the object config left closed, but it read thepropertiesmember as it stood.flexandobject-charthave noComponentPropsMaprow. Their bags are the flat mirrors' own members (FlexPropsBag,ObjectChartPropsBag), kept.passthrough()for the tolerant face (objectui#11276). So the shape-only read left each of those bags with an index signature of unknown, and a misspelled bag key compiled. The derivation now reads the bag's shape too (ClosedBag), so the TypeScript face is closed where the strict authoring face closes it.A spec-row bag is already closed.
PublicBlockNodeis unchanged, and an exact type equality pins that. Measured: among the nine carrier arms, the shape-only read leaves exactly two bags open (flexandobject-chart). Among the 27 public blocks it leaves none (theelement:dividerbag is a record of string to never, which refuses every key).Pins
All in
packages/types/src/__tests__/authoring-nodes-bag-carriers-11468.test.ts. The type-level assertions are judged by the package'stype-checktest leg:typesets equal the arms' own, for the eight-arm union and forflex.AuthoringNodeare exactlyObjectQLPublicBlockNode | FlexBlockNode.AuthoringNodemember has an open bag. The control: the shape-only derivation leaves exactlyobject-chartandflexopen.PublicBlockNodeequals the shape-only derivation, so closing the bag changes nothing for a spec row.The behaviour checks use the 11364 pin file's method:
BaseSchema's index signature is stripped at the type level, so they run now and after the removal.object-map: the spelled bag compiles. A misspelled bag key and a flat prop are refused.flex: the bag is closed. A flat prop, a node-levelchildrenandbodyare refused. An inline literal compiles at the prop.object-chart: the bag is closed.Ablations (run once and restored, not kept as tests)
Each ran through
ablation-replace.mjsin wrap mode against the committed head, with the two authoring-nodes pin files compiled by tsc:propertiesmember read as the arm declares it): 3 errors. The no-open-bag assertion fails with TS2344, and the closed-bag@ts-expect-errordirectives in the flex and object-chart cases become unused (TS2578). ThePublicBlockNodeequality stays green, as predicted.AuthoringNode: 3 errors. The join assertion fails with TS2344, and both inline literals (object-map and flex) are refused at the post-removal prop with TS2353 onproperties.The restore was proven each time: the blob equals the HEAD blob, and
git diff HEADis empty. The first attempt of each was refused by the tool before it measured anything, because the replacement text was a substring of the anchor. Each was restored and re-run with a distinct replacement.An earlier fifth type-level assertion ("every carrier fits the post-removal prop") still passed with the join removed, because a typed constant fits
BaseSchemastructurally either way. The flex inline literal replaced it, and that literal does discriminate.The doc corpus, re-judged under the P1 mutation
The P1 mutation deletes
BaseSchema's index signature and its docblock (wrap mode, restored afterwards) and rebuilds@object-ui/types. The dist then carries 1 signature, onComponentRendererProps. The readings are fromcheck:doc-snippets,check:doc-examples,check:doc-typesand the types examples' tsc.d93e53f5, all at baseThe base column matches the parent's P1 census (46 F3 diagnostics in 75).
crumbs, explained under "flex child list"). The 41 are 39 re-annotated blocks plus 2 inlineSchemaRendererobject-gridliterals in objectos-integration.mdx, which compile throughAuthoringNodewith no edit.Without the mutation, at head:
check:doc-snippetsjudged 776 of 776 blocks with 0 failed, andcheck:doc-examplesandcheck:doc-typesexit 0.Every document re-judged:
content/docs/plugins/plugin-map.mdx: 7 blocks re-annotated asObjectMapBlockNode. 5 keepBaseSchema(H3).content/docs/plugins/plugin-gantt.mdx: 10 blocks,ObjectGanttBlockNode.packages/plugin-grid/README.md: 11 blocks,ObjectGridBlockNode. Theirsatisfies ObjectGridPropsbag checks are kept.packages/plugin-form/README.md: 2 blocks,ObjectFormBlockNode.packages/plugin-map/README.md: 2 blocks,ObjectMapBlockNode.packages/plugin-gantt/README.md: 1 block,ObjectGanttBlockNode.content/docs/guide/objectos-integration.mdx: 1 block,ObjectGridBlockNode. Its 2 inline literals needed no edit.content/docs/utilities/index.mdandcontent/docs/utilities/data-objectstack.mdx: 1 block each,ObjectGridBlockNode.README.md: 1 block,ObjectFormBlockNode.packages/types/README.md: the nested flex block isFlexBlockNode, and its twosatisfies FlexLayoutPropsbag checks are replaced ("flex child list" below). "Authoring the spec's blocks in TypeScript" lists the new types.packages/types/examples/dashboard.ts: both flex nodes areFlexBlockNode(the outer one annotated, the inner one withsatisfies).H3: five plugin-map.mdx blocks author a key the arm refuses
The blocks are
clickableMap,storeLocator,deliveryMap,propertyMapandserviceMap. Each writesonMarkerClick(a function) on the node, beside the bag. The page teaches "a schema built in code carries it on the node, beside the bag".ObjectMapBlockSchema, not the TS twinObjectMapSchema. The strict face refuses it as an unrecognized key.ObjectMapBlockNode, each block failedcheck:doc-snippetswith TS2353 ononMarkerClick(measured). The type was not widened.BaseSchema. They compile while the signature exists, and under the mutation each still fails (onproperties, the first excess key TypeScript reports).onEventClick,onDateClick). The P1 census did not see these five, because TypeScript reportedpropertiesfirst.ObjectMapBlockNode, so the annotation can move once the handler key has a disposition.flex child list
FlexBlockSchemadeclaresproperties.childrenas a list of unknown, because the page walk judges each entry. The node type carries that by reference, soFlexBlockNodedoes not check a child written inline in a flex bag. The types README and the dashboard example name each inline child's type withsatisfies(FlexBlockNode,HeaderBarSchema). That is also what removes the types READMEcrumbsdiagnostic that P1 classed as F1: the header-bar child is now checked againstHeaderBarSchema, which declarescrumbs. Nothing is widened or narrowed.Gates, all at head
333f5a89unless namedpnpm --filter @object-ui/types run type-check(src, examples and tests): exit 0.pnpm --filter @object-ui/react run type-check(the reader ofAuthoringNodethroughSchemaRendererProps): exit 0.pnpm exec vitest run --maxWorkers=2 packages/types/, from the worktree root: 331 files and 8766 tests passed. The two authoring-nodes pin files run by name: 2 files and 11 tests passed.check:doc-snippets(776 of 776 judged, 0 failed),check:doc-examplesandcheck:doc-types: exit 0, after a rebuild of@object-ui/typesat head.check:control-bytes,check:new-line-citations(0 new),check:test-path-roots,check:pending-changeset-literals,check-changeset-no-major,check-changeset-presence(1 package, 1 changeset),check:readme-exports,check:doc-fences,check:doc-example-ids,check:doc-example-readers,check:spec-symbols,check:handler-key-reads,check:unreferenced-sources: exit 0.check:changeset-claimsis report-only. It names 12 pending changesets that cite a file this change touches. I read each paragraph, and none is falsified (the edits change annotations only).eslinton the 4 changed TS files gives 0 errors and 0 warnings. The repository lint run is CI's.check:component-surface-parityandcheck:sdui-registration-pins, because no registration input moved. Other packages' vitest was not run, because no runtime code changed.Overlap with in-flight work
packages/types/src/index.ts(read uncommitted in its worktree). Whichever lands second mergesmain. F1's slot union includesAuthoringNode, so the nine carriers flow into it.Acceptance notes
Generated by Claude Code