Skip to content

feat(spec): a calendar view can declare the date it opens on, calendar.initialDate - #28138

Merged
objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-28021-calendar-initial-date
Oct 31, 2026
Merged

objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-28021-calendar-initial-date

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

🤖 Generated with Claude Code

https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V

Fixes #28021

Clause-②: yes (widening)
Metadata-protocol: added
Skills-docs: none — no file under skills/** lists the calendar block's members. The key's describe ships to content/docs/references/ui/view.mdx and component.mdx, regenerated here. Until the Console reads the key (#28102), teaching it in a skill would advertise behaviour the renderer does not have yet.

维护者速读

  • 改了什么:日历视图配置 calendar 新增可选键 initialDate,取值三选一:'today' / 'first_record' / 'next_record'。作者可以声明日历打开时落在哪一天。不写这个键就是今天,存量日历行为不变。
  • 为什么改:日历总是打开在当月。记录都排在几个月以后的日历(比如续约日历),一打开就是空的一个月,作者无法改变。
  • 风险与回滚:纯放宽,只加了一个可选键,spec 侧没有默认值,存量视图解析结果逐字节不变。回滚就是 revert 本 PR。控制台读取这个键在 The Console calendar does not read calendar.initialDate, so it still opens on today #28102 做;在那之前写了这个键也照样打开在今天。
  • 先看:packages/spec/src/ui/view.zod.ts(CalendarConfigSchema.initialDate 的取值与 describe);packages/spec/src/ui/calendar-config-initial-date.test.ts;packages/spec/liveness/view.json(calendar 行注明此键暂为 planned)。
  • 两分钟验证:pnpm --filter @objectstack/spec exec vitest run src/ui/calendar-config-initial-date.test.ts,预期 19 个用例全部通过。
  • 需要你做的:批准键名 initialDate 和三个取值(不批准的话,请给出要换的名字或取值)。

What changes

  • CalendarConfigSchema gains initialDate: z.enum(['today', 'first_record', 'next_record']).optional(). The list view's calendar block and the object-calendar node's calendar prop both get it, because the prop takes the block by reference.
    • 'today': the calendar opens on the period that holds today. An omitted key does the same.
    • 'first_record': the period that holds the earliest startDateField value among the records the view selects.
    • 'next_record': the period that holds the earliest startDateField value on or after today.
    • When no record qualifies, the calendar opens on today. "Period" means the month, week or day of the active view mode.
  • Why this name. No sibling view config (gantt, timeline, map) declares an initial date or range, so there is no spelling to mirror. initialDate says where the calendar opens. It avoids the default* prefix, which on this platform also reads as "fallback value". The nearest precedent is object-calendar's defaultView ("Initial view mode"). If the maintainer wants the two to match, the alternative is defaultDate.
  • Why these values. next_record is included because it is the value the card's own reach needs. A renewals calendar that also holds past renewals would open years back under first_record. Under next_record it opens on the next renewal that is still ahead.
  • Why no fixed ISO date. A date stored on a view goes stale as time passes: the same view opens on an older month every day. No producer that asks for a fixed date was found. A fixed date ('2026-11-01'), a date-macro token ('{today}') and every near-miss spelling are refused with Zod's invalid_value at calendar.initialDate. The refusal message lists the three values. Admitting a date later would be a widening.
  • Why it lives on this block. The block's own TSDoc keeps defaultView out, as a UI preference with its home on the component. initialDate differs in two ways: a stored list view has no other place to author it, and two of its three values are defined by this block's startDateField binding.
  • No spec-side default. The reason is the same as for gantt viewMode: a materialized 'today' would be written onto every parsed calendar and would read as an author's choice.
  • Copies kept in step.
    • The object-calendar calendar prop's describe now lists initialDate?.
    • The liveness ledger's calendar row says initialDate rides at planned strength until its reader lands.
    • The authorable surface (authorable-surface/ui.json) and the reference docs (view.mdx, component.mdx) are regenerated.
    • Nothing under skills/** lists the block's members.
  • Console half: The Console calendar does not read calendar.initialDate, so it still opens on today #28102 (domain:ui, filed by this PR, lands after it). ObjectCalendar still seeds currentDate with useState(new Date()).

Tests

packages/spec/src/ui/calendar-config-initial-date.test.ts, 19 cases:

  • Accepted: each of the 3 values, on CalendarConfigSchema, on a whole stored ListViewSchema, and on the object-calendar node.

  • Absent: no default is materialized, so a calendar stored without the key parses to exactly the block it stored.

  • Refused: a fixed date, a fixed timestamp, first, firstRecord, TODAY and {today}. Each case asserts:

    • the issue code invalid_value;
    • the path ['calendar', 'initialDate'];
    • that the message names all three members;
    • that the wire envelope from zodIssuesToFields is { field: 'calendar.initialDate', code: 'invalid_option' };
    • the validation class status, 400.

    A non-string value is refused at the same path. An unknown key is still refused as unrecognized_keys.

Local runs at d7c3dce
  • pnpm --filter @objectstack/spec test (under the verify lock): Test Files 757 passed (757), Tests 22529 passed | 1 todo, VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec typecheck: exit 0, in the same locked run.
  • pnpm --filter @objectstack/spec check:generated, before regeneration: 13 of 14 green and check:docs stale. Then gen:docs was run. check:authorable-surface rewrote authorable-surface/ui.json (+1 line, ui/CalendarConfig:initialDate). authorable-surface.base.json was not touched.

Acceptance notes

  • ui/-owned copies that list the calendar block's keys. These are not edited here, because none of them reads the key and editing them would advertise behaviour the renderer does not have yet. They are named on The Console calendar does not read calendar.initialDate, so it still opens on today #28102:
    • the list-view registry input description (ui/packages/plugin-list/src/index.tsx), which feeds sdui.manifest.json and content/docs/ui/components/plugins.mdx;
    • the object-calendar registry calendar input description;
    • the hand-typed calendar options in ui/packages/types/src/designer.ts.
  • Mirror and Studio need no edit.
    • The @object-ui/types mirror takes the block by reference, so it accepts the key without an edit.
    • The Studio view inspector's SchemaForm is driven by the JSON Schema and renders an enum prop as a select. It picks a field picker only for names ending in Field, so initialDate should show as a select of the three values. This is from reading the code; it was not run in a browser.
  • Independent review: none run (quota). The PR waits for the seat's contract-review hand-off.

Verification

Derived gate families at d7c3dce
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 104 commands for 8 paths (+167 / -3).
  • All 104 were run, and each exit code was captured before any pipe. 97 exited 0.
  • 7 exited 3 (PREREQUISITE NOT MET) and are NOT MEASURED locally. Each one reads built output of packages outside this diff, and the container builds only @objectstack/spec. CI's Lint & Repo Gates and TypeScript Type Check run them:
    • pnpm --filter @objectstack/lint run check:doc-formula-expressions and check:doc-security-posture (need lint and formula built);
    • pnpm --filter @objectstack/spec run check:skill-examples (needs client-react built);
    • pnpm check:docs-transcript-drift (needs lint built);
    • pnpm check:dual-build-cjs-loads (needs every package built);
    • pnpm check:lean-entry-closure (needs objectql built);
    • pnpm check:type-check-debt (its closure build timed out in the verify lock queue).
  • --ran reconciliation: ✓ 104 derived famil(ies) accounted for — 97 run, 7 NOT-MEASURED (7 DERIVED from a recorded exit 3).
  • Local-only families:
    • check:skill-frame-freshness: exit 0.
    • check:dev-prereqs: exit 1, The workspace is not built — 1 unmet precondition. Only spec is built in this container, so this is a fact about the container, not about the diff.
  • Full dogfood: n/a. The title has no ! and there is no (narrowing) arm.

Generated by Claude Code

CalendarConfigSchema declares initialDate, a closed set of relative
anchors (today, first_record, next_record) for the date a calendar
opens on. Absent means today, so every stored calendar keeps its
behaviour; no spec-side default is materialized.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
… calendar initialDate, add changeset

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:ui tests tooling labels Oct 30, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 16 documentable anchor(s). ⚠️ 2 changed file(s) yielded no anchor (packages/spec/authorable-surface/ui.json, packages/spec/liveness/view.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

10 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/automation/flows.mdx (via dateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/data-modeling/field-types.mdx (via titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/data-modeling/formulas.mdx (via dateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/data-modeling/virtual-objects.mdx (via endDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), startDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/frontend/plugins/plugin-calendar.mdx (via allDayField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), colorField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), endDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), startDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/frontend/plugins/plugin-gantt.mdx (via endDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), startDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/frontend/plugins/plugin-map.mdx (via titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/frontend/plugins/plugin-timeline.mdx (via colorField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), endDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), startDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/ui/pages.mdx (via titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/ui/views.mdx (via colorField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), endDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), startDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))

⛔ 4 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v16.mdx (via dateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/releases/v17/17-1.mdx (via titleField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/releases/v17/17-5.mdx (via CalendarConfigSchema (symbol, a top-level const), dateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE), endField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))
  • content/docs/releases/v17/17-7.mdx (via startDateField (literal, a string literal in OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 changed file(s) yielded no anchor (packages/spec/authorable-surface/ui.json, packages/spec/liveness/view.json) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 58 of 210 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 3739d8d6c64f47f9f8e9e873a480cafe09b11bed → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 6e7a97e06784b10b897fb33e49b7ef8217ccade0 — the merge of head 254b2fb067ddc379fa28dcf20e0dacebe70056d7 into base 3739d8d6c64f47f9f8e9e873a480cafe09b11bed, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 6e7a97e06784b10b897fb33e49b7ef8217ccade0 && git checkout 6e7a97e06784b10b897fb33e49b7ef8217ccade0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 3739d8d6c64f47f9f8e9e873a480cafe09b11bed 254b2fb067ddc379fa28dcf20e0dacebe70056d7 && git checkout -B drift-repro 3739d8d6c64f47f9f8e9e873a480cafe09b11bed && git merge --no-ff 254b2fb067ddc379fa28dcf20e0dacebe70056d7

node scripts/docs-audit/affected-docs.mjs --json 3739d8d6c64f47f9f8e9e873a480cafe09b11bed

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 3739d8d6c64f47f9f8e9e873a480cafe09b11bed → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

席位核对 · ACCEPT (lane part) · card #28021 · 2026-10-30T13:48Z

  • Shape: 8 files, +167 / −3 at head d7c3dce6. CalendarConfigSchema.initialDate: z.enum(['today','first_record','next_record']).optional() (packages/spec/src/ui/view.zod.ts), with no spec-side default, so a stored calendar parses to exactly the block it stored and opens on today as before. The object-calendar node takes the same block by reference; only its describe moves (component.zod.ts). liveness/view.json carries the key at PLANNED strength on the calendar row, after the gantt viewMode precedent, until the console reads it. Regenerated: authorable-surface/ui.json (+1 row), content/docs/references/ui/view.mdx and component.mdx. Changeset: @objectstack/spec minor, Clause-②: yes (widening) / Metadata-protocol: added. Matches the card's Wanted (spec half).
  • Claim amendment (file surface): packages/spec/src/ui/component.zod.ts (the object-calendar prop describe) and packages/spec/liveness/view.json (the PLANNED note) join the claimed surface. Both follow from the key itself; neither changes an accept set beyond the one key.
  • Measured choices (for the contract reviewer and the maintainer):
    • Key name initialDate, not defaultDate: no sibling view config declares one, and default* reads as "fallback value" on this platform. ⛔ Not final until the maintainer approves the name and its three values in this PR.
    • Values: next_record is in because the card's own renewals case needs it (with past renewals present, first_record opens years back). A fixed ISO date is refused: a date stored on a view goes stale, and no producer asks for one.
  • Dev: opus under the quota-exhaustion exemption. New calendar-config-initial-date.test.ts, 19 cases: three values accepted on the config, on a whole list view and on the node; absence adds no default; six refusals assert invalid_value, path calendar.initialDate, the message naming the three values, the wire invalid_option and 400 (status through ErrorHttpStatusMap, not a live save); an unknown key is still refused. Spec tests 22529 passed, typecheck 0; gates 104 run, 97 pass, 7 exit 3 on unbuilt packages (CI answers). os-dev-report 6524362443.
  • Console half: The Console calendar does not read calendar.initialDate, so it still opens on today #28102 (ObjectCalendar reads the key; the ui/ registry copies that list the calendar keys move with it). Lands after this PR.
  • Owed before any landing stroke: the CONTRACT_REVIEW_TIER review (packages/spec/src/** hunks), green CI, and the maintainer's approval of the key name and values; this seat cannot serve that tier now and hands the review over below.

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head d7c3dce

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK

Contract-review-claim: session_01L6bhgV4fMGJHSdSdx3u9mK · head d7c3dce62b504f9036fa7c71810d029d20190c8d · 2026-10-30T15:09Z


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Contract-review-hold: session_017ihL2fi9zfJhUTubyJYb6V · head d7c3dce · the maintainer changed the value set, so this head's shape is being replaced · until the rework head is pushed and its handoff line names it

The maintainer wrote at 2026-10-30T15:08Z: 「而存在视图里的日期会一天天过时,这个可以利用公式啊」. initialDate will take the two record anchors, or a wrapped date-macro token (DATE_MACRO_TOKENS, as the dashboard date filter's defaultValue does), and bare 'today' goes. A review of this head would judge a shape that is being replaced, so the seat holds it. Triage claim 6526082865 can stand down. The new head brings a fresh Contract-review-handoff: line.

…o token

initialDate now accepts first_record / next_record, or a wrapped, known
date-macro token ({today}, {next_month_start}, {3_months_from_now}),
judged by the date-macro vocabulary's own predicate pair. The bare
'today' value is dropped ({today} is its one spelling; an absent key
still means today). A fixed date stays refused, and the refusal names
both forms and DATE_MACRO_TOKENS.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d7c3dce62b504f9036fa7c71810d029d20190c8d
Local-runs: none
Scope: packages/spec/src/ui/component.zod.ts, packages/spec/src/ui/view.zod.ts + packages/spec/liveness/view.json, packages/spec/scripts/liveness/undrilled-containers.baseline.json, packages/spec/liveness/README.md, packages/spec/src/ui/app.zod.ts (the navigation.dataSource PLANNED precedent), packages/spec/src/kernel/functional-completeness.ts, packages/spec/src/api/zod-issues-to-fields.ts, packages/lint/src/validate-list-view-field-refs.ts, ui/packages/plugin-calendar/src/ObjectCalendar.tsx, ui/packages/plugin-calendar/src/calendar-view-renderer.tsx, ui/packages/plugin-calendar/src/index.tsx, ui/packages/plugin-list/src/ListView.tsx, ui/packages/plugin-list/src/index.tsx, ui/packages/app-shell/src/views/objectViewOptions.ts, ui/packages/types/src/zod/complex.zod.ts, ui/packages/types/src/objectql.ts, ui/packages/types/src/designer.ts, docs/adr/0049-no-unenforced-security-properties.md, docs/adr/0078-no-silently-inert-metadata.md, docs/adr/0053-date-and-datetime-semantics.md

Inputs read: card #28021 (body, the claim comment and the os-dev-report), PR #28138 (body, 8-file list, net diff against main at the head above), the PR's two comments (docs-drift advisory and the lane seat's ACCEPT with its hand-off line), and the 55 check-runs on the head. Verdict rendered on the tree, not on the PR body's account of it.

① Derived judgments

Gate verdicts on the head: every required context is success — Lint & Repo Gates, TypeScript Type Check (the six check:generated gates, check:authorable-surface and check:docs among them), Test Core (8/8 shards), Build Core, Governed Surface Queue Guard, Lint UI (skipped by path filter), Type Check UI, Test UI, Build & E2E UI, Live E2E UI. Spec property liveness success, Check Changeset success, PR-body guards success, Check PR Size success. No red, no in_progress.

Accept-set changes the diff implies, each judged:

  • CalendarConfigSchema (view.zod.ts L2199) gains initialDate: z.enum(['today','first_record','next_record']).optional() inside an existing strictObject. Widening only: a block without the key parses byte-identical (no .default), an unknown key is still refused by name, a value outside the closed set is refused with the enum's invalid_value at calendar.initialDate, which zodIssuesToFields (L103-105) lowers to the wire code invalid_option. RIGHT — and pinned by the 19-case test file.
  • The same member rides the object-calendar node by reference (component.zod.ts L6192 ListViewSchema.shape.calendar), so the page-block door widens identically with no second declaration; only its .describe() text moves. RIGHT.
  • Public type surface: CalendarConfig / ListView['calendar'] / ObjectCalendarProps['calendar'] each gain one optional member; no export added, renamed or removed, so api-surface is untouched and check:api-surface is green. authorable-surface/ui.json gains exactly ui/CalendarConfig:initialDate; view.mdx / component.mdx regenerate the describe into four tables. RIGHT (generated output not reviewed, read to confirm the key lands once).
  • Liveness ledger: view/list.calendar stays live; the key's PLANNED strength is recorded in that row's note. The row is an undrilled container (scripts/liveness/undrilled-containers.baseline.json L144), so no per-key row exists to grade planned with authorWarn: the note is the only ledger form available. RIGHT in form, but see ④ M1 — the ledger note is written for ledger maintainers ("never shown to an author", liveness README) and cannot carry the author-facing marking by itself.
  • Console: no ui/ edit is implied. Measured on the head: ui/packages/types/src/objectql.ts derives ObjectCalendarBlockConfig from the spec schema (by reference, no re-listed key set); app-shell objectViewOptions.ts#calendarViewOptions forwards the declared block by spread ("so every spec key survives"); plugin-list ListView.tsx#collectViewFields (both the expandFields twin at L2548 and the $select twin at L3126) picks named binding keys only, so an authored initialDate is never projected as a field and cannot trip the REST INVALID_FIELD refusal; ObjectCalendar.tsx L524 still seeds currentDate with useState(new Date()), as the ledger note says. Writing the key today is inert, not harmful. RIGHT.
  • Lint: packages/lint/src/validate-list-view-field-refs.ts grades the calendar block through an explicit scalars map (L635-655), so initialDate: 'today' is not read as a field reference. RIGHT, no lint change owed.
  • Completeness predicate (functional-completeness.ts, the calendar row) keys on startDateField alone; unchanged, and nothing here changes what makes a calendar instance inert. RIGHT.
  • Skills-docs: none — on this tree no file under skills/** enumerates the calendar block's members (skills/objectstack-ui/rules/list-views.md L290 and skills/objectui/guides/page-builder.md L293-305 enumerate GANTT keys only). RIGHT.

② Semver level

Changeset .changeset/28021-calendar-initial-date.md: '@objectstack/spec': minor, carrying Clause-②: yes (widening) and Metadata-protocol: added on both the changeset and the PR body (PR-body guards and Check Changeset success). A new accepted key on a metadata schema is added, and a kind takes at least minor on the package the diff moves (AGENTS.md Post-Task Checklist step 3). No removal, no narrowed value, no changed default, so no BREAKING banner and no ADR-0087 disposition is owed; the title carries no !. The level matches what the diff publishes.

Clause-②: yes (widening) — one optional key with a closed value set, absence unchanged.

③ Boundary flags

Dev flags (os-dev-report deviations), each answered:

  1. File surface beyond the claim (component.zod.ts describe, liveness/view.json note) — both follow from the key itself; the lane seat amended the claim in its ACCEPT. Answered.
  2. Rejection status pinned through ErrorHttpStatusMap.validation === 400 plus the zodIssuesToFields envelope, not a live save door — acceptable for a spec-only widening; the save door's lowering is pinned elsewhere and the test asserts the envelope the door answers with. Answered.
  3. Seven derived gates NOT MEASURED locally (exit 3, prerequisite builds outside the diff) — the check-runs on the head answer them: Lint & Repo Gates and TypeScript Type Check success. Answered.
  4. PR body opens with the attribution lines before Fixes #28021 — PR-body guards success; cosmetic. Answered.
  5. No independent review run (quota) — this record is that review. Answered.
  6. Dedupe search for the follow-up card run by the dev (two queries, A calendar view always opens on the current month #28021 the only hit) — The Console calendar does not read calendar.initialDate, so it still opens on today #28102 exists and the PR names it. Answered.

open_questions (one): key name and values — A initialDate: today | first_record | next_record (as shipped), B defaultDate after object-calendar's defaultView, C drop next_record. Escalated to the maintainer, who the PR body already asks. Reviewer's reading, for that decision: A. Two facts from the tree bear on it — (i) the console's own calendar-view node retired a defaultDate key as inert (ui/packages/types/src/zod/complex.zod.ts L212-217, ADR-0049 enforce-or-remove), so B would revive a spelling with a tombstone history one node over; (ii) next_record is the only value that serves the card's renewals reach when past renewals are present, so C would leave the card's own scenario unserved. Nothing in this record depends on the answer; a rename is a one-token change plus regeneration.

Out-of-scope findings (two, carried on #28102): the ui/-owned key lists (plugin-list/src/index.tsx L327, plugin-calendar/src/index.tsx L449, types/src/designer.ts L819-826) and the pre-existing allDayField drift in the registry description. Read on the head, each is as described; leaving them to the console card is consistent with Prime Directive 10 (do not advertise what the renderer does not read). Noted, nothing further owed here.

④ Design judgment

Scenario the change is accepted against: an author of a stored calendar list view, or of an object-calendar page block, whose records fall months ahead declares where the calendar opens; the console half (#28102) reads the key where ObjectCalendar seeds currentDate. Judged against ADR-0049 / ADR-0078 (a declared property nothing reads), ADR-0053 (what "today" is), the renderer the describe promises behaviour for, and the first consumer of the block by reference.

packages/spec/src/ui/view.zod.ts — CalendarConfigSchema.initialDate

  • M1 (must-fix). The author-facing text advertises behaviour no renderer delivers, with no marker. The .describe() at L2199 — the text that ships to content/docs/references/ui/view.mdx (three tables) and component.mdx, and the text the Studio inspector and every AI author read — states in the present tense that 'first_record' "opens on the period containing the earliest start date" and so on. On this tree nothing reads the key: ObjectCalendar.tsx L524 seeds from the clock, the registry declares no such input, and calendarViewOptions forwards it into a component that ignores it. The only PLANNED record is the liveness/view.json note, which the liveness README says "is never shown to an author, on any row: it is written for this ledger's maintainers". That is the fourth state ADR-0049 and ADR-0078 §1 prohibit — parsed, unmarked, silently inert — and the shape Prime Directive 10 names (declared, not delivered). The PR body applies exactly this reasoning to refuse teaching the key in skills/** and in the ui/ registry copies, then ships the same advertisement through the describe. The house form already exists twice in this package for a key landed ahead of its reader inside an undrilled container: component.zod.ts L1098 BOUND_RECORD_BLOCK_EMPTY_STATE_DESCRIPTION opens with [PLANNED — not yet rendered] and names the flip condition, and app.zod.ts L421 navigation.dataSource does the same; the liveness README reads a describe marker as a status ("Also read from a spec .describe() marker"). The gantt viewMode the TSDoc cites is not the precedent it is taken for — that key IS read by the resource-view branch, so it was partially live when its note was written; initialDate is read by nothing. Fix: open the describe with [PLANNED — not yet rendered], state in one clause that no console reads the key yet and a calendar declaring it opens on today until the console half lands, name the condition under which the marker leaves (mirror the two precedents), then regenerate view.mdx / component.mdx (gen:schema && gen:docs). The ledger note then says the same thing from the maintainers' side and needs no change. One-line schema edit plus regeneration; no accept-set change.
  • S1 (should-fix). Whose "today". The describe's 'today' and 'next_record' ("on or after today") name a day without saying whose. ADR-0053 makes date a timezone-naive calendar day and datetime an instant rendered in a reference timezone; the renderer's today is the viewer's local clock (ObjectCalendar.tsx L1094 new Date()), which is also what the key's absence means. Say so in the describe — "today" is the viewer's local calendar day, and a date start field compares as a calendar day — so The Console calendar does not read calendar.initialDate, so it still opens on today #28102 implements one reading and a date renewal dated today is "on or after today" in every timezone.
  • S2 (should-fix). "The records the view selects" should say it means the view's filter scope, not the visible window: the renderer's fetch is not window-scoped ($filter / $orderby / the non-authorable $top ceiling at L831-842), so the anchor is computable from the fetched set, but a reader of the describe alone cannot tell whether the window or the filter is meant, and the window depends on the very date being chosen.
  • S3 (should-fix). The TSDoc's "no producer asking for a fixed date was found" and "nothing to mirror" are stated against the spec's view configs only. The console's calendar-view node reads an authored fixed currentDate (ui/packages/types/src/zod/complex.zod.ts L251-254, calendar-view-renderer.tsx#resolveAuthoredCurrentDate) and retired defaultDate as inert. Name both in the TSDoc: the first is the producer the sentence says was not found (and the reason it is deliberately not admitted here still holds — a fixed date on a stored view goes stale), the second is why defaultDate is the wrong spelling for this key. The decision is sound; its record should show it was taken with those two facts in view.

packages/spec/src/ui/component.zod.ts — ObjectCalendarPropsSchema.calendar describe

  • The describe now lists initialDate? beside the five bindings; by reference the node accepts the key, so the text is true to the accept set. Holds. M1 applies here through the referenced member's describe, not this line.
  • S4 (should-fix). OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE (L6154-6163) is left one key behind the describe three lines below it: its keys list does not name initialDate, so a flat initialDate on an object-calendar node is refused with a bare unrecognized_keys and no "write it inside calendar" prescription, and its prescription text still spells the block as { startDateField, endDateField, titleField, colorField, allDayField }. Add the key to keys and the prescription. Not a must-fix: the guidance set covers field bindings by name and the block itself is correct; this is the one copy inside the hits files that now disagrees with its neighbour.

Tried and did not break: absence byte-identity on both doors (test pins toEqual(binding)); the closed set against a fixed date, a timestamp, a macro token and three near-miss spellings (refused at the right path with the right code); the console fetch projection (named keys only, not projected); the console type mirror (by reference, no re-listed set); the lint field-ref walker (explicit scalars map); the liveness gate (undrilled container, note form, success on the head); the skills census (no calendar key list under skills/**); the changeset declarations against the diff kind.

Verdict on ④: one must-fix (M1), four should-fixes (S1-S4). A must-fix is a FAIL.

Implemented-by: claude/issue-28021-calendar-initial-date
Reviewed-by: session_01L6bhgV4fMGJHSdSdx3u9mK

VERDICT: FAIL


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK

Contract-review-claim: session_01L6bhgV4fMGJHSdSdx3u9mK · head fc292749a0bb1f7f6f683e8c372676c32d4da2f5 · 2026-10-30T15:17Z


Generated by Claude Code

…the date-macro vocabulary

A superRefine around isDateMacroToken left the published JSON Schema a
bare string. The accepted set is now one regex derived at load from
DATE_MACRO_TOKENS and DATE_MACRO_PARAM_RE, so json-schema carries the
rule as a pattern; parity with the macro predicate pair is pinned.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
…r calendar initialDate

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

维护者速读(席位终稿 · head 558ec1b7,按您的意见返工)

  • 改了什么: 日历视图新增可选键 calendar.initialDate,决定日历打开时停在哪一天。两种写法:记录锚点 first_record(最早一条记录所在的月/周/日)、next_record(今天之后最近一条记录所在的周期);或者日期公式(与筛选器、仪表盘日期筛选默认值同一套宏){today}、{next_month_start}、{3_months_from_now} 等,每次打开时重新计算。不写就是今天。固定日期(如 2026-11-01)和不带花括号的 today 会被拒,并给出处方。
  • 为什么改: 续约这类记录都在几个月后的日历,打开总是一片空白。按您的意见,存在视图里的日期会过时,所以只收公式和记录锚点,不收固定日期。
  • 风险与回滚: 只加可选键,已有日历解析结果不变。控制台读取这个键在后续卡 The Console calendar does not read calendar.initialDate, so it still opens on today #28102,之前写了也仍从今天打开。回退本 PR 即可。
  • 先看: packages/spec/src/ui/view.zod.ts 的 CALENDAR_INITIAL_DATE_RE(由现有宏词表派生,不是第二套语法)和 initialDate。
  • 两分钟验证: pnpm --filter @objectstack/spec exec vitest run src/ui/calendar-config-initial-date.test.ts,应为 64 passed。
  • 需要你做的: 这是 Tier H(重生成了两行 skills/** 索引),要您批准。请一并确认键名 initialDate 和上述两种写法。契约复审 PASS 在案后才请批。

席位意见: 按卡与您的裁定交付,ACCEPT(车道部分)。PR 正文仍是旧的三值描述(中继改不了 PR 正文),以本记录为准。

席位核对 · ACCEPT (lane part, rework) · card #28021 · 2026-10-30T16:16Z

  1. 形态: 10 files, +286 / −3 at head 558ec1b7, draft, Fixes #28021 once, Clause-②: yes (widening) / Metadata-protocol: added, changeset @objectstack/spec minor. check-governed-merges.mjs --pr 28138: ⛔ GOVERNED, skills/objectstack-ai/references/_index.md and skills/objectstack-data/references/_index.md (one regenerated line each, because view.zod.ts now imports date-macros.zod.ts); the [finding] skills/*/references/_index.md is generator-owned (gen:skill-refs) yet sits inside the skills/** governed-merge fence — every spec PR touching an indexed headline is forced to carry a governed-surface file #11705 generated-surface exception does not lift them (the generator declares no output set). So Tier H. Below 3000 lines.
  2. 前提实测: the maintainer's word 2026-10-30T15:08Z 「而存在视图里的日期会一天天过时,这个可以利用公式啊」 replaced the value set of head d7c3dce6 (hold posted then). DATE_MACRO_TOKENS / DATE_MACRO_PARAM_RE (packages/spec/src/data/date-macros.zod.ts) are the vocabulary the dashboard date filter's defaultValue already uses; DATE_MACRO_PARAM_RE has no flags, so deriving from its .source loses nothing.
  3. 门禁 check-runs: on 558ec1b7: 41 success, 9 skipped, 0 failed. The two earlier rework heads (fc292749, 562fb715) were red mid-rework and are superseded. Dev: spec 22574 tests, typecheck exit 0, check:generated 14/14; 109 gates derived and run, 103 exit 0, 6 exit 3 on the unbuilt workspace (check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:docs-transcript-drift, check:dual-build-cjs-loads, check:lean-entry-closure). os-dev-report delta 6527564631 on A calendar view always opens on the current month #28021. The seat re-reads checks before any landing stroke.
  4. 接受的偏差:
    • A pattern, not a superRefine. The accepted set is one regex derived at load from the vocabulary, so the published JSON Schema carries the rule (pattern); a refinement would have reached the parse only (the spec build refused it at 16 sites). Parity with DATE_MACRO_WRAPPED_RE + isDateMacroToken is pinned over every token and 25 edge spellings. Refusal code is invalid_format (was invalid_value on the enum head). For the contract reviewer to judge.
    • PR body stale. It still describes 'today' | 'first_record' | 'next_record'; this record is the current account. The dev's replacement body is kept for the record, not applied.
  5. 范围外去向: the console reader → The Console calendar does not read calendar.initialDate, so it still opens on today #28102, whose body now names both forms and resolveDateMacros() in @object-ui/core (dev edit, read back). Skills-docs: no hand-written skill text is affected; the two governed lines are generated indexes.
  6. 落地条款: Tier H. Owed: a same-shape CONTRACT_REVIEW_TIER PASS on this head (packages/spec/src/** non-test plus a governed path), then relay pr_request_reviewers + needs-user-decision, then the maintainer's approval of the key, its two forms and the PR. This record clears the hold on d7c3dce6; the review is handed over below.

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head 558ec1b

…ys whose today, and the flat spelling is prescribed

The describe now opens with `[PLANNED — not yet rendered]` and says a
calendar that declares the key still opens on today until the console
reads it, the house form for a key landed ahead of its reader inside an
undrilled container. It also says "today" is the viewer's local calendar
day and that the record anchors read the view's whole filter scope, not
the visible window.

The TSDoc names the console's fixed `currentDate` and retired
`defaultDate` on `calendar-view`, and when the marker leaves.

A flat `initialDate` on `object-calendar` is now refused with the
nested-shape prescription instead of a bare unrecognized key.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

New head · 2026-10-30T17:44Z · 0b105291050fe700b0a4cbbd320aec988de0075d (one commit on 558ec1b7). The contract review of the old head d7c3dce6 (6526258203, FAIL) judged text that the rework kept, so the seat applied its findings before handing the new value set over, rather than spending a review round on a known must-fix:

  • M1 → the initialDate describe opens with [PLANNED — not yet rendered] and says a calendar that declares the key still opens on today until the console reads it. The TSDoc names the flip condition (The Console calendar does not read calendar.initialDate, so it still opens on today #28102 reads it where ObjectCalendar seeds its current date, and removes the marker), mirroring navigation.dataSource and the bound-record empty state. view.mdx / component.mdx regenerated.
  • S1 → "Today" is the viewer's local calendar day, and a date start field compares as a calendar day.
  • S2 → the anchors read "the records the view's filter selects (its whole filter scope, not only the visible window)".
  • S3 → the TSDoc names the console calendar-view node's fixed currentDate (the one producer of a fixed opening date, deliberately not admitted) and its retired defaultDate.
  • S4 → OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE lists initialDate, so a flat one on object-calendar gets the nested-shape prescription; the prescription names it after the brace list, because calendar-config-allday-prescription-17054.test.ts parses every key inside the braces with a field-name value. New case in calendar-config-initial-date.test.ts.

Local: spec src/ui 165 files / 5931 tests pass, tsc --noEmit exit 0, check:generated 14/14 (after a dist rebuild; api-surface unchanged). The seat record 6527603811 stands for everything else, with this head; it is Tier H as before.

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head 0b10529

…derer by its repo path

The doc-block anchor gate resolves a `file#symbol` citation only from a
path it can find; the bare file name did not resolve.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

New head · 2026-10-30T18:03Z · 254b2fb067ddc379fa28dcf20e0dacebe70056d7. Lint · docs & code guards was red on 0b105291 at one gate, check:spec-docblock-symbol-anchors: the new TSDoc cited calendar-view-renderer.tsx#resolveAuthoredCurrentDate by bare file name, which the gate cannot resolve. The citation now carries the repo path ui/packages/plugin-calendar/src/calendar-view-renderer.tsx#resolveAuthoredCurrentDate; the gate passes locally (5272 anchors resolve). Comment text only. The handoff below replaces the one naming 0b105291 (6529484445).

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head 254b2fb

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-claim: session_01L9qibw58ehQ2gRHP2h2Puz · head 254b2fb067ddc379fa28dcf20e0dacebe70056d7 · 2026-10-31T02:26Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 254b2fb067ddc379fa28dcf20e0dacebe70056d7
Local-runs: none
Scope: packages/spec/src/ui/view.zod.ts (CalendarConfigSchema.initialDate, CALENDAR_INITIAL_DATE_RE, calendarInitialDateRefusal), packages/spec/src/ui/component.zod.ts (OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE, the object-calendar calendar describe), packages/spec/src/data/date-macros.zod.ts (DATE_MACRO_TOKENS, DATE_MACRO_PARAM_RE, DATE_MACRO_WRAPPED_RE, isDateMacroToken, read for parity), packages/spec/src/ui/calendar-config-initial-date.test.ts, packages/spec/liveness/view.json, packages/spec/authorable-surface/ui.json, content/docs/references/ui/view.mdx and component.mdx (regenerated), skills/objectstack-ai/references/_index.md and skills/objectstack-data/references/_index.md (generated transitive-dependency lines), the changeset.

Inputs: card #28021 (body, claim 6522851222, os-dev-report 6524362443 and its rework delta 6527564631), the prior record 6526258203 (FAIL on d7c3dce: M1, S1 to S4) and the seat's hold 6526108353, the seat's ACCEPT records 6524400046 and 6527603811 and its new-head notes 6529484445 and 6529945812, the PR body (stale: it still describes the three-value enum of d7c3dce; the tree is judged, not the body), the 10-file diff against merge base 6410029, main's own movement since that base (632 files, six shared with this diff: the view.zod.ts hunk main added is the kanban block, not the calendar block; git merge-tree is clean and GitHub reports the head mergeable, clean), the head's check-runs (read 2026-10-31T02:32Z: check-runs on 254b2fb: 50 total, 41 success (Auto Label, Build & E2E UI, Build Core, Build Docs, Build UI Deps, Check Changeset, Check Documentation Links, Check PR Size, Dogfood Regression Gate, Flag docs affected by code changes, Governed Surface Queue Guard, Lint & Repo Gates, Lint · CI, release & engine gates, Lint · ESLint, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus, Lint · scoped · tooling self-tests, Live E2E UI, PR-body guards (claim · duplicate · Part-of · single-writer path), Plan Test Core shards, Spec property liveness, Test Core, Test Core (all 8), Test UI, Type Check UI, Type Check · consumer gates, Type Check · debt ledger, Type Check · source gates, Type Check · workspace, TypeScript Type Check, filter); 9 skipped path-filtered (18.x upgrade harness (opt-in), Dogfood Regression Gate (matrix shard/3), Dogfood Verify CLI, Lint UI, Packed-tarball smoke (opt-in), Schedule gate · skip when a green push run covers the commit, Temporal Conformance (live PG + MySQL), Test UI (matrix shard/16), UI Published Artifacts); 0 failure, 0 in progress). Author user.login is objectstack-fleet[bot]; the drafter is session_017ihL2fi9zfJhUTubyJYb6V on claude/issue-28021-calendar-initial-date; the reviewer is not the drafter.

① Derived judgments

  • The accept set: CalendarConfigSchema gains one optional string key initialDate inside the existing strict object, validated by one anchored pattern: first_record or next_record, or a {...} or ${...} wrapper around a known fixed token or a parameterised N_unit_ago / N_unit_from_now token. Absence stays absent (no .default), an unknown key is still refused by name, and the object-calendar node takes the same member by reference, so both doors widen identically. RIGHT.
  • One vocabulary, not two: the token half of CALENDAR_INITIAL_DATE_RE is built at load from DATE_MACRO_TOKENS (every member is [a-zA-Z0-9_], so the alternation needs no escaping) and from the body of DATE_MACRO_PARAM_RE with its anchors stripped; the wrapper is the one DATE_MACRO_WRAPPED_RE accepts (^\$?\{...\}$). The closing brace and the outer anchors follow the group, so a token that is a prefix of another cannot match early. The parity battery pins the pattern against DATE_MACRO_WRAPPED_RE plus isDateMacroToken over every fixed token, both wrappings, bare spellings and 25 edge cases. RIGHT.
  • Refusal: invalid_format at calendar.initialDate, one issue, a message that names the value, both forms and DATE_MACRO_TOKENS, and tells a bare known token its wrapped spelling; zodIssuesToFields lowers it to the same catalog code under the validation class's 400. Because the rule is a pattern rather than a refinement, the published JSON Schema carries it too, which is why the dropped-refinements ledger did not have to grow. RIGHT.
  • The prior record's findings are discharged on this head: M1, the describe opens with [PLANNED — not yet rendered], says no console reads the key yet and names the flip condition (The Console calendar does not read calendar.initialDate, so it still opens on today #28102) in the TSDoc, matching the navigation.dataSource and bound-record precedents; S1, "today" is the viewer's local calendar day and a date start field compares as a calendar day; S2, the anchors read over the view's whole filter scope; S3, the TSDoc names the console calendar-view node's fixed currentDate and its retired defaultDate; S4, OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE lists initialDate and its prescription names it, pinned by a new case. The docblock citation now carries the repo path the check:spec-docblock-symbol-anchors gate resolves.
  • Regenerated copies agree: authorable-surface/ui.json gains exactly ui/CalendarConfig:initialDate, the four reference tables carry the describe, and the liveness calendar row note records the PLANNED strength with the flip instruction. The two skills/** lines are the generator's transitive-dependency index (view.zod.ts now imports date-macros.zod.ts), not teaching text, so Skills-docs: none still holds; they are what makes this Tier H.

② Semver level

@objectstack/spec: minor, carrying Clause-②: yes (widening) and Metadata-protocol: added on the changeset, the PR body and the claim. A new accepted key on a metadata schema is added and takes at least minor on the moved package; no removal, no narrowed value, no changed default, so no BREAKING banner and no ADR-0087 disposition is owed. The level matches the diff.

③ Boundary flags

  • Landing tier: Tier H (two generated lines under skills/**, check-governed-merges GOVERNED). This PASS is the contract prerequisite only; os-zhuang approves the key name, its two forms and the PR. Not a lane stroke.
  • Should-fix before the human gate, not blocking this record: the PR body still describes the superseded today | first_record | next_record enum and 19 tests; the maintainer reads the body first, so the seat should land the dev's replacement body (pr-body2.md) before requesting review, or state in the request that record 6527603811 is the current account.
  • Serial note: six files of this diff also moved on main since 6410029 (the kanban block in view.zod.ts and its generated copies); the merge is clean and the hunks do not touch each other. A merge of main before the queue would let CI measure the combined tree, but nothing read here requires it.
  • Out of scope, carried on The Console calendar does not read calendar.initialDate, so it still opens on today #28102: the ui/ key lists (plugin-list and plugin-calendar registry inputs, designer.ts options) and the console reader itself.

④ Design judgment

Scenario: an author of a stored calendar list view or an object-calendar page block whose records fall months ahead declares where the calendar opens; the console half (#28102) reads the key where ObjectCalendar seeds currentDate, resolving a macro through the same resolver the dashboard date filter's defaultValue uses. Judged against ADR-0049 / ADR-0078 (declared but unread properties), ADR-0053 (what "today" is), Prime Directive 12 (one key per concept) and the maintainer's ruling of 2026-10-30T15:08Z that a stored date goes stale and a formula should be used instead.

  • view.zod.ts, CalendarConfigSchema.initialDate: the shape answers the ruling exactly. A fixed date is refused with a reason; a macro is resolved each open; the two anchors are the only values that depend on the view's own records and binding, which is why the key lives on this block and not beside the component's defaultView. The pattern-over-refinement choice keeps the published schema honest. Holds.
  • The marking: parsed, documented as PLANNED, with the flip condition named at the source, the ledger and the reference tables. That is the house form for a key landed ahead of its reader. Holds.
  • Should-fix, not blocking: the describe is one long paragraph repeated in four reference tables; when The Console calendar does not read calendar.initialDate, so it still opens on today #28102 removes the marker it could also split the two forms into two sentences for the Studio inspector, which shows the describe as a tooltip.
  • Tried and did not break: absence byte-identity on both doors; the closed set against a fixed date, a timestamp, bare tokens, unknown and malformed wrapped tokens, near-miss anchors and case variants; a flat initialDate on the node gets the nested-shape prescription; the lint field-reference walker still reads the calendar block through its scalars map, so the string value is not taken for a field; the changeset declarations against the diff kind.

Verdict on ④: no must-fix; one should-fix.

Implemented-by: claude/issue-28021-calendar-initial-date
Reviewed-by: session_01L9qibw58ehQ2gRHP2h2Puz

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Seat hand-over to the approvers · 2026-10-31T02:39Z · head 254b2fb067ddc379fa28dcf20e0dacebe70056d7.

  • The current account is the seat record 6527603811 and the new-head notes 6529484445 and 6529945812, not the PR body. The body still describes the superseded today | first_record | next_record enum and 19 tests; the relay has no PR-body edit, so the record stands in for it (the review's should-fix 1). What this head does: initialDate on a calendar view (and the object-calendar block) accepts first_record, next_record, or a wrapped date-macro token such as {start_of_month} or {3_days_from_now}; a fixed date is refused, as 田騏 ruled on 2026-10-30T15:08Z (a stored date goes stale, a formula does not). It is marked [PLANNED — not yet rendered] until the console reads it (The Console calendar does not read calendar.initialDate, so it still opens on today #28102).
  • Contract review: PASS on this head, comment 6537839837 (Served-tier: CONTRACT_REVIEW_TIER), no must-fix. Should-fix 1 is answered by the line above; should-fix 2 (split the long describe into two sentences when the marker comes off) → note on The Console calendar does not read calendar.initialDate, so it still opens on today #28102, which removes the marker.
  • Checks on this head: 0 failed; check-expected-skips.mjs --pr 28138 OK (11 skipped, every one in main's roster). GitHub reports it mergeable.
  • Tier H (two generated lines under skills/**): review requested from the approvers in GOVERNED_APPROVERS in the same act, and needs-user-decision added; needs:contract-review comes off now that the PASS is on record.
  • 需要维护者做的: 批准本 PR(PASS 6537839837,Head-sha 254b2fb0):键名 initialDate,以及它接受的两种写法(锚点 first_record / next_record,或包起来的日期宏)。获批后席位过落地前检、翻 ready、挂 auto-merge。

@os-zhuang
os-zhuang marked this pull request as ready for review October 31, 2026 03:05
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Landing stroke · 2026-10-31T03:06Z · head 254b2fb067ddc379fa28dcf20e0dacebe70056d7.

  • Contract review: PASS on this head (comment 6537839837, Served-tier: CONTRACT_REVIEW_TIER), no must-fix; should-fix 1 answered in the hand-over 6537910172, should-fix 2 carried on The Console calendar does not read calendar.initialDate, so it still opens on today #28102.
  • Tier H: os-zhuang (in GOVERNED_APPROVERS) APPROVED this head (review 5720758894) and marked it ready. needs-user-decision comes off.
  • Checks on this head: 0 failed; check-expected-skips.mjs --pr 28138 OK. check-governed-merges.mjs --pr 28138: GOVERNED (skills/**, two generated lines), discharged by the approval above.
  • The seat arms auto-merge.

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 31, 2026
Merged via the queue into main with commit 8f36f6b Oct 31, 2026
62 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-28021-calendar-initial-date branch October 31, 2026 03:29
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 protocol:ui size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A calendar view always opens on the current month

2 participants