|
| 1 | +--- |
| 2 | +'@objectstack/spec': minor |
| 3 | +'@objectstack/platform-objects': patch |
| 4 | +--- |
| 5 | + |
| 6 | +**BREAKING** — retire `currencyConfig.precision`: a currency's decimal places are its currency's (#19992). |
| 7 | + |
| 8 | +`currencyConfig.precision` was declared, validated against ISO 4217, and baked to `2` |
| 9 | +into parse output — and **no renderer or runtime ever read it**. objectui's |
| 10 | +`CurrencyField` derives an amount's decimal places from the currency's ISO 4217 |
| 11 | +minor unit (2 for USD, 0 for JPY, 3 for KWD) and never looked at the key, so an |
| 12 | +author who wrote `precision: 4` saw the same two decimals as everyone else. Its |
| 13 | +only reader was its own contradiction check. ADR-0049 enforce-or-remove; triage |
| 14 | +direction REMOVE under ruling 乙 on #19910 — 「a currency's decimal places are the |
| 15 | +currency's, not a setting」. |
| 16 | + |
| 17 | +Clause-②: no |
| 18 | + |
| 19 | +## FROM → TO |
| 20 | + |
| 21 | +| you wrote (17.4 and earlier) | write instead | |
| 22 | +| --- | --- | |
| 23 | +| `currencyConfig: { precision: 2, currencyMode: 'fixed', defaultCurrency: 'USD' }` | `currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'USD' }` | |
| 24 | +| `currencyConfig.decimals` / `currencyConfig.scale` (always refused, with a suggestion to write `precision`) | nothing — delete the key; the refusal now says why instead of suggesting `precision` | |
| 25 | +| a field whose amounts need a different number of decimals | a different currency: the width is the currency's minor unit and is declared nowhere | |
| 26 | + |
| 27 | +**The one-line fix:** delete `precision` from every `currencyConfig`. ⛔ Do not move |
| 28 | +the number to the field-level `precision`: that key is the amount's TOTAL digit count |
| 29 | +(a DECIMAL(18,2) amount declares `precision: 18`), not its decimal places, and it is |
| 30 | +unchanged by this release. |
| 31 | + |
| 32 | +`os migrate meta --from 17` lists the mechanical edits for existing sources; apply |
| 33 | +them by hand. |
| 34 | + |
| 35 | +## The retirement kit |
| 36 | + |
| 37 | +- **`CurrencyConfigSchema.precision`** — removed from the shape. The schema is a |
| 38 | + `strictObject`, so the route is strict deletion plus a `guidance` entry: an |
| 39 | + authored key is refused as `unrecognized_keys` at `currencyConfig`, and the message |
| 40 | + carries the prescription (``currencyConfig.precision` was removed in |
| 41 | + @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — no renderer or runtime ever |
| 42 | + read it: …``). `tsc` refuses a literal in a typed position too — the key is off |
| 43 | + `CurrencyConfig`'s input type. |
| 44 | +- **The `decimals` / `scale` aliases** — gone with their target. Each is now answered |
| 45 | + with the same reason (`` `currencyConfig.scale` is not a currency configuration key, |
| 46 | + and nothing replaces it: … ``) and no rename suggestion. |
| 47 | +- **The ISO 4217 contradiction check** (the `.superRefine`) and **the |
| 48 | + default-materializing `.overwrite()`** — both existed only for this key and are |
| 49 | + removed. `CurrencyConfigSchema.parse({})` now returns exactly |
| 50 | + `{ currencyMode: 'dynamic', defaultCurrency: 'CNY' }`; `CurrencyConfigParsed` no |
| 51 | + longer declares `precision`. The internal helpers `currencyPrecisionContradiction` |
| 52 | + and `currencyFractionDigits` (never exported from a public entry) are removed; the |
| 53 | + CLDR table they read stays, because the `iso_4217_currency` value domain reads its |
| 54 | + key set. |
| 55 | +- **The field designer form** — the field-level `precision` row's help text read |
| 56 | + "Decimal places (e.g., 2 for $10.50)", the one reading the contract refuses. It now |
| 57 | + reads "Total digits", matching the key's describe and the object designer's row; |
| 58 | + the zh-CN / ja-JP / es-ES translations follow (`@objectstack/platform-objects`). |
| 59 | +- **Registry** — `RETIRED_KEYS_BY_MAJOR[18]` gains `data/CurrencyConfig:precision`; |
| 60 | + the protocol-18 step gains the D2 conversion `currency-config-precision-removed` and |
| 61 | + its D3 entry `currency-config-precision-retired`, which states the two judgments the |
| 62 | + strip cannot make: a width declared where the old check never looked (a `dynamic` |
| 63 | + field, or a code with no known ISO 4217 minor unit) never applied, and code of your |
| 64 | + own that read the served key must derive the width from the field's currency. |
| 65 | + |
| 66 | +## What an operator with STORED metadata sees |
| 67 | + |
| 68 | +Nearly every stored currency field carries this key without anyone having written it: |
| 69 | +the old `.overwrite()` baked `precision: 2` into parse output, so `sys_metadata` |
| 70 | +object rows and built artifacts hold it. Nothing breaks at read: the conversion |
| 71 | +`currency-config-precision-removed` is retired from the load path but replayed by the |
| 72 | +stored-row and artifact seams, which strip the key from every field's |
| 73 | +`currencyConfig` on objects and object extensions and serve the row canonical. The |
| 74 | +strip is lossless — the key never had an effect — and the field-level `precision` is |
| 75 | +never touched. `os migrate meta --stored --apply` rewrites the stored rows so the |
| 76 | +per-row notice stops. |
| 77 | + |
| 78 | +<!-- adr-0087: registered currency-config-precision-removed --> |
0 commit comments