Repository navigation
Commit 7e36a3c
spec(object-timeline): items describe names objectui as the item-shape owner (#20531)
Fixes #20283
Clause-②: no
## What changed
`ObjectTimelinePropsSchema.items`
(`packages/spec/src/ui/component.zod.ts`) stays `z.array(z.unknown())` —
no schema-shape change. Its `.describe()` no longer says "the author
owns the item shape". It now names the actual owner: each element is
objectui's declared timeline element, `@object-ui/types`'s
`TimelineFeedItem` (`variant` absent / `vertical` / `horizontal`) or
`TimelineGanttItem` (`variant: 'gantt'`), the arm this node's own
`variant` selects.
`content/docs/references/ui/component.mdx` was regenerated via
`gen:schema && gen:docs` — never hand-edited.
`.changeset/20283-object-timeline-items-element-owner-describe.md` —
`@objectstack/spec` `patch`.
## Route taken (per the card, not re-opened)
`items` keeps `z.array(z.unknown())`; the value contract stays owned by
objectui. Declaring the arms here would fork a second vocabulary.
`mapping` and `object-gantt.markers` hold the same VALUE posture
unchanged.
## Verification record
**Premise re-measure (required before touching code).** At
`.objectui-sha` `dd3f7e1be3561d63267d7162f3fc0ac52e72834d` (the pin this
branch built against), `TimelineFeedItem` and `TimelineGanttItem` are
declared as plain TypeScript interfaces in objectui's
`packages/types/src/data-display.ts` (lines 2773 and 2834), pinned by
objectui's own
`packages/types/src/__tests__/timeline-item-element-6356.test.ts`.
`data-display.ts` imports `ChartAxis` / `ChartType` / `I18nLabel` from
`@objectstack/spec/ui` for the unrelated chart surface, but neither
`TimelineFeedItem` nor `TimelineGanttItem` imports or re-declares
anything from `@objectstack/spec` — the premise holds, so the route is
followed as given (no fork to report).
**Four read-point re-reads**, `objectui` `ObjectTimeline.tsx` at the
same pin (`git show
dd3f7e1be3561d63267d7162f3fc0ac52e72834d:packages/plugin-timeline/src/ObjectTimeline.tsx`):
- `:254` — `const hasInlineItems = Array.isArray(schema.items) &&
schema.items.length > 0;` (loading-state seed)
- `:374` — `const fetchesForItself = !!schema.objectName && !boundData
&& !schema.items && !(props as any).data;` (fetch-skip gate)
- `:546` — `if (schema.items) return schema.items;` (matches the
docblock's citation exactly)
- `:771` — `const hasAuthoredItems = !!schema.items;` (matches the
docblock's citation exactly)
All four anchors in the existing docblock
(`packages/spec/src/ui/component.zod.ts`, the `object-timeline` doc
comment) are byte-accurate at this pin — no anchor drift, so no docblock
line-number edit was needed. `pnpm --filter @objectstack/spec run
check:spec-docblock-symbol-anchors` also confirms: 4044 anchors resolve,
0 new anchor drift.
The `variant` describe ("`gantt` needs authored `items`") still reads
true beside the new `items` describe — confirmed against
`ObjectTimeline.tsx:809`, `if (!hasAuthoredItems && schema.variant ===
'gantt')` — left unchanged.
**Full-repo pin sweep** for the stale sentence: `grep -rl "author owns
the item shape"` across the whole tree (excluding `node_modules`/`.git`)
found exactly the two carriers named at dispatch —
`packages/spec/src/ui/component.zod.ts` and the generated
`content/docs/references/ui/component.mdx` — both fixed here. No test
pins the old describe string (`grep` for it and for `becomes a
pass-through` outside these two files: zero hits), so no fixture triage
was needed.
**Round 2 correction — a false refusal clause, measured and dropped.**
The first cut of this describe (and the changeset) also said objectui's
strict authoring face "refuses a mismatched arm and undeclared keys" for
`object-timeline` itself. A seat review measured that false at the pin,
and this round independently re-measured it before editing: objectui's
zod authoring face (`AnyComponentSchema` / `StrictAnyComponentSchema`,
`packages/types/src/zod/index.zod.ts`) is a
`z.discriminatedUnion('type', …)` whose member literals — read via `git
grep -n "z.literal('object-" dd3f7e1be3561d63267d7162f3fc0ac52e72834d --
packages/types/src/zod` — are `object-grid` / `object-form` /
`object-view` / `object-map` / `object-tree` / `object-gantt` /
`object-calendar` / `object-kanban` / `object-chart` / `object-gallery`
/ `object-data-table` and, separately, `timeline` — **never
`object-timeline`**. To measure the actual runtime answer rather than
infer it, `packages/types` was exported read-only via `git archive
dd3f7e1be3561d63267d7162f3fc0ac52e72834d packages/types` into a
throwaway probe run with `tsx` against this repo's own built
`@objectstack/spec` (the objectui checkout itself was never built,
checked out, or stashed): `StrictAnyComponentSchema.safeParse({ type:
'object-timeline', items: [{ label: 'x' }], variant: 'vertical' })`
returns a single `invalid_union` issue, `"note": "No matching
discriminator"`, on both the tolerant and the strict face —
`object-timeline` is refused outright as an unrecognized node `type`,
before any per-item judgment runs. A control on a genuine `{ type:
'timeline', … }` node reproduces the arm-selection and
`unrecognized_keys` mechanism exactly (a gantt row's `label` under
`variant: 'vertical'` draws a named `custom` issue; a feed item's
undeclared `date` key draws `unrecognized_keys`) — that mechanism lives
on the sibling `timeline` zod node (`TimelineSchema`'s `.superRefine`),
which `object-timeline` types against only in TypeScript
(`ObjectTimeline.tsx`'s `schema: TimelineSchema & { … }`), never at
runtime for this node. The refusal clause is dropped from the describe
and the changeset; nothing else about the route changed. Re-verified
after the fix: `check:generated` (15/15 green), the two
component/docs-facing unit test files (`component.test.ts`,
`component-element-navigation-17987.test.ts` — 366 tests green),
`check:doc-authoring` and `check:spec-docblock-symbol-anchors` (both
green), and a fresh `dispatch-gates.mjs` reconciliation on the new
commit — same 102 derived families as round 1 (the diff only edits words
inside the same two describe strings), 99 run green, the same 3
`PREREQUISITE NOT MET` NOT MEASURED as round 1.
## Tests run (this worktree, `objectstack-issue-20283`, HEAD
`0197523247`; round 1 ran at HEAD `3635807a7f`)
- `pnpm --filter @objectstack/spec build` — exit 0 (rebuilt after
merging `origin/main`).
- `pnpm --filter @objectstack/spec check:generated` — exit 0, all 15
generated artifacts up to date (pre- and post-merge).
- `pnpm --filter @objectstack/spec test` — **573 test files passed
(573), 16809 tests passed | 1 todo**.
- `pnpm --filter @objectstack/spec typecheck` (`tsc --noEmit` +
`check:scripts-typecheck` + `check:test-typecheck`) — exit 0.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran` (an annotated ran-list file) reconciliation: **102 derived
families, 99 run green, 3 NOT MEASURED (`PREREQUISITE NOT MET`, exit 3),
0 unrun** — `pnpm --filter @objectstack/spec run check:skill-examples`,
`pnpm check:dual-build-cjs-loads`, `pnpm check:lean-entry-closure` each
refused locally before measuring anything because they read BUILT output
of unrelated packages (`@objectstack/client-react`, and — for
`dual-build-cjs-loads` — the whole workspace's `dist/`, 82+ packages)
that this describe-only change does not touch and that a full local
build did not fit this task's floor-tier scope; the shared
`os-verify-lock` queue was also heavily contended by sibling agents'
builds throughout this run. CI's full farm covers these.
- `pnpm check:doc-authoring` — exit 0: 16748 customer-facing strings
across 1170 spec sources clean, no internal issue-id references (the new
describe carries none).
- `pnpm check:nul-bytes`, `pnpm check:merge-driver`, `pnpm
check:objectui-pin-citations`, `check:changeset-gate-self-tests`
(`check:empty-changeset` / `check:adr-0087-registration` /
`check:changeset-no-major`) — all exit 0.
- Dependency-closure build (①): none — `packages/spec` has no workspace
dependencies, so the closure is empty by construction.
- Downstream consumer closure: not run — this is a `.describe()` text
change only; the compiled `.d.ts` type surface is byte-identical
(confirmed by `check:api-surface` and `check:export-origins` both green
with zero diff), so no downstream package's typecheck is implicated.
## Acceptance notes
No out-of-scope findings of class (a)/(b)/(c) surfaced while working
this card. `origin/main` advanced twice during this round (to
`fb194c70e5`, then merged again to `fb386074f5` after a clean `git merge
origin/main` with no conflicts and no overlap with the two touched
files); rebuilt and re-ran `check:generated` after the merge, still all
15 green.
---
_Generated by [Claude
Code](https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 288611e commit 7e36a3c
3 files changed
Lines changed: 9 additions & 2 deletions
File tree
- .changeset
- content/docs/references/ui
- packages/spec/src/ui
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
991 | 991 | | |
992 | 992 | | |
993 | 993 | | |
994 | | - | |
| 994 | + | |
995 | 995 | | |
996 | 996 | | |
997 | 997 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5207 | 5207 | | |
5208 | 5208 | | |
5209 | 5209 | | |
5210 | | - | |
| 5210 | + | |
5211 | 5211 | | |
5212 | 5212 | | |
5213 | 5213 | | |
| |||
0 commit comments