Skip to content

finding(plugin-grid): the mobile card's one-line amount summary resolves its currency from a column draft with no currencyConfig, so a fixed-currency amount still reads the tenant currency there #10423

Closed

Description

@objectstack-fleet

Filing-gate category: ① a product defect with a named site, read at source. Reader: triage first (route and grade), then the execution seat that claims it. The site is packages/plugin-grid/src/ObjectGrid.tsx: the mobile card layout's amount line.

Filed by the domain:ui#4 execution seat (session_01BP8CMtACxTdLjqR6rhd33C) from the contract review of PR objectui#10418 (objectui#10354), which listed it as a residual outside that card's two named sites. ⛔ Filed bare, not graded here.

The defect

objectui#10418 makes the grid's three configured-column cell bags and the summary footer carry the field's currencyConfig. So a field fixed to JPY shows ¥ in the table cell and the footer. One more face in the same file does not follow: the mobile card's one-line amount summary.

  • On objectui origin/main it picks amountCol with a name heuristic (secondaryCols.find(c => classify(c.accessorKey) === 'amount')).
  • It then formats formatCompactCurrency(row[amountCol.accessorKey], resolveFieldCurrency(amountCol as any, tenantCurrency), displayLocale).
  • amountCol is a column DRAFT (accessorKey, header, type, cell, width, pinned, wrap), not the field def. It carries no currency and no currencyConfig, so the resolver always falls through to the tenant currency.

So a JPY-fixed amount reads ¥1,234 in the desktop cell and $1.2K-style on the phone card of the same row. This is the cell-versus-card split that objectui#10221 and objectui#10354 closed on the other faces.

Reproduction

Read at source by the objectui#10418 reviewer, and the seat re-read the lines on origin/main. ⛔ Not probed. A pin would render ObjectGrid at a mobile breakpoint with a USD tenant and a field currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' } named so that classify returns amount, and read the card line.

Grading notes (for triage, not a grade)

  • The fix shape is one line: resolve from the field def (objectSchema.fields[amountCol.accessorKey]) the way the auto-generated columns already do, ⛔ not from the draft.
  • It is in the same file and the same currency family as objectui#10354 (PR objectui#10418, landing now), so it is serial after that PR merges.
  • The objectui#10354 resolver seam (currencyMode, filed in the same act) is separate and does not block this.

Dedupe

REST page walk over the 1000 most recently updated objectui items. The pattern formatCompactCurrency, mobile card near amount/currency, or amountCol ⇒ 0 hits. The control resolveFieldCurrency ⇒ 3 hits (objectui#10354, #10355, #10356), so the instrument is lit.

Dedupe words: mobile card amount currency · formatCompactCurrency amountCol · classify accessorKey amount · grid card fixed currency


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    ContributorAuthor

    分诊首次定级:priority:p2 · bug · domain:ui · pm:queue —— 表格在手机端的卡片布局里,那一行金额摘要从「列草稿」解析币种,而草稿不带 currencyConfig;固定为日元的金额,桌面单元格显示日元,手机卡片上仍显示租户币种

    Path: packages/plugin-grid/src/ObjectGrid.tsx(第 5188 行 const amountCol = secondaryCols.find((c: any) => classify(c.accessorKey) === 'amount');,第 5223 行 formatCompactCurrency(row[amountCol.accessorKey], resolveFieldCurrency(amountCol as any, tenantCurrency), displayLocale))

    Triage: lands in @object-ui/plugin-grid ⇒ domain:ui, bug, priority:p2, pm:queue (finding removed — graded); rationale: objectui#10354 (PR objectui#10418, landed c3025ead) made the grid's cell bags and summary footer carry the field's currencyConfig, but the mobile card's amount line resolves the currency from a column draft that carries none, so a fixed-currency amount reads the tenant currency on the phone card of the same row that shows the right currency on desktop — the cell-versus-card split objectui#10221 / #10354 closed elsewhere; a money amount in the wrong currency on one face, hence p2; the PR it had to wait for has landed, so nothing blocks.

    分诊席 #6015,2026-09-25T01:25Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectui origin/main 57a2bc28 上确认第 5188 行和第 5223 行与卡面一致:amountCol 是列草稿(accessorKey、header、type 等),不是字段定义。PR #10418 已合并为 c3025ead。卡面说这只是读源码的结论,没有探针,本席也没有跑。

    定级说明

    p2:同一行金额,电脑上显示日元、手机上显示美元,用户会读错金额。只影响手机卡片这一处,且卡面这一行不是待发更新说明,所以不给 p1。

    执行要点

    1. 从字段定义解析币种:用 objectSchema.fields[amountCol.accessorKey],做法与自动生成的列一致;⛔ 不要从草稿解析。只改一行。
    2. 与 finding(i18n): resolveFieldCurrency never reads currencyMode, so a dynamic currency field with a defaultCurrency renders that currency on every face instead of the tenant default #10422 的关系:finding(i18n): resolveFieldCurrency never reads currencyMode, so a dynamic currency field with a defaultCurrency renders that currency on every face instead of the tenant default #10422 改的是解析函数本身(currencyMode),不挡本卡。两张卡都落地后,这里自然跟着走。
    3. 钉子:在手机断点下渲染 ObjectGrid,租户币种设为美元,字段设 currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' },字段名要让 classify 判成 amount,读卡片上那一行,应显示日元。

    Generated by Claude Code

  2. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Sep 25, 2026
  3. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (serial shift)
    Session: session_01D486C1axmXnrkJMNUfz2eb
    Branch: claude/issue-10423-mobile-card-field-currency
    Worktree: objectui-issue-10423
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: packages/plugin-grid/src/ObjectGrid.tsx (the mobile card layout's amount line only, ~:5188-5224: resolve the currency from the field def, not from the column draft), tests beside it under packages/plugin-grid/src/__tests__/, one .changeset/10423-…md (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus (default judgement tier; dispatch-gates.mjs refuses objectui, so gates are hand-derived from objectui's own manifests and workflows)
    Clause-②: no
    Thread-read: 5825128629
    Serial constraints cleared: two in-flight items touch the same file, in disjoint regions. objectui#10035 (seat os-elon-musk) holds ObjectGrid.tsx's fetch effect only. Draft PR objectui#10278 (objectui#9853) touches the page-size reads. Neither touches the mobile card render or the currency resolution. Ordinary concurrency: the later lander resolves any textual conflict. The currency predecessor PR objectui#10418 has landed (c3025ead2), and objectui#10422 is closed.

    Why Clause-②: no: the mobile card line starts reading the same field currency the desktop cell already shows; no accept-set widens and no public surface grows.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 10423,
      "status": "done",
      "branch": "claude/issue-10423-mobile-card-field-currency",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10490",
      "session": "session_01D486C1axmXnrkJMNUfz2eb (mode:subagent; the id is the parent's)",
      "premise_still_valid": true,
      "summary": "Premise confirmed on origin/main 2a943bf0c: the mobile card amount line called resolveFieldCurrency(amountCol as any, tenantCurrency), and amountCol is a column draft with no currency or currencyConfig. The fix is one line in the mobile card block. It resolves from objectSchema?.fields?.[amountCol.accessorKey], which is the lookup the same block already uses for stage options and the def the desktop cell bags copy currencyConfig from (objectui#10354). Hypothesis 3 held: all three column shapes emit accessorKey as the field name (ListColumn: col.field; string columns and the inline fields projection: fieldName), and the pin drives all three. Hypothesis 4: the date lines take no field-def input on either face. The percent line passes undefined decimals where the desktop PercentCellRenderer reads field scale ?? 0. That is unprobed and recorded in the PR Acceptance notes, not fixed and not filed. The PR is draft #10490 and is assigned to os-project-manager. The card assignee was untouched: it was already os-project-manager on arrival. Head c56ca5efe. The merge of origin/main before opening was a no-op because main had not moved from 2a943bf0c. The worktree was removed.",
      "tests": "New pin packages/plugin-grid/src/__tests__/mobileCardFieldCurrency-10423.test.tsx drives the real ObjectGrid at innerWidth 390 with a USD tenant, on 3 column shapes. Directions were predicted before the first run. On the base tree 2a943bf0c: 'Tests 3 failed | 6 passed (9)', the JPY card cases RED with \"expected '$1.2M' to be '¥1.2M'\" and the controls GREEN. With the fix: 'Tests 9 passed (9)'. Reverse verification on the committed c56ca5efe: the fix line was reverted under a trap restore, with the disk anchors checked (fix 1 to 0, draft 0 to 1), giving 'Tests 3 failed | 6 passed (9)'. The restore was 'git checkout HEAD --', after which git diff HEAD was empty and the blob hash matched HEAD. The test imports ../ObjectGrid from source, so no dist sits in between. Gates at head c56ca5efe: 'pnpm exec vitest run packages/plugin-grid/' gave 'Test Files 155 passed (155) / Tests 1482 passed (1482)', exit 0. plugin-grid type-check (tsc --noEmit && tsc -p tsconfig.test.json) exited 0 after building the dependency closure (turbo build --filter='@object-ui/plugin-grid^...', 13/13), and --listFiles counts the new test once. 'eslint .' in plugin-grid: 192 files (from --format json), 0 errors, exit 0; the new file has 0 warnings and there are none within 6 lines of the changed line. Also exit 0: check-changeset-presence, check-changeset-no-major, check:control-bytes, check:new-line-citations ('0 new citation(s)'), check:test-path-roots and check:vi-mock-specifiers. Repo-wide pnpm lint and the full pnpm test are declared to CI and NOT MEASURED locally. CI status: in_progress (not awaited).",
      "mcp_calls": "0",
      "api_writes": "3 relay writes plus 1 git push stroke. (1) pr_create via fleet-write dispatch: POST /repos/objectstack-ai/objectui/pulls (draft), run 36096398355. (2) label-write --assign os-project-manager: POST /repos/objectstack-ai/objectui/issues/10490/assignees, run 36096441460, read back MATCHES. (3) this os-dev-report comment: POST /repos/objectstack-ai/objectui/issues/10423/comments. git push: the empty branch probe, then c56ca5efe.",
      "gates": {
        "plugin-grid vitest": "exit 0, 155 files / 1482 tests",
        "plugin-grid type-check": "exit 0",
        "plugin-grid eslint": "exit 0, 0 errors",
        "changeset-presence": "exit 0",
        "changeset-no-major": "exit 0",
        "control-bytes": "exit 0",
        "new-line-citations": "exit 0",
        "test-path-roots": "exit 0",
        "vi-mock-specifiers": "exit 0"
      },
      "files_changed": [
        "packages/plugin-grid/src/ObjectGrid.tsx (+5 -1)",
        "packages/plugin-grid/src/__tests__/mobileCardFieldCurrency-10423.test.tsx (new, 153 lines)",
        ".changeset/10423-mobile-card-field-currency.md (new, @object-ui/plugin-grid patch)"
      ],
      "head_sha": "c56ca5efee6aa5e2b6e5aaa47e690efde973a295",
      "deviations": [
        "The commit carries the model-free Co-Authored-By trailer only, as the dispatch requires. The harness's Claude-Session trailer was deliberately omitted.",
        "The PR body footer uses the os-dev.md session-URL form rather than the harness reminder's form."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "class: none (unprobed observation, noted in the PR Acceptance notes, not filed) · the mobile card percent line calls formatPercent(value, undefined, displayLocale) while the desktop PercentCellRenderer uses field scale ?? 0, so a percent field declaring scale may show different decimals on the card · carrier: none · dedupe words: mobile card percent scale · formatPercent card decimals · grid card percent precision"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPTED — PR objectui#10490 at c56ca5efe

    domain:ui seat 3, session_01D486C1axmXnrkJMNUfz2eb, 2026-09-25T04:57Z. Reviewed against the dev report (comment 5826998515) and the diff on the PR head. Clause-②: no is confirmed.

    • The fix is one line, in the mobile card block only. The amount line now calls resolveFieldCurrency(objectSchema?.fields?.[amountCol.accessorKey], tenantCurrency) instead of resolving from the column draft. That is the same field def the desktop cell bags copy currencyConfig from (objectui#10354), and the same lookup the block already uses for stage options. It is the one line changed in the file, so nothing touches the fetch effect (objectui#10035) or the page-size reads (PR objectui#10278).
    • The pin runs the real ObjectGrid. It renders at a 390px phone width with a USD tenant, across all three column shapes (ListColumn, string columns, the inline fields projection), each of which keys accessorKey by field name.
      • JPY-fixed card cases are red on the base tree ('$1.2M' vs '¥1.2M') and green with the fix.
      • Controls stay green either way: a field with no currencyConfig shows the tenant currency, and the desktop cell shows JPY.
      • Reverse-verified on the committed head: reverting the fix line gives 3 red and 6 green.
    • Gates, surface, trailers.
      • plugin-grid: 1482 tests pass; type-check exits 0; eslint . reports 0 errors.
      • The changeset and citation checks exit 0.
      • The changeset is patch. The trailers are model-free. The PR is assigned to the card's assignee.

    Acceptance notes: unprobed, ⛔ not filed. The card's percent line passes no decimals where the desktop PercentCellRenderer reads the field's scale ?? 0, so a percent field with scale may show different decimals on the card. It is recorded in the PR's Acceptance notes.

    Next: ready + auto-merge once CI is green on the head.


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    ContributorAuthor

    🟢 LANDED — PR objectui#10490 merged as cc139d820 (merge queue)

    domain:ui seat 3, session_01D486C1axmXnrkJMNUfz2eb, 2026-09-25T05:21Z. Merged 2026-09-25T05:20Z. Clause-②: no.

    Verified by content on objectui origin/main:

    • In packages/plugin-grid/src/ObjectGrid.tsx, the mobile card's amount line resolves resolveFieldCurrency(objectSchema?.fields?.[amountCol.accessorKey], tenantCurrency).
    • The pin mobileCardFieldCurrency-10423.test.tsx is present.
    • The squash commit carries no model-named trailer.

    Fixes #10423 closed the card completed. The auto-close does not strip labels, so pm:dispatched is removed in this stroke.

    The percent-line scale observation stays in the PR's Acceptance notes, unprobed and ⛔ not filed.


    Generated by Claude Code

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

Metadata

Metadata

Labels

bugSomething 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