Repository navigation
feat(types)!: an authored object-form takes its props in the spec's properties bag; the flat spelling is refused by name (objectui#10859, batch 4) - #11291
Conversation
…the flat spelling is refused by name (objectui#10859, batch 4)
New `ObjectFormBlockSchema`: BaseSchema + the `object-form` literal +
`properties` = propsBag('object-form', stripImportedDefaults(SpecObjectFormPropsSchema)),
the node's `dataSource` binding by reference, one aliasKeyRefusal per member
of the row (read off the row) pointing at `properties.KEY`, the five runtime
slots and the objectui#9256 content-channel refusals. It joins
ObjectQLPublicBlockComponentSchema; the flat ObjectFormSchema mirror leaves
ObjectQLComponentSchema and stays published as the post-hoist reading paired
with its TypeScript twin.
Census rows and fixture respellings the move forces, and the two
schema-catalog object-form fixtures rewritten to the bag.
Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
Co-authored-by: Claude <noreply@anthropic.com>
…oist reading; point the form `mode` refusal at the bag (objectui#10859, batch 4) The TypeScript twin stays published with its members unchanged: it is the node as ObjectForm reads it after SchemaRenderer hoists `properties`, and as code composes it. The zod README lists ObjectFormBlockSchema, and the `form` node's `mode` refusal teaches the bag spelling of an object-form node. Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ Co-authored-by: Claude <noreply@anthropic.com>
…ties bag; render pin and changesets (objectui#10859, batch 4) The root README, the schema reference, the CRUD guide, the ObjectOS migration fragment, the plugin-form page and the plugin-form README author object-form in the bag. The guide's render test reads the snippet's bag. A plugin-form render pin draws the showcase wizard node through the real registry, beside the flat spelling code composers still build. Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ Co-authored-by: Claude <noreply@anthropic.com>
…e authored after the bag move (objectui#10859, batch 4) Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ Co-authored-by: Claude <noreply@anthropic.com>
…ctui#10859, batch 4) Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ 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: PR objectui#11291 (draft, 27 files, +874 / −140 against the merge base ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
Part of #10859
Clause-②: yes
Clause-②: yes, copied from the PM claim5920453930:@object-ui/types' authoring faces narrow (a flatobject-formnode that parsed is refused) and widen (a spec-shaped bag node that was refused parses). This is objectui's narrowing-as-minorrule with a BREAKING (authoring) banner in the changeset, as batches 1 to 3 and the answer's step 2 state.Batch 4 of objectui#10859. It executes the seat's flat-arm answer at PR objectui#11248's ACCEPT (
5917261346) for ONE block,object-form: "A governs, by inheritance" from objectui#10872's triage answer A (5906817482), "Thepropertiesbag is the contract". The card stays open for the rest of the flat-arm fork (object-map,object-gantt), the designer six and the (ii) / (iii) keys.What changed
packages/types/src/zod/objectql.zod.ts: newObjectFormBlockSchema, the batch-2/3 construct. It isBaseSchema, plus theobject-formliteral, plusNODE_ENVELOPE, plusproperties=propsBag('object-form', stripImportedDefaults(SpecObjectFormPropsSchema)): the shared helper and the installed 17.5.0 row by reference, with no copy. Beside it:dataSource, the spec'sElementDataSourceSchemaby reference (the registration iselementDataSourceBlock-wrapped; the flat mirror has declared it since objectui#11070);aliasKeyRefusalper member of the row, keyed by the row's own key set read off the crossed row, so each prop written flat is refused on both faces withDid you mean KEY → properties.KEY?and one prescription string that shows the whole bag document;ObjectFormreads off the node (onSuccess,onCancel,onError,onOpenChange,onStepChange), declared exactly as on the flat mirror;body/childrenrefused with the flat mirror's objectui#9256 string.ObjectQLPublicBlockComponentSchema.ObjectFormSchema(the flat mirror) leavesObjectQLComponentSchema, stays exported, and stays paired with its TypeScript twin in the parity census.packages/types/src/objectql.ts: the TypeScriptObjectFormSchemais re-declared, not retired. Its members are unchanged; its docblock now says what it is: the node asObjectFormreads it afterSchemaRendererhoistsproperties, and as code composes it. The TypeScript union's docblock names the zod union's new count.packages/types/src/zod/form.zod.ts: theformnode'smoderefusal taught a flatobject-formdocument. Its prescription now writes the bag.packages/types/src/zod/index.zod.ts(one barrel export) andpackages/types/src/zod/README.md(the ObjectQL public-block group lists the arm).README.md,content/docs/api/schema-reference.md,content/docs/guide/building-crud-app.md,content/docs/guide/objectos-integration.mdx,content/docs/plugins/plugin-form.mdx, both schema-catalogobject-formfixtures, andpackages/plugin-form/README.md.packages/types/src/__tests__/object-form-properties-bag-10859-b4.test.tsandpackages/plugin-form/src/__tests__/objectFormPropertiesBag-10859.test.tsx..changeset/10859-object-form-properties-bag.md(@object-ui/typesminor, BREAKING (authoring) banner) and.changeset/10859-plugin-form-readme-object-form-bag.md(@object-ui/plugin-formpatch, README only).Files beyond the claimed surface, each forced and named:
zod-mirror-parity.test.ts: the oneEXCLUSIONSrow the new export forces; no pair moved (EXPECTED_MIRROR_PAIRSuntouched).imported-defaults-8317.test.ts: oneIMPORTEDrow for the new spec import.registered-type-arms-10859-b2.test.ts: its exactObjectQLPublicBlockComponentSchemaliteral list gainsobject-form.objectql-union-arms-7363.test.ts:ObjectQLComponentSchemaholds 11 arms, not 12, and a row thatobject-formis not among them.public-block-responsive-styles-10872.test.ts:object-formjoins the namedDECLARES_DATA_SOURCEset (it moved into the public-block population carrying the binding).strict-face-read-keys-11070.test.ts(oneBOUND_NODESrow),content-channel-e3-residual-9256.test.ts(the authoring-face reach row reads the bag; the mirror rows keep the post-hoist spelling),object-form-unmirrored-members-6152.test.ts(details under Acceptance notes),guideCrudAppRenders.test.tsx(reads the guide snippet's bag),catalog-gallery-render.test.tsx(its control uses the entries' spelling).Zone 2: the PM's mechanism assumptions, measured before building
@objectstack/spec17.5.0, and objectstackorigin/main75519e1c0a(spec source run withtsx):ComponentPropsMapcarries anobject-formrow, and it is the exportedObjectFormPropsSchema(same key set at both refs).PageComponentSchema.safeParse({ type: 'object-form', objectName: 'x' })refuses:unrecognized_keys ['objectName']("Unrecognized key(s) on this page component … ADR-0089 D3a"). Withmodebeside it:['objectName', 'mode'].propertiesare accepted, and the row accepts them.action:buttonactionTypeis refused the same way.f16c01e90e, the showcase wizard node (objectstackNewProjectWizardPage) was refused bysafeValidateSchema(objectNameinvalid_type,modeinvalid_value) and by the strict face (the same two, plusunrecognized_keys ['properties']). The flat control was accepted on both faces. The new pin on base, before the arm:Tests 58 failed | 7 passed (65). The 7 green rows are the lit controls, the row size check, the content-channel rows and the flat-mirror row, which all hold on base too.ObjectFormand its five variant forms (theschemaprop);ObjectView,RecordFormPage,ScreenView,AppContent,useActionModal,EmbeddableForm,MasterDetailForm,ViewPreview,StudioDesignSurface,ObjectManager,FieldDesigner);formslot (ObjectFormSlotKey; the zod slot isObjectFormSchema.omit(…).partial());Every one reads the post-hoist or code-composed flat node. None needs the authored shape, so the twin keeps its members and its publication. The authored node is typed by
BaseSchema(index signature) or the spec'sObjectFormProps. The bag arm is unpaired (oneEXCLUSIONSrow), as batch 2'sMasterDetailFormSchemasplit is. Type-level pins: the bag input equalsObjectFormProps | undefined, every row key is a refused flat member, and the twin staystype: 'object-form'withobjectName: stringandmoderequired, still theobject-formmember of the TypeScript ObjectQL union.schemaprop):README.md,schema-reference.md,building-crud-app.md,objectos-integration.mdx,plugin-form.mdx,object-form-record.json,object-form-tabbed-sections.json,packages/plugin-form/README.md(2 of its 3 nodes),form.zod.ts(a refusal's prescription)content/docs/utilities/data-objectstack.mdx({ type, dataSource }only)skills/objectui/guides/page-builder.md("Form plugin example")packages/cli/src/commands/validate.ts(a hint namingtype: 'object-form'withobjectName+sections)schemaprop, no hoist)examples/byo-backend-console/src/App.tsx(2),packages/plugin-form/README.md(theWizardFormmount), the@exampleblocks ofObjectForm/TabbedForm/WizardFormThis differs from batch 3's count ("13 authored") in two classes: the two
byo-backend-consolenodes and the two designer nodes are component mounts and code composers, not authored documents.5. Held. No composed node passes through
safeValidateSchema.SchemaRendererruns@object-ui/core's structuralvalidateSchema, and the only non-test callers of the zod faces areobjectui validate/objectui check. The render pin draws the flat spelling beside the bag.6. Not forced.
REFUSED_AT_TYPEdoes not move:object-formwas never refused attype. PR objectui#11069's files are untouched, andgit merge-treeof this head withorigin/mainis clean.Tests (the union at head
a32a4470cdunless marked; heavy runs throughos-verify-lock.sh, slotissue-10859)f16c01e90e, pin present, arm absent):Tests 58 failed | 7 passed (65).a32a4470cd:pnpm exec vitest run packages/types/ packages/cli/:Test Files 323 passed (323),Tests 7875 passed (7875), VERDICT command-exit 0.examples/schema-catalog/test/:Test Files 39 passed (39),Tests 2290 passed (2290).8e741e3fe4:packages/typesandpackages/clithat namesAnyComponentSchema,StrictAnyComponentSchema,safeValidateSchema,ObjectQLPublicBlockComponentSchema,ObjectQLComponentSchema,ObjectFormBlockSchema,nodeOracles,KNOWN_SCHEMA_TYPES,propsLevelOf,PUBLIC_BLOCKS,unmirroredAlias,collectArms,getPublicConfigs,ComponentPropsMap,validateSchemaorStrictAuthoringFace; or referencescheck-handler-key-read-sites,block-config-schema-parity,registry-inputs-spec-parity,strict-authoring-face,zod-mirror-parity,objectql.zod,index.zod,ObjectFormSchemaorobject-form.Test Files 180 passed (180) / Tests 4016 passed (4016)andTest Files 132 passed (132) / Tests 1626 passed (1626).a32a4470cd.pnpm --filter @object-ui/types build && pnpm --filter @object-ui/types type-check: VERDICT 0,dist completeness: 1 package(s) complete (138 emitted files verified). The pin is intsconfig.test.json's program (--listFilesOnly).pnpm --filter @object-ui/plugin-form type-check: exit 0, after building its dependency closure. Both plugin-form test files are in its test program.scripts/ablation-replace.mjsWRAP, plus the script's own EXIT/INT/TERM trap on absolute paths):ObjectFormBlockSchemafrom the public-block union: anchor x1 to x0, blob03e9d3554cebto5981e32df7dd.Tests 60 failed | 25 passed (85), with "objectui validaterefuses 73 registered bare key(s) attype; the pin is 72". Direction: red, as expected.03e9d3554ceb,git diff HEADempty.{ objectName? }:tsc -p tsconfig.test.jsonexit 2,TS2344: Type 'false' does not satisfy the constraint 'true'on the bag row.getObjectSchema('showcase_project')and draws the three step labels and the first step's field. The flat spelling draws the same. Control: a bag naming another object fetches that object and nevershowcase_project.Gates (exit codes read before any pipe)
check:handler-key-reads: "OK 140 arm(s), 212 registration(s) (138 keyed onto an arm), 56 reachable handler read(s), 56 judged";check:spec-symbols;check:new-line-citations: "VERDICT new-cross-file-line-citations: 0 new citation(s)";check:control-bytes: "OK (scanned 9718 tracked text file(s); skipped 85 binary)"; a self-scan over the 27 changed files gave 0 hits;node scripts/check-changeset-presence.mjs: "16 source file(s) of 2 released package(s) changed, and this change declares 2 changeset(s)";changeset:check: "No changeset declares amajorbump.";check:doc-fences,docs:check-links,markdown-test-inputs.mjs --audit("107 candidate test files, all adjudicated");check:doc-snippets: "697 of 697 block(s) judged, 0 failed", after its scoped build;check:doc-examples,check:doc-types,check:readme-exports;check:element-data-source-declaration,check:installed-pin-claims,check:test-path-roots,check:pending-changeset-literals,check:unreferenced-sources,check:esm-specifiers,type-check:coverage.check:changeset-claims(report-only): the pending.changeset/6152-object-form-unmirrored-members.mddescribes the flat members this change moves into the bag. Its body is not edited. This PR's changeset names how those members are authored now, so the release notes read together.check-governed-queue-guard.mjs --testover the 27 paths: NOT GOVERNED.eslint --no-inline-config --format jsonover the 16 changed.ts/.tsxfiles gives 0 errors. Warnings equal the base blobs file for file (43; the two new files carry 0).eslint.config.jssets noprojectService/parserOptions.project, so no untouched file's verdict can move. The fullpnpm lintis CI's.Acceptance notes
objectName/modeoptional;layoutisvertical/horizontalonly (17.5.0 retiredinline/grid);recordIdtakes a number (objectui#9511 refuses one on the flat mirror, and batch 2'sobject-master-detail-formbag already takes one). The row typessectionsentries asunknown, so a section's keys are unjudged inside the bag (the flat mirror closed them).buttons/defaults/subforms/groupsare the spec's form-VIEW members, not row members, so the bag refuses them.object-form-unmirrored-members-6152.test.tsnow says so for the three objectui#6152 declared: refused in the bag on both faces, still taken by the object-viewformslot. The "a section is a closed shape on the strict face" row reads that slot too.contentLayout/confirmOnDiscard, two row membersModalForm/DrawerFormread;BaseSchema's index signature types themany. This is an observation, not filed.skills/objectui/guides/page-builder.md("Form plugin example",os:check-marked). It still parses as JSON, which is allcheck:skill-examplesasks of a JSON fence, butobjectui validatenow refuses it. It goes through the governed path.packages/cli/src/commands/validate.tsstill suggeststype: 'object-form'withobjectName+sectionsflat.objectos-integration.mdxfragment also droppedfieldNames(no such key; the row's isfields), a node-level adapter and anonSubmitfunction, none of which the node ever took.Generated by Claude Code