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
{{ message }}
Repository navigation
[Decision] Should the calendar month grid move a datetime by calendar days (keeping its wall-clock time) instead of by elapsed milliseconds? Today a move across a DST change shifts it an hour, and a local-midnight datetime lands in the previous cell #11005
Ruled: 5881826705 · letter B (month grid moves by calendar days, keeps the wall-clock time) · 2026-09-29T01:25Z
Filed by the objectui domain:ui seat #1 (session_01DuWo5bdP9SdVebamn99GGk) from objectui#10866 slice 4 (PR objectui#10994): its dev's open question, and contract review 5873110729, which reproduced the defect. ⛔ Not graded here. This is a behaviour question about instants, so it needs the maintainer's ruling, not a dev's or a seat's choice.
What happens (measured)
CalendarView's MonthView.handleDrop moves an event by the milliseconds between the grab cell's local midnight and the drop cell's local midnight. Across a DST change that span is 23 or 25 hours, so:
Every datetime moved across a DST change shifts its wall-clock time by an hour.
A datetime at local midnight lands at 23:00 in the cell BEFORE the drop. Measured in America/Los_Angeles, identically on objectui main and on PR objectui#10994's head: a start of 2026-11-01T07:00:00.000Z (Nov 1, 00:00 local), grabbed on Nov 2 and dropped on Nov 3, is written as 2026-11-02T07:00:00.000Z, which is Nov 1, 23:00 local.
The calendar's own month-view quick-create writes exactly such local-midnight instants into datetime fields (pinned in slice 4's tests), so this reaches documents the calendar itself created.
Date-only values do not have this problem after PR objectui#10994: its ObjectCalendar repair moves a stored day by whole calendar days. That repair lives in the consumer because the grid cannot tell a day from an instant at local midnight.
Why it is a ruling, not a fix
objectui#10866's binding reading (release 5870108114) is "a datetime keeps its instant". Any fix here changes the instant a datetime move writes. That is exactly the kind of unruled instant change contract review 5869002399 failed on this card's slice 3.
Options
A. Leave it (today's state). Instants keep the grid's elapsed-time arithmetic; days are already repaired. Cost: a datetime moved across a DST change keeps its elapsed duration, not its wall-clock time.
B. Move by calendar days in the grid for every value, keeping the wall-clock time. A datetime at 10:00 stays at 10:00 on the dropped day, whatever the DST change. This is the behaviour most calendar products show, and it would also make the consumer-side day repair redundant. It is an instant behaviour change: every datetime moved across a DST change lands one hour away from where the arithmetic puts it today.
C. Move by calendar days only for values at local midnight. It fixes the previous-cell case, but it is a heuristic: it misfires on real midnight events, and it leaves the one-hour shift for every other datetime.
Seat's recommendation: B, as a small plugin-calendar slice with zone pins under LA and Shanghai. The reason is that the user moved an event to a day, not by a number of milliseconds. The review of PR objectui#10994 agrees that B is the right eventual fix for the whole class. The seat does not decide it: it changes what an instant field stores, which is outside every ruling on objectui#10866 so far.
Decision-box entry: needs-user-decision · priority:p2 · domain:ui · area:records. The 速读, the four-facet block and the prior-rulings line are completed here
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-09-28T16:55Z. ⛔ Not a claim, ⛔ not a dispatch.
Prior rulings on this card: none on this thread. Related: objectui#10866's binding reading (release 5870108114), 「a datetime keeps its instant」. It governs what a drop writes, which is why the seat asks rather than decides: every option but A changes the instant a datetime move writes.
① Long-term: B matches what the user did (moved an event to a day), and it would make the consumer-side day repair in ObjectCalendar redundant. A keeps an arithmetic that is wrong twice a year. C adds a heuristic.
② Real pull: a real defect, reproduced by contract review 5873110729 under America/Los_Angeles. It is reached by documents the calendar itself creates (quick-create writes local-midnight instants). Zero reach in zones without DST.
③ AI-error: none of the options makes an AI author write anything different. The difference is only what a drag stores.
④ Startup focus: B is a small plugin-calendar slice with zone pins (LA and Shanghai). A costs nothing. C is small but adds a permanent special case.
Recommendation: B, with A as the fallback. Only ① decides it; ②③④ do not flip it.
Confidence gap: the other calendar grids (week and day views) were not measured for the same arithmetic. If B is chosen, the slice measures them first.
Ruling: batch #241 item 2 · letter B · maintainer 「同意」 2026-09-29T01:21Z
Director seat (objectstack#12708, summon #30 续 2, session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-29, replying 「同意」 to the presented batches #240, #241 and #242 together — this item recommendation B, fallback A, the full four-axis body in chat on 2026-09-28.
Ruled: B. The month grid moves a value by calendar days and keeps its wall-clock time, for every value. MonthView.handleDrop (packages/plugin-calendar/src/CalendarView.tsx:673-678 today adds newTargetDay − anchorDay in milliseconds to the instant) computes the difference in calendar days between the grab cell and the drop cell and applies it with setDate on a local copy of the start and the end, hours / minutes / seconds untouched — for move and for resize-end alike. A (keep the elapsed-time arithmetic) and C (calendar days only for local-midnight values) are not taken. This is a deliberate change of the instant a drag writes; it changes nothing about what a datetime field stores or how it is read — objectui#10866's 「a datetime keeps its instant」 governs the binding, not the user's move.
Readings that decided it:
Long-term: the user moved an event to a day, not by a number of milliseconds; the consumer-side day repair in ObjectCalendar (PR objectui#10994) becomes redundant. A keeps an arithmetic that is wrong twice a year; C adds a heuristic that misfires on real midnight events.
Real use: a real defect, reproduced by review 5873110729 in America/Los_Angeles; the calendar's own quick-create writes local-midnight instants, so it reaches documents the calendar itself created; zero reach in zones without DST.
AI-safety: none of the options changes what an author writes; only what a drag stores.
Startup scope: a small plugin-calendar slice with zone pins; C would be a permanent special case.
Mainstream: Google, Outlook and Apple calendars, FullCalendar and react-big-calendar all keep the wall-clock time on a month-view drag.
Execution parameters (ruled in the same stroke):
This card → pm:queue; domain:ui, priority:p2 stay.
The slice measures the week and day views first; if their drop arithmetic is the same elapsed-time form, the same change rides the slice.
Pins under TZ=America/Los_Angeles and TZ=Asia/Shanghai: a datetime moved across a DST change keeps its wall-clock time; a local-midnight instant lands on the dropped day; a date-only value is unchanged; a zone without DST behaves as before; resize-end follows the same rule.
The ObjectCalendar day repair from PR objectui#10994 is removed once measured redundant, or kept with a comment saying why not.
Claim: PM loop round 1 — domain:ui execution seat 2
Session: session_011p7ikEivgXefNDaE5S5Uec
Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-11005-month-grid-calendar-days
Worktree: objectui-issue-11005
Domain: domain:ui
Seat: domain:ui#2
Ruling-ref: 5881826705
File surface (ruling B and its execution parameters, 5881826705):
packages/plugin-calendar/src/CalendarView.tsx: MonthView.handleDrop's move and resize-end arithmetic, by calendar days with the wall-clock time kept; the week and day views are measured first and ride the slice if their drop arithmetic has the same elapsed-time form.
packages/plugin-calendar/src/ObjectCalendar.tsx: the day repair from PR objectui#10994, removed once measured redundant, or kept with a comment saying why.
Zone pins under TZ=America/Los_Angeles and TZ=Asia/Shanghai, and one .changeset/11005-…md ('@object-ui/plugin-calendar': patch). If this change falsifies a sentence of the pending .changeset/10866-calendar-gantt-date-only-days.md, it is reconciled here in the dated-note form.
⛔ Not plugin-gantt, and not objectui#10866 slice 5's other items.
Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier --repo objectstack-ai/objectui over this surface: no path-derived mandate, at objectstack 288611e3)
Clause-②: no
Why no: the ruling's own execution parameter (Clause-②: no): a drag's written instant changes by ruling; no declared field shape, schema or accept set moves.
Thread-read: 5881826705
Serial constraints cleared: read 2026-09-29T01:47Z at objectui origin/main0eb9f36. Open PRs objectui#10930 (core dashboard filters, typescomplex.zod.ts), fix(app-shell): PageView refreshes a page action’s data in place on the invalidation bus instead of remounting the page (objectui#10519) #10777 (app-shellPageView.tsx), feat(plugin-grid): one display page size read from the spec, and a distinct fetch batch (objectui#9853) #10278 (plugin-gridObjectGrid.tsx) and chore: release packages #5400 (release): none touches packages/plugin-calendar. PR objectui#10994 (objectui#10866 slice 4) merged as 6650259. objectui#10866 slice 5 (its ObjectCalendar mixed-event half and the shared pending changeset) is serial behind this card and is re-priced when it lands.
{
"issue": 11005,
"status": "done",
"branch": "claude/issue-11005-month-grid-calendar-days",
"pr": "https://github.com/objectstack-ai/objectui/pull/11036",
"session": "session_011p7ikEivgXefNDaE5S5Uec — subagent of the PM session, so the id is the parent's; identity is the branch named in claim 5882077455",
"premise_still_valid": true,
"summary": "Ruled B is implemented in MonthView.handleDrop. The grid counts the calendar days between the grab cell and the drop cell from their local Y/M/D (calendarDaysBetween, a difference on the UTC calendar, with no rounding). It moves local copies of the start and end with setDate (moveByCalendarDays), for a move and for resize-end alike. The defect reproduced on base a33cf7e, including the card's exact case: 2026-11-01T07:00Z grabbed Nov 2 and dropped Nov 3 wrote 2026-11-02T07:00Z. ObjectCalendar's objectui#10866 slice-4 day repair (toMovedDateValue, isStoredDay, DAY_MS) is removed. It was measured redundant: slice 4's ten date day moves pass without it in LA and Shanghai, and they go red (the same four slice 4 named) when the base grid is put back. Zone-2 verdicts: (1) partly held — resize-end was not the deltaMs form, since it already kept h/m/s via setHours and dropped only the milliseconds, which it now keeps; (2) held — the week and day time grid places at snapped minutes on the drop day's own clock, a probe measured 10:00 kept across Nov 1 in LA, so it does not ride; (3) held; (4) the named .changeset/10866-calendar-gantt-date-only-days.md does not describe the repair and is untouched. The repair lives in .changeset/10866-calendar-dst-day-moves.md, which is reconciled in the dated-note form: two phrases are scoped \"at this change\" and a dated note names objectui#11005, with front matter byte-identical and the gantt/core bullets untouched. Worktree removed after the PR opened.",
"tests": "All at head 600e84c unless noted. (1) New pin CalendarView.monthMoveCalendarDays-11005, driven (OBJECTUI_DATE_ZONE_CHILD=1, --pool=forks). On base, before the fix: \"Tests 8 failed | 9 passed (17)\". The reds were the six LA moves, the LA Nov end drag and the suite-zone end drag; both end drags failed on milliseconds only (19:30:15.000Z for .250Z). (2) Head, the five calendar zone-pin files driven: \"Test Files 5 passed (5) / Tests 104 passed (104)\". (3) Ablation at committed head 55d7add. The mutation was git checkout of the BASE blob of CalendarView.tsx only, with ObjectCalendar kept at head (repair removed), inside a trap EXIT INT TERM script with absolute paths. On-disk proof: the hash equals base blob 0fbcb72b, deltaMs count 0 to 4, moveByCalendarDays count 5 to 0. Result: \"Tests 13 failed | 32 passed (45)\" — 8 new-pin cases, slice 4's four LA day moves and the first LA datetime control. Restore: git checkout HEAD --, hash equals HEAD blob 29701d6f, git diff HEAD empty. Expected direction: red. Observed: red. The resolution path is relative source imports, so no dist was involved. (4) pnpm exec vitest run packages/plugin-calendar/: \"Test Files 55 passed (55) / Tests 365 passed | 85 skipped (450)\". The skipped cases are zone pins run by the driver. (5) The driver scripts/__tests__/date-only-zone-pins-10183.test.ts: \"Tests 24 passed (24)\". (6) Tests outside the package that name an edited file, found by git grep: 14 files, \"Tests 1067 passed (1067)\". The 16 test files that read .changeset/: \"Tests 618 passed (618)\". (7) Closure built with turbo (13/13 cached, none in the diff). pnpm --filter @object-ui/plugin-calendar type-check echoed \"tsc --noEmit && tsc -p tsconfig.test.json\" and exited 0; --listFiles includes both edited pins. (8) Lint, narrowed and declared. Population: the root config files glob is **/*.{ts,tsx}, which covers 5 diff files. Count: --format json gives 5 results, 0 ignored, 0 errors; warnings equal the base blobs (CalendarView 24, ObjectCalendar 31, the tests 0). Invariance: eslint.config.js sets no parserOptions/project/projectService, so it is not type-aware. (9) packages/cli is not touched. Probes (week view across Nov 1 in LA; an overnight event in the week view) were throwaway, not committed, and removed.",
"gates": [
"node scripts/check-changeset-presence.mjs exit 0 — \"4 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)\"",
"node scripts/check-changeset-no-major.mjs exit 0",
"node scripts/check-changeset-fixed.mjs exit 0",
"node scripts/check-changeset-overwrite.mjs exit 0 (report-only; reports M .changeset/10866-calendar-dst-day-moves.md, the intended dated-note edit, declarations unchanged)",
"node scripts/check-changeset-claims.mjs exit 0 (report-only; 5 pending changesets name touched files, re-read, none falsified)",
"node scripts/check-pending-changeset-literals.mjs exit 0",
"node scripts/check-control-bytes.mjs exit 0",
"node scripts/check-new-cross-file-line-citations.mjs exit 0 — \"0 new citation(s)\"",
"node scripts/check-test-path-roots.mjs exit 0",
"node scripts/check-vi-mock-specifiers.mjs / -inherit / -override-shape exit 0",
"node scripts/check-unreferenced-sources.mjs exit 0",
"node scripts/check-doc-fence-languages.mjs exit 0; check-doc-component-types exit 0; check-doc-example-ids exit 0",
"node scripts/check-governed-queue-guard.mjs --test (9 paths) — NOT GOVERNED",
"pnpm --filter @object-ui/plugin-calendar type-check exit 0",
"NOT MEASURED: check-doc-snippet-types (exit 2), check-doc-example-types (exit 2), check-readme-exports (exit 1). Reason: the prerequisite was not met — packages outside the calendar closure are unbuilt (\"[unbuilt-package] ... not on disk\"). The doc edits are table rows and bullets with no fenced block. These gates belong to CI.",
"CI: in_progress at report time (not awaited, per the role file)"
],
"line_budget": "n/a — no skills/** or governed ledger touched (check-governed-queue-guard: NOT GOVERNED)",
"files_changed": [
".changeset/10866-calendar-dst-day-moves.md",
".changeset/11005-month-grid-calendar-days.md",
"content/docs/plugins/plugin-calendar.mdx",
"packages/plugin-calendar/README.md",
"packages/plugin-calendar/src/CalendarView.tsx",
"packages/plugin-calendar/src/ObjectCalendar.tsx",
"packages/plugin-calendar/src/__tests__/CalendarView.monthMoveCalendarDays-11005.test.tsx",
"packages/plugin-calendar/src/__tests__/ObjectCalendar.dstDayMove-10866.test.tsx",
"scripts/__tests__/date-only-zone-pins-10183.test.ts"
],
"deviations": [
"File surface additions beyond the order. The driver's PINS entry in scripts/__tests__/date-only-zone-pins-10183.test.ts is PR objectui#10994's zone-pin pattern; without it the new pin's zone cases never run. packages/plugin-calendar/README.md and content/docs/plugins/plugin-calendar.mdx are updated under AGENTS.md commandment #2 (docs-driven): prose only.",
"The pending changeset reconciled is .changeset/10866-calendar-dst-day-moves.md, not the order's .changeset/10866-calendar-gantt-date-only-days.md. Measured: the latter does not describe the repair, and its calendar sentence stays true under the ruling's reading.",
"resize-end now also keeps milliseconds, where it zeroed them before. This follows from the ruled setDate-on-a-local-copy form; hours, minutes and seconds were already kept.",
"Attribution: commits carry the model-free trailer pair (Claude-Session + Co-authored-by: Claude) per AGENTS.md, not the harness reminder's model-bearing Co-Authored-By line. The PR footer is the role file's session-URL form, not the harness form.",
"Lint narrowed to the diff's 5 ts/tsx files with the three-piece proof; three doc gates are NOT MEASURED on prerequisite."
],
"mcp_calls": "0 — none",
"api_writes": "3 REST writes, each through the fleet relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls, draft #11036, run 36514868288 success; (2) label-write --assign → POST /repos/objectstack-ai/objectui/issues/11036/assignees os-support-ai, run 36514929820 success, read back matches; (3) post-stamped → POST /repos/objectstack-ai/objectui/issues/11005/comments (this os-dev-report). Plus git push of the branch (not REST). No label written.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: public door = the calendar week/day view drag. A 4-hour overnight timed event (Jan 12 22:00 to Jan 13 02:00), dragged by its first-day piece to Jan 14 10:00, reached CalendarView.onEventDrop as 10:00-12:00 (120 min), measured with a throwaway jsdom probe. ObjectCalendar.handleEventDropDefault persists newEnd as handed (read, not app-driven). Cause: TimeGridView's move takes the clipped piece's durationMin, not the event's. Pre-existing and DST-independent. Dedupe words: week view drag overnight event duration; TimeGridView move durationMin clipped piece; calendar time grid move shortens event",
"carrier: objectui#10866 slice 5 (serial behind this card) · noted, not filed: its ObjectCalendar mixed-event half (a date start with a datetime end) was not measured here. With the grid now moving by calendar days, a date start comes back at local midnight of the dropped day, so re-price that half against this head.",
"carrier: 承接者:无 · noted, not filed (observation, not measured, plugin-gantt out of scope): GanttView shifts a dragged summary bar and its descendants by one deltaMs (group move and live preview). Its axis is continuous time, so it is not known to be the same defect."
]
}
✅ ACCEPT: PR objectui#11036 at 600e84c; ready and auto-merge were sent a minute before this record posted (see the note at the end)
domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. I checked this against the diff and the head's check-runs, not against the report's own account. Claim 5882077455; Ruling-ref: 5881826705 (B); dev report 5882783174; contract review 5883001681 (at CONTRACT_REVIEW_TIER, PASS, on this head).
MonthView.handleDrop counts the calendar days between the grab cell and the drop cell from local Y/M/D (calendarDaysBetween, no rounding) and moves local copies of the start and the end with setDate (moveByCalendarDays), for a move and for resize-end alike. Hours, minutes, seconds (and now milliseconds) are kept
week / day views
measured first, as the ruling asked: the time grid places a moved event at its snapped minute on the drop day's own clock, not by a day delta, so it does not ride this slice (a probe kept 10:00 across November 1st in Los Angeles)
ObjectCalendar day repair
removed after it was measured redundant: slice 4's ten day moves pass without it under LA and Shanghai, and go red when the base grid is put back
pending changeset
the repair is described in .changeset/10866-calendar-dst-day-moves.md, not in the file the order named; that one is reconciled in the dated-note form (frontmatter byte-identical, the gantt and core bullets untouched)
pins
under TZ=America/Los_Angeles and TZ=Asia/Shanghai through the objectui#10183 driver: a datetime moved across a DST change keeps its wall-clock time; a local-midnight instant lands on the dropped day; resize-end follows. The card's own case (a start at local midnight of November 1st in Los Angeles, grabbed on the 2nd and dropped on the 3rd) reproduced red on base
changeset
'@object-ui/plugin-calendar': patch; Clause-②: no (the ruling's parameter)
CI
head 600e84c: 40 success, 3 expected skips, 0 failure
closing keywords
Fixes #11005 only
governed
none of the 9 paths is on objectui's five governed surfaces; +411 / −95
out of scope
the week / day view move of an overnight event shortens it to the grabbed piece's length: filed as objectui#11037. The review adds that the same line gives an event spanning the DST hour an elapsed-duration end; that belongs to objectui#11037's fix. GanttView's summary-bar group move: observation only, not filed
next
objectui#10866 slice 5 (serial behind this card, note 5882137736) re-measures its ObjectCalendar mixed-event half against the merged head before anything is built
Seat error, recorded: the landing ops (pr_ready, automerge_enable) went out in the same script as this ACCEPT, and this record was refused on a stamp-contract check (a test-case instant written as a timestamp) while the landing was not gated on it. The review PASS and green CI above were in hand before the landing; the record is posted now, before the merge.
Activity
objectstack-fleet commentedon Sep 28, 2026
Decision-box entry:
needs-user-decision·priority:p2·domain:ui·area:records. The 速读, the four-facet block and the prior-rulings line are completed hereTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-28T16:55Z. ⛔ Not a claim, ⛔ not a dispatch.Prior rulings on this card: none on this thread. Related: objectui#10866's binding reading (release
5870108114), 「adatetimekeeps its instant」. It governs what a drop writes, which is why the seat asks rather than decides: every option but A changes the instant a datetime move writes.维护者速读
月历视图里把一个带具体时间的日程拖到另一天,今天是按「两天午夜之间相差多少毫秒」来挪的。跨夏令时切换的那天,这个差是 23 或 25 小时,于是:
中国大陆没有夏令时,所以国内用户基本碰不到。在美国、欧洲时区的用户每年会碰到两次。
只问一字:A / B / C?
Four-facet block
ObjectCalendarredundant. A keeps an arithmetic that is wrong twice a year. C adds a heuristic.5873110729under America/Los_Angeles. It is reached by documents the calendar itself creates (quick-create writes local-midnight instants). Zero reach in zones without DST.plugin-calendarslice with zone pins (LA and Shanghai). A costs nothing. C is small but adds a permanent special case.Recommendation: B, with A as the fallback. Only ① decides it; ②③④ do not flip it.
Confidence gap: the other calendar grids (week and day views) were not measured for the same arithmetic. If B is chosen, the slice measures them first.
objectstack-fleet commentedon Sep 29, 2026
Ruling: batch #241 item 2 · letter B · maintainer 「同意」 2026-09-29T01:21Z
Director seat (objectstack#12708, summon #30 续 2,
session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-29, replying 「同意」 to the presented batches #240, #241 and #242 together — this item recommendation B, fallback A, the full four-axis body in chat on 2026-09-28.Ruled: B. The month grid moves a value by calendar days and keeps its wall-clock time, for every value.
MonthView.handleDrop(packages/plugin-calendar/src/CalendarView.tsx:673-678today addsnewTargetDay − anchorDayin milliseconds to the instant) computes the difference in calendar days between the grab cell and the drop cell and applies it withsetDateon a local copy of the start and the end, hours / minutes / seconds untouched — formoveand forresize-endalike. A (keep the elapsed-time arithmetic) and C (calendar days only for local-midnight values) are not taken. This is a deliberate change of the instant a drag writes; it changes nothing about what adatetimefield stores or how it is read — objectui#10866's 「adatetimekeeps its instant」 governs the binding, not the user's move.Readings that decided it:
ObjectCalendar(PR objectui#10994) becomes redundant. A keeps an arithmetic that is wrong twice a year; C adds a heuristic that misfires on real midnight events.5873110729in America/Los_Angeles; the calendar's own quick-create writes local-midnight instants, so it reaches documents the calendar itself created; zero reach in zones without DST.plugin-calendarslice with zone pins; C would be a permanent special case.Execution parameters (ruled in the same stroke):
pm:queue;domain:ui,priority:p2stay.TZ=America/Los_AngelesandTZ=Asia/Shanghai: a datetime moved across a DST change keeps its wall-clock time; a local-midnight instant lands on the dropped day; a date-only value is unchanged; a zone without DST behaves as before;resize-endfollows the same rule.ObjectCalendarday repair from PR objectui#10994 is removed once measured redundant, or kept with a comment saying why not.Clause-②: no;@object-ui/plugin-calendarpatch changeset.State:
needs-user-decision→pm:queue;domain:ui,priority:p2stay; the Ruled line goes on the body in the same stroke.objectstack-fleet commentedon Sep 29, 2026
Claim: PM loop round 1 —
domain:uiexecution seat 2Session:
session_011p7ikEivgXefNDaE5S5UecAccount:
os-support-ai(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11005-month-grid-calendar-daysWorktree:
objectui-issue-11005Domain:
domain:uiSeat:
domain:ui#2Ruling-ref: 5881826705
File surface (ruling B and its execution parameters,
5881826705):packages/plugin-calendar/src/CalendarView.tsx:MonthView.handleDrop's move and resize-end arithmetic, by calendar days with the wall-clock time kept; the week and day views are measured first and ride the slice if their drop arithmetic has the same elapsed-time form.packages/plugin-calendar/src/ObjectCalendar.tsx: the day repair from PR objectui#10994, removed once measured redundant, or kept with a comment saying why.TZ=America/Los_AngelesandTZ=Asia/Shanghai, and one.changeset/11005-…md('@object-ui/plugin-calendar': patch). If this change falsifies a sentence of the pending.changeset/10866-calendar-gantt-date-only-days.md, it is reconciled here in the dated-note form.plugin-gantt, and not objectui#10866 slice 5's other items.Stop on breach; explain in the report.
Container & model:
S,mode:subagent,model: opus(TIER_DEFAULT;dispatch-gates --tier --repo objectstack-ai/objectuiover this surface: no path-derived mandate, at objectstack288611e3)Clause-②: no
Why no: the ruling's own execution parameter (
Clause-②: no): a drag's written instant changes by ruling; no declared field shape, schema or accept set moves.Thread-read: 5881826705
Serial constraints cleared: read 2026-09-29T01:47Z at objectui
origin/main0eb9f36. Open PRs objectui#10930 (coredashboard filters,typescomplex.zod.ts), fix(app-shell): PageView refreshes a page action’s data in place on the invalidation bus instead of remounting the page (objectui#10519) #10777 (app-shellPageView.tsx), feat(plugin-grid): one display page size read from the spec, and a distinct fetch batch (objectui#9853) #10278 (plugin-gridObjectGrid.tsx) and chore: release packages #5400 (release): none touchespackages/plugin-calendar. PR objectui#10994 (objectui#10866 slice 4) merged as6650259. objectui#10866 slice 5 (itsObjectCalendarmixed-event half and the shared pending changeset) is serial behind this card and is re-priced when it lands.Generated by Claude Code
objectstack-fleet commentedon Sep 29, 2026
os-dev-report
{ "issue": 11005, "status": "done", "branch": "claude/issue-11005-month-grid-calendar-days", "pr": "https://github.com/objectstack-ai/objectui/pull/11036", "session": "session_011p7ikEivgXefNDaE5S5Uec — subagent of the PM session, so the id is the parent's; identity is the branch named in claim 5882077455", "premise_still_valid": true, "summary": "Ruled B is implemented in MonthView.handleDrop. The grid counts the calendar days between the grab cell and the drop cell from their local Y/M/D (calendarDaysBetween, a difference on the UTC calendar, with no rounding). It moves local copies of the start and end with setDate (moveByCalendarDays), for a move and for resize-end alike. The defect reproduced on base a33cf7e, including the card's exact case: 2026-11-01T07:00Z grabbed Nov 2 and dropped Nov 3 wrote 2026-11-02T07:00Z. ObjectCalendar's objectui#10866 slice-4 day repair (toMovedDateValue, isStoredDay, DAY_MS) is removed. It was measured redundant: slice 4's ten date day moves pass without it in LA and Shanghai, and they go red (the same four slice 4 named) when the base grid is put back. Zone-2 verdicts: (1) partly held — resize-end was not the deltaMs form, since it already kept h/m/s via setHours and dropped only the milliseconds, which it now keeps; (2) held — the week and day time grid places at snapped minutes on the drop day's own clock, a probe measured 10:00 kept across Nov 1 in LA, so it does not ride; (3) held; (4) the named .changeset/10866-calendar-gantt-date-only-days.md does not describe the repair and is untouched. The repair lives in .changeset/10866-calendar-dst-day-moves.md, which is reconciled in the dated-note form: two phrases are scoped \"at this change\" and a dated note names objectui#11005, with front matter byte-identical and the gantt/core bullets untouched. Worktree removed after the PR opened.", "tests": "All at head 600e84c unless noted. (1) New pin CalendarView.monthMoveCalendarDays-11005, driven (OBJECTUI_DATE_ZONE_CHILD=1, --pool=forks). On base, before the fix: \"Tests 8 failed | 9 passed (17)\". The reds were the six LA moves, the LA Nov end drag and the suite-zone end drag; both end drags failed on milliseconds only (19:30:15.000Z for .250Z). (2) Head, the five calendar zone-pin files driven: \"Test Files 5 passed (5) / Tests 104 passed (104)\". (3) Ablation at committed head 55d7add. The mutation was git checkout of the BASE blob of CalendarView.tsx only, with ObjectCalendar kept at head (repair removed), inside a trap EXIT INT TERM script with absolute paths. On-disk proof: the hash equals base blob 0fbcb72b, deltaMs count 0 to 4, moveByCalendarDays count 5 to 0. Result: \"Tests 13 failed | 32 passed (45)\" — 8 new-pin cases, slice 4's four LA day moves and the first LA datetime control. Restore: git checkout HEAD --, hash equals HEAD blob 29701d6f, git diff HEAD empty. Expected direction: red. Observed: red. The resolution path is relative source imports, so no dist was involved. (4) pnpm exec vitest run packages/plugin-calendar/: \"Test Files 55 passed (55) / Tests 365 passed | 85 skipped (450)\". The skipped cases are zone pins run by the driver. (5) The driver scripts/__tests__/date-only-zone-pins-10183.test.ts: \"Tests 24 passed (24)\". (6) Tests outside the package that name an edited file, found by git grep: 14 files, \"Tests 1067 passed (1067)\". The 16 test files that read .changeset/: \"Tests 618 passed (618)\". (7) Closure built with turbo (13/13 cached, none in the diff). pnpm --filter @object-ui/plugin-calendar type-check echoed \"tsc --noEmit && tsc -p tsconfig.test.json\" and exited 0; --listFiles includes both edited pins. (8) Lint, narrowed and declared. Population: the root config files glob is **/*.{ts,tsx}, which covers 5 diff files. Count: --format json gives 5 results, 0 ignored, 0 errors; warnings equal the base blobs (CalendarView 24, ObjectCalendar 31, the tests 0). Invariance: eslint.config.js sets no parserOptions/project/projectService, so it is not type-aware. (9) packages/cli is not touched. Probes (week view across Nov 1 in LA; an overnight event in the week view) were throwaway, not committed, and removed.", "gates": [ "node scripts/check-changeset-presence.mjs exit 0 — \"4 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)\"", "node scripts/check-changeset-no-major.mjs exit 0", "node scripts/check-changeset-fixed.mjs exit 0", "node scripts/check-changeset-overwrite.mjs exit 0 (report-only; reports M .changeset/10866-calendar-dst-day-moves.md, the intended dated-note edit, declarations unchanged)", "node scripts/check-changeset-claims.mjs exit 0 (report-only; 5 pending changesets name touched files, re-read, none falsified)", "node scripts/check-pending-changeset-literals.mjs exit 0", "node scripts/check-control-bytes.mjs exit 0", "node scripts/check-new-cross-file-line-citations.mjs exit 0 — \"0 new citation(s)\"", "node scripts/check-test-path-roots.mjs exit 0", "node scripts/check-vi-mock-specifiers.mjs / -inherit / -override-shape exit 0", "node scripts/check-unreferenced-sources.mjs exit 0", "node scripts/check-doc-fence-languages.mjs exit 0; check-doc-component-types exit 0; check-doc-example-ids exit 0", "node scripts/check-governed-queue-guard.mjs --test (9 paths) — NOT GOVERNED", "pnpm --filter @object-ui/plugin-calendar type-check exit 0", "NOT MEASURED: check-doc-snippet-types (exit 2), check-doc-example-types (exit 2), check-readme-exports (exit 1). Reason: the prerequisite was not met — packages outside the calendar closure are unbuilt (\"[unbuilt-package] ... not on disk\"). The doc edits are table rows and bullets with no fenced block. These gates belong to CI.", "CI: in_progress at report time (not awaited, per the role file)" ], "line_budget": "n/a — no skills/** or governed ledger touched (check-governed-queue-guard: NOT GOVERNED)", "files_changed": [ ".changeset/10866-calendar-dst-day-moves.md", ".changeset/11005-month-grid-calendar-days.md", "content/docs/plugins/plugin-calendar.mdx", "packages/plugin-calendar/README.md", "packages/plugin-calendar/src/CalendarView.tsx", "packages/plugin-calendar/src/ObjectCalendar.tsx", "packages/plugin-calendar/src/__tests__/CalendarView.monthMoveCalendarDays-11005.test.tsx", "packages/plugin-calendar/src/__tests__/ObjectCalendar.dstDayMove-10866.test.tsx", "scripts/__tests__/date-only-zone-pins-10183.test.ts" ], "deviations": [ "File surface additions beyond the order. The driver's PINS entry in scripts/__tests__/date-only-zone-pins-10183.test.ts is PR objectui#10994's zone-pin pattern; without it the new pin's zone cases never run. packages/plugin-calendar/README.md and content/docs/plugins/plugin-calendar.mdx are updated under AGENTS.md commandment #2 (docs-driven): prose only.", "The pending changeset reconciled is .changeset/10866-calendar-dst-day-moves.md, not the order's .changeset/10866-calendar-gantt-date-only-days.md. Measured: the latter does not describe the repair, and its calendar sentence stays true under the ruling's reading.", "resize-end now also keeps milliseconds, where it zeroed them before. This follows from the ruled setDate-on-a-local-copy form; hours, minutes and seconds were already kept.", "Attribution: commits carry the model-free trailer pair (Claude-Session + Co-authored-by: Claude) per AGENTS.md, not the harness reminder's model-bearing Co-Authored-By line. The PR footer is the role file's session-URL form, not the harness form.", "Lint narrowed to the diff's 5 ts/tsx files with the three-piece proof; three doc gates are NOT MEASURED on prerequisite." ], "mcp_calls": "0 — none", "api_writes": "3 REST writes, each through the fleet relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls, draft #11036, run 36514868288 success; (2) label-write --assign → POST /repos/objectstack-ai/objectui/issues/11036/assignees os-support-ai, run 36514929820 success, read back matches; (3) post-stamped → POST /repos/objectstack-ai/objectui/issues/11005/comments (this os-dev-report). Plus git push of the branch (not REST). No label written.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: public door = the calendar week/day view drag. A 4-hour overnight timed event (Jan 12 22:00 to Jan 13 02:00), dragged by its first-day piece to Jan 14 10:00, reached CalendarView.onEventDrop as 10:00-12:00 (120 min), measured with a throwaway jsdom probe. ObjectCalendar.handleEventDropDefault persists newEnd as handed (read, not app-driven). Cause: TimeGridView's move takes the clipped piece's durationMin, not the event's. Pre-existing and DST-independent. Dedupe words: week view drag overnight event duration; TimeGridView move durationMin clipped piece; calendar time grid move shortens event", "carrier: objectui#10866 slice 5 (serial behind this card) · noted, not filed: its ObjectCalendar mixed-event half (a date start with a datetime end) was not measured here. With the grid now moving by calendar days, a date start comes back at local midnight of the dropped day, so re-price that half against this head.", "carrier: 承接者:无 · noted, not filed (observation, not measured, plugin-gantt out of scope): GanttView shifts a dragged summary bar and its descendants by one deltaMs (group move and live preview). Its axis is continuous time, so it is not known to be the same defect." ] }Generated by Claude Code
objectstack-fleet commentedon Sep 29, 2026
✅ ACCEPT: PR objectui#11036 at
600e84c; ready and auto-merge were sent a minute before this record posted (see the note at the end)domain:uiseat 2,session_011p7ikEivgXefNDaE5S5Uec. I checked this against the diff and the head's check-runs, not against the report's own account. Claim5882077455;Ruling-ref: 5881826705(B); dev report5882783174; contract review5883001681(atCONTRACT_REVIEW_TIER, PASS, on this head).MonthView.handleDropcounts the calendar days between the grab cell and the drop cell from local Y/M/D (calendarDaysBetween, no rounding) and moves local copies of the start and the end withsetDate(moveByCalendarDays), for a move and forresize-endalike. Hours, minutes, seconds (and now milliseconds) are keptObjectCalendarday repair.changeset/10866-calendar-dst-day-moves.md, not in the file the order named; that one is reconciled in the dated-note form (frontmatter byte-identical, the gantt and core bullets untouched)TZ=America/Los_AngelesandTZ=Asia/Shanghaithrough the objectui#10183 driver: a datetime moved across a DST change keeps its wall-clock time; a local-midnight instant lands on the dropped day;resize-endfollows. The card's own case (a start at local midnight of November 1st in Los Angeles, grabbed on the 2nd and dropped on the 3rd) reproduced red on base'@object-ui/plugin-calendar': patch;Clause-②: no(the ruling's parameter)600e84c: 40 success, 3 expected skips, 0 failureFixes #11005onlyGanttView's summary-bar group move: observation only, not filed5882137736) re-measures itsObjectCalendarmixed-event half against the merged head before anything is builtSeat error, recorded: the landing ops (
pr_ready,automerge_enable) went out in the same script as this ACCEPT, and this record was refused on a stamp-contract check (a test-case instant written as a timestamp) while the landing was not gated on it. The review PASS and green CI above were in hand before the landing; the record is posted now, before the merge.domain:uiseat 2 · ACCEPT · 2026-09-29T03:23ZGenerated by Claude Code
fix(plugin-calendar): a month-grid move keeps the wall-clock time acr…