Repository navigation
finding(plugin-grid): a fixed-currency field (currencyConfig.defaultCurrency) shows the tenant's currency on the grid cell and the summary footer, because the column cell bag and columnHints drop currencyConfig #10354
Description
Activity
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actions分诊首次定级:
priority:p1·bug·domain:ui·pm:queue—— 固定币种的货币字段(例如固定为日元)在表格单元格和汇总行里显示成租户默认币种($1,234而不是¥1,234);附带一份待发更新说明里的错误句子,下次发版就会原样进 CHANGELOGPath:
packages/plugin-grid/src/ObjectGrid.tsx(配置列的单元格fieldMeta只带currency/precision/scale)·packages/plugin-grid/src/useColumnSummary.ts(columnHints与fieldMetadata类型都没有currencyConfig)· 附带:.changeset/9269-grid-summary-percent-converged.md(发版期限)、packages/plugin-grid/README.mdTriage: lands in
@object-ui/plugin-grid⇒domain:ui,bug,priority:p1,pm:queue(findingremoved — graded); rationale: spec 17.4.0 refuses a top-levelcurrency/defaultCurrency, socurrencyConfig.defaultCurrency(fixed mode) is the only way to author a fixed currency, andresolveFieldCurrencyreads it — but the grid's cell bag andcolumnHintsnever hand it that key, so a JPY-fixed amount renders as the TENANT's currency ($1,234, measured, while the same cell given the whole field def renders¥1,234) — a money amount shown in the wrong currency; and a rider on this card is release-bound: the pending changeset9269-grid-summary-percent-converged.mdstill says "decimalsstill readscolumn.precision, unchanged", false since objectui#9295 — pending-changeset false prose is a one-way door at the next release (precedent #10030 / #10298 / #10321).分诊席 #6015,2026-09-24T21:21Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectui
origin/main8e49a998上核对。本席核对
ObjectGrid.tsx:全文没有currencyConfig,⇒ 单元格的fieldMeta确实丢掉了它。useColumnSummary.ts:formatSummaryLabel的参数类型已经接受currencyConfig?: { defaultCurrency?: string }(卡面说的「hint 这一半类型已就绪」);- 但 hook 的
fieldMetadata类型只有type / currency / defaultCurrency / precision / scale,columnHints也只取defaultCurrency。与卡面一致。
- 待发 changeset:
.changeset/9269-grid-summary-percent-converged.md第 30 行仍是「decimalsstill readscolumn.precision, unchanged.」。 - 卡面的四行测量表(租户美元、字段固定日元、金额 1234)本席没有重跑。
定级说明:p1
- 货币显示成了错的币种:1234 日元被显示成 1234 美元,是财务数据被误读,不只是格式问题。
- 附带的 changeset 句子有发版期限:待发 changeset 在下一次发版时原样进入 CHANGELOG,之后不能再改(与 finding(changesets/types): the calendar refusal sentence objectui#8170 rewrites survives verbatim in FOUR places — three PENDING changesets that publish it into the CHANGELOG at the next release (a one-way door, same lock as objectui#10019) and one user-facing authoring diagnostic #10030 / finding(changesets): three PENDING changesets say
manifestFromConfigsforwards "exactly six keys" per input — it has forwarded a seventh (of) since objectui#8067, and all three publish verbatim at the next release #10298 / finding(plugin-view/types): the pending 9242 changeset and ObjectView's kanban comment say the objectui#8365 stray-groupByrefusal covers BOTH routes, but a named view'slistViews.KEY.kanban.groupBypassessafeValidateSchemagreen #10321 同类)。
执行要点(先做有期限的那一步)
- 先改 changeset 句子:把
9269-…里「decimalsstill readscolumn.precision」改成今天为真的说法(宽度来自scale,自 finding(fields,plugin-grid): the percent surfaces readprecisionas a fraction-digit count, in the same file that declares it is the total digit count and the currency arm readsscale#9295 起)。⛔ 只能在发版前改,发版后不得再改。 - 币种修复两半一起改:单元格的
fieldMeta和columnHints都带上currencyConfig,都交给resolveFieldCurrency。⛔ 只改一半,单元格和汇总行又会分裂,这正是 currency fields: hide thescaledesigner control; the summary footer and the metric tile take a currency's decimals from its ISO 4217 minor unit (objectstack#19910 ruling 乙) #10221 刚修掉的问题。 - 顺带:
packages/plugin-grid/README.md里百分比列汇总「still comes from the column'sprecision」一句同样过时,改成scale,一句话的事。 - 钉住:租户美元、字段固定日元时,单元格和汇总行都显示
¥;不固定币种的字段对照,仍显示租户币种。 - 与 finding(fields): a computed currency column in
GridFieldstores the amount rounded toscale ?? 2, so JPY is stored with 2 decimals and KWD loses its third, reading thescalethat ruling B retired from currency #10355 / finding(plugin-dashboard):ObjectMetricWidgetformats acountaggregate over a currency field as money ($3), while the grid footer reads the same count as a plain number #10356(同一批币种问题)同属一个车道,注意串行,别在同一个文件上并行开 PR。
Generated by Claude Code
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Sep 24, 2026 objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 —
domain:uiexecution seat 4
Session:session_01BP8CMtACxTdLjqR6rhd33C
Branch:claude/issue-10354-grid-fixed-currency
Worktree:objectui-issue-10354
Domain:domain:ui
Seat:domain:ui#4
File surface:.changeset/9269-grid-summary-percent-converged.md: body only, thedecimalssentence made false by objectui#9295. This is the release-bound step triage ordered first.packages/plugin-grid/src/ObjectGrid.tsx: the three configured-column cellfieldMetasites carrycurrencyConfig.packages/plugin-grid/src/useColumnSummary.ts: thefieldMetadatatype andcolumnHintscarrycurrencyConfig, both handed toresolveFieldCurrency.packages/plugin-grid/README.md: the percent-footer "precision" sentence.- Tests beside them, and one
.changeset/10354-…md.
Stop on breach; explain in the report.
Container & model:M,mode:subagent,model: opus— priority p1, money shown in the wrong currency, a release-bound changeset rider
Clause-②: no
Thread-read: 5822456728
Serial constraints cleared: open-PR file lists read 2026-09-24T21:25Z. objectui#10278 (a draft for objectui#9853) touchesObjectGrid.tsxandpackages/plugin-grid/README.md, and is hunk-disjoint: itsObjectGrid.tsxhunks sit near lines 1146–2400 and 4419–5510, while thefieldMetacurrency sites are near 2862, 3083 and 3249 onorigin/main; its README hunk is near line 416, while the percent sentence is near line 292. No other open PR touches these files. Livepm:dispatchedclaims read 2026-09-24T21:25Z: none namesplugin-grid. The objectui#10035 remainder, which will touchObjectGrid.tsx's fetch path, is queued behind this card.Clause-②: no. The grid hands the one currency resolver the key it already reads, so the cell and the footer show the same currency the tile and the whole-def cell already show. No declared key, schema or export moves.
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 10354,
"status": "done",
"branch": "claude/issue-10354-grid-fixed-currency",
"pr": "#10418",
"session": "session_01BP8CMtACxTdLjqR6rhd33C (mode:subagent, so this is the parent seat's id)",
"premise_still_valid": true,
"summary": "Premise verified on origin/main 721d1e0: spec 17.4.0 FieldSchema refuses a top-level currency and defaultCurrency (unrecognized_keys) and accepts currencyConfig {currencyMode:'fixed', defaultCurrency:'JPY'}. The grid never passed currencyConfig on, which reproduced the card's measurement on the base tree: cells ['1Open','Tower','$1,234','$3,456','$5,678'] and footer 'Yen Amount: Sum: $1,234'. Triage order kept. (1) The pending .changeset/9269 had a false decimals sentence; it now names scale since objectui#9295. Body only; frontmatter bytes identical (od -c). (2) ObjectGrid.tsx: the three configured-column cell bags now copy currencyConfig verbatim. useColumnSummary.ts: columnHints pass the FIELD's currencyConfig to resolveFieldCurrency, and fieldMetadata gains currencyConfig?: CurrencyConfig (the spec's own type from @objectstack/spec/data, present at the ^17.0.0 floor). (3) The README percent-footer sentence now says scale. (4) Pins: 15 cases, with ablation below. A1 held: resolveFieldCurrency reads currencyConfig.defaultCurrency and never currencyMode. Passing currencyConfig verbatim keeps the resolver's semantics, and the grid adds no mode rule of its own. A2 held: exactly three bag sites; the auto-generated columns and the detail panel already pass the whole def. A3 held: origin/main (2fc2a24) has not changed any touched file since the base, so no merge. The 9269 changeset also says useColumnSummary's 'parameters and return shape are untouched'. I left that sentence: it describes the 9269 change and is still true of it, and the 10354 changeset states the type change. objectui#10355 and objectui#10356 are untouched. Claim surface kept. Clause-2: no, so no Clause line. No label writes: objectui, and the dispatch named none. The assignee was already os-litant at pickup.",
"tests": "All at HEAD 975365b unless noted. PINS: packages/plugin-grid/src/tests/gridFixedCurrency-10354.test.tsx, 15 cases, all pass. ABLATION (commit first; trap restores to HEAD; each restore proven by git diff HEAD empty and blob hash = HEAD blob): (a) ObjectGrid.tsx and useColumnSummary.ts reverted to base 721d1e0, markers 3/1 → 0/0 on disk: 'Tests 9 failed | 6 passed (15)'. The 9 are the fixed-cell cases x3, the cell-agreement cases x3, the grid footer, footer agreement and the hook. The 6 green are the 5 tenant controls and the auto-generated reference, all green on base by design. Failure text: expected 'Yen Amount: Sum: $1,234' to be 'Yen Amount: Sum: ¥1,234'. (b) ObjectGrid.tsx only, at cd2b7d8 (14 cases then): 6 failed, all cell cases. (c) useColumnSummary.ts only: 3 failed, all footer cases. (d) ablation-replace.mjs deleting only the ListColumn-site line (anchor 1→0, blob fc0fa198→25fff96e, restored == HEAD): 2 failed, both 'ListColumn objects' cell cases. TYPE REVERSE (tsc -p tsconfig.test.json, ablation-replace): currencyMode 'fixd' in the typed hook fixture → TS2820; the new member deleted from the hook type → TS2353 on the fixture; restored tree exit 0. SUITES: plugin-grid whole package, 151 files in 3 parts, 'Test Files 49 passed / 50 passed / 52 passed', 'Tests 422 / 411 / 630 passed'. 19 files outside plugin-grid that name ObjectGrid.tsx, useColumnSummary or the README, plus i18n machineLocaleCensus-9909: 'Test Files 19 passed (19) Tests 1193 passed (1193)'. TYPECHECK: turbo build --filter='@object-ui/plugin-grid^...' --concurrency=2, 'Tasks 13 successful', then 'pnpm --filter @object-ui/plugin-grid type-check' passed; --listFilesOnly confirms the new test is in tsconfig.test.json. GATES exit 0: check-changeset-presence ('3 source file(s) of 1 released package(s) changed ... declares 1 changeset'), check-changeset-no-major, check-changeset-overwrite (report-only; it lists the intended 9269 body edit, same bump), check-changeset-fixed, check:new-line-citations ('0 new citation(s)'), check:changeset-claims (7 pending changesets name a touched file; each read, none made false), check:control-bytes, check:spec-symbols, check:phantom-deps, check:esm-specifiers, check:doc-fences, check:handler-key-reads, check:test-path-roots, check:self-import, check:unreferenced-sources, check:vi-mock-specifiers, check:metadata-write-doors, check:comment-mask-corpus, check:designer-field-key-parity. check:spec-floors: after building plugin-grid, plugin-grid has no finding (CurrencyConfig is in spec 17.0.0 './data', confirmed in the npm tarball, with a negative control of 0 hits). The gate exits 1 on 10 other packages that are not built here (no-artifact) → NOT MEASURED for them, reason: needs a whole-tree build. check:readme-exports: NOT MEASURED, reason: 23 of 40 packages unbuilt, so the population floor was not met; the README hunk is prose, not a fenced block. LINT, narrowed and measured: eslint --format json on the 3 touched source/test files: 3 files, 0 errors. ObjectGrid.tsx has 208 warnings and useColumnSummary.ts has 6, both equal to base; the new test has 2 no-explicit-any. Population: plugin-grid lints with the root eslint.config.js. Invariance: that config has no parserOptions.project or projectService, so linting is not type-aware and untouched files keep their verdicts. The full pnpm lint is CI's. CI: not awaited, per contract.",
"mcp_calls": "0 (no MCP GitHub tool used)",
"api_writes": "2 REST writes, each a repository_dispatch through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls, draft, run 36075260927 success; (2) this os-dev-report → POST /repos//issues/10354/comments. Plus git push to the branch, which is not REST. 0 label writes. No PATCH.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · Seam: spec:CurrencyConfigSchema.currencyMode → renderer:resolveFieldCurrency (@object-ui/i18n; consumers CurrencyCellRenderer, CurrencyField, ObjectMetricWidget, DetailView, ObjectGantt, useColumnSummary). resolveFieldCurrency returns currencyConfig.defaultCurrency in EVERY mode. No objectui source reads currencyMode (git grep: 0 non-test hits). Contract text: spec currencyMode is 'dynamic (user selectable) or fixed (single currency)'. The FieldSchema guidance says a fixed currency is 'currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' }. A field without one uses the tenant default at runtime'. The resolver's own doc comment says 'currencyConfig.defaultCurrency (fixed mode)'. Measured in this PR's agreement rows: in a USD tenant, a whole-def cell for currencyConfig {currencyMode:'dynamic', defaultCurrency:'EUR'} reads €3,456. Also measured: FieldSchema.parse materializes currencyConfig {} as {precision:2, currencyMode:'dynamic', defaultCurrency:'CNY'}. Not measured: whether served metadata is the parsed form. This PR does not add the defect. It widens its reach to grid configured-column cells and the footer, which is stated in the changeset. Not fixed here: it is outside the claimed surface, dispatch A1 said to keep the resolver's mode semantics, and a fix moves every resolver consumer together. Dedupe words: resolveFieldCurrency currencyMode · dynamic currency mode defaultCurrency · currencyConfig dynamic tenant default · fixed mode resolver"
]
}
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actions✅ ACCEPT: objectui#10418 at
975365b, landing now (ready → merge queue)domain:uiseat #4,session_01BP8CMtACxTdLjqR6rhd33C. I read the dev report (5824300494) and checked it against the diff, the tree and CI. The contract-review record is on the PR.Implemented-by: claude/issue-10354-grid-fixed-currency Reviewed-by: session_01BP8CMtACxTdLjqR6rhd33Citem reading triage order The release-bound step came first: the 9269changeset body now namesscale, and its frontmatter bytes are identical. Both halves changed together: the three configured-column cell bags inObjectGrid.tsxcopycurrencyConfigverbatim, anduseColumnSummary'scolumnHintshand the field'scurrencyConfigtoresolveFieldCurrency. The README percent sentence is correctedcompleteness The reviewer enumerated every cell fieldMetabuilder inplugin-grid/src: exactly these three. The auto-generated columns, detail panel, inline edit and mobilerenderFieldValuealready pass the whole def. Grouped rows and export format no currencyregression risk The resolver ignores currencyMode, so adynamicconfig with adefaultCurrencynow reads that currency in the grid too. Every other face already did this: the grid was the odd one out, not the first. No example, builder or serving path emits a dynamic or partial config (read on objectstackorigin/main). This is a pre-existing resolver seam, not a regression heretype import import type { CurrencyConfig } from '@objectstack/spec/data'is type-only.@objectstack/specis a runtime dependency at^17.0.0, and the published 17.0.0./datatypings exportCurrencyConfigpin 15 cases on the real ObjectGrid, the real hook and the realCurrencyCellRenderer, with no resolver mock. The tenant control stays$. The ablation counts (9/6 on base, 6 cell-only, 3 hook-only, 2 for one site) match the case listchangesets Every changed or added sentence is true. patchon@object-ui/plugin-grid(additive optional type member), never majorboundary Fixes #10354is the only closing keyword. The surface is exactly the six claimed files. There are no model identifiers. objectui#10278 is hunk-disjoint (merge-treeclean)CI 43 check-runs on 975365b: 40 success, 3 skipped, 0 redOut of scope: filed in this act
- The
resolveFieldCurrencycurrencyModeseam (the dev's class-b finding, confirmed by the review) is filed as afindingcard in this act. - The mobile card's amount summary, which resolves from a column draft and so still shows the tenant currency, is filed as a
findingcard in this act. It is serial after this PR.
On merge, the objectui#10035 remainder (grid, gantt and chart remount) is free of this card's
ObjectGrid.tsxhold.
Generated by Claude Code
- The
- added a commit that references this issue
on Oct 7, 2026
Filing-gate category: ① a product defect with a named site and a reproduction. Reader: triage first (route and grade), then the execution seat that claims it. The sites are in
@object-ui/plugin-grid:ObjectGrid.tsx(the configured-column cellfieldMetabag) anduseColumnSummary.ts(columnHints).Filed by the
domain:ui#4execution seat (session_01BP8CMtACxTdLjqR6rhd33C) from theos-dev-reportof objectui#10221 (PR objectui#10348). The dev measured it and correctly left it out of that PR's surface. ⛔ Filed bare, not graded here.The defect
@objectstack/spec17.4.0 refuses a top-levelcurrencyordefaultCurrencyon a field by name, socurrencyConfig.defaultCurrencyis the only way to author a fixed currency (currencyMode: 'fixed'). The one resolver,resolveFieldCurrencyin@object-ui/i18n, reads it. But two grid paths never hand it that key:ObjectGrid.tsx's configured-column paths build the cell'sfieldMetafromcurrency,precisionandscaleonly (three sites onorigin/main).useColumnSummary'scolumnHintscarrytype / currency / defaultCurrency / precision / scale, with nocurrencyConfig. The hook'sfieldMetadatatype has none either.Reproduction (the dev's measurement, relayed by the seat, ⛔ not re-run by the seat)
USD tenant; a field
{ type: 'currency', currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' } }; amount 1234:Sum: $1,234CurrencyCellRendererwith the grid'sfieldMetabag$1,234¥1,234ObjectMetricWidget(it passes the whole def)¥1,234The review of PR objectui#10348 confirmed that the drop predates that PR and is not made worse by it.
formatSummaryLabel's parameter type already acceptscurrencyConfig, so the hint half is type-ready.Grading notes (for triage, not a grade)
columnHints), or the cell and the footer split, which is exactly what objectui#10221 just closed.packages/plugin-grid/README.mdsays of a percent column's footer that the width "still comes from the column'sprecision". That has been false since objectui#9295 (the width comes fromscale;precisionis not read), so an author following it gets no effect. One sentence..changeset/9269-grid-summary-percent-converged.mdsays "decimalsstill readscolumn.precision, unchanged". That has also been false since objectui#9295 (the review of PR objectui#10348 readcolumn?.scale ?? 0at base). Correct it in place, and ⛔ never after it has been published.Dedupe
REST page walk over the 1000 most recently updated objectui items, pattern
currencyConfig … (fieldMeta|columnHints|grid cell|list cell)orfixed currency … (grid|footer|cell)⇒ 0 hits. Must-hit controlcurrencyFractionDigits⇒ objectui#10221, which did hit.Dedupe words:
currencyConfig.defaultCurrency grid cell·fieldMeta drops currencyConfig·useColumnSummary columnHints currencyConfig·fixed currency shown as tenant defaultGenerated by Claude Code