Skip to content

Commit 73b7270

Browse files
feat(spec): currencyConfig.homeAmount — a record-mode amount declares its stored home-currency projection by pointer (multi-currency M2-1) (#28096)
🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V Fixes #27191 ⛔ not released alone — R2: pairs with #27192 (the write-time projection that writes the home amount), #27185, #27190, #27198, #27193, #27196 (one Version Packages release; ADR-0144 D9: "the `homeAmount` key never ships ahead of the engine") Clause-②: yes (widening) Metadata-protocol: added Skills-docs: updated here Independent review: none run (quota); the PR waits for the seat's contract-review hand-off. ## 维护者速读 - **改了什么:** 按客户币种记账(`currencyMode: 'record'`)的金额字段,现在可以声明 `homeAmount`:指明换算成本位币后的金额存在哪个字段、按哪个日期字段取汇率、实际使用的汇率存在哪个字段。三个字段都必须是同一对象上作者自己声明的字段,平台不注入列、不猜默认(不默认 `created_at`);本位币金额字段与汇率字段只由平台写入,作者须标 `readonly: true`。 - **为什么改:** 合并报表要在本位币下汇总;只有把换算结果连同当时的汇率一起存下来,报表、汇总与分析才能直接读一个普通的本位币金额字段(ADR-0144 D1/D5)。 - **风险与回滚:** 纯新增可选键(minor),不写 `homeAmount` 的应用零变化;本 PR 只有声明与拒收,真正写入本位币金额的引擎在 #27192。⛔ 不单独发版:必须与 #27192 同一次 Version Packages 发布,否则是「声明了却不兑现」。回滚即撤 PR。 - **先看:** `packages/spec/src/data/object.zod.ts` 的 `refuseDishonestHomeAmount`(指针所指字段的全部拒收);`packages/spec/src/data/field.zod.ts` 的 `HomeAmountSchema` 与 `refuseRecordModeKeyMismatch` 新增的一臂;`skills/objectstack-data/rules/field-types.md` 币种段。 - **两分钟验证:** `pnpm --filter @objectstack/spec exec vitest run src/data/currency-config-home-amount.test.ts`,预期全绿:非 `record` 模式写 `homeAmount`、缺任一指针、本位币字段不是 `dynamic` 币种字段、日期字段不是日期、汇率字段不是数字、两字段未标 `readonly` 各自被拒并带处方。 - **需要你做的:** 本 PR 改了 `skills/**`(受管面 Tier H),请在 PR 上审批技能文本;之后由席位在契约复审通过后落地,并与 #27192 同批发版。 ## What changes - **`CurrencyConfigSchema.homeAmount`** (`packages/spec/src/data/field.zod.ts`, ADR-0144 D5): a new optional key, a closed shape `{ field, rateDate, rateField }`. All three pointers are required whenever `homeAmount` is declared, and none may be empty. ADR-0144 D5 corrects the card's draft `rateField?` to required. A missing pointer and an empty one each get their own message with a remedy. Near-miss spellings (`rate`, `date`, `homeField`, …) are steered to the declared pointer by the shape's `aliases`. `refuseRecordModeKeyMismatch` gains one arm: `homeAmount` under `dynamic` or `fixed` (including the defaulted mode) is refused at `homeAmount`, because only a `record` amount is converted. - **`refuseDishonestHomeAmount`** (`packages/spec/src/data/object.zod.ts`), in `ObjectSchema`'s superRefine beside the `currencyField` arm. It judges what the pointers name, against the authored field map. There is one located issue per offending pointer, at `fields.AMOUNT.currencyConfig.homeAmount.POINTER`. Each issue carries a remedy and the object's candidate fields. - The amount must be a stored `currency` field. A `formula` amount is computed on read and never written, so it is refused at `homeAmount` itself. - `field` must name another declared `currency` field in `dynamic` mode. An absent `currencyConfig` counts as `dynamic`. This follows ADR-0144 D8 rule 5: "the home field is a `dynamic`-mode currency field", so metadata never names the home currency. A second amount may not claim a home field that another amount already writes. - `rateDate` must name a declared `date` or `datetime` field. Nothing defaults it to `created_at`. - `rateField` must name a declared `number` field. Two amounts may share one rate field only when they name the same `currencyField` and the same `rateDate`, because otherwise they would store two different rates in one column. - **Platform-written mark.** The home field and the rate field are written only by the engine. They say so with the mark the spec already has for that, `readonly: true`, which drops every non-system write of the field from the payload. Neither field may also declare an `expression`, which would be a second writer. No new key is invented. - **Skills** (`skills/objectstack-data/rules/field-types.md`, governed `skills/**`): the currency block teaches `homeAmount` in one example line and one paragraph; the example names are guidance, "never a contract" (ADR-0144 D8 rule 2). Paid for by deleting restatement in the same file: the intro line, the "Text with Max Length" example (a duplicate of the file's first code block), the "Master-Detail with Cascade" example (the Relational table's row says it) and a removed-key history comment. 3207 → 3181 tokens, 323 → 304 lines; bundle 219711 → 219685 tokens. - **Changeset** `.changeset/27191-home-amount-pointer.md`: `@objectstack/spec` minor and `@objectstack/skills` minor. The body carries `Clause-②: yes (widening)`, `Metadata-protocol: added` and the R2 pairing line. - **Generated, not hand-edited:** `packages/spec/authorable-surface/data.json` (gen:schema) and `content/docs/references/**` (gen:docs). - **ADR anchors:** the ADR-0144 entries on `field.zod.ts` and `object.zod.ts` gain the D5 invariant. ## Tests - New `packages/spec/src/data/currency-config-home-amount.test.ts`: - **The config door.** The accepted shape round-trips. A `record` config without `homeAmount` parses byte-identical to before. `homeAmount` is refused under `fixed`, `dynamic` and the defaulted mode. Each missing pointer and each empty pointer is refused at its own path. An unknown key is steered to `rateField`. - **The object door.** The honest shape is accepted, including `datetime` and an explicit `dynamic` home field, and `parse(parse(x))` equals `parse(x)`. A consistently shared rate field is accepted. Each refusal is pinned with `code`, `path` and the message's first clause: - `field`: points into nothing, at the amount itself, at a non-`currency` field (a `number`, a currency `formula`), at a `fixed` or `record` home field, or at a home field another amount already writes; - `rateDate`: points into nothing, or at a non-date field; - `rateField`: points into nothing, at a non-`number` field, or at a rate field shared inconsistently; - a home or rate field without `readonly: true`, or one declaring an `expression`; - a `formula` amount. - The R1 suite `currency-config-record-mode.test.ts` stays green, unchanged. - One ablation, a gate run, and the package test and typecheck readings come with the os-dev-report comment on #27191, at the final head. ## Acceptance notes - **What holds the key from a lone release, as measured: nothing mechanical.** The R1 template (#27268) held its key with three things: a `⛔ not released alone — pairs with …` line in its PR body, a `⛔ Not released alone` sentence in its changeset, and the maintainer's hand on Version Packages (Prime Directive #15; the epic #8345 body: "the maintainer merges Version Packages only when a pair is complete"). This PR does the same. No gate, ledger or `release-pending-publish.mjs` mode reads a pairing marker, and `.changeset/config.json` has no pre-release mode. Once this lands, `changeset-release/main` (#26517) folds its changeset into the next Version Packages release with every other pending one. The epic's R2 sibling `.changeset/27185-exchange-rate-table.md` is already on `main` in the same state. - **`readonly: true` and the engine (#27192):** `readonly` strips every non-system write of the field from the payload, on insert and on update. So the write-time projection has to store the home amount and the rate on a path that strip does not undo: a system-context write, or a write after the strip. That is #27192's to build and pin. - **Refusals beyond the card's list, declared for the contract review:** a `formula` amount, a home field claimed twice, a rate field shared inconsistently, and an `expression` on a home or rate field. Each refuses a shape in which the engine would write a value that is wrong, or that another writer can overwrite. Each refusal is pinned. - **Not touched:** the Studio field form (`field.form.ts`) offers no `homeAmount` row; the read-only display of the home field is #27196 (M3-2). The hand-written page `content/docs/data-modeling/currency.mdx` does not mention `homeAmount`. - No engine write path is in this diff. ## Verification Gate readings (`dispatch-gates.mjs --commands` on the final diff, each exit code captured before any pipe, `--ran` reconciliation), the package test and typecheck runs, and the ablation are reported with the head sha in the os-dev-report comment on #27191. --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e063a87 commit 73b7270

13 files changed

Lines changed: 607 additions & 42 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/skills': minor
4+
---
5+
6+
feat(spec): `currencyConfig.homeAmount: { field, rateDate, rateField }` — a record-mode amount declares its stored home-currency amount by pointer (ADR-0144 D5)
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: added
10+
11+
⛔ Not released alone: this ships in the same release as the write-time home-currency projection that fills these fields (ADR-0144 D9, release R2: "the `homeAmount` key never ships ahead of the engine").
12+
13+
An amount in `currencyMode: 'record'` can now declare where its value is stored after conversion into the organization's home currency (the `localization.currency` setting), which date picks the exchange rate, and where the rate used is stored. Consolidated totals then aggregate the home field like any other stored currency field.
14+
15+
```ts
16+
fields: {
17+
currency_code: Field.text({ label: 'Currency', valueDomain: 'iso_4217_currency' }),
18+
invoice_date: Field.date({ label: 'Invoice date' }),
19+
amount: Field.currency({
20+
label: 'Amount',
21+
currencyConfig: {
22+
currencyMode: 'record',
23+
currencyField: 'currency_code',
24+
homeAmount: { field: 'amount_home', rateDate: 'invoice_date', rateField: 'amount_rate' },
25+
},
26+
}),
27+
amount_home: Field.currency({ label: 'Amount (home)', readonly: true }),
28+
amount_rate: Field.number({ label: 'Rate used', readonly: true }),
29+
}
30+
```
31+
32+
- **Three required pointers.** When `homeAmount` is declared, `field`, `rateDate` and `rateField` must all be given, and none may be empty. There is no default, no injected column and no fixed field name. The document date is never taken from `created_at`. `homeAmount` is refused under `dynamic` and `fixed`.
33+
- **What the pointers name, refused at parse with a remedy and the object's candidates.** Each refusal is located at `fields.AMOUNT.currencyConfig.homeAmount.POINTER`.
34+
- `field` must name another `currency` field of the same object in `dynamic` mode (it displays in the home currency, so metadata never names that currency). No other amount may already store into it.
35+
- `rateDate` must name a `date` or `datetime` field.
36+
- `rateField` must name a `number` field. Two amounts may share it only when they have the same `currencyField` and `rateDate`.
37+
- The amount itself must be a stored `currency` field. A `formula` amount is refused.
38+
- **The home and rate fields are written by the platform only.** They must declare `readonly: true`, the existing mark that drops a client's write of the field, and no `expression`.
39+
- **Skills:** `objectstack-data/rules/field-types.md` teaches `homeAmount`. Its field names (`amount_home`, `amount_rate`) are examples, not a contract.
40+
- **Nothing to migrate.** `homeAmount` is new, and no existing config changes meaning.

‎content/docs/references/data/field.mdx‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ const result = CurrencyConfigSchema.parse(data);
3131
| **currencyMode** | `Enum<'dynamic' \| 'fixed' \| 'record'>` | optional (default: `"dynamic"`) | Currency mode. `fixed`: the field has one currency, `defaultCurrency`. `dynamic` (the default): the field has no currency of its own — amounts display in the tenant default currency (the `localization.currency` setting; a plain number when none is set) and `defaultCurrency` is not read. `record`: each record has its own currency, the ISO 4217 code stored in the sibling field `currencyField` names; `defaultCurrency` is refused. The value is a bare number in every mode (ADR-0104 D1). |
3232
| **defaultCurrency** | `string` | optional | The currency code (ISO 4217, e.g. USD, CNY, EUR) of a `fixed`-mode field: its one currency, required under `fixed`. Not read under `dynamic` (the default), where amounts display in the tenant default currency, and refused under `record`, where each record names its own. |
3333
| **currencyField** | `string` | optional | `record` mode only, and required there: the name of the field on the same object that holds each record's currency — a `text` field declaring `valueDomain: 'iso_4217_currency'` (conventionally `currency_code`). Refused under `dynamic` and `fixed`, and never empty. |
34+
| **homeAmount** | `{ field: string; rateDate: string; rateField: string }` | optional | `record` mode only, optional: where the engine stores this amount converted into the organization's home currency (the `localization.currency` setting) at write, at the rate of the record's document date, and the rate it used. `field` names a `dynamic`-mode `currency` field, `rateDate` a `date` / `datetime` field and `rateField` a `number` field, all on the same object; all three are required, and the home and rate fields declare `readonly: true` because only the engine writes them. Consolidated totals aggregate the home field. Refused under `dynamic` and `fixed`. |
35+
36+
### Nested Shape: `CurrencyConfig.homeAmount`
37+
38+
| Property | Type | Required | Description |
39+
| :--- | :--- | :--- | :--- |
40+
| **field** | `string` | ✅ | The field on the same object that stores the amount converted into the home currency: a stored `currency` field in `dynamic` mode (it displays in `localization.currency`, so metadata never names the home currency), declaring `readonly: true` — only the engine writes it. Conventionally `AMOUNT_home`. |
41+
| **rateDate** | `string` | ✅ | The field on the same object holding the record's document date, whose value picks the exchange rate: a `date` or `datetime` field. Required, with no default — the engine never guesses the date (not `created_at`). |
42+
| **rateField** | `string` | ✅ | The field on the same object that stores the exchange rate the conversion used: a `number` field declaring `readonly: true` — only the engine writes it. Required: the home amount is stored with the rate used. Conventionally `AMOUNT_rate`. |
3443

3544

3645
---
@@ -92,7 +101,7 @@ const result = CurrencyConfigSchema.parse(data);
92101
| **summaryOperations** | `{ object: string; field?: string; function: Enum<'count' \| 'sum' \| 'min' \| 'max' \| 'avg'>; relationshipField?: string; … }` | optional | Roll-up summary definition. The engine recomputes the value when child records are inserted/updated/deleted. |
93102
| **language** | `string` | optional | Programming language for syntax highlighting (e.g., javascript, python, sql) |
94103
| **step** | `number` | optional | Step increment for slider (default: 1) |
95-
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
104+
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string; homeAmount?: object }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
96105
| **dimensions** | `integer` | optional | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
97106
| **trackHistory** | `boolean` | optional | Render this field's value changes as human-readable entries on the record activity timeline (ADR-0052 §5b). Opt-in per field. |
98107
| **group** | `string` | optional | Field group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system") |
@@ -250,6 +259,7 @@ const result = CurrencyConfigSchema.parse(data);
250259
| **currencyMode** | `Enum<'dynamic' \| 'fixed' \| 'record'>` | optional (default: `"dynamic"`) | Currency mode. `fixed`: the field has one currency, `defaultCurrency`. `dynamic` (the default): the field has no currency of its own — amounts display in the tenant default currency (the `localization.currency` setting; a plain number when none is set) and `defaultCurrency` is not read. `record`: each record has its own currency, the ISO 4217 code stored in the sibling field `currencyField` names; `defaultCurrency` is refused. The value is a bare number in every mode (ADR-0104 D1). |
251260
| **defaultCurrency** | `string` | optional | The currency code (ISO 4217, e.g. USD, CNY, EUR) of a `fixed`-mode field: its one currency, required under `fixed`. Not read under `dynamic` (the default), where amounts display in the tenant default currency, and refused under `record`, where each record names its own. |
252261
| **currencyField** | `string` | optional | `record` mode only, and required there: the name of the field on the same object that holds each record's currency — a `text` field declaring `valueDomain: 'iso_4217_currency'` (conventionally `currency_code`). Refused under `dynamic` and `fixed`, and never empty. |
262+
| **homeAmount** | `{ field: string; rateDate: string; rateField: string }` | optional | `record` mode only, optional: where the engine stores this amount converted into the organization's home currency (the `localization.currency` setting) at write, at the rate of the record's document date, and the rate it used. `field` names a `dynamic`-mode `currency` field, `rateDate` a `date` / `datetime` field and `rateField` a `number` field, all on the same object; all three are required, and the home and rate fields declare `readonly: true` because only the engine writes them. Consolidated totals aggregate the home field. Refused under `dynamic` and `fixed`. |
253263

254264
### Nested Shape: `Field.conditionalFormatting[number]`
255265

‎content/docs/references/data/object.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ const result = ApiMethod.parse(data);
270270
| **summaryOperations** | `{ object: string; field?: string; function: Enum<'count' \| 'sum' \| 'min' \| 'max' \| 'avg'>; relationshipField?: string; … }` | optional | Roll-up summary definition. The engine recomputes the value when child records are inserted/updated/deleted. |
271271
| **language** | `string` | optional | Programming language for syntax highlighting (e.g., javascript, python, sql) |
272272
| **step** | `number` | optional | Step increment for slider (default: 1) |
273-
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
273+
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string; homeAmount?: object }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
274274
| **dimensions** | `integer` | optional | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
275275
| **trackHistory** | `boolean` | optional | Render this field's value changes as human-readable entries on the record activity timeline (ADR-0052 §5b). Opt-in per field. |
276276
| **group** | `string` | optional | Field group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system") |
@@ -636,7 +636,7 @@ const result = ApiMethod.parse(data);
636636
| **summaryOperations** | `{ object: string; field?: string; function: Enum<'count' \| 'sum' \| 'min' \| 'max' \| 'avg'>; relationshipField?: string; … }` | optional | Roll-up summary definition. The engine recomputes the value when child records are inserted/updated/deleted. |
637637
| **language** | `string` | optional | Programming language for syntax highlighting (e.g., javascript, python, sql) |
638638
| **step** | `number` | optional | Step increment for slider (default: 1) |
639-
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
639+
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string; homeAmount?: object }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
640640
| **dimensions** | `integer` | optional | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
641641
| **trackHistory** | `boolean` | optional | Render this field's value changes as human-readable entries on the record activity timeline (ADR-0052 §5b). Opt-in per field. |
642642
| **group** | `string` | optional | Field group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system") |

‎content/docs/references/system/migration.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Add a new field to an existing object
104104
| **summaryOperations** | `{ object: string; field?: string; function: Enum<'count' \| 'sum' \| 'min' \| 'max' \| 'avg'>; relationshipField?: string; … }` | optional | Roll-up summary definition. The engine recomputes the value when child records are inserted/updated/deleted. |
105105
| **language** | `string` | optional | Programming language for syntax highlighting (e.g., javascript, python, sql) |
106106
| **step** | `number` | optional | Step increment for slider (default: 1) |
107-
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
107+
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string; homeAmount?: object }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
108108
| **dimensions** | `integer` | optional | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
109109
| **trackHistory** | `boolean` | optional | Render this field's value changes as human-readable entries on the record activity timeline (ADR-0052 §5b). Opt-in per field. |
110110
| **group** | `string` | optional | Field group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system") |
@@ -537,7 +537,7 @@ Add a new field to an existing object
537537
| **summaryOperations** | `{ object: string; field?: string; function: Enum<'count' \| 'sum' \| 'min' \| 'max' \| 'avg'>; relationshipField?: string; … }` | optional | Roll-up summary definition. The engine recomputes the value when child records are inserted/updated/deleted. |
538538
| **language** | `string` | optional | Programming language for syntax highlighting (e.g., javascript, python, sql) |
539539
| **step** | `number` | optional | Step increment for slider (default: 1) |
540-
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
540+
| **currencyConfig** | `{ currencyMode?: Enum<'dynamic' \| 'fixed' \| 'record'>; defaultCurrency?: string; currencyField?: string; homeAmount?: object }` | optional | Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode. |
541541
| **dimensions** | `integer` | optional | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
542542
| **trackHistory** | `boolean` | optional | Render this field's value changes as human-readable entries on the record activity timeline (ADR-0052 §5b). Opt-in per field. |
543543
| **group** | `string` | optional | Field group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system") |

‎docs/audits/2026-07-unknown-key-strictness-ledger.counts/data.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The `strict` column is the one the campaign schedules against; it counts both th
2121

2222
| Dir | Sites | strict | passthrough | catchall | strip |
2323
|---|---|---|---|---|---|
24-
| `data/` | 155 | 89 | 2 | 0 | 64 |
24+
| `data/` | 156 | 90 | 2 | 0 | 64 |
2525

2626
## `data/` — sites
2727

@@ -45,7 +45,7 @@ classify and is not listed (it becomes reportable the day it grows its first sit
4545
| `driver/turso.zod.ts` | 2 |
4646
| `external-catalog.zod.ts` | 4 |
4747
| `field-value.zod.ts` | 4 |
48-
| `field.zod.ts` | 14 |
48+
| `field.zod.ts` | 15 |
4949
| `filter.zod.ts` | 13 |
5050
| `hook-body.zod.ts` | 2 |
5151
| `hook.zod.ts` | 8 |
@@ -57,15 +57,15 @@ classify and is not listed (it becomes reportable the day it grows its first sit
5757
| `seed-loader.zod.ts` | 12 |
5858
| `seed.zod.ts` | 2 |
5959
| `validation.zod.ts` | 6 |
60-
| **total** | **155** |
60+
| **total** | **156** |
6161

6262
## `data/` — open
6363

6464
Per file, how many of its sites still silently discard unknown keys. The `Class`
6565
column that decides the bucket split is hand-written in the ledger; the arithmetic
6666
over it is here.
6767

68-
**64 strip of 155**, in 10 file(s).
68+
**64 strip of 156**, in 10 file(s).
6969

7070
| File | Strip | Sites |
7171
|---|---|---|
@@ -74,12 +74,12 @@ over it is here.
7474
| `driver-sql.zod.ts` | 2 | 2 |
7575
| `driver.zod.ts` | 9 | 9 |
7676
| `external-catalog.zod.ts` | 4 | 4 |
77-
| `field.zod.ts` | 1 | 14 |
77+
| `field.zod.ts` | 1 | 15 |
7878
| `filter.zod.ts` | 11 | 13 |
7979
| `hook.zod.ts` | 5 | 8 |
8080
| `query.zod.ts` | 4 | 5 |
8181
| `seed-loader.zod.ts` | 12 | 12 |
82-
| **total** | **64** | **155** |
82+
| **total** | **64** | **156** |
8383

8484
| Bucket | Sites |
8585
|---|---|

‎packages/spec/authorable-surface/data.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
"data/CurrencyConfig:currencyField",
105105
"data/CurrencyConfig:currencyMode",
106106
"data/CurrencyConfig:defaultCurrency",
107+
"data/CurrencyConfig:homeAmount",
107108
"data/DataEngineAggregateOptions:aggregations",
108109
"data/DataEngineAggregateOptions:context",
109110
"data/DataEngineAggregateOptions:filter",

0 commit comments

Comments
 (0)