You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(spec): correct GanttConfig.timeZone describe — date fields don't persist as real instants (#20495)
Fixes#20466
Clause-②: no
## What changed
`packages/spec/src/ui/view.zod.ts`, the `GanttConfig` `timeZone`
member's
`.describe()`: replaced only the false clause "persisted data stays real
instants" with the card's true wording — a datetime value is still
written
as the real instant, and a date value as the calendar day it was dropped
on
in this zone's calendar (`YYYY-MM-DD`). Nothing else in the describe
moved.
Verified against the spec's own storage rule
(`packages/core/src/utils/temporal-storage-form.ts`, ADR-0053):
`datetime`
stores canonical UTC ISO text; `date` stores a timezone-naive
`YYYY-MM-DD`
calendar day. The new sentence is true of the contract, not of one
renderer.
No mention of objectui's DST shim defect (objectstack-ai/objectui#10866
slice 5) — that stays a renderer bug, per triage.
Regenerated the reference docs that carried the old sentence verbatim
(`content/docs/references/ui/view.mdx` ×3, `component.mdx` ×1) via
`pnpm --filter @objectstack/spec gen:schema && gen:docs` — never by
hand.
Grepped the exact phrase across the whole repo; the only other copies
were
those four generated doc occurrences (plus the JSON-Schema manifest,
which
only ratchets schema names, not prose). No hand-written copy found, no
test
pins the old text.
## Verification record
- `pnpm --filter @objectstack/spec build` — green (36/36 declared
`.d.ts`, 130 declaration files, 394/394 relative references resolved).
- `pnpm --filter @objectstack/spec check:generated` — 15/15 generated
artifacts green (only `check:docs` was stale before `gen:docs`, now
current).
- `pnpm --filter @objectstack/spec typecheck` (`tsc --noEmit` + scripts
+ test-layer) — green.
- `pnpm --filter @objectstack/spec test` — 572 test files, 16789 tests
passed, 1 todo (unrelated pre-existing todo).
- Targeted first: `view.test.ts` +
`view-gantt-tree-config-closed-15469.test.ts` — 502 tests passed. No
test pins the old describe text; none needed updating.
- `packages/spec`'s own build closure (`pnpm --filter
'@objectstack/spec^...' build`) is EMPTY — nothing in this repo depends
on `@objectstack/spec` as a workspace package the way `turbo`'s graph
tracks it here, so ① has nothing to build.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` derived 102 gate commands from the diff (4 files, +25/-5, 30
changed lines). Ran all 102:
- **99/102 green** on the real command (exit 0), including
`check:doc-authoring` (no tracker number in the describe),
`check:nul-bytes`, `check:merge-driver`, `check:changeset-no-major`,
`check:empty-changeset`,
`check:issue-citations`/`check:closing-keyword-parity` (the `Fixes#20466` line), and every `packages/spec` `check:*` gate the diff
touches.
- **3/102 NOT MEASURED** — `PREREQUISITE NOT MET` (exit 3, not a
finding): `check:skill-examples` (client SDK surface needs
`@objectstack/client-react`+`@objectstack/client` built),
`check:dual-build-cjs-loads` (needs ~80 packages' `dist/`, effectively a
whole-repo build) and `check:lean-entry-closure` (needs
`@objectstack/objectql` built). None is in `packages/spec`'s own build
closure (which is empty); building them locally would mean rebuilding
most of the monorepo for a single-clause prose fix. Deferred to CI's
full build, which measures all three.
- 3 of the original 6 exit-3s (`check:doc-formula-expressions`,
`check:doc-security-posture`, `check:docs-transcript-drift`) needed only
`@objectstack/formula` + `@objectstack/lint` built — built those two
directly and reran: all green.
- Merged `origin/main` (view.zod.ts carried seat 4's landed #20474
`view-console-round-trip-keys` change past my region) via `bash
scripts/pm/os-regen-merge.sh`: the driver deferred
`content/docs/references/ui/view.mdx` (both sides changed it),
regenerated with `gen:schema && gen:docs` on the merged tree, verified
`#20474`'s symbols and prose survived byte-for-byte (`git grep` against
`origin/main`), then committed the regeneration as its own commit per
the runbook. `git diff origin/main HEAD --
packages/spec/src/ui/view.zod.ts` shows exactly the one-clause change,
nothing else.
- Reverified no further origin/main commits touch this file surface
after the merge (`git log HEAD..origin/main -- <the 3 touched paths>` —
empty).
## Acceptance notes
- objectui's `@object-ui/types` zod mirror
(`stripImportedDefaults(SpecGanttConfigSchema).shape.timeZone`) is a
spec-derived reuse of this describe. Per triage's direction, objectui is
not edited here — its mirror picks up the corrected text at its next
spec bump.
---
_Generated by [Claude
Code](https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: content/docs/references/ui/component.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -676,7 +676,7 @@ Sort field and direction pair
676
676
|**summaryExtent**|`Enum<'children' \| 'self'>`| optional | How a summary bar's span is computed. 'children' (renderer default) rolls the bar up from its children — min start, max end, duration-weighted progress — and ignores the record's own dates; 'self' renders the record's OWN start, end and progress and falls back to rollup only for records without dates (use it when the parent's schedule is authoritative, e.g. a shift plan whose work-order children are locked history) |
677
677
|**defaultCollapsedDepth**|`integer`| optional | Auto-collapse tree nodes at or below this 0-indexed depth on first render (roots are depth 0): every node at that depth or deeper that has children starts folded; the user can still expand them. Omit to start fully expanded |
678
678
|**dependencyTypes**|`boolean`| optional | Whether the backing store persists dependency link TYPES (fs, ss, ff, sf); renderer default true. Set false when dependencies are bare predecessor ids: the link menu hides the type switcher (a switch would be silently reverted on refetch) and drag-created links are always finish-to-start |
679
-
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; persisted data stays real instants. An invalid name falls back to the browser zone with a console warning |
679
+
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; a datetime value is still written as the real instant, and a date value as the calendar day it was dropped on in this zone's calendar (YYYY-MM-DD). An invalid name falls back to the browser zone with a console warning |
680
680
|**exportFileName**|`string`| optional | Base name for exported PNG and PDF files (e.g. the view's display label — the host's view schema often reaches the renderer stripped of label); falls back to the object schema label, then the object API name. A timestamp suffix is always appended |
681
681
|**interactions**|`{ move?: boolean; resize?: boolean; progress?: boolean; link?: boolean }`| optional | Per-interaction switches, each defaulting to true: allow bar moves but pin durations (resize: false), or keep the dependency UI read-only (link: false). They only narrow what readOnly and row locks already allow |
682
682
|**timeSegments**|`{ dayStart?: string; bands: object[]; showMidnight?: boolean }`| optional | Shift segmentation for the day-mode timeline: splits each shift-day (starting at dayStart) into the configured bands — a two-tier header (date over band), per-band tints and drag/resize snapping to band boundaries. No shift concept is hardcoded; bands are pure config. Off when omitted |
|**summaryExtent**|`Enum<'children' \| 'self'>`| optional | How a summary bar's span is computed. 'children' (renderer default) rolls the bar up from its children — min start, max end, duration-weighted progress — and ignores the record's own dates; 'self' renders the record's OWN start, end and progress and falls back to rollup only for records without dates (use it when the parent's schedule is authoritative, e.g. a shift plan whose work-order children are locked history) |
582
582
|**defaultCollapsedDepth**|`integer`| optional | Auto-collapse tree nodes at or below this 0-indexed depth on first render (roots are depth 0): every node at that depth or deeper that has children starts folded; the user can still expand them. Omit to start fully expanded |
583
583
|**dependencyTypes**|`boolean`| optional | Whether the backing store persists dependency link TYPES (fs, ss, ff, sf); renderer default true. Set false when dependencies are bare predecessor ids: the link menu hides the type switcher (a switch would be silently reverted on refetch) and drag-created links are always finish-to-start |
584
-
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; persisted data stays real instants. An invalid name falls back to the browser zone with a console warning |
584
+
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; a datetime value is still written as the real instant, and a date value as the calendar day it was dropped on in this zone's calendar (YYYY-MM-DD). An invalid name falls back to the browser zone with a console warning |
585
585
|**exportFileName**|`string`| optional | Base name for exported PNG and PDF files (e.g. the view's display label — the host's view schema often reaches the renderer stripped of label); falls back to the object schema label, then the object API name. A timestamp suffix is always appended |
586
586
|**interactions**|`{ move?: boolean; resize?: boolean; progress?: boolean; link?: boolean }`| optional | Per-interaction switches, each defaulting to true: allow bar moves but pin durations (resize: false), or keep the dependency UI read-only (link: false). They only narrow what readOnly and row locks already allow |
587
587
|**timeSegments**|`{ dayStart?: string; bands: object[]; showMidnight?: boolean }`| optional | Shift segmentation for the day-mode timeline: splits each shift-day (starting at dayStart) into the configured bands — a two-tier header (date over band), per-band tints and drag/resize snapping to band boundaries. No shift concept is hardcoded; bands are pure config. Off when omitted |
@@ -979,7 +979,7 @@ View filter rule
979
979
|**summaryExtent**|`Enum<'children' \| 'self'>`| optional | How a summary bar's span is computed. 'children' (renderer default) rolls the bar up from its children — min start, max end, duration-weighted progress — and ignores the record's own dates; 'self' renders the record's OWN start, end and progress and falls back to rollup only for records without dates (use it when the parent's schedule is authoritative, e.g. a shift plan whose work-order children are locked history) |
980
980
|**defaultCollapsedDepth**|`integer`| optional | Auto-collapse tree nodes at or below this 0-indexed depth on first render (roots are depth 0): every node at that depth or deeper that has children starts folded; the user can still expand them. Omit to start fully expanded |
981
981
|**dependencyTypes**|`boolean`| optional | Whether the backing store persists dependency link TYPES (fs, ss, ff, sf); renderer default true. Set false when dependencies are bare predecessor ids: the link menu hides the type switcher (a switch would be silently reverted on refetch) and drag-created links are always finish-to-start |
982
-
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; persisted data stays real instants. An invalid name falls back to the browser zone with a console warning |
982
+
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; a datetime value is still written as the real instant, and a date value as the calendar day it was dropped on in this zone's calendar (YYYY-MM-DD). An invalid name falls back to the browser zone with a console warning |
983
983
|**exportFileName**|`string`| optional | Base name for exported PNG and PDF files (e.g. the view's display label — the host's view schema often reaches the renderer stripped of label); falls back to the object schema label, then the object API name. A timestamp suffix is always appended |
984
984
|**interactions**|`{ move?: boolean; resize?: boolean; progress?: boolean; link?: boolean }`| optional | Per-interaction switches, each defaulting to true: allow bar moves but pin durations (resize: false), or keep the dependency UI read-only (link: false). They only narrow what readOnly and row locks already allow |
985
985
|**timeSegments**|`{ dayStart?: string; bands: object[]; showMidnight?: boolean }`| optional | Shift segmentation for the day-mode timeline: splits each shift-day (starting at dayStart) into the configured bands — a two-tier header (date over band), per-band tints and drag/resize snapping to band boundaries. No shift concept is hardcoded; bands are pure config. Off when omitted |
@@ -1362,7 +1362,7 @@ View filter rule
1362
1362
|**summaryExtent**|`Enum<'children' \| 'self'>`| optional | How a summary bar's span is computed. 'children' (renderer default) rolls the bar up from its children — min start, max end, duration-weighted progress — and ignores the record's own dates; 'self' renders the record's OWN start, end and progress and falls back to rollup only for records without dates (use it when the parent's schedule is authoritative, e.g. a shift plan whose work-order children are locked history) |
1363
1363
|**defaultCollapsedDepth**|`integer`| optional | Auto-collapse tree nodes at or below this 0-indexed depth on first render (roots are depth 0): every node at that depth or deeper that has children starts folded; the user can still expand them. Omit to start fully expanded |
1364
1364
|**dependencyTypes**|`boolean`| optional | Whether the backing store persists dependency link TYPES (fs, ss, ff, sf); renderer default true. Set false when dependencies are bare predecessor ids: the link menu hides the type switcher (a switch would be silently reverted on refetch) and drag-created links are always finish-to-start |
1365
-
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; persisted data stays real instants. An invalid name falls back to the browser zone with a console warning |
1365
+
|**timeZone**|`string`| optional | Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; a datetime value is still written as the real instant, and a date value as the calendar day it was dropped on in this zone's calendar (YYYY-MM-DD). An invalid name falls back to the browser zone with a console warning |
1366
1366
|**exportFileName**|`string`| optional | Base name for exported PNG and PDF files (e.g. the view's display label — the host's view schema often reaches the renderer stripped of label); falls back to the object schema label, then the object API name. A timestamp suffix is always appended |
1367
1367
|**interactions**|`{ move?: boolean; resize?: boolean; progress?: boolean; link?: boolean }`| optional | Per-interaction switches, each defaulting to true: allow bar moves but pin durations (resize: false), or keep the dependency UI read-only (link: false). They only narrow what readOnly and row locks already allow |
1368
1368
|**timeSegments**|`{ dayStart?: string; bands: object[]; showMidnight?: boolean }`| optional | Shift segmentation for the day-mode timeline: splits each shift-day (starting at dayStart) into the configured bands — a two-tier header (date over band), per-band tints and drag/resize snapping to band boundaries. No shift concept is hardcoded; bands are pure config. Off when omitted |
summaryExtent: z.enum(['children','self']).optional().describe("How a summary bar's span is computed. 'children' (renderer default) rolls the bar up from its children — min start, max end, duration-weighted progress — and ignores the record's own dates; 'self' renders the record's OWN start, end and progress and falls back to rollup only for records without dates (use it when the parent's schedule is authoritative, e.g. a shift plan whose work-order children are locked history)"),
1918
1918
defaultCollapsedDepth: z.number().int().min(0).optional().describe('Auto-collapse tree nodes at or below this 0-indexed depth on first render (roots are depth 0): every node at that depth or deeper that has children starts folded; the user can still expand them. Omit to start fully expanded'),
1919
1919
dependencyTypes: z.boolean().optional().describe('Whether the backing store persists dependency link TYPES (fs, ss, ff, sf); renderer default true. Set false when dependencies are bare predecessor ids: the link menu hides the type switcher (a switch would be silently reverted on refetch) and drag-created links are always finish-to-start'),
1920
-
timeZone: z.string().optional().describe("Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; persisted data stays real instants. An invalid name falls back to the browser zone with a console warning"),
1920
+
timeZone: z.string().optional().describe("Business time zone, an IANA name such as 'Asia/Shanghai': the chart's calendar — shift bands, day columns, snapping, the today line, date labels — renders in this zone's wall time for every viewer instead of the browser's zone; a datetime value is still written as the real instant, and a date value as the calendar day it was dropped on in this zone's calendar (YYYY-MM-DD). An invalid name falls back to the browser zone with a console warning"),
1921
1921
exportFileName: z.string().optional().describe("Base name for exported PNG and PDF files (e.g. the view's display label — the host's view schema often reaches the renderer stripped of label); falls back to the object schema label, then the object API name. A timestamp suffix is always appended"),
0 commit comments