Skip to content

fix(plugin-calendar): a calendar opens on the date its calendar.initialDate declares - #28334

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-1tllxq
Oct 31, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-1tllxq

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #28102

Clause-②: yes
Metadata-protocol: none

Clause-②: yes because the diff touches packages/spec: the [PLANNED — not yet rendered] marker leaves CalendarConfigSchema.initialDate's describe, which is split one sentence per form (carry-forward 6537924895). The accepted set is unchanged: same pattern, same refusal, no key added or removed.

维护者速读

  • 改了什么:日历视图现在按 calendar.initialDate 打开——日期宏(如 {next_month_start})直接跳到对应日期,first_record / next_record 先查一条记录再跳到它所在的月/周/日;没写或查不到时仍是今天。列表视图和 ObjectView 两个生成日历节点的地方也把这个键传下去了。
  • 为什么改:规范半边已声明这个键,但控制台从不读它;续约日历这种记录都在几个月后的视图,打开永远是空的当月。
  • 风险与回滚:仅在声明了该键的日历上多一次一行查询,初始日期只在挂载时设一次,之后用户翻页说了算;回滚即 revert 本 PR,未声明该键的日历行为不变(有对照测试)。
  • 先看:ui/packages/plugin-calendar/src/ObjectCalendar.tsx(seed 与 anchor 查询的 effect)、ui/packages/plugin-calendar/src/initialDate.ts(查询形状与 next_record 的今天边界)、ui/packages/plugin-list/src/ListView.tsx(calendarBlock 里新增的一行转发)。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-calendar/src/ObjectCalendar.initialDate-28102.test.tsx,预期 14 个用例全部通过。
  • 需要你做的:无,席位落地。

What changes

  • ObjectCalendar seeds its date from calendar.initialDate, once, on mount (ui/packages/plugin-calendar/src/initialDate.ts holds the pure half):
    • absent ⇒ today, as before;
    • a wrapped date-macro token ⇒ the date resolveDateMacros() (@object-ui/core, the resolver filter values use) gives it, read in the useState initializer, so the first visible range the calendar reports to a windowing host is already the seeded one;
    • first_record / next_record ⇒ one one-row read from the same source the record fetch reads (the object provider's data source, or a ValueDataSource over inline rows), behind the same object-schema gate: the view's resolved filter AND a present start date (first_record) or a start date on or after the start of today (next_record), $orderby start field ascending, $top: 1. The next_record bound is spelled by the start field's declared type through the file's existing toStoredDateValue: a date field as the local calendar day, anything else as the instant of local midnight;
    • no qualifying record, no source to read, or a failed read (one console.warn) ⇒ today.
      The calendar shows the month, week or day of its active mode that holds the date. A navigation flag makes a late anchor answer a no-op once the user has navigated, and the seed flag is set when the answer lands, not when the read starts, so a re-run that discards an in-flight read asks again.
  • Both producers forward the key. ListView's calendar branch (the calendarBlock literal) and ObjectView's generateViewSchema calendar branch forward the block's keys by name, so initialDate died there and a stored list view never reached the renderer with it. Each now forwards it inside the node's calendar block (seat-approved surface extension).
  • Spec: the [PLANNED — not yet rendered] marker leaves CalendarConfigSchema.initialDate; the describe now reads an intro plus one sentence per form, and the TSDoc names the reader instead of promising one. content/docs/references/ui/{component,view}.mdx regenerated (gen:docs).
  • Liveness: packages/spec/liveness/view.json's calendar row note now states initialDate as plain live, citing the renderer read and both producer forwards.
  • ui-owned key copies kept in step: the object-calendar / calendar registry calendar input description (it also lacked allDayField), the list-view registry calendar input description, and the hand-typed calendar options in ui/packages/types/src/designer.ts. sdui.manifest.json, its record and content/docs/ui/components/plugins.mdx regenerated.
  • Changeset: .changeset/28102-calendar-opens-on-initial-date.md, patch on the five packages moved.

Tests

  • ui/packages/plugin-calendar/src/ObjectCalendar.initialDate-28102.test.tsx (14 rows): CONTROL — no key opens on today and issues no anchor read; {next_month_start} (and the first reported range already holds it); {3_months_from_now}; first_record opens on the read's date; the read's exact shape ($top: 1, $orderby { due: 'asc' }, ['and', VIEW_FILTER, ['due', 'is_not_null']]); no record ⇒ today; failed read ⇒ today; inline staticData earliest dated row with an undated row skipped; next_record bound as a calendar day on a date field and as the local-midnight instant on a datetime field; inline past rows skipped; no record ahead ⇒ today; a navigation after the seed survives a re-render (one anchor read); an anchor answer landing after the user navigated is discarded.
  • ui/packages/plugin-list/src/__tests__/ListView.calendarInitialDate-28102.test.tsx and ui/packages/plugin-view/src/__tests__/ObjectView.calendarInitialDate-28102.test.tsx (4 rows each): each form reaches the node inside calendar, never flat; CONTROL — a block without the key carries none.

Acceptance notes

  • The anchor reads the view's authored filter, not toolbar filters or search. That is the spec's wording ("the records the view's filter selects"); a user filter applied later does not re-seed, by the seed-once rule.
  • A host that hands data down with no data source (an embedded renderer) has nothing to read an anchor from, so it opens on today. Both console producers hand a data source down.
  • ListView's first window still assumes today (initialCalendarWindow in plugin-list/src/calendarWindow.ts, and its comment says the hosted calendar opens on today). With a seeded date the calendar's first report differs from that window, so the list fetches once more for the seeded window: correct rows, one extra request. Left alone because it is outside this card's approved ListView lines; it is a cost note, not a defect.
  • next_record with an undeclared field type (an adapter with no getObjectSchema) bounds at the local-midnight instant; a date-only value compared against it as a string is still right east of UTC and drops today's records west of UTC. Declared date fields are bounded as days.
  • Token resolution is the client resolver's. A token the spec accepts that resolveDateMacros leaves unresolved opens on today rather than throwing; no such token was found.
  • Dedupe words: calendar initialDate renderer, ObjectCalendar currentDate seed, calendar first_record next_record.

Verification

Head 471be6e7 (includes a merge of origin/main); every reading below is on that tree unless it says pre-merge.

Derived gates — 115 derived, 113 run green, 2 NOT MEASURED

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, every line run with stdin closed, exit codes recorded before any pipe; reconciled with --ran: ✓ dispatch-gates --ran: 115 derived famil(ies) accounted for — 113 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3).

  • NOT MEASURED, prerequisite: pnpm --filter @objectstack/spec run check:skill-examples (needs packages/client-react/dist), pnpm check:dual-build-cjs-loads (needs a full pnpm build). Neither reads a file this diff touches; CI runs both.
  • node scripts/check-plugin-teardown-shape.mjs --self-test first refused (exit 3, shallow clone could not read its pinned fixture commit); after fetching that one commit it ran green (exit 0, 48 cases).
  • Post-merge re-runs on the merged tree: check-sdui-manifest, check:sdui-reference, check:liveness, check:issue-citations, check:doc-authoring all exit 0.
Tests and type-check
  • pnpm --dir ui exec vitest run packages/plugin-calendar/ packages/plugin-list/src/__tests__/ListView.calendar packages/plugin-view/src/__tests__/ObjectView.calendar on the merged tree: Test Files 74 passed (74), Tests 530 passed | 95 skipped (625) (the skips are pre-existing in plugin-calendar).
  • Pre-merge: pnpm --dir ui exec vitest run packages/plugin-list/src/__tests__/ListView.calendar packages/plugin-view/src/__tests__/ObjectView.calendar packages/types/ → 392 passed; spec src/ui/calendar-config-initial-date.test.ts src/ui/view.test.ts → 537 passed.
  • pnpm --filter @object-ui/plugin-calendar --filter @object-ui/plugin-list --filter @object-ui/plugin-view --filter @object-ui/types run type-check → all four Done, VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec build && check:generated on the merged tree → ✓ All 14 generated artifacts are up to date.
  • node scripts/gen-sdui-manifest-node.mjs + node scripts/gen-sdui-reference.mjs re-run on the merged tree.
Reverse verification — five ablations, direction predicted before running

Each through node scripts/ablation-replace.mjs (anchor must hit; restore proven by blob == HEAD and an empty git diff HEAD). The tests import the source directly, so no build sits between the mutation and the run.

  • A — delete the ListView forward: 3 forward rows red, CONTROL green.
  • B — delete the ObjectView forward: 3 forward rows red, CONTROL green.
  • C — seed useState with new Date() only: the two macro rows red, 12 green.
  • D — drop setCurrentDate(anchorDate): 5 anchor rows red (incl. the navigation-survives row, which waits for the seed), the shape / no-record / failure rows green.
  • E — drop the user-navigated guard: only the late-answer row red.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (Repo-wide lint is CI's run.)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

…c marker, key copies

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 1 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (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.

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

  • content/docs/releases/v17/17-5.mdx (via CalendarConfigSchema (symbol, a top-level const))

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
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/view.json) — pages documenting those are invisible to this run
  • the SDK route bridge reached 59 of 211 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 efdddc90603d4855ca41168e9e507e87edf4316f → packageMentionDocs.

Which tree this was computed on

This run read content/docs from bda1f3aa116bf765fc4434e20321744e77404052 — the merge of head 471be6e722d42329d229b032157594798cc632c7 into base efdddc90603d4855ca41168e9e507e87edf4316f, 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 bda1f3aa116bf765fc4434e20321744e77404052 && git checkout bda1f3aa116bf765fc4434e20321744e77404052
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin efdddc90603d4855ca41168e9e507e87edf4316f 471be6e722d42329d229b032157594798cc632c7 && git checkout -B drift-repro efdddc90603d4855ca41168e9e507e87edf4316f && git merge --no-ff 471be6e722d42329d229b032157594798cc632c7

node scripts/docs-audit/affected-docs.mjs --json efdddc90603d4855ca41168e9e507e87edf4316f

⚠️ 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 efdddc90603d4855ca41168e9e507e87edf4316f → 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:ui#3 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-claim: session_01L9qibw58ehQ2gRHP2h2Puz · head 471be6e722d42329d229b032157594798cc632c7 · 2026-10-31T05:31Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 471be6e722d42329d229b032157594798cc632c7
Local-runs: none
Scope: packages/spec/src/ui/view.zod.ts (CalendarConfigSchema.initialDate's TSDoc and describe; CALENDAR_INITIAL_DATE_RE and calendarInitialDateRefusal read on main for parity, untouched), packages/spec/liveness/view.json (the calendar row note), ui/packages/plugin-calendar/src/initialDate.ts (whole: isCalendarRecordAnchor, resolveInitialDateMacro, recordAnchorQuery, anchorDateFromResult), ui/packages/plugin-calendar/src/ObjectCalendar.tsx (the currentDate initializer, userNavigatedRef, the anchor effect, onNavigate; toStoredDateValue / isDateOnlyField read for the bound), ui/packages/plugin-calendar/src/index.tsx (the calendar input description), ui/packages/plugin-list/src/ListView.tsx (the calendarBlock literal), ui/packages/plugin-list/src/index.tsx (the calendar input description), ui/packages/plugin-view/src/ObjectView.tsx (generateViewSchema's calendar branch), ui/packages/types/src/designer.ts (UnifiedViewConfig.calendar.initialDate), the three test files, the regenerated manifest, its record and the three reference pages, .changeset/28102-calendar-opens-on-initial-date.md + ui/packages/core/src/utils/date-macros.ts on main (resolveDateMacros(filter, now)), the spec half's record 6537839837 on PR #28138 (its should-fix 2, the describe split)

Inputs: card #28102 (body and all six comments: triage 6523386496, the spec half's carry-forward 6537924895, the unblock 6538742793, the seat's claim 6538841986 and its amendment 6538859721 which adds the two producer forwards and the liveness note, the dev report 6539576260), PR #28334 (body, the docs-drift comment, the file list of 18 files, the diff of 910 lines against main read whole, the nine commits from merge-base 501c864), the 65 check-runs on this head (read 2026-10-31T06:02Z: all 65 runs completed, none failed, none cancelled, none in progress; 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 UI, 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, Test UI (all 16), Type Check UI, Type Check · consumer gates, Type Check · debt ledger, Type Check · source gates, Type Check · workspace, TypeScript Type Check, filter; skipped: 18.x upgrade harness (opt-in), Dogfood Regression Gate (matrix shard/3), Dogfood Verify CLI, Packed-tarball smoke (opt-in), Schedule gate · skip when a green push run covers the commit, Temporal Conformance (live PG + MySQL), UI Published Artifacts), and the tree at this head and on main for the items the Scope line names. The head is mergeable and clean against today's main (merge-tree clean); none of the files main moved since the merge-base is in this diff.

① Derived judgments

  • The renderer reads the key where it seeds its date, once, with the three outcomes the spec names - right. Absent: useState falls back to new Date(), as before (CONTROL pinned: today, and no anchor read). A wrapped token: resolveInitialDateMacro hands the string to resolveDateMacros, the client resolver filter values use, inside the useState initializer, so the first visible range the calendar reports is already the seeded one (pinned for {next_month_start} and {3_months_from_now}); a token the resolver leaves as it found it, or that does not parse as a date, answers null and the calendar opens on today rather than throwing. A record anchor: one one-row read through recordAnchorQuery (the view's resolved filter AND is_not_null on the start field for first_record, or "at or after the start of today" for next_record, $orderby start ascending, $top: 1), from the same source the record fetch reads (the object provider's data source, or a ValueDataSource over inline rows), behind the same object-schema gate; no source, no qualifying record or a failed read (one warning) leaves today. The period is the active mode's, because currentDate is what the month, week and day grids already read. Pinned fourteen ways, including the exact read shape.
  • "Today" and the next_record bound follow the spec half's S1 - right. The bound is the start of the viewer's local day, spelled by the start field's declared type through the file's own toStoredDateValue: a date field as the calendar day (toDateInputValue), anything else as the instant of local midnight; pinned on a date field and on a datetime field. With no declared type (an adapter without getObjectSchema) it falls to the instant, which the body names as a bound west of UTC; declared date fields, the HotCRM case, are bounded as days.
  • Seed once; the user owns the date after - right. userNavigatedRef is set in onNavigate before setCurrentDate, and the anchor answer returns without moving the calendar once it is set (pinned: a late answer after navigation is discarded); anchorSeededRef is set when an answer or a failure lands, not when the read starts, and the effect's cleanup drops an in-flight answer, so a re-run asks again instead of seeding from a stale read (pinned: a navigation survives a re-render with one read).
  • Both producers forward the key inside the calendar block - right, and necessary: ListView's calendarBlock literal and ObjectView's generateViewSchema forward the block's five bindings by name, so a stored list view's initialDate died there and never reached the renderer. Each now forwards it nested, never flat (the node's schema refuses flat keys), pinned four ways each with a CONTROL. The seat accepted both files in amendment 6538859721.
  • The spec edit is the marker removal the spec half promised, and the accepted set is unchanged - right. CALENDAR_INITIAL_DATE_RE and calendarInitialDateRefusal are untouched; the TSDoc's "lands ahead of its reader" paragraphs go and name the reader; the describe loses [PLANNED — not yet rendered] and is split by form (the absence rule and the period first, the record anchors as one sentence, the token as another), which is the spec half's should-fix 2 (record 6537839837, carried forward as 6537924895) discharged. No key added or removed, no refusal moved, so Clause-②: yes is the declaration the diff owes for touching packages/spec and nothing an author writes moves.
  • Liveness and the ui-owned copies - right. The calendar row note moves initialDate from PLANNED strength to plain live and cites the renderer read, the pure module and both producer forwards by path and symbol; the object-calendar and list-view registry calendar input descriptions and the designer's calendar options list the key (the former also gains the allDayField it lacked), and the manifest, its record and the reference pages are regenerated.
  • Check-runs as gate verdicts - read as above; every run on this head completed and none is red, cancelled or in progress at the read.

② Semver level

  • @object-ui/plugin-calendar, @object-ui/plugin-list, @object-ui/plugin-view, @object-ui/types, @objectstack/spec all patch; Clause-②: yes; Metadata-protocol: none - accepted. The renderer gains behaviour only where a key that was declared-but-inert is present; designer.ts gains an optional member; the spec entry is a describe and TSDoc change on an existing key with the same pattern and refusal. Metadata-protocol: none is right.

③ Boundary flags

④ Design judgment

  • Nothing blocking, and no should-fix on the diff. Tried: a token the client resolver does not know (today, not a throw); a date start field with rows dated today (included, since the bound is the calendar day itself); inline rows with an undated row first (skipped by is_not_null, pinned); the schema arriving after mount for the object provider (the effect waits on objectSchemaReady, so the bound is spelled by the declared type, never guessed); an anchor read that resolves after the component unmounted (the cleanup's live flag drops it). Keeping the pure half in initialDate.ts and the one source-of-truth read beside the record fetch is the right split, and the resolver reuse keeps one date-macro grammar in the console.

Verdict reasoning. The reader does what the spec half declared, in the three outcomes it named, with the day-versus-instant bound the spec half's review asked for, seeded once and then owned by the user; the two producer forwards are what makes a stored view reach it; the spec edit is the promised marker removal with the accepted set unchanged and the carried-forward describe split done. Semver is patch everywhere. What remains is the one extra window fetch in ListView, named for its own card.

Implemented-by: claude/project-thread-1tllxq
Reviewed-by: session_01L9qibw58ehQ2gRHP2h2Puz

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · os-tesla · session_01L9qibz8HEj53Wx2uphTo2o

维护者速读

  • 改了什么:Console 的日历视图开始读 calendar.initialDate。不写时照旧打开今天;写日期宏(如 {next_month_start})时打开该日期所在的月/周/日;写 first_record / next_record 时用一次单行查询,打开第一条记录或下一条未来记录所在的时段,查不到就打开今天。之后用户翻页不会被重置。
  • 为什么改:The Console calendar does not read calendar.initialDate, so it still opens on today #28102(A calendar view always opens on the current month #28021 的消费半,spec 半 PR feat(spec): a calendar view can declare the date it opens on, calendar.initialDate #28138 已合并):这个键在 spec 里已声明,但渲染器不读,作者配置了也没效果,日历总是打开今天。
  • 风险与回滚:只在视图写了这个键时才改变行为;列表视图和 ObjectView 两个生产方把这个键原样传进日历块。spec 只去掉了 [PLANNED] 标记、拆开了说明句,可接受的取值不变。回滚即 revert。
  • 先看:ui/packages/plugin-calendar/src/initialDate.ts,以及 ObjectCalendar.tsx 里 currentDate 的初始化和锚点读取。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-calendar/src/ObjectCalendar.initialDate-28102.test.tsx,全部通过。
  • 需要你做的:无,席位落地。

席位意见:渲染器的读法正好是 spec 半声明的三种结果,日期宏复用了现有的解析器,没有第二套语法;契约复审 PASS,可以直接落地。

席位核对

ACCEPT · seat domain:ui#3 · head 471be6e7 · 2026-10-31T06:50Z

  1. Shape: Fixes #28102, draft, base main, 18 files, +652/−21. initialDate.ts (new, pure) and the seed in ObjectCalendar.tsx (initializer, anchor effect, userNavigatedRef). The calendarBlock in ListView.tsx and generateViewSchema in ObjectView.tsx forward the key nested (the seat's amendment 6538859721). designer.ts gains an optional member. In packages/spec/src/ui/view.zod.ts the [PLANNED] marker is removed and the describe split by form (the spec half's carry-forward 6537924895). The liveness calendar note is plain live. Also: registry input descriptions, the regenerated manifest, its record and three reference pages, three test files, and a changeset.
  2. Premise measured: on main, the renderer never read initialDate (the card's measurement, re-checked by the dev). The producers dropped the key before it reached the renderer, which is why the amendment added the two forwards.
  3. Gates / check-runs: on head 471be6e7 all 65 check-runs completed, none failed, cancelled or in progress, and mergeable_state is clean. Dev: 113 of 115 derived gates exit 0, and 2 were NOT MEASURED (exit 3, build prerequisites: check:skill-examples and check:dual-build-cjs-loads), backstopped by CI's build legs. 5 ablations went red as predicted (os-dev-report 6539576260).
  4. Accepted deviations: none. Contract review: lane record 6539855429, Served-tier: CONTRACT_REVIEW_TIER, PASS on this head, with no should-fix.
  5. Out of scope: ③'s ListView first-window note (a seeded calendar fetches once more for the seeded window: correct rows, one extra request). The seat screens it out for now because it fails the business test (no user-visible defect). It will be re-raised if a measurement shows a cost. The prose in the changeset and the three reference pages matches the diff (the key's three forms and their periods). Skills-docs: none — Metadata-protocol: none.
  6. Landing: check-governed-merges --pr 28334 says NOT governed (0 of 18 paths), 673 changed lines ≤ 3000. Contract review PASS on this head. The seat readies the PR and arms auto-merge under 「按 pm-dispatch 审过的pr你可以自主落地」.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 31, 2026 06:51
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 31, 2026
Merged via the queue into main with commit 71de060 Oct 31, 2026
66 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-1tllxq branch October 31, 2026 07:13
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/l tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The Console calendar does not read calendar.initialDate, so it still opens on today

1 participant