Skip to content

feat(types): arm object-timeline by reference to its spec row (objectui#10859, batch 3) - #11248

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-10859-object-timeline-by-reference
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-10859-object-timeline-by-reference

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Part of #10859
Clause-②: yes

Clause-②: yes, copied from the PM claim 5915916825: @object-ui/types/zod accepts a new node type (object-timeline was refused at type and now has an arm), a widening of the published accept set. Batches 1 and 2 declared yes on the same method.

Batch 3 of objectui#10859, route A (release 5867551936: "a spec ComponentPropsMap row counts as a published declaration. properties is judged by reference"). object-timeline is registered by @object-ui/plugin-timeline, curated by ADR-0080, and declared by @objectstack/spec 17.5.0's ComponentPropsMap['object-timeline'] row, but AnyComponentSchema had no arm for it. So safeValidateSchema, and objectui validate with it, refused every document naming it with invalid_union at type. The card stays open for the designer six, the (ii) and (iii) keys, and the flat-arm fork measured below.

What changed

  • packages/types/src/zod/objectql.zod.ts: new ObjectTimelineBlockSchema, built the way batch 2 built ObjectMetricBlockSchema. It is BaseSchema, plus the object-timeline literal, plus properties, which is propsBag('object-timeline', stripImportedDefaults(SpecObjectTimelinePropsSchema)): the shared helper, the row by reference, no copy and no third helper. The node also declares dataSource as the spec's ElementDataSourceSchema by reference (see below), and the two batch-2 arms (object-metric, object-master-detail-form) declare the same dataSource with the same construct (patch round 1). body and children are refused by name with the objectui#9256 neitherContentChannelGuidance construct. The arm joins ObjectQLPublicBlockComponentSchema, so AnyComponentSchema's arm list does not change.
  • packages/types/src/zod/index.zod.ts: one barrel export.
  • packages/types/src/__tests__/object-timeline-arm-10859-b3.test.ts: the new pin.
  • packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts: REFUSED_AT_TYPE goes from 73 to 72, the moved key is named in the docblock, and one row counts object-timeline as armed. Draft PR objectui#11069's hunks are not touched.
  • packages/types/src/__tests__/zod-mirror-parity.test.ts: the one EXCLUSIONS row the new export forces, in batch 2's wording; patch round 1 rewords the two batch-2 rows to name their new dataSource member (no new row). The union row's "the two public-block arms above" became "the public-block arms above", because "two" is no longer true.
  • .changeset/10859-object-timeline-zod-arm.md: '@object-ui/types': minor, with no BREAKING banner because this is a pure widening.

Files beyond the claimed surface. Each one was forced, and each is named here:

  • imported-defaults-8317.test.ts: its census goes red for any spec schema a mirror imports without an IMPORTED row. This change adds one row.
  • registered-type-arms-10859-b2.test.ts: its exact list of ObjectQLPublicBlockComponentSchema literals gains object-timeline; patch round 1 adds one row per batch-2 arm (a dataSource-bound bag node, strict and tolerant faces, with a lit control).
  • packages/types/src/zod/README.md: the "ObjectQL Public Blocks" group now lists the new arm (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2).

Zone 2: the PM's mechanism assumptions, measured before building

  1. Held. object-timeline is registered (ComponentRegistry.register('object-timeline', ObjectTimelineRenderer, …)) and listed in KNOWN_SCHEMA_TYPES. packages/types/src/zod/ exported no arm for it. On base cb2f6fb5bf, both { type: 'object-timeline' } and { type: 'object-timeline', properties: { objectName: 'task' } } are refused on both faces with exactly one invalid_union at ['type'].
  2. Held. Installed @objectstack/spec is 17.5.0. ComponentPropsMap['object-timeline'] === ObjectTimelinePropsSchema at runtime. The row is strict, has no required member, and has 15 keys. Unlike batch 2's rows, it carries spec defaults (timeline.scale, navigation.mode / preventNavigation / openNewTab / size), so the import boundary hands back a rebuilt copy. The pin holds that this face writes no default into a parsed document; its control is that the spec's own parse does. The renderer reads neither content channel: ObjectTimeline and the renderer.tsx it composes have no children / body read (one comment hit), and the registration renders ObjectTimeline through ElementDataSourceGate. So the arm refuses both channels.
  3. Held. Measured once through the real registry (import '@object-ui/plugin-timeline', SchemaRenderer inside SchemaRendererProvider, a recording adapter), with a temporary file that is not committed:
    • the spec-shaped { type, properties: { objectName: 'campaign', timeline, limit: 25 } } gives find("campaign", {"$top":25}), the timeline-canvas renders, and both seeded titles are drawn;
    • the flat spelling gives the identical call and render;
    • { dataSource: { object: 'campaign' }, properties: { timeline } } gives find("campaign", {"$top":100}) and renders;
    • control: a bag with no objectName makes 0 find calls;
    • control: a bag timeline with no date axis renders timeline-missing-date-axis, which shows the bag's timeline is read.
  4. Measured, no edit. See the fork table below.
  5. Held. The census forced exactly one EXCLUSIONS row for ObjectTimelineBlockSchema. The spec import forced one IMPORTED row in the objectui#8317 census, listed above.

One addition the order did not name: dataSource. The registration is wrapped in elementDataSourceBlock, so the node reaches ObjectTimeline through ElementDataSourceGate, which reads the node's dataSource (measured in item 3). That key is the spec's PageComponentSchema.dataSource, not a member of the props row. Without a declaration, the strict authoring face would refuse a spec-valid { type: 'object-timeline', dataSource: { object: … } } by name. It is declared the way objectui#11070 declared it on object-grid and the other gate-wrapped arms of the same module: stripImportedDefaults(SpecElementDataSourceSchema) with the module's existing ELEMENT_DATA_SOURCE_BINDING_DESCRIPTION. The declaration is by reference, and nothing is restated.

Tests (every run below at head 9fe676e31c, through os-verify-lock.sh, slot issue-10859)

  • Red on base, first. On base with only the pin present, vitest run over the pin and a temporary measurement file gives Tests 16 failed | 2 passed (18). That is 16 red pin rows and 1 green pin row, plus the measurement file. The one green pin row is the lit control, which says the fixture is spec-valid by the spec's own row.

  • Green.

    • The pin, registered-type-arms-10859-b2, imported-defaults-8317, zod-mirror-parity and the ratchet: Test Files 6 passed (6), Tests 312 passed (312). That run included a temporary measurement file, not committed.
    • pnpm exec vitest run packages/types/ packages/cli/: Test Files 316 passed (316), Tests 7432 passed (7432).
  • Arm-list consumer sweep (ruling 5862923926). It covers every tracked test file matching one of the following, found with git grep -lw and git grep -l:

    • the words AnyComponentSchema, StrictAnyComponentSchema, safeValidateSchema, ObjectQLPublicBlockComponentSchema, nodeOracles, KNOWN_SCHEMA_TYPES, propsLevelOf, PUBLIC_BLOCKS, unmirroredAlias, collectArms, getPublicConfigs, ComponentPropsMap, validateSchema or StrictAuthoringFace;
    • a reference to check-handler-key-read-sites, block-config-schema-parity, registry-inputs-spec-parity, strict-authoring-face, zod-mirror-parity, objectql.zod or index.zod.

    That is 326 files. The 144 outside packages/types/ and packages/cli/ gave Test Files 144 passed (144), Tests 2575 passed (2575). They include app-shell's block-config-schema-parity-8216, public-contract, registry-inputs-spec-parity, public-block-binding-reach and check-handler-key-read-sites.

  • Type check. pnpm --filter @object-ui/types build exited 0 with ✓ dist completeness: 1 package(s) complete. pnpm --filter @object-ui/types type-check (tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json) exited 0, and tsc -p tsconfig.test.json --listFilesOnly lists the new pin.

  • Runtime ablation. This used ablation-replace.mjs in WRAP mode with its own EXIT/INT/TERM trap. ObjectTimelineBlockSchema was removed from ObjectQLPublicBlockComponentSchema: the anchor went from 1 to 0 hits, and the blob went from 71b873d0a086 to 69e995b14a66.

    • Result: pin + ratchet gave Tests 18 failed | 20 passed (38), with refuses 73 registered bare key(s) at type; the pin is 72.
    • 16 pin rows went red, plus the two ratchet rows.
    • The green rows are the lit control, the by-reference row that reads the arm directly, and the untouched ratchet rows.
    • Vitest aliases @object-ui/types/zod to src, so no build ran between mutation and reading.
    • Restored: blob equals HEAD 71b873d0a086, and git diff HEAD is empty.
  • Type-level reverse validation. The bag was replaced with z.strictObject({ objectName: z.string().optional() }). tsc -p tsconfig.test.json then exited 2 with exactly one error: TS2344 Type 'false' does not satisfy the constraint 'true' on the pin's bag-equality row. Restored: blob equals HEAD, and git diff HEAD is empty.

  • End to end. objectui validate ran in-process through validate() from commands/validate.ts, with a temporary file that is not committed.

    • The bag document prints ✓ Schema is valid! and exits 0.
    • A page holding a dataSource-bound timeline prints ✓ Schema is valid! and exits 0.
    • Control: properties.variant: 'grid' prints ✗ Schema validation failed! and exits 1.

Gates (exit code captured before any pipe; each gate's own verdict line)

  • node scripts/check-changeset-presence.mjs exit 0: 8 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)
  • pnpm changeset:check exit 0: No changeset declares a major bump
  • pnpm check:control-bytes exit 0: OK (scanned 9642 tracked text file(s); skipped 85 binary)
  • pnpm check:handler-key-reads exit 0: OK 140 arm(s), 212 registration(s) … every judged read is a declared member of its arm
  • pnpm check:new-line-citations exit 0: 0 new citation(s)
  • These all exited 0: check:pending-changeset-literals, check:changeset-claims (report-only), check:test-path-roots, check:spec-symbols, check:installed-pin-claims, check:element-data-source-declaration, type-check:coverage, markdown-test-inputs.mjs --audit, census:changeset-polarity, check:doc-types, check:unreferenced-sources, check:esm-specifiers.
  • The governed-surface check (check-governed-queue-guard.mjs --test) printed NOT GOVERNED — 9 path(s).
  • eslint, narrowed. The command was eslint --no-inline-config --format json over the 7 changed .ts files. The population comes from each package's own lint script: @object-ui/types lints . and @object-ui/cli lints src. Result: 0 errors and 3 warnings (no-explicit-any). The same 3 warnings are on the two base blobs, so this change adds none. eslint.config.js has no projectService or parserOptions, so linting is not type-aware, and this diff cannot move any untouched file's verdict. The full pnpm lint is CI's.
  • NOT MEASURED: check:readme-exports. Reason: the population collapsed because 34 packages are unbuilt (packagesRead: found 3, floor is 25), so the gate itself says this run proves nothing. No README code fence changed; CI measures it.
  • Serial. git merge-tree --write-tree against origin/main b32e7debc8 exits 0. Against PR objectui#11069's head a11f73347d, the only conflict is packages/cli/src/commands/check.ts, which conflicts between main and that PR on its own. The ratchet file merges clean.

The fork for the next batch: the three flat-arm neighbours (measured, no edit)

ObjectFormSchema, ObjectMapSchema and ObjectGanttSchema are FLAT arms in objectql.zod.ts, while the installed spec gives each block a properties row, and each row is ComponentPropsMap[...] by identity. The producer column comes from a classifier over each node literal:

  • BAG means a properties key opens on the node.
  • FLAT means a record-source key sits on the node.
  • A lit control shows both classes fire: objectstack's showcase object-metric nodes are all BAG (8), and objectui's object-form nodes are FLAT.
block (a) spec-shaped bag node, e.g. { type, properties: { objectName } } (spec row: valid) (b) objectui FLAT producers BAG producers
object-form refused. Tolerant face: objectName invalid_type, mode invalid_value. Strict face adds properties unrecognized_keys. 13 authored: content/docs 5, examples 5 (byo-backend-console 2, schema-catalog 2 JSON + 1 test), skills 1, designer 2 (ObjectManager / FieldDesigner runtime form schemas). Also plugin-form README 3, plus 20 runtime composers in package sources (app-shell, plugin-form, plugin-view), which the validator never sees. objectui 0. objectstack 1: the showcase new-project-wizard page, which objectui validate refuses today (the carrier note 5885358145).
object-map refused. Tolerant face: custom "no record source" at the root. Strict face adds properties. 20: content/docs 15 (+1 Schema API block), schema-catalog 3 JSON, console test fixtures 2. Also plugin-map README 3 (+1 Schema API block), and runtime composers in ListView / ObjectView. 0, and 0 in objectstack
object-gantt refused. Tolerant face: custom "no record source" at the root. Strict face adds properties. 16: content/docs 11 (+1 Schema API block), schema-catalog 3 JSON, skills 1, console test 1. Also plugin-gantt README 10 (+1 Schema API block), and runtime composers in ListView / ObjectView. 0, and 0 in objectstack

The flat spelling of each block is accepted on both faces (controls). objectstack was read at origin/main 72f8c38201: examples, apps, content, skills and packages/studio, with zero FLAT producers of any of the three. Converting a flat arm to the bag while live flat producers exist is a narrowing, and it needs its own ruling. The dev report's open_questions carries it with the four-axis analysis.

Acceptance notes

  • Strict face vs dataSource on batch 2's arms: folded into this PR in patch round 1 (26f8120ca2). object-metric and object-master-detail-form are gate-wrapped (elementDataSourceBlock) and read the node's dataSource. At 9fe676e31c their batch-2 arms did not declare it, so StrictAnyComponentSchema refused { type: 'object-metric', dataSource: { object: 'task' } } with unrecognized_keys ['dataSource'] (measured on the built dist), while the tolerant face accepted it. Both arms now declare dataSource with the same construct as object-timeline, with one row per arm in the batch-2 pin, reproduced red first. Both arms are still unreleased, so against the last release this only shapes what they accept on arrival.
  • object-timeline producers: no authored document in objectui or objectstack writes one today. The only writers are ListView / ObjectView runtime composers, which never meet the validator. So this arm changes no shipped document's verdict.

Implemented by session_0122Knsowci76D2rBWReCzzZ (https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ), branch claude/issue-10859-object-timeline-by-reference.


Generated by Claude Code

…ctui#10859, batch 3)

`safeValidateSchema` refused every `object-timeline` document at `type`:
the block is registered and curated, and `@objectstack/spec` 17.5.0 declares
its `ComponentPropsMap` row, but `AnyComponentSchema` carried no arm.

`ObjectTimelineBlockSchema` is built the way batch 2 built `object-metric`:
`BaseSchema` + the literal + `properties` = the row by reference through the
import boundary (its spec defaults stripped), plus the node's `dataSource`
binding as the spec's `ElementDataSourceSchema`, and the objectui#9256
refusals of both content channels. It joins `ObjectQLPublicBlockComponentSchema`.

The bare-key ratchet falls 73 -> 72; the census rows the new export and the
new spec import force are added.

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

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 38 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/10872-container-children-channel.md

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

    Also in this change, with no behaviour change: objectql.zod.ts's two public-block arms (object-metric, object-master-detail-form) build their properties member with the same propsBag helper as the other public-block arms, instead of a byte copy of it. The member's description text is unchanged.

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

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

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

  • 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/6940-rowactions-boolean-mirror.md

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

    The list view's same-named rowActions in zod/objectql.zod.ts — z.array(z.string()), the legacy bare-name action list on ObjectGridSchema — is a different key that is correct as it stands, is in parity with its own TS twin (rowActions?: string[]), and is not touched.

.changeset/7113-chart-data-model.md

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

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

.changeset/7200-object-form-section-style-keys-undeclared.md

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

    The authored-metadata type now agrees with @objectstack/spec, whose FormSectionSchema is a strict object declaring neither key, and with the ruling's rationale (maintainer 2026-09-01, verbatim): "retire the reads … Declaring the keys was weighed and not adopted: it would formally invite free Tailwind strings into authored metadata, the exact class the boundary exists to keep out." A ?: never tombstone was not used: ObjectFormSection has no zod mirror (ObjectFormSchema in zod/objectql.zod.ts does not declare sections), so there is no parse door to refuse at, and a tombstone is still a declaration in completion and in the published .d.ts.

.changeset/7265-types-user-filter-field-derives.md

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

    zod/objectql.zod.ts declared two schemas under names @objectstack/spec/ui already exports. They were triaged separately, by reading their sites, and went different ways.

.changeset/7322-object-kanban-group-by-limit.md

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

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

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

.changeset/7352-drill-down-config-mirror.md

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

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

.changeset/7363-objectql-union-arms.md

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

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.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 objectql.zod.ts → packages/types/src/zod/objectql.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.

  • 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/8478-describe-line-addresses.md

.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/8735-objectql-mirror-docblocks-not-defaulted.md

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

    Correct four zod/objectql.zod.ts docblocks that described the behaviour objectui#8317 removed. Since that change the zod mirrors strip imported @objectstack/spec defaults at this package's import boundary, but the docblocks on HttpRequestSchema, ListColumnSchema, SelectionConfigSchema and PaginationConfigSchema still said, in the present tense, that method, prefix.type, type and pageSize are defaulted on parse — the opposite of what each export does. Each now says the key is declared and accepted but NOT defaulted on parse.

.changeset/8801-object-kanban-allow-collapse-retired.md

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

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8885-object-chart-drilldown-title-compareto.md

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

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

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

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

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

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

.changeset/8992-user-actions-collapse-and-docblock.md

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

    objectql.zod.ts's UserActionsSchema read stripImportedDefaults(Spec).extend({ group, hideFields, rowColor }), an extension that existed only because @objectstack/spec did not declare those three keys while normalizeListViewSchema folded objectui's legacy showGroup / showHideFields / showColor onto them. The protocol adopted all three in 17.3.0 (objectui#5435's ruling), so the extension is now a second local copy of a protocol declaration — the shape two faces start drifting from — and it collapses into the plain by-reference re-export its own note always said it would become.

.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/9309-object-gallery-filter-destination-typed.md

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

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

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

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

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • 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/9549-tree-filter-declared.md

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

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9606-object-kanban-card-title.md

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

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3577.1 KB 3607.4 KB
Main entry chunk (gzip) 149.8 KB 350 KB
Entry file index-CaBznM1D.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 569.34KB 136.09KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 228.91KB 63.54KB
fields (index.js) 261.17KB 66.27KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.88KB 11.46KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.73KB 37.05KB
plugin-designer (index.js) 216.32KB 44.56KB
plugin-detail (index.js) 242.11KB 63.60KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.07KB 44.44KB
plugin-gantt (index.js) 173.03KB 43.07KB
plugin-grid (index.js) 230.79KB 63.39KB
plugin-kanban (index.js) 48.46KB 15.12KB
plugin-list (index.js) 116.28KB 28.88KB
plugin-map (index.js) 23.50KB 7.82KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.05KB 9.67KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.55KB 39.23KB
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 (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.82KB 7.15KB
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: 9fe676e31cc761ee1910b26969cfc30d7af26db7
Local-runs: none

Read: card objectui#10859 (body and all 19 comments — the route A release 5867551936, the carrier note 5885358145, the claim 5915916825 and the dev report 5916433162 among them), PR objectui#11248 (body, the 9-file list, the net diff against main at merge-base cb2f6fb5bf, +371/−15), the check-runs on the head, the installed spec's source at the @objectstack/spec@17.5.0 tag commit (ComponentPropsMap, ObjectTimelinePropsSchema, PageComponentSchema.dataSource, ElementDataSourceSchema), objectui#10872's triage answer 5906817482, and draft PR objectui#11069's hunks in the ratchet file (fetched by ref for the "untouched" check). Nothing built, run or re-run.

Check-runs on the head: 43 in all — 40 success, 3 skipped (Test (coverage), the coverage shard matrix, dependabot), 0 failure, 0 in_progress. At the first read of this review 11 were still in_progress (Spec Main Shape Gate, the eight Test (shard n/8), Type Check, Lint); at the last read before this post every one had concluded success, and the Test rollup with them. Their conclusions are the gate verdicts: Test (dist pins), Build & E2E, README Export Check, Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read, Governed Surface Queue Guard, Line Citation Gate, Spec Main Shape Gate, Type Check and Lint are all green.

① Derived judgments

  1. The arm, by reference — right. ObjectTimelineBlockSchema is BaseSchema + z.literal('object-timeline') + properties: propsBag('object-timeline', stripImportedDefaults(SpecObjectTimelinePropsSchema)) — the same three-term construction the two batch-2 arms carry at this head (both build properties with the shared propsBag from public-blocks.zod.ts, objectui#10872's one copy), no local helper, no restated member. The row is the installed spec's ComponentPropsMap['object-timeline'], which is ObjectTimelinePropsSchema by identity at the 17.5.0 tag commit: a strict object of 15 optional members. packages/types/package.json pins ^17.5.0 and the lockfile resolves @objectstack/spec@17.5.0, so the release's condition ("under route A, object-timeline becomes (i) when the spec pin moves past 17.4.0") is met, and the key leaves the (ii) list it sat on in the split 5861157913.

  2. "By reference" with a rebuilt copy — honest, and the substitute pin is adequate. This row carries defaults (scale inside TimelineConfigSchema; the navigation members), so the objectui#8317 boundary hands back a derived graph, not the export. That is what batch [WIP] Fix action run issue in CI/CD pipeline #90 ruled for every default-carrying crossing ("a mirror member re-exporting one of these re-exports this package's derivation, not the spec object itself. That is exactly what batch [WIP] Fix action run issue in CI/CD pipeline #90 ruled"), and it is how every objectui#11070 dataSource, the ListView slots and the objectui#10872 rows already cross. The walker clones through cloneWithDef, keeping checks and registry metadata, and leaves every default-free subtree reference-equal, so the copy is the spec's row minus the substitution. Batch 2 pinned stripImportedDefaults(row) toBe row only because neither of its rows had a default; that assertion is false by construction here, and the pin substitutes (i) key-set equality read off the installed spec at run time, (ii) eight probes answered exactly as the spec answers them, nested defaulted members among them (timeline.scale valid and invalid, navigation), (iii) a type-level invariant equality of the bag's input type to the spec's published ObjectTimelineProps, with a non-vacuity control and a reverse validation the report records, and (iv) the "authors no default" row with the spec's own parse as its lit control. Beyond the pin, the new IMPORTED row puts the row under the 8317 census's own rows: no ZodDefault survives, no member became required, every corpus probe answers as the spec does, and the parallel walk holds keys, node types, arm counts and check counts. Together that is stronger than reference identity, which says nothing about parse behaviour.

  3. dataSource — right, and a widening the strict face needs. The spec's PageComponentSchema declares dataSource: ElementDataSourceSchema.optional() on every node; the key is not a props-row member. At the head, plugin-timeline/src/index.tsx registers ObjectTimelineRenderer as elementDataSourceBlock(...) rendering through ElementDataSourceGate, so the runtime reads the node's dataSource. BaseSchema is .passthrough() and declares no dataSource, and the strict face closes every arm to undeclared keys, so without the declaration the spec-valid { type: 'object-timeline', dataSource: { object } } would be refused by name on the strict face — the batch-2 arms show exactly that (③, the first finding). Declared as ObjectGridSchema and the module's other gate-wrapped arms declare it (objectui#11070): stripImportedDefaults(SpecElementDataSourceSchema).optional().describe(ELEMENT_DATA_SOURCE_BINDING_DESCRIPTION). Beyond the order's words, and declared as such in the report's deviations[0] and the PR body. check:element-data-source-declaration polices the registration seam, not the zod arm, so nothing forced this by gate; the spec forces it. The pin's adapter-name row (dataSource: 'objectstack' refused on both faces) shows the older string spelling is not re-admitted.

  4. body / children refused — right; the non-read is measured, the refusal is pinned. At the head, ObjectTimeline.tsx has one children hit and it is a comment; renderer.tsx and index.tsx have none; the registration hands the node through the gate to ObjectTimeline. The neitherContentChannelGuidance string states a type-checker measurement; for this node that reading is objectui#9256's package-level one recorded on the timeline arm ("packages/plugin-timeline contains no body / children read of any kind, on any receiver"), which covers the same package, and the dev's source read at this head — repeated here — shows nothing added since. The two refusal rows pin the arm's behaviour; the non-read is measured, not pinned — the same shape as batch 2's two arms.

  5. The ratchet — right. REFUSED_AT_TYPE 73 → 72; the docblock names object-timeline and its 17.5.0 row; one new row asserts the key is in BARE_KEYS and not refused. NAMESPACED_REFUSED_AT_TYPE untouched at 391. It falls; nothing raises it. PR objectui#11069's hunks in the file (the docblock's safeValidateSchema sentences, the import, refusedAtType's body, the control row) are disjoint from this diff's two hunks (the REFUSED_AT_TYPE block and the batch-3 row after the batch-2 row); the head still imports safeValidateSchema, so those hunks are untouched.

  6. The forced census rows — each exactly the row the new export forces. (a) zod-mirror-parity: "every exported const in ../zod/ is either a registered pair or an excluded one" forces one EXCLUSIONS row for objectql.zod.ts#ObjectTimelineBlockSchema, written in batch 2's wording plus the one member that differs (dataSource IS the spec's ElementDataSourceSchema); EXPECTED_MIRROR_PAIRS stays 170, since no TS declaration is paired. The union row's "the two public-block arms above" → "the public-block arms above" is a count the diff made false, correctly dropped. (b) imported-defaults-8317: "every symbol the mirrors import is covered by the differential" forces one IMPORTED row for ObjectTimelinePropsSchema; SpecElementDataSourceSchema already has its row from objectui#10872 batch 2. (c) registered-type-arms-10859-b2: the exact-list assertion over ObjectQLPublicBlockComponentSchema gains object-timeline; the union is the same public export with one more member, a widening, and the report's 326-file sweep names no other exact-list consumer.

  7. The public surface — right. @object-ui/types/zod exports one new schema; AnyComponentSchema's arm list is unchanged (the arm joins through ObjectQLPublicBlockComponentSchema); the strict face derives the new arm (pinned: accepted, and closed to an invented node key by name). README Export Check is green on the head. The README's "ObjectQL Public Blocks (3)" group matches the diff, dataSource sentence and "none of the three renderers reads a content channel" included.

  8. One count the diff makes false and does not fix — a text fix owed before ready. packages/types/src/zod/public-blocks.zod.ts:225-226, the propsBag docblock: "The ONE copy: ./objectql.zod.ts's two public-block arms (object-metric, object-master-detail-form) import it rather than restate it". At this head three arms import it. The dev applied this very rule to the objectql.zod.ts docblock and to the parity union row, and missed the helper's own docblock. It is internal (the helper is deliberately not re-exported), with no accept-set or public-surface effect, so it does not turn the verdict; it belongs in the delta before ready, in one line. The other "two" sentences at the head (zod-mirror-parity.test.ts:4427, the b2 pin's header, the pending .changeset/10872-container-children-channel.md) describe batch 2's own rows or name the two arms that change touched, and stay true.

② Semver level

'@object-ui/types': minor, Clause-②: yes, no BREAKING — right. Every object-timeline document was refused at type on both faces (one invalid_union at ['type'], measured on base cb2f6fb5bf per the report and consistent with the ratchet's 73 on main), so the accept set of AnyComponentSchema and of StrictAnyComponentSchema only widens: by one type literal, by the row as its bag, and by the spec's dataSource binding. ObjectQLPublicBlockComponentSchema gains a member — a widening of an exported union. Nothing that parsed before is refused now. The Clause-②: yes line sits on the PR body's second line and in the changeset. Changeset text against the diff: the construction, the two named default sites (timeline.scale, the navigation members — the spec's own ObjectTimelinePropsParsed docblock names both), the objectui#11070 construct for dataSource, the objectui#9256 refusals and the flat-key posture ("passes the tolerant face unjudged and is refused by name on the strict face", which the pin's strictness-control row shows) all match. One precision note, not a fix: "refused at type, at the root and at every child slot" holds for every slot that judges its element with AnyComponentSchema; a slot typed z.unknown() never refused and still does not, which leaves the semver reading exactly where it is. Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check and Changeset Claim Re-read are green on the head.

③ Boundary flags

Dev deviations, each answered:

  1. dataSource declared beyond the order — accepted (①.3).
  2. File surface beyond the claim (imported-defaults-8317, the b2 pin, the README) — accepted; each forced (①.6, ①.7).
  3. The union-row rewording — accepted (①.6); the same rule reaches public-blocks.zod.ts:225 (①.8).
  4. The rebuilt copy and the substitute pin in place of batch 2's identity row — accepted (①.2).
  5. Attribution trailers and the PR footer in the role file's form — not a contract matter; nothing owed.
  6. The write-pace refusal on the first pr_create — procedural; one retry, one PR, nothing written twice.
  7. The body / children measurement by source read — accepted (①.4).

open_questions[0] — the flat-arm fork (object-form / object-map / object-gantt), options A / B / C, recommendation A. Answer: objectui#10872's answer A (5906817482) governs the PRINCIPLE by inheritance; the CONVERSION needs its own seat ruling on four execution points — which is what the dispatch order said ("a narrowing that needs its own ruling"), and it is not a new triage question.

  • Inherited, no new ruling: (a) it is the same family — three ADR-0080 public blocks whose ComponentPropsMap rows are published declarations under route A (5867551936); (b) B is out, verbatim: "A flat channel in objectui's arms is a second dialect: objectui validate would accept what os validate refuses". The three flat arms already ARE that dialect (the spec's strict PageComponentSchema refuses flat props as mis-layered, ADR-0089 D3a), and B would keep it beside the bag; (c) C is out by the same text — "It leaves the governed instructions file teaching a node the validator refuses" — here objectui's own docs, skills and READMEs teaching a spelling the spec refuses, and a spec-valid document (the showcase object-form page, the carrier note's measured public-door defect) refused by objectui validate; under route A it also leaves three published declarations with no arm that reads them, the class this card was filed to close.
  • Not inherited — the seat rules: 10872's A was rendered on arms that did not exist ("no behaviour is lost", "not a decision-box item"). Here each flat arm is a published accept set with live producers (13 / 20 / 16 authored in objectui, plus READMEs), and converting it moves the accept set BOTH ways at once: on the strict face every flat producer becomes refused by name (the BREAKING (authoring) banner the dev's A already names); on the tolerant face — the public door until PR objectui#11069 lands — a flat key stops being judged at all (a flat mode: 'bogus' that ObjectFormSchema refuses today would pass BaseSchema's passthrough unjudged). Second, and missing from the dev's four-axis analysis: the three flat arms mirror published TS declarations in objectql.ts and are PAIRED in the mirror-parity census (EXPECTED_MIRROR_PAIRS = 170); unpairing them reopens the "declaration with no mirror" gap this card exists to close unless the TS twins are retired or redeclared in the same PR. The master-detail precedent does not cover this: MasterDetailFormSchema lives in @object-ui/plugin-form, not on @object-ui/types' own TS face. Ruling 5861220023's posture applies — settle the declaration before the mirror moves. Third, the producers include governed files (skills), where the maintainer's word is given at the migration PR's approval, as 10872 put it. Fourth, order: 10872's migration (objectui#11183) lands before objectui#11069; the same serial applies here, or 11069's landing turns objectui's own docs red at the public door.
  • A against C, weighed: C keeps today's judging of the flat spelling and costs no migration, and that is all it has — it freezes a second dialect the governing text has already refused, leaves a spec-valid page refused at a public door, and grows the divergence with every spec release that touches a row. A pays the migration once, on bounded and counted producers, and ends with one strictly judged spelling. A wins on the governing text and on the long term; C's one real merit (no unjudged window on the tolerant face) is answered by landing the conversion behind objectui#11069, not by keeping the flat arm.
  • Recommendation to the seat: A, one block per batch, object-form first (the one live BAG producer, refused today). Each conversion PR carries: the arm in the objectui#10872 shape with dataSource kept; the block's flat producers moved to the bag with a zero-hit census as its gate; the TS twin's fate (retire under a BREAKING banner, or redeclare as the row) written into the same PR; Part of #10859; serial before objectui#11069. The seat can rule on the four points; only a retirement of the three TS declarations, if that route is taken, is the kind of narrowing that may want the maintainer's criterion.

out_of_scope_findings[0] — the batch-2 arms' dataSource refused on the strict face (carrier: PR objectui#11069). Real, latent, and mis-carried. Real: object-metric and object-master-detail-form are gate-wrapped and read the key, the spec declares it on every node, and their arms do not — the strict face refuses a spec-valid node by name. Latent: no CLI caller of the strict face on main. Mis-carried: objectui#11069 is objectui#5250's wiring; landing a types-arm fix inside it widens that PR's surface and puts the fix behind the very landing that exposes the defect. Disposition: a Part of #10859 patch on this card — two dataSource: declarations in objectql.zod.ts with this PR's construct, two rows in the b2 pin, no new census row (the import and its 8317 row exist) — serial before objectui#11069, the way 10872 put its migration before it. The seat may fold it into this PR's delta round, since the file and the construct are already in this diff; this record does not widen the order.

out_of_scope_findings[1] — no authored object-timeline document exists in objectui or objectstack. Noted; it is why this arm changes no shipped document's verdict, consistent with the pure-widening reading in ②.

Implemented-by: claude/issue-10859-object-timeline-by-reference
Reviewed-by: session_0122Knsowci76D2rBWReCzzZ

VERDICT: PASS

…e-count the propsBag docblock (objectui#10859, batch 3 patch 1)

`object-metric` and `object-master-detail-form` are elementDataSourceBlock-
wrapped and read the node's `dataSource` through ElementDataSourceGate, but
their arms did not declare it, so the strict authoring face refused a
spec-valid bound node by name. Both now declare it with the construct the
`object-timeline` arm uses: the spec's ElementDataSourceSchema by reference,
described by the module's ELEMENT_DATA_SOURCE_BINDING_DESCRIPTION. One
strict-face row per arm in the batch-2 pin.

The propsBag docblock no longer counts its importers ("two" was false once
`object-timeline` joined). Existing parity rows, the README and the pending
changeset name the new member; no census row added.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3581.1 KB 3607.4 KB
Main entry chunk (gzip) 149.8 KB 350 KB
Entry file index-D7aqEg__.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 569.34KB 136.09KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 228.91KB 63.54KB
fields (index.js) 261.16KB 66.27KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.88KB 11.46KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.73KB 37.05KB
plugin-designer (index.js) 216.32KB 44.56KB
plugin-detail (index.js) 242.11KB 63.60KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.07KB 44.44KB
plugin-gantt (index.js) 173.03KB 43.07KB
plugin-grid (index.js) 230.88KB 63.41KB
plugin-kanban (index.js) 48.46KB 15.12KB
plugin-list (index.js) 116.42KB 28.89KB
plugin-map (index.js) 23.50KB 7.82KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.05KB 9.67KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.55KB 39.23KB
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 (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.82KB 7.15KB
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: 26f8120ca26ed22e9e5e703e7779f28e231dce76
Local-runs: none

Delta review on the round-1 record 5916849828 (PASS on head 9fe676e31cc761ee1910b26969cfc30d7af26db7). The new head is one commit, a fast-forward from the reviewed head with no merge of main; the merge-base stays cb2f6fb5bf. Judged here: the delta git diff 9fe676e31c 26f8120ca2 (6 files, +62/−8) in the three sections below, and the net diff against main at the merge-base (10 files, +431/−21, which is what the PR reports) only where the delta touches it. Round 1's ① items stand where the delta does not reach them.

Read: the round-1 record; the delta and the net diff; the card's one comment newer than the record, the dev's round report 5917048524 on objectui#10859; the PR body and the PR's comment list; the check-runs on the head, twice; at the head, objectql.zod.ts (every dataSource: declaration, the timeline arm, the two imports the declarations use), public-blocks.zod.ts, the b2 pin (imports, type-level rows, the keysOf runtime row), zod-mirror-parity.test.ts around the reworded rows, the imported-defaults-8317 census, the README, the changeset, check-element-data-source-declaration.mjs, and the two registration sites in plugin-dashboard/src/index.tsx and plugin-form/src/index.tsx; at origin/main (32dcf29650), packages/types/CHANGELOG.md, packages/types/package.json, the .changeset/ listing and .changeset/10859-pivot-object-block-zod-arms.md; the spec source at 0f6dcac5e9 (packages/spec/src/ui/page.zod.ts: ElementDataSourceSchema at line 194, PageComponentSchema.dataSource at line 395). Nothing built, run or re-run.

Check-runs on the head. First read: 42 — 34 success, 3 skipped, 5 in_progress (Test (shard 1/8), 2/8, 5/8, 6/8, 7/8; the Test rollup not yet created). Re-poll at 2026-09-30T18:21Z: 43 — 40 success, 3 skipped (Test (coverage), the coverage shard matrix, dependabot), 0 failure, 0 in_progress; every shard and the Test rollup concluded success. The gate verdicts are green: Test (dist pins), Build & E2E, README Export Check, Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate, Spec Main Shape Gate, Type Check, Lint.

① Derived judgments

  1. The docblock fix (round 1 ①.8) — done, closed. packages/types/src/zod/public-blocks.zod.ts:225: "The ONE copy: ./objectql.zod.ts's two public-block arms (object-metric, object-master-detail-form) import it rather than restate it (objectui#10872)" became "The ONE copy: ./objectql.zod.ts's public-block arms import it rather than restate it (objectui#10872)". The count is gone and the sentence states what the code does: at the head three arms call propsBag (objectql.zod.ts:3414, 3469, 3550) and nothing else does. Comment only; no accept-set or public-surface effect.

  2. dataSource on both batch-2 arms — the same construct as object-timeline's. objectql.zod.ts:3415-3417 (ObjectMetricBlockSchema) and 3473-3475 (ObjectMasterDetailFormBlockSchema) each read stripImportedDefaults(SpecElementDataSourceSchema).optional().describe(ELEMENT_DATA_SOURCE_BINDING_DESCRIPTION), byte-identical to the timeline arm's 3551-3553 and to the module's seven other gate-wrapped declarations (300, 531, 1728, 2149, 2227, 2392, 2673). SpecElementDataSourceSchema is the module's existing import (line 56, the spec's ElementDataSourceSchema); the description constant is the module's own (line 283). No new import, no local helper, no restated member. The key is what the spec declares on every node: PageComponentSchema.dataSource is ElementDataSourceSchema.optional() (page.zod.ts:395), and ElementDataSourceSchema (page.zod.ts:194) is a strict object with object required and view, filter (the ViewFilterRule array form), sort, limit optional. The two docblock paragraphs say what the code does: the key is the spec's, not a props-row member; it is declared by reference the objectui#11070 way; the strict face refused a spec-valid bound node without it.

  3. Both registrations are elementDataSourceBlock-wrapped, so the gate reads the key. At the head, packages/plugin-dashboard/src/index.tsx:207 builds ObjectMetricBlock as elementDataSourceBlock(...) and registers it as 'object-metric' at 226-228; packages/plugin-form/src/index.tsx:425 builds MasterDetailFormRenderer as elementDataSourceBlock(...) and registers it as 'object-master-detail-form' at 454. check-element-data-source-declaration.mjs polices exactly that seam (a file that consumes the gate must call elementDataSourceBlock(, and the seam injects the dataSource input at Registry.register); the dev ran it exit 0 over 14 gate-consuming files. So ElementDataSourceGate reads the node's dataSource for both renderers, and each zod arm now declares the key its runtime reads — the defect round 1's ③ named, closed with this PR's construct.

  4. The two pin rows — red first, with a lit control. registered-type-arms-10859-b2.test.ts gains one it.each with one row per arm (a spec-shaped bound bag node each). Each row asserts, in order: the spec's own ElementDataSourceSchema accepts the fixture's binding (the lit control — independent of objectui's arms, so lit at both heads); the strict face accepts the node; the tolerant face accepts it; and { type, dataSource: 'objectstack' } is refused on both faces (judged as the binding, not merely admitted). The dev's round report: at 9fe676e31c with the rows present and the declarations absent, "Tests 2 failed | 28 passed (30)", both failures unrecognized_keys at ['dataSource'], path [], on the strict face, the lit control passing; at 26f8120ca2, 7434 passed (7432 before, plus the two rows). That red is what the construction predicts — at 9fe676e31c neither arm declared dataSource and the strict face closes every arm to undeclared keys — and it is the same measurement round 1's ③ and the PR body's Acceptance-notes bullet recorded (unrecognized_keys ['dataSource'] on the built dist). The pin's type-level rows are untouched and needed no change: they assert the bag's input type and the three runtime slots, not the node's key set, and the keysOf runtime row compares the bag to the spec row; the assertionSpecRowArmsAreTheRow docblock now names the new member as prose. Type Check and every Test shard are green on the head.

  5. No new census row — right; the two EXCLUSIONS rows were reworded, not added. The zod-mirror-parity.test.ts delta is two lines replaced: the EXCLUSIONS keys for objectql.zod.ts#ObjectMetricBlockSchema, #ObjectMasterDetailFormBlockSchema and #ObjectTimelineBlockSchema number 3 at both heads; EXPECTED_MIRROR_PAIRS is 170 at both heads and the delta does not touch it. imported-defaults-8317.test.ts is not in the delta: ElementDataSourceSchema has carried its IMPORTED row since objectui#10872 batch 2 (line 294 at the head), and the declarations import no spec symbol the module did not already import. Nothing forced a row; none was added. The rewording adds "the node's dataSource binding, which IS the spec's ElementDataSourceSchema" to each row's composition string, which the new member had made incomplete — the rule round 1 accepted for the union row (①.6), applied again.

  6. README and changeset prose — match the diff. packages/types/src/zod/README.md's "ObjectTimelineBlockSchema also declares the node's dataSource binding" became "Each arm also declares the node's dataSource binding, the spec's ElementDataSourceSchema, which all three registrations read through ElementDataSourceGate" — true at the head (①.2, ①.3); README Export Check is green. The changeset's "It reaches" bullet now opens with ObjectTimelineBlockSchema, which keeps its pronoun unambiguous beside the new bullet.

  7. Carry-over. Round 1's ①.1 to ①.7 stand: the delta touches neither ObjectTimelineBlockSchema nor index.zod.ts, the b3 pin, the ratchet, or the 8317 census. ①.8 is closed by item 1.

② Semver level

'@object-ui/types': minor, Clause-②: yes, no BREAKING — still right; the changeset gains one bullet and keeps both. The dev's claim that the two batch-2 arms are unreleased holds at origin/main (32dcf29650): .changeset/10859-pivot-object-block-zod-arms.md is still in .changeset/, pending; packages/types/CHANGELOG.md tops at 17.6.0 and names no ObjectMetricBlockSchema, ObjectMasterDetailFormBlockSchema or ObjectQLPublicBlockComponentSchema (its one object-master-detail-form hit, line 3970, is an older unrelated entry), and the pending changeset's opening sentence appears nowhere in it; the batch-2 commit 3b469c8ea1 (objectui#10927) is not an ancestor of the latest CHANGELOG commit 34bfd6060d; packages/types/package.json is 17.6.0. So against the last release, every object-metric and object-master-detail-form document was refused at type on both faces (the pending changeset's own Clause-② paragraph), and the delta only shapes what the two arms accept on arrival. Measured on each face: the strict face's accept set for the two arms widens (a spec-valid bound node, refused by name before, is accepted); the tolerant face, which kept any dataSource value through BaseSchema's passthrough, now judges the key as the binding, so a malformed value (an adapter name, say) is refused — a narrowing against unreleased main only, which the dev's deviations[1] names, and invisible against the release. "Nothing that parsed before is refused now" holds against the release, which is what the level measures. The new bullet's text matches the diff and the pin: both faces accept a bound node, an adapter name is refused, and "Both arms are new in this release" cites the pending changeset that proves it. Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read and Changeset Overwrite Report are green on the head.

③ Boundary flags

Dev deviations in 5917048524, each answered:

  1. Two existing EXCLUSIONS rows reworded to name the new member — accepted (①.5): not a new row, not a forced one, a ledger's prose kept true.
  2. The changeset bullet is release-relative — accepted (②); the reading is checked, not taken on trust.
  3. PR body not edited by the dev (the role file's one-write rule) — procedural; nothing owed by the dev; the seat's body edit carries it.
  4. The two stale PR-body statements — the exact sentences, and whether the suggested replacements are true.
    • Acceptance notes, first bullet. Three of its sentences went stale at the delta: "Their batch-2 arms do not declare it, so StrictAnyComponentSchema refuses { type: 'object-metric', dataSource: { object: 'task' } } with unrecognized_keys ['dataSource'] (measured on the built dist)." — true of 9fe676e31c, false at the head; "Carrier: PR objectui#11069, which wires objectui validate to the strict face." — the carrier is now this PR's patch round 1; "This PR declares the key on object-timeline only." — false. "The tolerant face accepts it." stays true (a bound node parses on both faces). The dev's replacement — "Folded in patch round 1 (26f8120): object-metric and object-master-detail-form declare dataSource with the same construct; one strict-face row per arm in the batch-2 pin." — is true against the delta: the construct is byte-identical (①.2) and the b2 pin gains one it.each row per arm whose headline assertion is the strict face's acceptance (each row also carries the tolerant-face and adapter-name assertions, so "strict-face row" understates and does not misstate). The seat's edit should retire all three stale sentences together, or recast the first in the past tense as the measurement at 9fe676e31c; replacing only the last one leaves the bullet contradicting itself.
    • "What changed", first bullet. Not false, incomplete: it describes only ObjectTimelineBlockSchema's work in objectql.zod.ts. The dev's addition — "and the two batch-2 arms declare the same dataSource (patch round 1)" — is true, and fits after "The node also declares dataSource as the spec's ElementDataSourceSchema by reference (see below)".
    • Two more body sentences the delta left incomplete (not false), for the seat's discretion in the same edit: the "What changed" bullet for zod-mirror-parity.test.ts ("the one EXCLUSIONS row the new export forces, in batch 2's wording. The union row's ...") — in patch round 1 the two batch-2 rows were reworded as well; and the "Files beyond the claimed surface" bullet for registered-type-arms-10859-b2.test.ts ("its exact list of ObjectQLPublicBlockComponentSchema literals gains object-timeline") — it also gains the two dataSource rows. The Tests section is headed "at head 9fe676e31c" and stays true as history; the head-26f8120ca2 runs are in the round report.
  5. mcp_calls 0, one API write (the report), the push not counted — procedural; nothing owed.

open_questions: none. out_of_scope_findings: none new. Round 1's out_of_scope_findings[0] (the batch-2 arms' dataSource refused on the strict face) is closed by this delta in the disposition round 1 proposed — two declarations in this PR's construct, two pin rows, no new census row — and the serial point (this PR before objectui#11069) still holds for the PR as a whole.

Implemented-by: claude/issue-10859-object-timeline-by-reference
Reviewed-by: session_0122Knsowci76D2rBWReCzzZ

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 18:29
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit ae0b9d3 Sep 30, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10859-object-timeline-by-reference branch September 30, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: cli package: types tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants