Skip to content

list grid: a date column mixes relative and absolute formats in the same column ("昨天 / 3天前 / 7天前 / 9月25日 / 2025年9月20日"), so a sorted column cannot be read as sorted #25884

Closed

Description

@os-steve

Filing gate ① a user-visible defect with a named landing site. Batch-of: 2026-10-25 browser pass on @objectstack/* 18.1.0 (second batch, 8 cards). Filed by the maintainer's account (os-steve) from the HotCRM pass driven in session session_01AwpXhq2nFKU6J7GmbCEmZu; ⛔ not a claim. Grade and routing are objectui triage's.

What is seen (HotCRM on @objectstack/console 18.1.0, zh-CN)

list column values top to bottom
报价单 (sorted by 报价日期 desc) 报价日期 昨天 · 3天前 · 7天前 · 9月25日 · 9月10日 · 8月26日
报价单 到期日期 11月23日 · 11月21日 · 11月17日 · 昨天 · 10月10日 · 9月25日
合同 开始日期 / 结束日期 2025年9月20日 · 昨天 · 11月24日 · 11月8日 / 2027年10月24日 …
营销活动 开始日期 / 结束日期 9月20日 · 10月10日 · 10月13日 · 后天 · 6天后 · 11月13日 / 4天前 · 11月15日 …

31-crm_quote.png, 32-crm_contract.png, 43-crm_campaign.png. The 活动 list, by contrast, prints 2026/11/1 上午9:30 on every row and reads cleanly.

Within ±7 days a date becomes a relative word, beyond that a month-day, beyond the year a full date. Three formats in one column: the eye cannot scan it, a sorted column does not look sorted, and "昨天" in an expiry column reads as a status. Relative time is right for an activity feed, not for a grid cell that is compared with its neighbours.

reach: the public UI, measured once as the dev admin; every date column on every list shows it.

Expected

Grid cells render dates in one absolute format per column (the locale's short date, year included when it is not the current year); relative wording stays in feeds, timelines and highlight strips if desired. If the relative style is wanted somewhere in lists, it is a column option, not the default.

Dedupe

MCP search_issues objectui "list date column mixes relative dates yesterday 3 days ago with absolute dates in the same column" → 0 hits. Report: REPORT.md.

Activity

  1. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    and removed on Oct 25, 2026
  2. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Triage: first grade — bug · priority:p3 · domain:ui · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-25T14:54Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • One date format per column: absolute dates in a sortable column, with relative wording at most as a tooltip.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Transferred 2026-10-26T02:43Z from objectstack-ai/objectui#13533, with its comments and timeline; the old URL redirects here. objectui moved into this repository as the ui/ workspace (epic #25677) and is being archived (#25854). The body is left exactly as filed.

    Paths. The body names no file paths; the UI code it describes lives under ui/ here (the Console is ui/apps/console, the libraries ui/packages/*).

    No stale pm:dispatched or assignee to strip.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Premise · domain:ui seat 2 · 2026-10-26T14:45Z · read at origin/main 365fe5e

    Verdict: holds, and nothing on main has done it yet. Not claimed yet; stays pm:queue.

    • Root cause. ui/packages/fields/src/index.tsx:1208 sets the date cell's default to dateField.format || 'relative'. formatRelativeDate (ui/packages/core/src/utils/date-display.ts:533-546) is relative only within ±7 days and absolute outside that range, so a single column mixes both faces. datetime defaults to compact and is not affected.
    • The target face already exists. formatDate(v, undefined, …) gives a locale short date, with the year shown only when it is not the current year. No new formatter or i18n key is needed.
    • ObjectGrid restates the default at ObjectGrid.tsx:1716 for group headings, which groupDateHeading-13234 pins equal to the cell, so it must flip in step.

    Seat reading of the 2026-10-25 ruling ("absolute in a sortable column, relative at most as a tooltip"):

    • Scope is grid columns. DateCellRenderer is shared with the detail body, the highlights strip and mobile cards. The fix should make absolute the grid default (and the group heading), rather than silently changing every surface. If the implementer finds that a shared flip is the only clean seam, the PR must say so.
    • dueLike columns go absolute too. The red overdue styling stays, because it is independent of the wording (isOverdueInstant). The relative/"Overdue Nd" wording moves to the cell tooltip, replacing the raw ISO title. Authors who want relative keep it via the existing field.format: 'relative'.
    • About 7 tests pin today's relative default and will flip, including ObjectGrid.deadlineSettled-11815 and groupDateHeading-13234. The changeset must call out the metadata-visible default change.

    Sequencing. The fix moves scripts/sdui-manifest.sources/fields.json and plugin-grid.json, the same records as #26050 (plugin-grid chain #26030 → #26033 → #26050). I will claim it after #26050 merges. It stays outside the DateTimeCellRenderer region (index.tsx 1230-1345).

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 5 · 2026-10-26T18:27Z
    Session: session_01SMps7wq7rBTk53e8KTSEup
    Account: os-steve
    Branch: claude/issue-25884-grid-date-absolute
    Worktree: objectstack-issue-25884
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/fields/src/index.tsx (DateCellRenderer's default face, :1208, outside the DateTimeCellRenderer region), ui/packages/plugin-grid/src/ObjectGrid.tsx (the group-heading restatement :1684–1713 only), the grid-column seam that tells the cell it is in a grid if a grid-only default needs one, the tests that pin today's relative default (about 7, e.g. ObjectGrid.deadlineSettled-11815, groupDateHeading-13234), root .changeset/, scripts/sdui-manifest.sources/fields.json and plugin-grid.json (re-record under the lock). ⛔ ui/packages/core/src/utils/date-display.ts formatters (reuse formatDate(v, undefined, …)), locale packs, ui/.github/**, root ci.yml.
    Container & model: M, mode:subagent, model: default tier, effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: a grid date column that mixes relative and absolute wording | the 2026-10-25 ruling: absolute in a sortable column, relative at most as a tooltip | every list grid with a date column whose field declares no format
    Thread-read: 6418945034
    Premise: holds 2026-10-26T14:45Z, re-read at origin/main e05e0de89f: fields/src/index.tsx:1208 still defaults a date cell to dateField.format || 'relative', and ObjectGrid.tsx:1709 restates it for group headings. No open PR touches fields/src/index.tsx, ObjectGrid.tsx or date-display.ts.
    Serial constraints cleared: #26050 (fields / plugin-grid) MERGED 2026-10-26T18:06Z. On the plugin-grid line this PR enqueues after #26217 (#25942 step 2) merges.
    Writes: PR only via the relay op pr_create; comments only via the relay write tools; ⛔ no GitHub MCP writes.

    • Ruling section: the 2026-10-25 ruling on the card, as the seat reads it in 6418945034.
    • Seat's route:
      • Grid columns (cells and the group heading, in step) default to the absolute short date when the field declares no format. A declared format still wins.
      • dueLike columns go absolute too. The overdue red stays, and the relative / "Overdue Nd" wording moves to the cell's tooltip.
      • Keep the detail body, the highlights strip and mobile cards unchanged unless a shared flip is the only clean seam, in which case the PR says so.
      • Flip the pins that encode the old default, each named in the report. The changeset calls out the metadata-visible default change.
      • Fixes #25884.
  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
     "issue": 25884,
     "status": "done",
     "branch": "claude/issue-25884-grid-date-absolute",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/26341",
     "head": "aa24a3a2c861172463cd0063682084267ccb5c83",
     "session": "session_01SMps7wq7rBTk53e8KTSEup",
     "premise_still_valid": true,
     "summary": "CellRendererProps gains inGridColumn. With it set, DateCellRenderer paints formatDate(v, undefined, ...) for a date field with no declared format, which is the locale short absolute date with the year shown only outside the current year. The relative phrase (Yesterday / In 2 days / Overdue Nd) becomes the cell title when it differs from the face, the overdue red stays, and a declared format still wins. ObjectGrid passes inGridColumn on all 7 column-cell call sites in generateColumns, and temporalGroupHeading restates the selection (format || undefined), so headings still equal cells. The detail body, highlights strip, kanban, gallery, tree, RelatedList and the grid record panel are unchanged; a date title on a mobile grid card flips with the column. The card's assignee is os-steve and the PR assignee mirrors it.",
     "files_changed": [
      ".changeset/25884-grid-date-absolute.md",
      "scripts/sdui-manifest.sources/fields.json",
      "scripts/sdui-manifest.sources/plugin-grid.json",
      "ui/packages/fields/src/index.tsx",
      "ui/packages/plugin-grid/src/ObjectGrid.tsx",
      "ui/packages/plugin-grid/src/__tests__/ObjectGrid.dateColumnOneFace-25884.test.tsx",
      "ui/packages/plugin-grid/src/__tests__/ObjectGrid.deadlineSettled-11815.test.tsx"
     ],
     "line_budget": "+294 / -26 = 320 changed lines over 7 files vs merge base 69aa630b9; human-merge threshold 3000: under",
     "pins_flipped": [
      "ui/packages/plugin-grid/src/__tests__/ObjectGrid.deadlineSettled-11815.test.tsx (7 cases): it read Overdue 5d / 5 days ago / 4 days ago as the grid cell TEXT, which encoded the old relative default. It now reads them from the cell title, asserts the text is the absolute date, and keeps red on the open row and no red on the done row and the undeclared control. groupDateHeading-13234 needed no flip: it pins heading == cell, and both moved together. No fields-level pin flipped, because a cell without inGridColumn keeps relative."
     ],
     "tests": "RED FIRST at 4f461580 (the new test alone on e05e0de8): ObjectGrid.dateColumnOneFace-25884 failed 4/4 (paths A/B/C/D) with: expected 'Yesterday' not to match the relative-wording pattern. The column holds -1/-3/-6/+2/-40/-400-day dates; in-window rows painted relative phrases, and out-of-window rows painted absolute through formatRelativeDate's fallback (that half is derived from the code, not printed by the run). GREEN after the fix, at 089cca6b: the same test 4/4, plus 16 targeted files across fields, plugin-grid, plugin-list, plugin-detail, plugin-kanban and plugin-tree: 16 passed, 1 skipped, 113 tests passed. FULL SUITES pre-merge at 089cca6b: vitest run packages/fields packages/plugin-grid, 529 files passed / 1 skipped, 6536 tests passed. POST-MERGE at b5bc0328, the final run: fields + plugin-grid full + 8 cross-package date pins: Test Files 538 passed, 1 skipped (539); Tests 6566 passed, 7 skipped; lock VERDICT command-exit 0. TYPE-CHECK at b5bc0328: @object-ui/fields type-check exit 0, @object-ui/plugin-grid type-check exit 0. The pre-merge type-check exited 2 only on TS2307 for unbuilt sibling dist; it was rerun after the registry build. SDUI: node scripts/gen-sdui-manifest-node.mjs re-recorded 2 of 27 records (fields, plugin-grid), manifest unchanged; node scripts/check-sdui-manifest.mjs exit 0. aa24a3a2 differs from b5bc0328 only in the changeset prose. Separate ablation: none beyond the red leg. The tests resolve fields via the vitest src alias, so the pre-fix run is that reading.",
     "gates": "At aa24a3a2: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 46 families; 45 ran with exit 0, each captured before any pipe. pnpm check:type-check-debt exited 3: its closure build queued on the shared lock and never got a turn, so it is NOT-MEASURED and CI runs it (Lint & Repo Gates). --ran: 46 derived, 45 run, 1 NOT-MEASURED (derived from exit 3), 0 UNRUN, exit 0. CI check-runs on #26341: in_progress, not awaited.",
     "dogfood_battery": "n/a: no ! in the PR title and Clause-② is no without a (narrowing) arm",
     "mcp_calls": "0",
     "api_writes": "2 relay strokes: (1) pr_create via scripts/pm/fleet-write/dispatch.mjs, request fw-20261026T215406Z-dd088c, run 40408196934 success: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /issues/26341/assignees; read-back identical, 5876 bytes. (2) this os-dev-report comment via scripts/pm/post-stamped.mjs: POST /issues/25884/comments. git push is not counted.",
     "deviations": [
      "Merged origin/main once before opening the PR (deffcea7). #26217 had landed and moved scripts/sdui-manifest.sources/plugin-grid.json and fields.json, so a re-record on the old base would have conflicted. Main moved 7 more commits afterwards, with zero paths overlapping fields, plugin-grid or the sources records, so there was no second merge.",
      "The red leg needed @objectstack/spec, formula, client, lint and metadata-protocol built first (turbo, under the lock). The first two red attempts failed to resolve those imports, which is not a test verdict.",
      "Commit 8f4a261c lost the DateCellRenderer signature edit, which failed in a parallel batch, so its first targeted run was red on ReferenceError inGridColumn. 089cca6b fixed it, and every later run is at or after 089cca6b.",
      "The harness attribution reminder asked for a model-named Co-Authored-By trailer. Every commit uses the AGENTS.md model-free pair (Claude-Session + Co-authored-by: Claude) instead, as the card delta instructs.",
      "Standard order item 2 (tell the seat thread, wait for the Claim) and item 8 (message the seat thread) are superseded by the card delta: the Claim was already posted naming this branch, and I did not message the seat."
     ],
     "open_questions": [
      {
       "question": "Metadata-protocol line. The claim says none (copied verbatim into the PR body and changeset, patch level), but AGENTS.md classes a changed default as semantic. The undeclared date format now renders differently in a grid, although the spec key and its accepted values are unchanged.",
       "options": [
        "A keep none / patch: the spec contract is untouched and only the renderer's presentation default for one host moves",
        "B semantic / minor on fields and plugin-grid: the seat edits the changeset and the PR body line"
       ],
       "recommendation": "A, because no authorable key, value or spec default changed; the seat owns the call"
      },
      {
       "question": "Tooltip. The relative phrase replaces the ISO title only when it differs from the painted face. Outside the 7-day window the phrase equals the absolute face, so the ISO title stays there.",
       "options": [
        "A keep as is (no redundant tooltip, the raw-value hover survives for far dates)",
        "B always replace the ISO title, even when it repeats the face"
       ],
       "recommendation": "A"
      },
      {
       "question": "RelatedList (plugin-detail, RelatedList.tsx around line 1654) builds its own table cells without inGridColumn, so a record page's related-list date column still mixes faces.",
       "options": [
        "A leave it to a follow-up claim that adds inGridColumn there and re-records plugin-detail.json",
        "B fold it into this PR (widens the surface beyond the claim)"
       ],
       "recommendation": "A, because it is outside this claim's file surface"
      }
     ],
     "out_of_scope_findings": [
      "carrier: none (承接者:无) · RelatedList table date columns keep the relative default (plugin-detail RelatedList.tsx cell builder passes no inGridColumn) · read-only inference with no reach measured, so not filed; noted in the PR Acceptance notes · dedupe words: related list date column relative, RelatedList inGridColumn, record page related table mixed date faces"
     ]
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    Contributor

    Landed · seat 2 · 2026-10-27T03:19Z

    probe reading
    PR #26341 MERGED 2026-10-27T03:03Z, merge commit 9c3097eb, head 5dc16e94 (+292/−24, seat record on #26341)
    origin/main contains it (git merge-base --is-ancestor exit 0)
    queue branch gh-readonly-queue/main/pr-26341-*: none left (consumed)
    card closed (completed) by Fixes #25884 on #26341

    Status: in a grid column an undeclared date shows the absolute date, with the relative phrase as the hover title when it says something different; a declared format still wins, and the detail body, highlights, kanban, gallery, tree and record panel keep the relative face. RelatedList date columns: #26344, now unblocked. pm:dispatched removed.

  8. added a commit that references this issue on Oct 27, 2026
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:uipriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions