Repository navigation
fix(app-showcase): showcase money reads one way — roll-up scale, USD project amounts, one total-budget format - #25543
Merged
objectstack-fleet[bot] merged 2 commits intoOct 23, 2026
Conversation
The expense report money roll-ups declare scale 2, project budget and spent declare the fixed USD currency Accounts uses, budget_remaining declares a currency result, and both dashboards write the total budget with one pattern and one currency. A pin holds the declarations. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy
Contributor
Author
席位核对 · ACCEPT · 2026-10-23T22:00Z
Generated by Claude Code |
objectstack-fleet
Bot
deleted the
claude/issue-25504-showcase-money-format
branch
October 23, 2026 22:16
This was referenced Oct 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Sales · project thread
Fixes #25504
Clause-②: no
Metadata-protocol: none
What changes
Showcase money now reads one way. Every change is a metadata declaration in
examples/app-showcase. Nothing inpackages/specor objectui is edited.main225.75,917,8,900,1,500.5. Approved and Reimbursable have the same problem.scale: 2on thetotal_amount,approved_amountandreimbursable_amountroll-upsFieldSchema.scale,packages/spec/src/data/field.zod.ts:1353. The superRefine atfield.zod.ts:2836refuses it only ontype: 'currency', so it is valid on asummary. The renderer reads it: the@object-ui/fields18.0.0 changelog entry for objectui#11752 says "Ascaleon the field fixes the width in both faces (scale: 2reads15,750.50)".200,000.00with no currency. Accounts → Annual Revenue readsUS$12,000,000.00.currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'USD' }onbudget, and onspent(see below). This is the exact value onshowcase_account.annual_revenue.FieldSchema.currencyConfig,field.zod.ts:1940, which isCurrencyConfigSchema(field.zod.ts:546).defaultCurrencyis read only undercurrencyMode: 'fixed'(field.zod.ts:552).200,000.returnType: 'currency',currencyConfigUSD fixed andscale: 2on thebudget_remainingformulaFieldSchema.returnType,field.zod.ts:1880, where'currency'landed with #22727 (commit e865300). The formula's owncurrencyConfig(field.zod.ts:1940) names its currency.scaleon a formula rounds the computed result (field.zod.ts:1353describe;roundFormulaValueinpackages/objectql/src/engine.ts).109万, and Delivery Operations → Total Budget reads1,090,000, for the same sum.0,0.00and currency USDobject-metric:ObjectMetricPropsSchema.format/.currency,packages/spec/src/ui/component.zod.ts:5774-5775. Dataset-bound tile:DatasetMeasureSchema.format/.currency,packages/spec/src/ui/dataset.zod.ts:308and:320.The KPI format: two decimals with currency, on both
Today
kpi()incommand-center.page.tsspreads itsformatargument into theobject-metricproperties, andcc_k6passes'0.0a'.kpi()now also takes an optionalcurrency.cc_k6passesBUDGET_FORMAT = '0,0.00'andBUDGET_CURRENCY = 'USD'.I picked two decimals with currency over a compact format for two reasons:
It matches the money columns. After this change, the Projects list writes an amount as
US$200,000.00. A total budget in the same shape reads as the same kind of number.A compact format cannot render the same on both tiles. I read the 18.0.0 npm builds of
@object-ui/plugin-dashboardand@object-ui/core:object-metrictile formats throughMetricWidget. It honours a numeralaasIntlcompact notation, with or without a currency.formatMeasure(@object-ui/core,utils/dataset-format.js). With a currency, it counts the zeros after the dot as fraction digits and never applies compact notation.0.0awould readUS$109万on one dashboard andUS$1,090,000.0on the other.With
0,0.00, both tiles produceUS$1,090,000.00in zh-CN. The tile layout is built for a value that long. ThemetricTile.d.tsdocblock says "a seven-digit money figure with cents — takes a size ladder from 14 px to 24 px".The
object-metrictile reads no currency from the field: the 18.0.0plugin-dashboardbuild contains nocurrencyConfigordefaultCurrencyread. Socc_k6must name the currency itself.The dataset-bound tile gets its currency from the server's column annotation: the measure's
currency, then the field's fixedcurrencyConfig.defaultCurrency(service-analyticsplugin.ts, the #20091 block).budget_sumtherefore needs nocurrencyof its own now thatbudgetdeclares USD.Landing note. The claim names "the Delivery Operations dashboard" for the second KPI's format. Its
kpi_total_budgetwidget has no format key of its own.DashboardWidget.optionsdeclares none (packages/spec/src/ui/dashboard.zod.ts, the widget-options docblock: "a number's face is the dataset MEASURE'sformat+currency"). So the format lives in the producer,src/ui/datasets/chart-gallery.dataset.ts:budget_sumchanges from0,0to0,0.00.spent_sumgets the same change, because the "Budget vs Spent by Account" tables print the two measures side by side.budget/spenthad no fixed currency. I rewrote it to match.In-place addition:
spentdeclares USD tooThe claim names
currencyConfigonbudgetonly. I also declared it onspent, in the same file. A currency result onbudget_remainingis only honest if both amounts it subtracts are in one currency.inferFormulaReturn(packages/formula/src/formula-return.ts) answers "two different currencies meeting … is unproven". With USDbudgetand dynamicspent, it would stampreturnType: 'number'for this expression, not'currency'. With both in USD, it stamps exactly the pair this PR declares, and the pin asserts that.This also keeps the Projects list to one currency treatment, as the issue's Expected section asks. It meets the bounded in-place criteria: the same defect class, a mechanical declaration, a file inside the claimed surface, and no new gate family.
Tests
The new pin is
examples/app-showcase/test/money-format-declarations.test.ts. It follows the existing showcase style: it reads the authored metadata and walks the page tree through the helpers. Its five cases assert:scale: 2on the three money roll-ups.budgetandspentcarry the samecurrencyConfigasshowcase_account.annual_revenue.budget_remainingisreturnType: 'currency'with USD fixed andscale: 2.inferFormulaReturnstamps for its expression over the object's fields.cc_k6'sformatequalsbudget_sum'sformat, andcc_k6'scurrencyequals the currency the dataset tile resolves: the measure's, else the field's fixed one.Ablation. I ran
scripts/ablation-replace.mjson the committed fix (2a70334), with an EXIT/INT/TERM trap restore. Each leg's anchor hit as declared, the blob changed, and the restore was proven by blob == HEAD and an emptygit diff HEAD:scale: 2lines (anchor x3 → x0)Tests 1 failed / 4 passedbudget'scurrencyConfig(x1 → x0)Tests 3 failed / 2 passed(cases 2, 4 and 5)returnType: 'currency'Tests 2 failed / 3 passed(cases 3 and 4)BUDGET_FORMATchanged to'0.0a'Tests 1 failed / 4 passed(case 5)After all four legs, the three mutated blobs equal HEAD and
git status --porcelainis empty.Runs on the final head 5afdc0d (
origin/main5ea211c merged in). Every run is underos-verify-lock, and each VERDICT iscommand-exit 0:pnpm --filter @objectstack/example-showcase typecheck: exit 0.tsc --listFilesincludes the new test.pnpm --filter @objectstack/example-showcase exec vitest run --maxWorkers=2:Test Files 39 passed (39),Tests 483 passed (483).pnpm --filter @objectstack/example-showcase validate(os validate):✓ Validation passed, 64 warnings.Gates
node scripts/pm/dispatch-gates.mjs --commandson 5afdc0d derived 46 commands. I ran each one and captured its exit code before any pipe:pnpm check:dual-build-cjs-loadsexited 3,PREREQUISITE NOT MET. It needs a whole-workspacedist/, and this worktree built only the showcase closure. It is NOT MEASURED here; CI'sLint & Repo Gatesruns it.dispatch-gates --ran, with the recorded exit codes, reconciles to46 derived famil(ies) accounted for — 45 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).Changeset: none, label
skip-changeset.@objectstack/example-showcaseisprivate: trueand publishes nothing.Acceptance notes
FieldSchema.returnTypeis described as the value type "of a formula field" (field.zod.ts:1880). objectui'sSummaryFielddocblock (18.0.0) says "A summary declares noreturnType".formula-return.tsnotes that "a roll-up of a currency field is itself money".scale: 2reads1,500.50) but no currency.amountis left without acurrencyConfig. Declaring USD there would putUS$on the lines and a bare number on the roll-ups, which recreates the four-ways defect inside one object.subtotal_sumandrevenue_sum(revenue-pulse.dataset.ts,0,0) are outside this card.🤖 Generated with Claude Code
https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy