Skip to content

fix(studio): the dataset inspector stores no guessed measure currency - #27208

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-0rmmxq
Oct 28, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-0rmmxq

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread

Fixes #27156

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么: Studio 数据集检查器里选「货币」格式但不选币种时,不再往度量上写 currency: 'USD';货币字段上的度量默认「继承」,保存的度量没有 currency 键。
  • 为什么改: 度量自带的 currency 优先于字段固定币种和组织默认币种,猜出来的 USD 让人民币组织的仪表盘显示 $(裁决 6464202770,Q2 = X:任何地方都不猜币种)。
  • 风险与回滚: 只影响检查器的写入与读回;已存的 currency: 'USD' 原样保留、不迁移。回滚 = revert 本 PR。
  • 先看: DatasetDefaultInspector.tsx 的 buildMeasureFormat 与 MeasureFormatField;新测试 DatasetDefaultInspector.currencyNoGuess-27156.test.tsx。
  • 两分钟验证: Studio 打开一个数据集,给 sum(金额) 度量选「货币」不选币种并保存,度量定义里没有 currency 键,币种框显示「继承 —— 字段或组织的默认币种」。
  • 需要你做的: 无,席位落地。

What changes

  • buildMeasureFormat('currency', …) with an empty currency returns currency: undefined instead of 'USD', and the currency picker no longer pre-selects USD (it read measure.currency || 'USD').
  • The save path drops the key: a new module-private writeMeasureFormat rebuilds the measure without format / currency when the picker leaves them unset (the writeRowField rule), so the held draft and the saved body both carry no currency key, rather than currency: undefined.
  • Over a currency-type source field the picker gains an "Inherit — field or organization default" row (''), which is the default. Over any other field it offers no inherit row and shows the placeholder "Choose a currency".
  • parseMeasureFormat takes a monetaryField flag: a code-less, non-percent numeral format over a currency field reads back as Currency · inherit.
  • The kind the author picks is held in component state while the stored format is still the one that pick wrote, so "Currency" does not snap back to "Number" before a code is chosen over a plain number field.
  • @object-ui/i18n studio namespace: engine.inspector.dataset.currencyInherit and engine.inspector.dataset.currencyChoose (en, zh). Patch changeset for @object-ui/i18n.

Why

Maintainer ruling 6464202770 on #27119 (Q2 = X): no surface guesses a currency. The analytics chain resolves a monetary measure's currency as explicit measure currency, then the source field's fixed currency, then the tenant default; a stored guess outranks both.

Tests

New DatasetDefaultInspector.currencyNoGuess-27156.test.tsx (6 cases, the inspector mounted with a stateful draft holder):

  • empty pick over a currency field: the measure has no currency property (not.toHaveProperty, so currency: undefined would fail too), format: '0,0', the picker reads inherit;
  • CONTROL: picking CNY stores currency: 'CNY';
  • a loaded currency: 'USD' measure: no patch on mount, the picker shows USD, a decimals change keeps currency: 'USD';
  • over a number field: no currency key, kind stays Currency, the picker shows "Choose a currency" and offers no inherit row;
  • load: a code-less format over a currency field reads Currency · inherit; CONTROL: the same format over a number field reads Number.

Ablation (committed fix, node scripts/ablation-replace.mjs with anchor currency: currency || undefined }; replaced by currency: currency || 'USD' };): 2 failed / 4 passed — "stores no currency key when Currency is picked with no code" and the number-field case go red; restore verified (blob 10ecdd83 equals HEAD, git diff HEAD empty).

Acceptance notes

  • Stored currencies are left as authored. A measure that already carries currency: 'USD' (including one this inspector wrote earlier) is explicit on the wire: no migration, no rewrite on load, and it round-trips through edits unchanged (pinned above).
  • Mechanism assumption measured, partly disproved. The order assumed the empty state reads as "inherit" for every measure. The analytics service treats a measure as monetary only when it declares a currency or aggregates a currency-type field; any other measure never receives a code. So "inherit" is offered only over a currency field; over other fields the empty state asks for a code, following the ruling's intent (no guess) rather than offering an inherit that resolves to nothing.
  • Read-back change over currency fields. A code-less numeral format over a currency field used to read back as "Number"; it now reads as Currency · inherit. The runtime already rendered those measures with a currency, so the new reading matches what dashboards show. A consequence: choosing "Number" over a currency field reads back as Currency after a reload, because the runtime attaches a currency to it either way.
  • The sample under the picker shows a plain number for an inherit measure: the inspector does not know the field's fixed currency or the tenant default. Noted, not changed.
  • USD scan of the write path: after this diff the only 'USD' left in views/metadata-admin (non-test) is the CURRENCY_OPTIONS row itself. The formatKind.currency label still shows $1,234.50 as an example; it is display text and writes nothing.
  • Serial: open PR feat(app-shell): Studio authors relatedList, the related-list block's columns/sort/filter, ordered highlight fields, and slotted-by-default record pages #27163 edits this file's imports and filter section, not buildMeasureFormat; origin/main was merged before the gates.

Verification

Final head 77475026. The last commit only drops an export keyword; the derived gates, the ui scripts suite and the two inspector test files were re-run on it, the wider suites ran on dcfac927.

Local runs
  • On 77475026: node scripts/pm/dispatch-gates.mjs --commands (list unchanged), all 34 families exit 0, --ran reconciliation 34 derived, 34 run, 0 NOT-MEASURED; pnpm --dir ui exec vitest run scripts/ plus DatasetDefaultInspector.currencyNoGuess-27156.test.tsx and DatasetDefaultInspector.test.tsx (verify lock): 177 files passed, 2 skipped; 5040 tests passed, 2 skipped.
  • On dcfac927: pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/inspectors/ packages/i18n/ (verify lock): 286 files passed, 4116 tests passed, 14 skipped.
  • pnpm --filter @object-ui/app-shell --filter @object-ui/i18n run type-check: both type-check: Done, exit 0.
  • pnpm --dir ui run check:new-line-citations: 0 new citations, exit 0.
  • eslint --no-inline-config on the four changed files: 0 errors (pre-existing warnings only).
  • dispatch-gates --tier: no path-derived mandate; 233 changed lines.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (changed files linted locally; repo-wide run is CI's)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (not touched)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English. (the 维护者速读 block is the dispatch order's Chinese summary)
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

Picking the Currency display format with no code no longer stores
currency: 'USD'; the picker defaults to inherit over a currency field and
the measure carries no currency key, so it inherits the field's fixed
currency and then the tenant default.

Claude-Session: https://claude.ai/code/session_01JQwxbakr3SQTyXX1NuZkt3
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Oct 28, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · seat domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · head 77475026 · 2026-10-28T10:47Z

席位意见:Studio 数据集检查器不再替作者猜币种:选「货币」格式但不选币种时,度量不写 currency,按字段固定币种、再按组织默认币种继承;选择器也不再默认选中 USD。已存的 currency: 'USD' 原样保留。符合 #27119 的裁定 6464202770。

  1. Shape: Fixes #27156; 5 files, +223/−10: DatasetDefaultInspector.tsx +74/−10, one new test file (6 tests), two keys engine.inspector.dataset.currencyInherit / currencyChoose (en + zh), changeset @object-ui/i18n patch.
  2. Premise measured: buildMeasureFormat('currency', …) now returns currency: currency || undefined, and the save path goes through writeMeasureFormat, which drops an unset key instead of storing undefined, so a measure on "inherit" has no currency key. The picker reads measure.currency ?? '', so nothing pre-selects USD. The "inherit" row is offered only over a currency-type field (fieldOptions[].type), because only there does the analytics chain have a code to inherit; over any other field the picker asks for a code (partial disproof of the order's mechanism, routed to the ruling's intent). A numeral format with no code over a currency field reads back as "Currency · inherit", which matches what the runtime does with it. A stored code, 'USD' included, is not touched on load.
  3. Gates / check-runs: PR check-runs on 77475026: 43 success, 11 skipped, 0 failure; mergeable_state clean. Dev's local run: 34/34 derived gates exit 0 (--ran 34/34); the ablation (restore || 'USD') turns the no-key test red.
  4. Accepted deviations: @object-ui/i18n is published, so a patch changeset instead of skip-changeset; the "inherit" row is offered only over currency fields (above). Seat trial merge with origin/main is clean. With seat 4's open PR feat(app-shell): Studio authors relatedList, the related-list block's columns/sort/filter, ordered highlight fields, and slotted-by-default record pages #27163 (Studio: the object and field inspectors author what the v3 record page reads — relatedList (show / hide / primary), related-list columns / filter / limit on the block, and a new record page starts empty instead of a copy of the synthesized regions #27054) it conflicts on one adjacent pair of lines in this file (the MeasureFormatField call beside the filter field, which feat(app-shell): Studio authors relatedList, the related-list block's columns/sort/filter, ordered highlight fields, and slotted-by-default record pages #27163 renames to FilterConditionField); whichever lands second keeps both changes.
  5. Out of scope: none. Skills-docs: none — Studio inspector only.
  6. Landing: not Tier H; the seat readies and arms auto-merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 28, 2026 10:48
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 28, 2026
…-0rmmxq

# Conflicts:
#	ui/packages/app-shell/src/views/metadata-admin/inspectors/DatasetDefaultInspector.tsx
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · addendum

ACCEPT stands · seat domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · head f210e197 · 2026-10-28T11:19Z

The merge queue removed this PR for the conflict the ACCEPT foresaw: #27163 landed as fd73f2b3. The dev merged origin/main without force. The seat compared every file's +/- lines of 77475026 and f210e197 against their own merge bases. The file set is the same and every file is identical, so the resolution keeps this PR's MeasureFormatField call beside main's FilterConditionField. PR check-runs on f210e197: 43 success, 11 skipped, 0 failure; mergeable_state clean. The seat re-arms auto-merge.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 48bffe3 Oct 28, 2026
54 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-0rmmxq branch October 28, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

2 participants