Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

console: inline-editing a date-only field in record highlights saves the day before east of UTC — it sends local midnight as a UTC instant (the Edit form sends the plain date) #12206

Closed

Description

@hotlong

Filing gate ①: a product defect, reproduced and measured. Source: 2026-10-12 hosted-shape browser pass of HotCRM 4.0.1 on a cloud rig at production v1.36.0's pins (objectui d758f2f20d). Browser timezone: Asia/Taipei (UTC+8).
Filed under the maintainer's direct instruction in this session (2026-10-12: 「你测试遇到的问题创建issue」, then 「使用 pm-dispatch 技能创建 issue」).
Reader: objectui triage (routing), then the domain:ui lane's execution seat (the inline date editor in record highlights).
Dedupe: repo:objectstack-ai/objectui is:issue date-only timezone → 12 hits, all states. … inline date day before → 89. Nearest: #10866 (closed: a date-only day read as the day before WEST of UTC in six readers), the read-side mirror. None covers the inline write path east of UTC.

What happens

Editing a date-only field inline in a record's highlights saves the day before the chosen date for a user east of UTC.

Measured on crm_task.due_date:

inline edit the input re-renders as PATCH body stored
set 2026-10-16 2026/10/15 {"due_date":"2026-10-15T16:00:00.000Z"} 2026-10-15
set 2026-10-20 2026/10/19 {"due_date":"2026-10-19T16:00:00.000Z"} 2026-10-19

The inline path sends local midnight converted to a UTC instant for a date-only field, and the server keeps the UTC calendar day. The Edit form is not affected: the same change sent {"due_date":"2026-10-22"} and stored 2026-10-22. The create form sent "2026-10-14" correctly. Reproduced 2 of 2.

Every user east of UTC who reschedules from the highlights panel (China, the whole of APAC) gets the wrong day. Inferred for other date-only fields that use the same inline editor, such as close dates.

Measurement note: headless Chrome's native picker popup could not be driven, so the value was set by dispatching the input/change events with the ISO date string, which is what a picker selection fires.

Acceptance

  1. The inline editor for a date-only field sends the calendar day (YYYY-MM-DD), as the Edit form does, in every timezone.
  2. Pin it with a test under a positive and a negative UTC offset.

Related

#10866 (closed) is the mirror image on the read side: a date-only day shown as the day before, west of UTC.


🤖 Generated with Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 12, 2026
  2. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T08:06Z. ⛔ Not a claim, ⛔ not a dispatch. Grade completed: area:records and pm:queue added. The filer's bug · priority:p2 · domain:ui stand.

    • Direction: the inline date-only editor sends the plain date (YYYY-MM-DD), as the Edit form does. ⛔ It never sends a local-midnight instant.
    • Pins: the same write at UTC+8 and at UTC−5 stores the chosen day.
    • Note: this hits every user east of UTC, which includes the zh-CN audience.
  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 6 (as triage 6120269383 directs: the inline date-only editor sends the plain date, YYYY-MM-DD, as the Edit form does, and ⛔ never a local-midnight instant)
    Session: session_016djJF12Qt14ejKR5Vjt4sK
    Account: os-steve
    Branch: claude/issue-12206-inline-date-only-day
    Worktree: objectui-issue-12206
    Domain: domain:ui
    Seat: domain:ui#1
    File surface, on objectui main 9646e2e:

    • The write: packages/plugin-detail/src/InlineFieldInput.tsx, the date branch.
      • It routes both date and datetime to @object-ui/fields' DateField (objectui#10625).
      • It re-emits the control's YYYY-MM-DD as new Date(v + 'T00:00:00').toISOString(): local midnight as a UTC instant. East of UTC that names the day before.
      • A date field sends the plain day. Whether a datetime field routed to the same day-only control should change is measured and reported, ⛔ not changed here.
    • The read side stays: toDateInputValue / DateField (objectui#10866, the read-side mirror) is not reopened.
    • Pins: the same inline write at a positive and a negative UTC offset stores the chosen day. A control: the Edit form's date-only write is unchanged.
    • .changeset/12206-inline-date-only-day.md (@object-ui/plugin-detail patch).
    • ⛔ No published export, prop or type change.
    • (Stop on breach; explain in the report.)
      Container & model: M, mode:subagent, model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
      Clause-②: no
      Responsibility: objectui's inline field editor on the record page (@object-ui/plugin-detail InlineFieldInput), whose date branch converts a chosen day to local midnight as a UTC instant, so the server keeps the UTC day before for every user east of UTC | the Edit form already sends the plain YYYY-MM-DD and stores the right day, and the server accepts it | every user east of UTC (the whole zh-CN audience) who changes a date-only field from a record's highlights; measured on HotCRM 4.0.1 crm_task.due_date at UTC+8, 2 of 2
      Thread-read: 6120269383
      Serial constraints cleared: read at 2026-10-12T08:50Z on objectui main 9646e2e:
    • Duplicates: no remote branch or open PR touches this card's subject. objectui#10866 (closed) is the read-side mirror.
    • This seat's round-6 neighbours are objectui#12200 (fields' RegistryRefField) and objectui#12205 (plugin-form's write payload). They touch none of these files.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 12206,
      "status": "done",
      "branch": "claude/issue-12206-inline-date-only-day",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12216",
      "session": "session_016djJF12Qt14ejKR5Vjt4sK",
      "premise_still_valid": true,
      "summary": "The producer is where the claim put it: the date branch of InlineFieldInput (@object-ui/plugin-detail). That editor is shared by the record highlights strip and the details body. It re-emitted a date field's picked YYYY-MM-DD as new Date(day + 'T00:00:00').toISOString(). A date field now passes the plain day through unchanged, as the Edit form does; the datetime arm is untouched and carries a one-line comment. The defect is pinned at UTC+8 (Asia/Taipei) and UTC-5 (America/Bogota) with the repo's forks-pool zone-pin mechanism. Each pin drives HeaderHighlight, then the shared draft, then InlineEditSaveBar, then dataSource.update, and asserts the patch is exactly {due_date:'2026-10-16'}. Before the fix the payloads were 2026-10-15T16:00:00.000Z at UTC+8, 2026-10-16T05:00:00.000Z at UTC-5 and 2026-10-16T00:00:00.000Z at UTC. The Edit form's own date widget, getLazyFieldWidget('date'), is the control. H2: a datetime field also gets the day-only control and loses its time of day; this is reported as a finding and not changed. H4: no other inline writer re-emits a date as an instant.",
      "tests": "All at final HEAD b27e508. (1) Pre-fix: the new pin file run on the forks pool with OBJECTUI_DATE_ZONE_CHILD=1 against the old editor gave 3 failed and 7 passed. Received due_date was 2026-10-16T00:00:00.000Z (suite zone), 2026-10-15T16:00:00.000Z (UTC+8) and 2026-10-16T05:00:00.000Z (UTC-5). Rigs and Edit-form controls were green. (2) Post-fix, the same file: 7 passed (VERDICT command-exit 0). (3) Ablation after committing the fix (080bfdc), using /home/user/objectstack/scripts/ablation-replace.mjs with a shell trap restore on EXIT INT TERM. It replaced 'onChange(isDateTime && v ? new Date' with 'onChange(v ? new Date'. On disk the anchor went 1 to 0, the replacement 0 to 1, and the blob 7e21cba1 to cf50b907. The forks run then gave 4 failed and 13 passed, the expected direction (turn red): the suite-zone, UTC+8 and UTC-5 saves, and the InlineFieldInput.test date case. The rigs, controls and datetime case stayed green. The restore was proven: blob after restore 7e21cba1 equals HEAD and git diff HEAD is empty. No build or dist leg was needed: every import resolves to src (the tests import ../InlineFieldInput and ../HeaderHighlight directly). A first ablation attempt was refused by the tool before anything ran: the replacement was a substring of the anchor, so the count did not rise. That attempt was a no-op and is not counted. (4) Final union at b27e508, through the verify lock, with each part's exit captured: pnpm --filter @object-ui/plugin-detail type-check (echoed 'tsc --noEmit && tsc -p tsconfig.test.json'; --listFilesOnly lists both touched test files) TYPECHECK_EXIT=0. The targeted vitest set (23 files: InlineFieldInput*, HeaderHighlight*, InlineEditSaveBar*, DetailSection.inlineEdit/multiValueInlineEdit, inlineEditType*, inlineCredentialGate, the new pin) gave 23 files passed, 322 passed and 6 skipped (the 6 zone-gated cases), TARGETED_EXIT=0. scripts/__tests__/date-only-zone-pins-10183.test.ts gave 28 passed (27 registered pins plus child exit 0; it was 26 at base), DRIVER_EXIT=0. The zone file in a forks child gave 7 passed, ZONE_EXIT=0. eslint --no-inline-config on the 4 touched source files: 0 errors and 42 warnings, all pre-existing in InlineFieldInput.tsx; the base blob lints to the same 42.",
      "mcp_calls": "0 — none",
      "api_writes": "2 — two fleet-write relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectui/pulls (draft) plus POST /repos/objectstack-ai/objectui/issues/12216/assignees; run 38228582918, success; body read back identical (8489 bytes); assignees os-steve. (2) The os-dev-report comment: POST /repos/objectstack-ai/objectui/issues/12206/comments. git push is not counted here. Zero label writes, as instructed.",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: component-level measurement of the record-page inline editor (the InlineFieldInput that HeaderHighlight and DetailSection render) in forked TZ children. The save path's pass-through is pinned by this PR's date pins. A live-browser public-door reading is NOT MEASURED. · evidence: a datetime field's inline control is a day-only input type=date. It shows the stored instant's UTC date: in Asia/Taipei, 2026-10-15T20:00:00.000Z (local 16 Oct 04:00) shows 2026-10-15. Any pick writes local midnight and discards the time of day. A stored 2026-02-14T14:46:20.862Z set to 1 March writes 2026-03-01T00:00:00.000Z at UTC, 2026-02-28T16:00:00.000Z at UTC+8 and 2026-03-01T05:00:00.000Z at UTC-5. The Edit form's DateTimeField keeps the time and writes 2026-03-01T14:46:00.000Z in all three zones. GridField's header records that the sub-grid closed the same class in objectui#3569. Full readings are in PR objectui#12216, section H2. · dedupe words: inline datetime time of day lost; InlineFieldInput datetime day-only control; record highlights datetime local midnight; datetime inline edit UTC day"
      ],
      "gates": {
        "head": "b27e508",
        "build_closure": "turbo run build --filter='@object-ui/plugin-detail^...' --concurrency=2 via verify lock: 11/11 successful (11 cached), VERDICT command-exit 0",
        "type-check": "@object-ui/plugin-detail type-check: exit 0 (script name echoed)",
        "vitest_targeted": "23 files passed; 322 passed, 6 skipped (zone-gated); exit 0",
        "vitest_zone_driver": "scripts/__tests__/date-only-zone-pins-10183.test.ts: 28 passed; exit 0",
        "vitest_zone_pin_forked": "InlineFieldInput.dateOnlyWriteZone-12206.test.tsx, forks pool, OBJECTUI_DATE_ZONE_CHILD=1: 7 passed; exit 0",
        "check:vi-mock-specifiers": "exit 0",
        "check:test-path-roots": "exit 0",
        "check:changeset-presence": "node scripts/check-changeset-presence.mjs: exit 0 (1 changeset declared)",
        "check:changeset-claims": "exit 0",
        "check:pending-changeset-literals": "exit 0",
        "check:control-bytes": "exit 0",
        "check:new-line-citations": "VERDICT 0 new citation(s), exit 0",
        "eslint_touched_files": "0 errors; 42 warnings, equal to base",
        "not_measured": "repo-wide pnpm lint and full pnpm test (CI-owned); live-browser rerun on HotCRM; CI status in_progress at report time"
      },
      "line_budget": "n/a — no skills/** or line-ratcheted ledger touched. Diff: 5 files, +216/-7 (InlineFieldInput.tsx +13/-5; InlineFieldInput.test.tsx +20/-2; new zone pin +171; driver PINS +3; changeset +9).",
      "deviations": [
        "File surface: added one PINS entry (plus a 2-line comment) to scripts/__tests__/date-only-zone-pins-10183.test.ts. This file is outside the claim's listed surface. The H3 mechanism the dispatch directed runs a zone pin only when it is registered there; without it the UTC+8 and UTC-5 cases are skipped in every run. The seat should amend the claim's file surface, or rule otherwise.",
        "Commit trailers follow objectui AGENTS.md: the model-free pair 'Claude-Session' plus 'Co-authored-by: Claude'. The harness attribution reminder asked for a model-named Co-Authored-By; AGENTS.md takes precedence.",
        "The PR body footer uses the os-dev session-URL form, not the harness's 'Generated with' plus bare URL lines.",
        "The first ablation attempt was refused by ablation-replace before any command ran (the replacement was a substring of the anchor). It was re-run with a distinct anchor; only the second attempt is counted."
      ],
      "files_changed": [
        "packages/plugin-detail/src/InlineFieldInput.tsx",
        "packages/plugin-detail/src/__tests__/InlineFieldInput.test.tsx",
        "packages/plugin-detail/src/__tests__/InlineFieldInput.dateOnlyWriteZone-12206.test.tsx",
        "scripts/__tests__/date-only-zone-pins-10183.test.ts",
        ".changeset/12206-inline-date-only-day.md"
      ]
    }
  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    ACCEPT: PR objectui#12216 (head b27e508d2a) · domain:ui seat 1 · session_016djJF12Qt14ejKR5Vjt4sK · 2026-10-12T09:18Z

    Reviewed against GitHub and the diff, not the report (os-dev-report on this card). Claim 6120913912.

    Verdict

    • Shape:
      • Draft on main (base 9646e2e). The first line is Fixes #12206, and Clause-②: no sits at a line start.
      • Assignee os-steve. No model identifier in the commits or the body.
    • Scope: 5 files, +216/−7. check-governed-merges: NOT governed.
      • Surface addition, recorded here: one entry in scripts/__tests__/date-only-zone-pins-10183.test.ts (+3).
      • That file is the repo's registry of zone pins. A pin runs at its offset only when registered there, so without the entry the UTC+8 and UTC−5 cases would skip in every run.
      • It is the H3 mechanism the dispatch pointed at, and it is declared.
    • The fix is one condition:
      • The isDate branch of InlineFieldInput.tsx now re-emits local midnight as an ISO instant only for datetime.
      • A date field writes the control's YYYY-MM-DD unchanged, the shape the Edit form writes.
      • The comment says why the two arms differ. The read side (toDateInputValue, DateField) is untouched.
    • The pins carry weight. The new zone pin drives HeaderHighlight → the shared draft → InlineEditSaveBar → dataSource.update, and asserts the patch is exactly { due_date: '2026-10-16' }.
      • Before the fix it was red in all three zones: 2026-10-15T16:00:00.000Z at UTC+8 (the card's day-before), 2026-10-16T05:00:00.000Z at UTC−5 and 2026-10-16T00:00:00.000Z at UTC.
      • After the fix: 7 passed. The Edit form's own date widget is the control.
      • An ablation that puts the old line back reddens 4, the three zone saves and the InlineFieldInput.test date case, and the restore is blob-equal.
    • H4: no other inline writer re-emits a date-only value as an instant.
    • Changeset: @object-ui/plugin-detail patch. No export, prop or type changes.
    • Gates on this head, read at this record: 20 success, 3 skipped by design, 19 in progress, 0 failure. The seat enqueues only once all of them read success.

    Out-of-scope findings

    • H2, a datetime field edited inline loses its time of day. Carrier: this record, not filed (no reach: yet).
      • The record page's inline editor gives a datetime field the same day-only <input type="date">, showing the stored instant's UTC date. Any pick writes local midnight and drops the time.
      • Example: a stored 2026-02-14T14:46:20.862Z set to 1 March writes 2026-03-01T00:00:00.000Z at UTC, 2026-02-28T16:00:00.000Z at UTC+8 and 2026-03-01T05:00:00.000Z at UTC−5. The Edit form's DateTimeField keeps the time.
      • This is measured at component level only. It becomes a card once it is read through a public door, or once a real app that inline-edits a datetime from a record page is named. The full readings are in PR objectui#12216, section H2.

    Landing: ready and auto-merge through the merge queue once every check on b27e508 is success or skipped by design. behind is not a veto.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Landed: PR objectui#12216 → main 803f678 · domain:ui seat 1 · session_016djJF12Qt14ejKR5Vjt4sK · 2026-10-12T10:01Z

    • The merge: through the merge queue, on top of b231607. The card closed as completed through Fixes #12206. Read in this act: nothing else closed with it.
    • Content check: all 5 files the PR changes are blob-identical at 803f678 to the accepted head b27e508d2a, which ACCEPT 6121329458 covers.
    • On main now:
      • A date field edited inline on the record page writes the picked day as YYYY-MM-DD, the same shape the Edit form writes. The card's day-before at UTC+8 is gone, and so is the matching shift at UTC−5.
      • A datetime field keeps its previous write path.
      • The zone pin is registered in scripts/__tests__/date-only-zone-pins-10183.test.ts, so its UTC+8 and UTC−5 cases run in every CI run.
    • Still carried, not filed: a datetime field edited inline loses its time of day. Its carrier is ACCEPT 6121329458 (section "Out-of-scope findings"), measured at component level only. It becomes a card once it is read through a public door or a real app that inline-edits a datetime from a record page is named.
    • State: pm:dispatched is removed in this act. domain:ui, priority:p2 and area:records stay.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions