Skip to content

feat(types): arm record:line_items from its @objectstack/spec 17.6.0 row, the last public block refused at type (objectui#10872) - #11570

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-10872-record-line-items-arm
Oct 3, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-10872-record-line-items-arm

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #10872
Clause-②: yes

safeValidateSchema (what objectui validate runs) and the strict authoring face accept record:line_items, the last ADR-0080 public block they refused at type. @objectstack/spec 17.6.0, which objectui main resolves, carries the block's ComponentPropsMap row, measured at LineItemsPanel's reads, and its STRING_ARM_REGISTERED_TYPES ledger is empty. The arm reads that row by reference, by the batch-1 method, with the flat-props refusal and the content-channel refusals as on every other arm.

This is Part of the card: the record:reference_rail README sentence (comment 5943728376) stays on it, because open PR objectui#11512 holds packages/plugin-detail/README.md.

What changed

  • packages/types/src/zod/public-blocks.zod.ts: RecordLineItemsBlockSchema, a member of PublicBlockComponentSchema:
    • properties is ComponentPropsMap['record:line_items'] through the objectui#8317 import boundary (stripImportedDefaults(RecordLineItemsProps)), so relationshipField and columns are required in the bag and childObject is optional, as the row declares;
    • NODE_ENVELOPE (responsiveStyles) and flatPropRefusals: a row member written on the node is refused by name, toward properties.KEY;
    • dataSource, the spec's ElementDataSourceSchema by reference. The registration is gate-wrapped and ElementDataSourceGate puts dataSource.object into childObject, which is why the row leaves childObject optional. This follows the module's own rule (an arm whose renderer reads the binding declares it) and the objectui#11440 precedent. Without it the strict face would refuse the row's own bound node as unrecognized_keys;
    • children / body: neither-channel tombstones, from one neitherContentChannelGuidance string.
    • The docblock's "NOT armed here" entry is rewritten as a held-and-now-armed note.
  • packages/types/src/zod/index.zod.ts: the barrel exports the arm.
  • Pins:
    • a new record-line-items-arm-10872.test.ts covers the row's requiredness, the bound node, the binding by reference, and both content channels, each held to the installed spec's own verdict;
    • the batch-1 (public-block-arms-10872), batch-10 (flat-props-refusal-10872) and batch-8 (public-block-responsive-styles-10872, DECLARES_DATA_SOURCE) population rows gain the block;
    • the import-boundary IMPORTED list (imported-defaults-8317) gains the row;
    • the cli namespaced refused-at-type ratchet goes 361 → 360, with a named row.
  • any-component-union-fanout.test.ts: the unknown-type bound now reads the message LESS the discriminator's options list. That list names every type literal, so it grows by one per arm by design. The whole message read 4,007 against the 4,000 bound at 204 literals. The docblock gains the new reading beside the old one.
  • zod-mirror-parity.test.ts: one EXCLUSIONS row (see serial notes).
  • Changesets: .changeset/10872-record-line-items-arm.md (@object-ui/types minor), and dated notes appended to 10872-public-block-zod-arms.md and 10872-held-public-block-arms.md. Each note corrects only the "record:line_items is still refused at type" sentences this change makes false. Both frontmatters are byte-identical.

Measurements

  • Red first, base ab18797, by a source probe: 8 record:line_items documents × 2 faces = 16 readings. All are invalid_union at type: the block was refused, not passed unjudged.
  • Ablation: the union member line was removed with ablation-replace.mjs (WRAP mode, anchor x1 → x0). The five pin files read 26 failed, 371 passed. The restore was proved by "blob == HEAD (060da1ed48fd) and git diff HEAD is empty". The pins import src through the vitest alias, so there is no dist leg.
  • The new fanout bound fails on the flat union, as the file's docblock requires of every bound. The test's parse was swapped for z.union(AnyComponentSchema.options, …) (the same 20 members and the same message map), and the bound reported "expected 14126 to be less than or equal to 4000". Restored: "blob == HEAD (370406be767a) and git diff HEAD is empty". The discriminated reading is 193.
  • Type reverse check (one-off file, deleted): PublicBlockNode accepts the bag node. It refuses an invented bag key (TS2353) and a flat relationshipField (TS2322). There were exactly those two errors.
  • Content channels, taken because the neither-channel text states this method:
    • the @object-ui/plugin-form dependency closure was built (11 packages);
    • a TypeScript compiler-API census of the plugin-form program (39 files, 0 type errors) found 2 children / body reads, both React children props of unrelated components, and 0 in LineItemsPanel or its registration;
    • the @object-ui/react program's one hit is ElementDataSourceGate's own render-prop children;
    • a runtime probe through the real SchemaRenderer and registry (one-off) rendered node-level children / body markers 0 times, with the DOM equal to the no-channel mount. Control: page:card properties.children rendered its marker once;
    • the installed spec's PageComponentSchema refuses a node-level children on this block (pinned).
  • registry-inputs-spec-parity.test.ts passes unchanged: the arm moves no booked count.

Tests (head efa2ef2)

  • pnpm exec vitest run --maxWorkers=2 packages/types/ packages/cli/ gives Test Files 373 passed (373) and Tests 9719 passed (9719), VERDICT command-exit 0.
  • pnpm --filter @object-ui/types type-check and pnpm --filter @object-ui/cli type-check both exit 0.
  • At b9a8a40, the head before the two test-only changes in efa2ef2: the consumer sweep (21 files outside packages/types that read the union or the ratchet, including registry-inputs-spec-parity and public-contract) passed 680 tests, VERDICT command-exit 0.
  • Gates, all exit 0:
    • check:control-bytes;
    • check:new-line-citations (0 new);
    • check:changeset-claims (report-only; the 21 pending changesets that name a touched file were read, and none is falsified by one arm in an existing module, one EXCLUSIONS row, or the bound change);
    • check:pending-changeset-literals;
    • check:handler-key-reads;
    • check:test-path-roots;
    • check-changeset-presence;
    • check-changeset-no-major.
  • pnpm --filter '@object-ui/types^...' build has an empty closure (ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT), so nothing ran. pnpm --filter @object-ui/types build exits 0.
  • NOT MEASURED: repo-wide pnpm lint, which CI owns.

Serial notes

  • packages/types/src/__tests__/zod-mirror-parity.test.ts is also edited by open PR objectui#11512. This PR adds exactly ONE EXCLUSIONS row, 'public-blocks.zod.ts#RecordLineItemsBlockSchema', directly after the RecordAlertBlockSchema entry, and changes nothing else in that file. objectui#11512's hunks there sit in the WiderThanDeclared census summary, the WiderThanDeclared interface and the WIDER_ARMS map, so the two do not overlap textually. The seat admitted the row in comment 5972030168.
  • Two shared counters move here: the cli NAMESPACED_REFUSED_AT_TYPE pin, and the fanout bound's population, the discriminator literals. A sibling lane that arms a block, such as objectui#11216 in objectql.zod.ts, moves the same ratchet. Whichever lands second recomputes it.

Acceptance notes

  • The registration's inputs declare childObject required: true, while the spec row makes it optional. As a result, the JSX page compile and validateTree refuse a dataSource-bound node without childObject (missing-required-prop), and the zod faces accept it. Measured; the seat files it as its own card. plugin-form is not touched here.
  • record:related_list is gate-wrapped too, and its arm declares no dataSource, so the strict face refuses a node-level binding there. This is dormant: the strict face has no consumer yet, and the undeclared set is pinned as a decision. Noted only.

Generated by Claude Code

claude added 2 commits October 3, 2026 17:58
…ComponentPropsMap row

The last ADR-0080 public block AnyComponentSchema refused at `type`. The arm
reads ComponentPropsMap['record:line_items'] by reference as its properties
bag, spreads the flat-props refusals and the node envelope, declares the
node's dataSource binding as the spec's ElementDataSourceSchema (the
registration is gate-wrapped; the row leaves childObject optional because
the binding supplies it), and refuses node-level children / body by name.

Pins: the batch-1 / batch-10 / batch-8 population rows gain the block, the
import-boundary list gains the row, the namespaced refused-at-type ratchet
falls 361 -> 360, and a new pin file carries the block's own readings.

Claude-Session: https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2
Co-authored-by: Claude <noreply@anthropic.com>
…nknown-type message less its options list

zod-mirror-parity: one EXCLUSIONS row, directly after RecordAlertBlockSchema,
recording that RecordLineItemsBlockSchema is spec-owned by reference.

any-component-union-fanout: the unknown-type refusal's message carries the
discriminator's options list, which grows by one literal per arm; at 204
literals the whole message read 4,007 against a 4,000 bound. The bound now
reads the message less that list, and the docblock gains the reading (flat
union 14,126 -> discriminated 193) beside the original one.

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

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 21 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/__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/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/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.

  • names zod/public-blocks.zod.ts → packages/types/src/zod/public-blocks.zod.ts — edited by this change

    ⚠️ Dated note, 2026-09-28 — a second category module — objectui#10872. Later still in this same release zod/public-blocks.zod.ts joins them as well and imports zod/base.zod.ts too, so both counts in the mechanical note above are two higher, not the one the objectui#10859 note says; the reason the arm cannot be an import is unchanged. The rest of this entry, and that note, are kept as their readings.

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

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3310.5 KB 3330.4 KB
Main entry chunk (gzip) 151.1 KB 350 KB
Entry file index-DxMF6d7Y.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) 17.22KB 6.37KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
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) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.60KB 64.57KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.44KB 45.28KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.02KB 64.63KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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 (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
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) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

…ma's declaration stays under TS's serialization ceiling

Against @objectstack/spec built from objectstack main, the record:line_items
row is larger, and with the arm printed inline `AnyComponentSchema` failed
declaration emit with TS7056, so @object-ui/types emitted no .d.ts (Spec
Main Shape Gate). The arm is now built as a private const and exported as
RecordLineItemsBlockSchema typed by an exported interface that extends the
arm's own inferred type and adds no member, so declaration emit prints the
arm once and refers to it by name. Runtime object, parse results and the
strict face are the arm's; compile-time rows pin the arm's input and output
types against the spec row and binding.

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

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3310.5 KB 3330.4 KB
Main entry chunk (gzip) 151.1 KB 350 KB
Entry file index-DxMF6d7Y.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) 17.22KB 6.37KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
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) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.60KB 64.57KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.44KB 45.28KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.02KB 64.63KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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 (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
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) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

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

Written 2026-10-03T19:10Z by an isolated at-tier reviewer (subagent of the domain:ui seat 1 session named under Reviewed-by:). Inputs: card objectui#10872 (body; comments 5936443227 through 5972182398), PR objectui#11570 (body, file list, comments, net diff against main at the head, read with git show by ref, no checkout), the check-runs on the head, the published @objectstack/spec 17.6.0 tarball (npm pack, unpacked in scratch, read only), and PR objectui#11512's file list and its patch for zod-mirror-parity.test.ts. Nothing was built, run, re-run or ablated. The seat's review 5972182398 and answer 5972030168 were read as claims and tested against the diff.

History of this record. An earlier head of this PR, efa2ef2 (spelled without a code span on purpose: this record is a review of c9e205d alone), was NOT passed: its Spec Main Shape Gate run (check-run 111264389756, started 2026-10-03T18:25Z) failed with TS7056 at packages/types/src/zod/index.zod.ts:593 (the AnyComponentSchema initializer) compiled against objectstack main 5c9138b4b672, and dist/zod/index.zod.d.ts was then not emitted (a TS7016 cascade in packages/cli and packages/core tests). The red was this diff's: the merge-base ab1879721 had run the same gate green at 2026-10-03T17:13Z against a spec tree with no packages/spec commit between the two runs, and sibling PR objectui#11568 (which adds to objectql.zod.ts) ran it green at 2026-10-03T18:24Z against the same objectstack sha. The seat held the review; the dev pushed c9e205d (one commit, two files, +92 / −4, read through the compare API efa2ef2...c9e205d). Every reading below of a file that commit did not touch was taken on efa2ef2 and stands; the two touched files were re-read on c9e205d.

① Derived judgments

Diff against main at the head: 13 files, +437 / −15 from the merge-base ab1879721 (the PR's base sha; the API file list agrees); no governed path.

  1. The arm and its membership — RIGHT. public-blocks.zod.ts builds RecordLineItemsBlockArm as BaseSchema.extend({ type: z.literal('record:line_items'), ...NODE_ENVELOPE, ...flatPropRefusals(type, row), properties: propsBag(type, row), dataSource, body, children }), the same spelling as RecordRelatedListBlockSchema (batch 1), the element:number arm (batch 2) and the batch-10 refusals; PublicBlockComponentSchema's z.discriminatedUnion('type', [...]) list gains the one member, and AnyComponentSchema (index.zod.ts:593, twenty members) lists PublicBlockComponentSchema, so both the tolerant face (safeValidateSchema) and the strict face (StrictAnyComponentSchema, derived from AnyComponentSchema at run time) now claim the literal. Before, every document naming the type was invalid_union at type on both faces (the cli ratchet counted it among the 361 namespaced keys refused).
  2. The properties bag IS the spec row — RIGHT. The published 17.6.0 tarball carries export const RecordLineItemsProps, a lazySchema over a strictObject (src/ui/component.zod.ts:2111) and 'record:line_items': RecordLineItemsProps in ComponentPropsMap (:6169); dist/ui/index.js defines and exports it, with childObject: z.string().optional(), relationshipField: z.string() and columns: z.array(InlineGridColumnSchema).min(1); STRING_ARM_REGISTERED_TYPES = [] (dist/ui/index.js:17509); the ./ui subpath is in the tarball's exports. objectui main resolves 17.6.0 (pnpm-lock.yaml; packages/types/package.json ^17.6.0). The arm passes the row through stripImportedDefaults, the objectui#8317 boundary every other row crosses (a cloning walk that keeps every check and returns the same object when there is nothing to strip), and propsBag makes it optional with the provenance description. The requiredness of relationshipField and columns and the optionality of childObject are the row's, and the new pin holds each verdict to ROW.safeParse as a control.
  3. Flat-prop refusals — RIGHT. flatPropRefusals reads the row's shape and refuses every key not in PAGE_COMPONENT_NODE_KEYS (type, id, label, properties, events, style, className, responsiveStyles, visibleWhen, visibility, dataSource, responsive, aria); none of the row's fifteen keys is in that list, so all fifteen are refused flat toward properties.KEY, and the arm's own later members (dataSource, body, children) win over the generated ones. flat-props-refusal-10872 reads the arms off the live unions, so its VALID_BAG row for the block was forced, and the new pin checks relationshipField and columns flat with invalid_type naming the bag member.
  4. The dataSource declaration — RIGHT. The spec's PageComponentSchema declares dataSource: ElementDataSourceSchema.optional() (src/ui/page.zod.ts:395); the registration (packages/plugin-form/src/index.tsx:563-588, main) is elementDataSourceBlock with RECORD_LINE_ITEMS_DATA_SOURCE = { object: 'childObject', filter: true, sort: true, limit: 'limit' }, skipFallback: true; the row's own childObject description says it is optional because the binding can supply the object. The arm declares the key as stripImportedDefaults(SpecElementDataSourceSchema).optional(), the spelling of the element:number arm and the objectui#11440 object-pivot / embeddable-form arms. So a bound node without childObject passing both faces is right given the row and the gate, and the pin's lit control (PageComponentSchema.safeParse(BOUND).success) agrees. A node with neither childObject nor a binding also passes; that is the row's verdict (no refinement in the row), and an arm narrower than its row would be the defect this module records twice. The arm declares nothing the spec's page component does not.
  5. The body / children tombstones — RIGHT. retirementTombstone(g) is z.never({ error: g }).optional().describe(g); neitherContentChannelGuidance yields the "reads NEITHER content channel" text naming LineItemsPanel; both members share one string (pinned); the spec's PageComponentSchema is a strict object with no children, so the pin's second lit control holds. The message claims a type-checker census on a built tree; the dev's report 5972001469 records that census (plugin-form program, 0 reads on this node).
  6. The barrel export — RIGHT. index.zod.ts gains the one name RecordLineItemsBlockSchema in its export list; @object-ui/types/zod publishes exactly one new value, as the changeset says.
  7. No document that parsed before is refused now — RIGHT. Every record:line_items node was refused at type before, at any depth (objectui#8344's recursion point); no other arm, union or helper changed; the three test-file changes move no accept set; there is no open string arm in AnyComponentSchema.
  8. The spec's defaults do not leak — RIGHT. The row and the binding both cross stripImportedDefaults; imported-defaults-8317's IMPORTED census (which reddens when a mirror imports a schema the list does not name) gains the row, and its probe differential covers it.
  9. The c9e205d fix — RIGHT, and it changes no type a consumer reads. The arm is kept as a private const; type RecordLineItemsBlockArmType = typeof RecordLineItemsBlockArm (private); export interface RecordLineItemsBlockSchemaType extends RecordLineItemsBlockArmType { shape: RecordLineItemsBlockArmType['shape'] } adds no member and restates shape by reference (only to satisfy no-empty-object-type); export const RecordLineItemsBlockSchema: RecordLineItemsBlockSchemaType = RecordLineItemsBlockArm. An interface is printed by name in declaration emit, so PublicBlockComponentSchema and AnyComponentSchema refer to it instead of inlining the arm; that is the repo's own method for PageKindNodeSchemaType (layout.zod.ts), AppSchemaRendererNodeSchemaType (app.zod.ts) and ReportNodeZodType (reports.zod.ts), each measured against the same gate. The runtime object is the same (the pin's PublicBlockComponentSchema.options contains the export), so parse results and the strict-face derivation are the arm's; the compile-time Equal rows pin z.input / z.output of type, properties and dataSource against the spec row and binding, with a lit control that distinguishes another row, and tsconfig.test.json (include: src/**/*.test.ts) compiles them under the package's type-check. On the published d.ts face: the interface is not on the ./zod barrel (the export list names only the const), dist/zod/public-blocks.zod.d.ts is not addressable through exports (./zod maps to index.zod.d.ts alone; no wildcard, no typesVersions), and it is reachable from the entry's type graph only as the declared type of the exported const; the three precedents are published the same way and none is named in a changeset. So the changeset's "exports one new schema" stays exact and no naming is owed. One prose flag on the interface's docblock, carried to ③.
  10. The two admitted test-file changes (5972030168). (a) zod-mirror-parity.test.ts: exactly one EXCLUSIONS row (+2 lines at @@ -4761), directly after RecordAlertBlockSchema, and nothing else; its text is accurate (BaseSchema + the literal + properties which IS the row + dataSource which IS the spec's binding + the two refusals; no TS declaration restates the node, confirmed by a grep of packages/types/src outside zod/ and __tests__/). objectui#11512 is still at cb687dfad7; its three hunks in that file sit at main lines 635 (census summary), 3962 (interface WiderThanDeclared) and 4192 (WIDER_ARMS); EXCLUSIONS opens at 4705 and the anchor row sits at 4762. Textually and semantically disjoint; the non-overlap claim holds. (b) any-component-union-fanout.test.ts: the unknown-type bound now reads messageLessOptions(message).length at most 4,000; messageLessOptions parses the message, asserts JSON.stringify(issues, null, 2) equals the message FIRST, then deletes the top-level options only, so a change in zod's message shape fails loudly rather than mis-measuring silently. The flat union's top-level issues carry no options (its payload is the per-arm errors arrays), so the strip removes nothing from the flat reading and the assertion still fails on the flat union by construction; the 14,126 figure is the dev's measurement, not re-run here, and it is of the same order as the docblock's original 14,855; the docblock table is appended, not overwritten; the options.length and literal-uniqueness rows stay. Not a weakening of the bound's stated purpose; the one thing no longer bounded is the linear growth of the discriminator's own options list, which is the discriminated union's design and is capped downstream by union-arm-diagnostics.
  11. Other pins on main naming the type. apps/console/.../public-contract.test.ts lists it in the exact PUBLIC_BLOCKS coverage list (registry coverage, not a validator reading); registry-inputs-spec-parity.test.ts books its caps under objectui#11536 (the dev reports it unchanged and green; the test shards on the head are the verdict); no held-block pin names it.

② Semver level

  • .changeset/10872-record-line-items-arm.md: @object-ui/types minor — RIGHT. One new type literal in the accept set of both faces and one new named export on @object-ui/types/zod; nothing narrows (AGENTS.md: Clause-②: yes takes at least minor). Clause-②: yes is right: the accept set widens. The body's sentences each match the diff: the row by reference with its requiredness; flat members refused toward properties.KEY; the binding by reference and the bound node without childObject; both content channels refused; "every document naming record:line_items was refused before". The c9e205d fix adds no accept-set change and no barrel export, so the changeset is unchanged and still exact.
  • The two dated notes: 10872-held-public-block-arms.md quotes its own line 24 ("record:line_items is still refused at type: the spec has no row for it yet") and 10872-public-block-zod-arms.md quotes its "Not armed in this release" item and the 2026-09-30 note's "only record:line_items is still refused at type" — both quotes exist at main as written; both diffs are pure appends after the last line (+2 each), frontmatter untouched. ACCURATE and APPEND-ONLY.
  • The bot's re-read (5972153358, 21 pending changesets naming a touched file): every quoted paragraph was read; they are ledger entries, mechanical notes or dated past readings, and none goes false from one arm in an existing module, one EXCLUSIONS row, the bound change or the type annotation. The only pending bodies that claimed the type was still refused are the two that got the notes.

③ Boundary flags

  1. childObject class (b) (registration inputs required: true vs the row's optional, the save-gate compile refusing a bound node): objectui#11569 exists, open, filed bare for triage by the seat with the dev's measurement and seam. The arm is right to follow the row; the contradiction is the registration's, and plugin-form is out of surface. Answered; carrier in place.
  2. record:related_list node-level dataSource: its arm (main public-blocks.zod.ts:690) declares no dataSource while its registration is gate-wrapped (plugin-detail/src/index.tsx:252), so the strict face refuses a spec-declared key there; the tolerant face passes it; public-block-responsive-styles-10872's DECLARES_DATA_SOURCE pins the undeclared set as a named decision. Not this PR's. The seat's answer (stays in Acceptance notes; the strict face has no consumer, so no measured reach under the filing gate) is accepted.
  3. cli ratchet 361 → 360 (registered-types-validate-ratchet-10859.test.ts): the pin's own text says to LOWER it in the same change; a named row (ARMED_PUBLIC_BLOCKS_10872_LINE_ITEMS) is added; skipFallback: true means no bare twin moved, which the row also asserts. RIGHT; within "as on every other arm".
  4. The extra pin files (imported-defaults-8317, public-block-responsive-styles-10872, public-block-arms-10872, flat-props-refusal-10872): each is a population census keyed off the live union or the import list and was forced red by the arm; none is in objectui#11512 or objectui#11568. RIGHT.
  5. The double report: forced by the brief's stop-on-breach rule; one comment over budget; no content effect. Accepted as procedural.
  6. Prose flags for the seat's ACCEPT, not contract matters. (a) The new interface's docblock says main's spec makes this row larger because columns[].readonlyWhen / requiredWhen "carry their ast". Read against objectstack main 5c9138b4b672 through the contents API: the RecordLineItemsProps block, the ElementDataSourceSchema block, the InlineGridColumnSchema block and the whole of src/shared/expression.zod.ts are identical to the 17.6.0 tarball's; src/ui/component.zod.ts grew from 6,543 to 7,316 lines elsewhere. So the causal sentence is not borne out by the files it names; the ceiling is on the whole AnyComponentSchema declaration and growth in any arm tips it. The remedy is right regardless, and the sentence ships in a d.ts comment, so it is worth one correction. (b) The PR body's "Tests (head efa2ef2)" section and the card carry no reading for c9e205d; the dev's readings for the fix reached this reviewer through the seat only.
  7. main moved under the head. objectui#11568 (objectui#11216, object-kanban grouping by reference) merged as a7557a7 after c9e205d was pushed; the PR's merge-base stays ab1879721. The two PRs share no file, and objectui#11568 adds no type literal, so neither shared counter the PR's serial note names (the cli namespaced pin, the fanout literal population) is moved and no recompute is owed. The queue leg re-measures the merged tree, the shape gate included; that is the seat's landing step, not this record's.

Check-runs on the head (REST, commits/c9e205d.../check-runs, read repeatedly until none was in progress). First read at 2026-10-03T18:57Z: 42 runs, 23 success, 3 skipped, 16 in progress, 0 failure. Final read at 2026-10-03T19:10Z: 43 runs, 40 success, 3 skipped (Test (coverage), its shard matrix, dependabot), 0 failure, 0 in progress. Spec Main Shape Gate is success (completed 19:04Z, its only annotation the runner-image notice; no TS7056), Type Check success (19:07Z), Lint success, Build & E2E success, Test (dist pins) success, all eight test shards success. Nothing was re-run.

Implemented-by: claude/issue-10872-record-line-items-arm
Reviewed-by: session_01FjqrwXPfSMkSfkKYDSRkN2

VERDICT: PASS

…use to the measured one

The docblock said objectstack main's spec makes the record:line_items row
larger. Measured on objectstack main 5c9138b, the arm's own serialized size
is the same as against 17.6.0; the rest of AnyComponentSchema grew. Comment
only; the family is tracked in objectui#11573.

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

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3310.7 KB 3330.4 KB
Main entry chunk (gzip) 151.3 KB 350 KB
Entry file index-Be3MieO3.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) 17.22KB 6.37KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
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) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.60KB 64.57KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.44KB 45.28KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.02KB 64.63KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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 (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
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) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

needs:contract-review removed: an at-tier PASS is on record, and the only later delta is the docblock correction the record flagged · domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-03T19:30Z.

  • Record: 5972576098 on this PR: ## Contract review, Served-tier: CONTRACT_REVIEW_TIER, Head-sha: c9e205dfe390b80f711c087a2ee687a0b184bd76, Local-runs: none, Implemented-by: claude/issue-10872-record-line-items-arm / Reviewed-by: session_01FjqrwXPfSMkSfkKYDSRkN2, PASS. The reviewer's transcript shows that one post (across both rounds, including the hold on the earlier head) and its read-back, and no other write.
  • The head at this act is 6217cea60, one commit after the reviewed c9e205dfe. Read by the seat through the compare API, c9e205d...6217cea is ahead_by: 1, with exactly one file: packages/types/src/zod/public-blocks.zod.ts, +8 / −7. Every changed line is inside the RecordLineItemsBlockSchemaType docblock.
    • This is the record's ③6(a) correction. The docblock's causal sentence (main's spec makes the row larger because readonlyWhen / requiredWhen carry their ast) was this seat's brief hypothesis. The dev's measurement and the reviewer's source read both falsified it: the arm's serialized size is the same on spec 17.6.0 and on objectstack main, and what grew is the rest of AnyComponentSchema.
    • The docblock now says that, and points to objectui#11573 for the family and the remaining headroom.
    • No code, type, test or changeset moved, so the PASS covers every contract face at this head.
  • The dev's readings for the fix (c9e205d), recorded here because the PR body's Tests section predates it (the record's ③6(b)):
    • against objectstack main 5c9138b (injected the way the Spec Main Shape Gate does it): TS7056 reproduced on the previous head, absent on base ab18797, gone on c9e205d;
    • @object-ui/types builds with 146 emitted files, and types + cli type-check passes;
    • on 17.6.0: types + cli vitest 9,720 / 9,720, with type-check and build green;
    • CI's Spec Main Shape Gate was green on c9e205d.
  • Pre-landing checks on 6217cea60:
    • every check is success or an expected skip;
    • check-governed-merges --pr objectstack-ai/objectui#11570: NOT governed.
  • Landing in this act: ready, then auto-merge, so it enters the merge queue. The PR is Part of #10872; the card stays open for the record:reference_rail README sentence, after objectui#11512.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 3, 2026 19:32
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 3, 2026 19:32
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 8d0ca91 Oct 3, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10872-record-line-items-arm branch October 3, 2026 19:47
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