diff --git a/.changeset/27182-currency-value-schema-retired.md b/.changeset/27182-currency-value-schema-retired.md new file mode 100644 index 00000000000..2e219b36c80 --- /dev/null +++ b/.changeset/27182-currency-value-schema-retired.md @@ -0,0 +1,16 @@ +--- +'@objectstack/spec': minor +--- + +feat(spec)!: `CurrencyValueSchema` and its `CurrencyValue` type are removed from `@objectstack/spec/data` (ADR-0104 D1) + +Clause-②: no (narrowing) +Metadata-protocol: narrowed + + + +**BREAKING** for TypeScript code only: `import { CurrencyValueSchema } from '@objectstack/spec/data'` (or from `@objectstack/spec`), and `import type { CurrencyValue }`, no longer compile (TS2305). The schema declared a `{ value, currency }` object that nothing ever parsed or stored, and it contradicted the real contract: a `currency` field's value is a bare number in the record validator, the SQL driver, import coercion and the field-zoo oracle, and the currency code is field configuration. ADR-0104 had already decided the deletion; the export stayed `@deprecated` until now, and it goes before multi-currency work starts so that no author reads it as the shape that records a currency. No metadata document changes, and runtime behaviour is unchanged. + +- `CurrencyValueSchema` / `CurrencyValue` (`{ value: 1000.5, currency: 'USD' }`) → none. Write and read the bare number (`1000.5`), and declare the code on the field: `currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'USD' }`. To type or check a value, use `valueSchemaFor(field, 'stored')` from `@objectstack/spec/data`, which answers a number for a currency field. + +The fix: delete the import and use `number` for the value. The upgrade guide entry is `currency-value-schema-retired`, and `data/CurrencyValue` is listed in `RETIRED_DEFS_BY_MAJOR[18]`. diff --git a/content/docs/protocol/objectql/types.mdx b/content/docs/protocol/objectql/types.mdx index 8b8fac14d53..252f11723bd 100644 --- a/content/docs/protocol/objectql/types.mdx +++ b/content/docs/protocol/objectql/types.mdx @@ -314,8 +314,8 @@ is field configuration, never stored per value: under `currencyMode: fixed` it i under `dynamic`, the default, it is the tenant default currency (the `localization.currency` setting) and `defaultCurrency` is not the displayed currency. The old per-value object shape (`CurrencyValueSchema`) was -never consumed by the validator, the driver, or import coercion and is -deprecated in the spec. +never consumed by the validator, the driver, or import coercion and has +been removed from the spec. **Features:** diff --git a/content/docs/references/data/field-value.mdx b/content/docs/references/data/field-value.mdx index db0fbb50657..cec50d67f33 100644 --- a/content/docs/references/data/field-value.mdx +++ b/content/docs/references/data/field-value.mdx @@ -25,8 +25,8 @@ Two canonical forms exist per field (ADR-0104 D1): "Reality wins": where the deployed stored shape is coherent, the contract adopts it — deployed data is a wire contract we don't get to rewrite by -editing Zod. This is why `currency` is a bare number (not the never-consumed -`CurrencyValueSchema` object) and `location` is `{lat, lng}` (what field-zoo +editing Zod. This is why `currency` is a bare number (the never-consumed +`CurrencyValueSchema` object is deleted) and `location` is `{lat, lng}` (what field-zoo stores), not the never-consumed `{latitude, longitude}` shape. Purity: schemas/constants/derivation only — no runtime logic, no caching diff --git a/content/docs/references/data/field.mdx b/content/docs/references/data/field.mdx index bfca6a80361..d1258c145b3 100644 --- a/content/docs/references/data/field.mdx +++ b/content/docs/references/data/field.mdx @@ -1,7 +1,7 @@ --- title: Field schema — Data Protocol reference navTitle: Field -description: "Field schemas of the ObjectStack Data Protocol: CurrencyConfig, CurrencyValue, Field and 7 more — each property with its type, default and a TypeScript example." +description: "Field schemas of the ObjectStack Data Protocol: CurrencyConfig, Field and 7 more — each property with its type, default and a TypeScript example." --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -13,8 +13,8 @@ description: "Field schemas of the ObjectStack Data Protocol: CurrencyConfig, Cu ## TypeScript Usage ```typescript -import { CurrencyConfigSchema, CurrencyValueSchema, FieldSchema, FieldMaskingKeepSchema, FieldMaskingRuleSchema, FieldType, InlineGridColumnSchema, LocationCoordinatesSchema, SelectOptionSchema, UniqueScopeSchema } from '@objectstack/spec/data'; -import type { CurrencyConfig, CurrencyValue, Field, FieldMaskingKeep, FieldMaskingRule, FieldType, InlineGridColumn, LocationCoordinates, SelectOption, UniqueScope } from '@objectstack/spec/data'; +import { CurrencyConfigSchema, FieldSchema, FieldMaskingKeepSchema, FieldMaskingRuleSchema, FieldType, InlineGridColumnSchema, LocationCoordinatesSchema, SelectOptionSchema, UniqueScopeSchema } from '@objectstack/spec/data'; +import type { CurrencyConfig, Field, FieldMaskingKeep, FieldMaskingRule, FieldType, InlineGridColumn, LocationCoordinates, SelectOption, UniqueScope } from '@objectstack/spec/data'; // Validate data const result = CurrencyConfigSchema.parse(data); @@ -32,18 +32,6 @@ const result = CurrencyConfigSchema.parse(data); | **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. | ---- - -## CurrencyValue - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **value** | `number` | ✅ | Monetary amount | -| **currency** | `string` | ✅ | Currency code (ISO 4217) | - - --- ## Field diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index fc034cb7933..17a7acbbad1 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,7 +1,7 @@ --- title: Protocol reference — every schema by module navTitle: Protocol Reference -description: Every schema published by @objectstack/spec — 1560 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1559 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -23,7 +23,7 @@ counts are sums of the rows they head. Regenerate with | [AI Protocol](/docs/references/ai) | 12 | 68 | Agents, tools, skills, RAG and knowledge sources, model registry, conversations. | | [API Protocol](/docs/references/api) | 32 | 440 | REST contracts, endpoints, routing, realtime, batch, discovery. | | [Automation Protocol](/docs/references/automation) | 15 | 77 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. | -| [Data Protocol](/docs/references/data) | 31 | 185 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | +| [Data Protocol](/docs/references/data) | 31 | 184 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | | [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. | | [Integration Protocol](/docs/references/integration) | 1 | 12 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. | | [Kernel Protocol](/docs/references/kernel) | 29 | 151 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | @@ -34,7 +34,7 @@ counts are sums of the rows they head. Regenerate with | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 37 | 287 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 172 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **202** | **1560** | 14 protocol modules | +| **Total** | **202** | **1559** | 14 protocol modules | --- @@ -132,7 +132,7 @@ Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execu ## Data Protocol -**Source:** `packages/spec/src/data/` · **Import:** `@objectstack/spec/data` · **31 pages, 185 schemas** +**Source:** `packages/spec/src/data/` · **Import:** `@objectstack/spec/data` · **31 pages, 184 schemas** Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. @@ -156,7 +156,7 @@ Objects, fields, queries, filters, datasources and drivers — the ObjectQL laye | [`driver/turso.zod.ts`](/docs/references/data/driver-turso) | `TursoConfig`, `TursoTransportMode` | | [`external-catalog.zod.ts`](/docs/references/data/external-catalog) | `ExternalCatalog`, `ExternalColumn`, `ExternalTable` | | [`feed.zod.ts`](/docs/references/data/feed) | `FeedFilterMode`, `FeedItemType` | -| [`field.zod.ts`](/docs/references/data/field) | `CurrencyConfig`, `CurrencyValue`, `Field`, `FieldMaskingKeep`, `FieldMaskingRule`, `FieldType`, `InlineGridColumn`, `LocationCoordinates`, `SelectOption`, `UniqueScope` | +| [`field.zod.ts`](/docs/references/data/field) | `CurrencyConfig`, `Field`, `FieldMaskingKeep`, `FieldMaskingRule`, `FieldType`, `InlineGridColumn`, `LocationCoordinates`, `SelectOption`, `UniqueScope` | | [`field-value.zod.ts`](/docs/references/data/field-value) | `Address`, `AddressValue`, `CalendarDateValue`, `ClockTimeValue`, `FileLikeValue`, `FileReferenceIdValue`, `FileRefusedValue`, `FileValue`, `InstantValue`, `LocationValue`, `ReferenceIdValue` | | [`filter.zod.ts`](/docs/references/data/filter) | `ComparisonOperator`, `EqualityOperator`, `FieldOperators`, `FieldReference`, `FilterArray`, `FilterCondition`, `NormalizedFilter`, `NowAnchor`, `QueryFilter`, `RangeOperator`, `SetOperator`, `SpecialOperator`, `StringOperator` | | [`hook.zod.ts`](/docs/references/data/hook) | `Hook`, `HookContext`, `HookEvent`, `HookRefusal` | diff --git a/docs/adr/0104-field-runtime-value-shape-contract.md b/docs/adr/0104-field-runtime-value-shape-contract.md index 906c53e1e06..a4cd8f7413d 100644 --- a/docs/adr/0104-field-runtime-value-shape-contract.md +++ b/docs/adr/0104-field-runtime-value-shape-contract.md @@ -76,7 +76,7 @@ lists in three packages, or silently corrupting data. The spec does export three per-type value schemas — and they make things worse, not better, because **all three are dead and two contradict reality**: -- `CurrencyValueSchema` (`packages/spec/src/data/field.zod.ts#CurrencyValueSchema`) declares `{value, currency}`; +- `CurrencyValueSchema` (in `data/field.zod.ts`; deleted 2026-10-28, see the note under "Reality wins") declares `{value, currency}`; the validator, the SQL driver, import-coerce, and the field-zoo round-trip all treat currency as a **bare number**. - `LocationCoordinatesSchema` (`packages/spec/src/data/field.zod.ts#LocationCoordinatesSchema`) declares @@ -163,13 +163,30 @@ Directive #2. It exports: **Reality wins.** Where the de-facto stored shape is coherent, the contract adopts it — deployed data is a wire contract we don't get to rewrite by editing Zod. Concretely: `currency` **is a scalar number** — -`CurrencyValueSchema` is deleted (tombstoned in `UNKNOWN_KEY_GUIDANCE` / -changelog with the FROM → TO note); `location` adopts the stored `{lat, lng}` +`CurrencyValueSchema` is deleted (registered in `RETIRED_DEFS_BY_MAJOR` with a +D3 semantic entry and the changelog carrying the FROM → TO note — see the +2026-10-28 note below); `location` adopts the stored `{lat, lng}` and `LocationCoordinatesSchema` is rewritten to match; `AddressSchema` is either adopted by the contract and enforced, or deleted — it does not remain exported-but-dead. An exported-but-unconsumed value schema is exactly the inert metadata ADR-0078 forbids. +> **Note (2026-10-28, #27182, PR #27233) — `CurrencyValueSchema` is deleted.** +> The deletion this paragraph decided had not happened: through 18.2.0 the +> schema and its `CurrencyValue` type stayed exported from +> `@objectstack/spec/data`, `@deprecated`, with zero readers. They are now +> removed, ahead of the multi-currency epic #8345 (ruling 6465431966 on +> #27119), so that no author reads `{value, currency}` as the shape that +> records a currency. The schema had no carrier key, so there is no +> `retiredKey()` tombstone and no guidance-map entry: the +> FROM → TO note (a currency value is a bare number; the code is +> `currencyConfig.defaultCurrency`) is carried by `RETIRED_DEFS_BY_MAJOR[18]` +> (`data/CurrencyValue`, entry file +> `packages/spec/src/migrations/entries/retired-defs/18.data__CurrencyValue.ts`), +> the D3 semantic entry `currency-value-schema-retired` (entry file +> `packages/spec/src/migrations/entries/semantic/18.currency-value-schema-retired.ts`) +> and the changelog. + **Consumers converge on the contract** (each keeps its role, loses its private type lists): diff --git a/docs/audits/2026-07-unknown-key-strictness-ledger.counts/data.md b/docs/audits/2026-07-unknown-key-strictness-ledger.counts/data.md index 6c4f9fcb8c2..37c7e35c590 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.counts/data.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.counts/data.md @@ -21,7 +21,7 @@ The `strict` column is the one the campaign schedules against; it counts both th | Dir | Sites | strict | passthrough | catchall | strip | |---|---|---|---|---|---| -| `data/` | 165 | 88 | 2 | 0 | 75 | +| `data/` | 164 | 88 | 2 | 0 | 74 | ## `data/` — sites @@ -45,7 +45,7 @@ classify and is not listed (it becomes reportable the day it grows its first sit | `driver/turso.zod.ts` | 2 | | `external-catalog.zod.ts` | 4 | | `field-value.zod.ts` | 4 | -| `field.zod.ts` | 14 | +| `field.zod.ts` | 13 | | `filter.zod.ts` | 13 | | `hook-body.zod.ts` | 2 | | `hook.zod.ts` | 8 | @@ -57,7 +57,7 @@ classify and is not listed (it becomes reportable the day it grows its first sit | `seed-loader.zod.ts` | 12 | | `seed.zod.ts` | 2 | | `validation.zod.ts` | 6 | -| **total** | **165** | +| **total** | **164** | ## `data/` — open @@ -65,7 +65,7 @@ Per file, how many of its sites still silently discard unknown keys. The `Class` column that decides the bucket split is hand-written in the ledger; the arithmetic over it is here. -**75 strip of 165**, in 10 file(s). +**74 strip of 164**, in 10 file(s). | File | Strip | Sites | |---|---|---| @@ -74,18 +74,18 @@ over it is here. | `driver-sql.zod.ts` | 2 | 2 | | `driver.zod.ts` | 9 | 9 | | `external-catalog.zod.ts` | 4 | 4 | -| `field.zod.ts` | 2 | 14 | +| `field.zod.ts` | 1 | 13 | | `filter.zod.ts` | 11 | 13 | | `hook.zod.ts` | 5 | 8 | | `query.zod.ts` | 4 | 5 | | `seed-loader.zod.ts` | 12 | 12 | -| **total** | **75** | **165** | +| **total** | **74** | **164** | | Bucket | Sites | |---|---| | authorable — the ruling's forced scope | 0 | | unresolved — needs a per-schema verdict | 0 | | wire / open — out of forced scope | 73 | -| no door — no carrier, ADR-0049 territory | 2 | +| no door — no carrier, ADR-0049 territory | 1 | | no gate — carrier live, no parse | 0 | | covered — no carrier, no parse, guarded at every consumer | 0 | diff --git a/docs/audits/2026-07-unknown-key-strictness-ledger.md b/docs/audits/2026-07-unknown-key-strictness-ledger.md index ebac7ae894a..4784ee03e55 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.md @@ -1263,7 +1263,7 @@ triage row record which one was taken. | `query.zod.ts` | open | ~~⚠️ classification conflict — see #4721~~ **RESOLVED (11:41Z ruling, closed by #4721).** The conflict was real and the answer was that per-FILE classification was the imprecise instrument: `SortNodeSchema` was carved out as `authorable` and closed (`strictObject` + `aliases: { direction: 'order' }`), the other 4 sites keep `open`. Those 4 are the dialect proper — `BaseQuerySchema`, `AggregationNodeSchema`, `FullTextSearchSchema`, `GroupByNodeSchema`'s object arm — and `BaseQuerySchema`'s own top-level strictness is #4001's to schedule, deliberately **not** taken by #4721 | | `external-catalog.zod.ts` | wire (p) | **out of scope** | | `hook.zod.ts` | wire | **out of scope** — `HookContextSchema` + `.session`/`.provenance`/`.user` are the runtime shape handed to a handler; verified in the data step | -| `field.zod.ts` | no door | ⛔ **not strictness work — re-verdicted 2026-08-13 (#4001 data batch).** This row's own instruction was "check whether they are record data (→ open) before closing", and the measured answer is the THIRD one: neither authorable nor open. Both remaining strip sites (`LocationCoordinatesSchema`, `CurrencyValueSchema`) are `@deprecated` DEAD EXPORTS that contradict the enforced value contract — `currency` stores a BARE NUMBER everywhere (validator, SQL driver `float` column, import coercion, field-zoo oracle), `location` stores `{lat, lng}` not `{latitude, longitude}`. Carrier: absent — no schema in the tree references either, so unreachability from every authoring root holds by construction and no BFS is needed (the only non-test references are two `type-alias-convention.pin.test.ts` rows). Parse: absent outside their own `field.test.ts` cases. Consumers' vocabulary: absent — zero references in objectui; `field-value.test.ts` pins from the other direction that the enforced contract REJECTS the retired `CurrencyValueSchema` object shape. The ADR-0049 answer this class prescribes already exists: ADR-0104's "Reality wins" section decides both removals ("an exported-but-unconsumed value schema is exactly the inert metadata ADR-0078 forbids"), the JSDoc deprecations are on `main` with "Removal rides the next spec major", and the removal is tracked at **#8562** — this row points there, never at a batch. Closing them instead would be #4583's precisely-validated dead slot, and worse than most instances of it: a `strictObject` `surface` name plus did-you-mean suggestions on a shape authors must NOT use is an invitation dressed as enforcement, on the exact spelling (`{value, currency}` / `{latitude, longitude}`) the real contract rejects. The third named shape the old row carried, `Address`, was never this file's site — `AddressSchema` is DECLARED in `field-value.zod.ts` since #7127 and only re-exported here | +| `field.zod.ts` | no door | ⛔ **not strictness work — re-verdicted 2026-08-13 (#4001 data batch).** *(2026-10-28, #27182: `CurrencyValueSchema` and its `CurrencyValue` type are DELETED — registered as `RETIRED_DEFS_BY_MAJOR[18]` `data/CurrencyValue` with the D3 entry `currency-value-schema-retired`, ADR-0104 D1 carried out ahead of the multi-currency epic #8345. One strip site remains, `LocationCoordinatesSchema`, and the verdict below stands for it.)* This row's own instruction was "check whether they are record data (→ open) before closing", and the measured answer is the THIRD one: neither authorable nor open. Both remaining strip sites (`LocationCoordinatesSchema`, `CurrencyValueSchema`) are `@deprecated` DEAD EXPORTS that contradict the enforced value contract — `currency` stores a BARE NUMBER everywhere (validator, SQL driver `float` column, import coercion, field-zoo oracle), `location` stores `{lat, lng}` not `{latitude, longitude}`. Carrier: absent — no schema in the tree references either, so unreachability from every authoring root holds by construction and no BFS is needed (the only non-test references are two `type-alias-convention.pin.test.ts` rows). Parse: absent outside their own `field.test.ts` cases. Consumers' vocabulary: absent — zero references in objectui; `field-value.test.ts` pins from the other direction that the enforced contract REJECTS the retired `CurrencyValueSchema` object shape. The ADR-0049 answer this class prescribes already exists: ADR-0104's "Reality wins" section decides both removals ("an exported-but-unconsumed value schema is exactly the inert metadata ADR-0078 forbids"), the JSDoc deprecations are on `main` with "Removal rides the next spec major", and the removal is tracked at **#8562** — this row points there, never at a batch. Closing them instead would be #4583's precisely-validated dead slot, and worse than most instances of it: a `strictObject` `surface` name plus did-you-mean suggestions on a shape authors must NOT use is an invitation dressed as enforcement, on the exact spelling (`{value, currency}` / `{latitude, longitude}`) the real contract rejects. The third named shape the old row carried, `Address`, was never this file's site — `AddressSchema` is DECLARED in `field-value.zod.ts` since #7127 and only re-exported here | | `driver-sql.zod.ts` | wire | **out of scope** | **Authorable strip in `data/`:** @@ -1807,7 +1807,7 @@ from an abandoned one. 121 non-authorable in 21 rows — #13802 closed `field-value.zod.ts`'s two `open` sites by maintainer ruling; the counts file carries the live number.)* The `no door` ones carry the only follow-up in the set, and it is a different ratchet: - ADR-0049 removal, tracked at #8562 for `field.zod.ts`'s two. + ADR-0049 removal, tracked at #8562 for `field.zod.ts`'s two *(2026-10-28: one, after #27182 deleted `CurrencyValueSchema`)*. - **The nine untriaged directories.** They were never in the ruling's forced scope and are classified coarsely; a future campaign that wants them starts by giving them per-file rows, at which point this gate begins holding them too. diff --git a/packages/spec/api-surface/data.json b/packages/spec/api-surface/data.json index 0d8cd5c1cb9..9031830606f 100644 --- a/packages/spec/api-surface/data.json +++ b/packages/spec/api-surface/data.json @@ -143,8 +143,6 @@ "CurrencyConfig (type)", "CurrencyConfigParsed (type)", "CurrencyConfigSchema (const)", - "CurrencyValue (type)", - "CurrencyValueSchema (const)", "CustomPersistenceConfig (type)", "CustomPersistenceConfigSchema (const)", "DATABASE_DRIVER_SELECTION_ALIASES (const)", diff --git a/packages/spec/authorable-surface/data.json b/packages/spec/authorable-surface/data.json index c6278e47f81..b102ad8959d 100644 --- a/packages/spec/authorable-surface/data.json +++ b/packages/spec/authorable-surface/data.json @@ -103,8 +103,6 @@ "data/CubeJoin:name", "data/CurrencyConfig:currencyMode", "data/CurrencyConfig:defaultCurrency", - "data/CurrencyValue:currency", - "data/CurrencyValue:value", "data/DataEngineAggregateOptions:aggregations", "data/DataEngineAggregateOptions:context", "data/DataEngineAggregateOptions:filter", diff --git a/packages/spec/declaration-map/data.json b/packages/spec/declaration-map/data.json index 305b8efa5c2..790a2205074 100644 --- a/packages/spec/declaration-map/data.json +++ b/packages/spec/declaration-map/data.json @@ -51,8 +51,6 @@ "CubeSchema": "data/Cube", "CurrencyConfig": "data/CurrencyConfig", "CurrencyConfigSchema": "data/CurrencyConfig", - "CurrencyValue": "data/CurrencyValue", - "CurrencyValueSchema": "data/CurrencyValue", "DataEngineAggregateOptions": "data/DataEngineAggregateOptions", "DataEngineAggregateOptionsSchema": "data/DataEngineAggregateOptions", "DataEngineAggregateRequestSchema": "data/DataEngineAggregateRequest", diff --git a/packages/spec/export-origins/data.json b/packages/spec/export-origins/data.json index 31ca2e009c5..c393808c02d 100644 --- a/packages/spec/export-origins/data.json +++ b/packages/spec/export-origins/data.json @@ -140,8 +140,6 @@ "CurrencyConfig": "src/data/field.zod.ts#CurrencyConfig (type)", "CurrencyConfigParsed": "src/data/field.zod.ts#CurrencyConfigParsed (type)", "CurrencyConfigSchema": "src/data/field.zod.ts#CurrencyConfigSchema (const)", - "CurrencyValue": "src/data/field.zod.ts#CurrencyValue (type)", - "CurrencyValueSchema": "src/data/field.zod.ts#CurrencyValueSchema (const)", "CustomPersistenceConfig": "src/data/driver/memory.zod.ts#CustomPersistenceConfig (type)", "CustomPersistenceConfigSchema": "src/data/driver/memory.zod.ts#CustomPersistenceConfigSchema (const)", "DATABASE_DRIVER_SELECTION_ALIASES": "src/data/driver/config-registry.zod.ts#DATABASE_DRIVER_SELECTION_ALIASES (const)", diff --git a/packages/spec/json-schema.manifest/data.json b/packages/spec/json-schema.manifest/data.json index 0153cab3ee6..0ab42398d16 100644 --- a/packages/spec/json-schema.manifest/data.json +++ b/packages/spec/json-schema.manifest/data.json @@ -28,7 +28,6 @@ "data/Cube", "data/CubeJoin", "data/CurrencyConfig", - "data/CurrencyValue", "data/DataEngineAggregateOptions", "data/DataEngineAggregateRequest", "data/DataEngineCountOptions", diff --git a/packages/spec/src/data/currency-value-retirement.test.ts b/packages/spec/src/data/currency-value-retirement.test.ts new file mode 100644 index 00000000000..f0219fb2636 --- /dev/null +++ b/packages/spec/src/data/currency-value-retirement.test.ts @@ -0,0 +1,206 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * `CurrencyValueSchema` / `CurrencyValue` (`data/field.zod.ts`, the + * `{value, currency}` shape) — RETIRED (#27182, ADR-0049 enforce-or-remove), + * as ADR-0104 D1 decided ("`currency` is a scalar number — + * `CurrencyValueSchema` is deleted") and as the multi-currency epic #8345 + * needs before it starts (ruling 6465431966 on #27119). A currency field's + * value is a BARE NUMBER; its code is field configuration + * (`CurrencyConfigSchema`). + * + * Zero readers, measured before the removal on objectstack `fd73f2b3`: every + * hit outside `packages/spec/src/data/field.zod.ts` was its own + * `field.test.ts` block, its `Iso_` row in `type-alias-convention.pin.test.ts`, + * the generated baselines and reference docs, changelogs, or prose (control: + * `CurrencyConfigSchema`, read by the record validator and the object form). + * Nothing under `ui/` or `skills/`. + * + * Bookkeeping shapes, pinned below: + * 1. No carrier key, so no `retiredKey()` tombstone and no D2 conversion: the + * schema was mounted by no stack key and is no metadata type. + * 2. `RETIRED_DEFS_BY_MAJOR[18]` carries `data/CurrencyValue`, and the D3 + * entry `currency-value-schema-retired` carries the FROM → TO note. + * 3. The export is gone from `@objectstack/spec/data` and the root entry, + * while `CurrencyConfigSchema` survives (the lit control). + * 4. Tree-scoped absence: nothing inside the declared radius still imports + * the retired names from a spec specifier or reaches them through `Data.`. + */ + +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +import * as data from './index'; +import * as root from '../index'; +import { MIGRATIONS_BY_MAJOR, RETIRED_DEFS_BY_MAJOR } from '../migrations/registry'; + +describe('the currency value shape is retired, and registered', () => { + it('RETIRED_DEFS_BY_MAJOR[18] carries `data/CurrencyValue`', () => { + expect(RETIRED_DEFS_BY_MAJOR[18]).toContain('data/CurrencyValue'); + }); + + it('the D3 entry `currency-value-schema-retired` says a currency value is a bare number', () => { + const entry = MIGRATIONS_BY_MAJOR[18]!.semantic.find((s) => s.id === 'currency-value-schema-retired'); + expect(entry).toBeDefined(); + expect(entry!.replacement).toMatch(/BARE NUMBER/); + expect(entry!.replacement).toMatch(/defaultCurrency/); + expect(entry!.reason).toMatch(/ADR-0049/); + expect(entry!.reason).toMatch(/ADR-0104 D1/); + expect(entry!.acceptanceCriteria).toMatch(/TS2305/); + // No conversion judged: there is no seam a conversion could run on. + expect(entry!.conversionIds).toBeUndefined(); + }); +}); + +describe('the export is gone from every entry that carried it', () => { + it('`CurrencyValueSchema` is exported neither from `@objectstack/spec/data` nor from the root entry', () => { + expect(Object.keys(data)).not.toContain('CurrencyValueSchema'); + expect(Object.keys(root)).not.toContain('CurrencyValueSchema'); + }); + + it('the field-config `CurrencyConfigSchema` survives — the lit control', () => { + expect(Object.keys(data)).toContain('CurrencyConfigSchema'); + }); + + it('the value contract still answers a bare number for a currency field', () => { + const schema = data.valueSchemaFor({ type: 'currency' }); + expect(schema.safeParse(1000.5).success).toBe(true); + expect(schema.safeParse({ value: 1000.5, currency: 'USD' }).success).toBe(false); + }); +}); + +// ─── Tree-scoped absence, with a DECLARED radius ───────────────────────────── +// +// `tsc` is the primary sweeper — the export is gone, so every typed import +// fails to compile (TS2305). The residue is what `tsc` never judges: MD/MDX +// code fences, JSON, YAML and untyped `.js`. This walk covers that residue +// across the five repo roots `scripts/cross-package-test-inputs.mjs` declares +// for `@objectstack/spec#test` (mirrored in `turbo.json`), plus the example +// apps' own `src/` trees, declared there as `examples/*/src/**/*.ts`. +// +// Two matchers, each judging a USE, never a mention: an `import` / `export … +// from` naming a retired name from an `@objectstack/spec` specifier, and a +// `Data.CurrencyValueSchema` access through the documented namespace import. +// Inline code is prose and is stripped before judging. The bound, stated: +// `docs/**`, `.claude/**`, `.github/**` and the repo-root files are outside +// what this walk sees. +describe('tree-scoped absence: nothing inside the declared radius still imports the currency value shape', () => { + const SPEC_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); + const REPO_ROOT = path.resolve(SPEC_ROOT, '../..'); + const THIS_FILE = path.relative(REPO_ROOT, fileURLToPath(import.meta.url)).split(path.sep).join('/'); + + /** The walked roots — declared in `scripts/cross-package-test-inputs.mjs` under `@objectstack/spec`. */ + const WALK_ROOTS = ['packages', 'examples', 'skills', 'content', 'scripts']; + const SCANNED_EXT = new Set(['.ts', '.mts', '.cts', '.tsx', '.js', '.mjs', '.cjs', '.json', '.md', '.mdx', '.yaml', '.yml']); + /** Under `examples/` the non-code extensions, plus `.ts` inside an app's own `src/` tree. */ + const EXAMPLES_EXT = new Set(['.json', '.md', '.mdx', '.yaml', '.yml']); + const EXAMPLE_APP_SRC_TS = /^examples\/[^/]+\/src\/.+\.ts$/; + const SKIPPED_DIRS = new Set(['node_modules', 'dist', '.git', '.turbo', '.cache', '.objectstack', 'coverage', '.next', '.source']); + + const RETIRED_NAMES = '(CurrencyValueSchema|CurrencyValue)'; + const USES = [ + // An import or re-export naming a retired name from a spec specifier. + new RegExp(`\\b(import|export)\\s+(type\\s+)?\\{[^}]*\\b${RETIRED_NAMES}\\b[^}]*\\}\\s*from\\s*['"]@objectstack/spec`, 'm'), + // An access through the documented `import * as Data` namespace. + new RegExp('\\bData\\.CurrencyValueSchema\\b', 'm'), + ]; + + /** + * Inline code spans are prose — the house style `check:doc-authoring` enforces + * — so stripping single-backtick spans separates "the retirement kit naming + * what it removed" from "a source still using it". Newline-bounded: a fenced + * block's content is NOT stripped. + */ + const stripInlineCode = (text: string): string => text.replace(/`[^`\n]*`/g, ''); + const judge = (text: string): RegExpExecArray | null => { + const stripped = stripInlineCode(text); + for (const re of USES) { + const m = re.exec(stripped); + if (m) return m; + } + return null; + }; + + /** + * Structural exclusions — the retirement kit, each with its reason. ⛔ NOT an + * allowlist file (`spec-property-retirement` §4). + */ + const EXCLUDED = new Set([ + // This pin spells the retired names to assert their absence. + THIS_FILE, + ]); + const EXCLUDED_PREFIXES = [ + // Release-owned prose records the removal; never edited by a code PR. + 'content/docs/releases/', + // GITIGNORED build output (`packages/spec/json-schema/`), reached only + // because this is a FILESYSTEM walk. Its source is the Zod tree. + 'packages/spec/json-schema/', + ]; + /** tsup's own bundle of `tsup.config.ts`, written and deleted mid-build. */ + const TSUP_BUNDLED_CONFIG = /\.bundled_[^./]+\.mjs$/; + + /** Tolerates ONLY a path that vanished mid-walk; every other read fault is re-raised. */ + const readIfPresent = (full: string): string | undefined => { + try { + return fs.readFileSync(full, 'utf-8'); + } catch (err) { + if ((err as NodeJS.ErrnoException)?.code !== 'ENOENT') throw err; + return undefined; + } + }; + + it('the matcher recognises a use and ignores a prose mention and the neighbours (anti-vacuity)', () => { + // Uses — in each syntax the walk reads. + expect(judge("import { CurrencyValueSchema } from '@objectstack/spec/data';")).not.toBeNull(); + expect(judge("import type { Field, CurrencyValue } from '@objectstack/spec/data';")).not.toBeNull(); + expect(judge("Prose.\n\n```ts\nimport { CurrencyValueSchema } from '@objectstack/spec';\n```\n")).not.toBeNull(); + expect(judge("export { CurrencyValueSchema } from '@objectstack/spec/data';")).not.toBeNull(); + expect(judge('const v = Data.CurrencyValueSchema.parse(x);')).not.toBeNull(); + // Neighbours that must NOT match. + expect(judge('the `CurrencyValueSchema` export was retired')).toBeNull(); + expect(judge("import { CurrencyConfigSchema, type CurrencyConfig } from '@objectstack/spec/data';")).toBeNull(); + expect(judge("import { CurrencyValueSchema } from './local-money';")).toBeNull(); + expect(judge('const v = Data.CurrencyConfigSchema.parse(x);')).toBeNull(); + }); + + it('no use of a retired export survives inside the declared radius outside the retirement kit', () => { + const offenders: string[] = []; + let visited = 0; + let exampleSources = 0; + const walk = (dir: string) => { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + const rel = path.relative(REPO_ROOT, full).split(path.sep).join('/'); + if (entry.isDirectory()) { + if (SKIPPED_DIRS.has(entry.name) || entry.name.startsWith('.')) continue; + walk(full); + continue; + } + if (!entry.isFile()) continue; + const ext = path.extname(entry.name); + const scanned = rel.startsWith('examples/') + ? EXAMPLES_EXT.has(ext) || EXAMPLE_APP_SRC_TS.test(rel) + : SCANNED_EXT.has(ext); + if (!scanned) continue; + if (entry.name === 'CHANGELOG.md') continue; // release prose records the removal + if (EXCLUDED.has(rel) || EXCLUDED_PREFIXES.some((p) => rel.startsWith(p))) continue; + if (TSUP_BUNDLED_CONFIG.test(entry.name)) continue; + visited += 1; + if (EXAMPLE_APP_SRC_TS.test(rel)) exampleSources += 1; + const text = readIfPresent(full); + if (text === undefined) continue; + const m = judge(text); + if (m) offenders.push(`${rel} uses \`${m[0].trim().replace(/\s+/g, ' ')}\``); + } + }; + for (const root of WALK_ROOTS) walk(path.join(REPO_ROOT, root)); + // Anti-vacuity: the walk really covered the tree, and the example apps' + // sources were really read. + expect(visited).toBeGreaterThan(1000); + expect(exampleSources).toBeGreaterThan(50); + expect(offenders, 'a use of the retired currency value export means the retirement is being undone').toEqual([]); + }); +}); diff --git a/packages/spec/src/data/field-value.zod.ts b/packages/spec/src/data/field-value.zod.ts index 3702ff95fa0..b3535d1a426 100644 --- a/packages/spec/src/data/field-value.zod.ts +++ b/packages/spec/src/data/field-value.zod.ts @@ -20,8 +20,8 @@ * * "Reality wins": where the deployed stored shape is coherent, the contract * adopts it — deployed data is a wire contract we don't get to rewrite by - * editing Zod. This is why `currency` is a bare number (not the never-consumed - * `CurrencyValueSchema` object) and `location` is `{lat, lng}` (what field-zoo + * editing Zod. This is why `currency` is a bare number (the never-consumed + * `CurrencyValueSchema` object is deleted) and `location` is `{lat, lng}` (what field-zoo * stores), not the never-consumed `{latitude, longitude}` shape. * * Purity: schemas/constants/derivation only — no runtime logic, no caching diff --git a/packages/spec/src/data/field.test.ts b/packages/spec/src/data/field.test.ts index c6f0efecf63..ebabb6904ac 100644 --- a/packages/spec/src/data/field.test.ts +++ b/packages/spec/src/data/field.test.ts @@ -5,13 +5,11 @@ import { FieldType, SelectOptionSchema, CurrencyConfigSchema, - CurrencyValueSchema, Field, BOUNDED_STRING_FIELD_TYPES, VALUE_DOMAIN_FIELD_TYPES, type SelectOption, type CurrencyConfig, - type CurrencyValue, } from './field.zod'; import { ObjectSchema } from './object.zod'; import { MULTI_CAPABLE_TYPES, MULTI_OPTION_TYPES, isMultiValueField } from './field-value.zod'; @@ -133,46 +131,6 @@ describe('CurrencyConfigSchema', () => { }); }); -describe('CurrencyValueSchema', () => { - it('should accept valid currency value', () => { - const validValue: CurrencyValue = { - value: 1000.50, - currency: 'USD', - }; - - expect(() => CurrencyValueSchema.parse(validValue)).not.toThrow(); - }); - - it('should accept zero value', () => { - const zeroValue: CurrencyValue = { - value: 0, - currency: 'CNY', - }; - - expect(() => CurrencyValueSchema.parse(zeroValue)).not.toThrow(); - }); - - it('should accept negative values', () => { - const negativeValue: CurrencyValue = { - value: -500.00, - currency: 'EUR', - }; - - expect(() => CurrencyValueSchema.parse(negativeValue)).not.toThrow(); - }); - - it('should reject invalid currency codes', () => { - expect(() => CurrencyValueSchema.parse({ value: 100, currency: 'US' })).toThrow(); - expect(() => CurrencyValueSchema.parse({ value: 100, currency: 'USDD' })).toThrow(); - }); - - it('should reject missing required fields', () => { - expect(() => CurrencyValueSchema.parse({ value: 100 })).toThrow(); - expect(() => CurrencyValueSchema.parse({ currency: 'USD' })).toThrow(); - expect(() => CurrencyValueSchema.parse({})).toThrow(); - }); -}); - // =========================================================================== // #8163 — field-level `currency` is rejected with no pointer to the // declarable nested form (`currencyConfig.defaultCurrency`, under diff --git a/packages/spec/src/data/field.zod.ts b/packages/spec/src/data/field.zod.ts index efa71ced0e3..248369f6132 100644 --- a/packages/spec/src/data/field.zod.ts +++ b/packages/spec/src/data/field.zod.ts @@ -599,25 +599,6 @@ export const CurrencyConfigSchema = lazySchema(() => strictObject({ // output is `{ currencyMode }` plus the `defaultCurrency` the author wrote. }).superRefine(refuseFixedCurrencyWithoutCode)); -/** - * Currency Value Schema - * Runtime value structure for currency fields - * - * Note: Currency codes are validated by length only (3 characters) to support flexibility. - * See CurrencyConfigSchema for details on currency code validation strategy. - * - * @deprecated This shape was never consumed and contradicts the actual runtime - * contract: a `currency` field's value is a BARE NUMBER everywhere (validator, - * SQL driver `float` column, import coercion, field-zoo oracle); the currency - * code lives in field config (`CurrencyConfigSchema`), not per value. Use - * `valueSchemaFor` from `field-value.zod.ts` (ADR-0104 D1). Removal rides the - * next spec major. - */ -export const CurrencyValueSchema = lazySchema(() => z.object({ - value: z.number().describe('Monetary amount'), - currency: z.string().length(3).describe('Currency code (ISO 4217)'), -})); - /** * Address Schema — structured address for the `address` field type. * @@ -3094,7 +3075,6 @@ export type Address = z.input; export type CurrencyConfig = z.input; /** Post-parse shape of {@link CurrencyConfig} — defaults applied, transforms run (ADR-0122). */ export type CurrencyConfigParsed = z.infer; -export type CurrencyValue = z.input; /** * Field Factory Helper diff --git a/packages/spec/src/migrations/entries/retired-defs/18.data__CurrencyValue.ts b/packages/spec/src/migrations/entries/retired-defs/18.data__CurrencyValue.ts new file mode 100644 index 00000000000..b054fee523f --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.data__CurrencyValue.ts @@ -0,0 +1,19 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #27182 — `data/CurrencyValue` (`{value, currency}`), exported from +// `@objectstack/spec/data` as `CurrencyValueSchema` / `CurrencyValue` +// (`data/field.zod.ts`), leaves under ADR-0049 enforce-or-remove. ADR-0104 D1 +// already decided it ("`currency` is a scalar number — `CurrencyValueSchema` is +// deleted"); it stayed on the published surface `@deprecated` with "Removal +// rides the next spec major", and the multi-currency epic (#8345, ruling +// 6465431966 on #27119) needs it gone first so no author reads it as the shape +// that records a currency. It was never consumed and contradicted the enforced +// contract: a `currency` field's value is a BARE NUMBER everywhere (validator, +// SQL driver `float` column, import coercion, field-zoo oracle), and the code +// lives in field config (`CurrencyConfigSchema`). Mounted by no stack key, +// registered as no metadata type, absent from every liveness ledger; on +// objectstack `fd73f2b3` every hit outside its own test, its type-alias pin and +// the generated baselines was prose. No carrier key, so no tombstone and no D2 +// conversion: this table plus the D3 semantic entry +// `currency-value-schema-retired` ARE the declaration. +export const entry = 'data/CurrencyValue'; diff --git a/packages/spec/src/migrations/entries/semantic/18.currency-value-schema-retired.ts b/packages/spec/src/migrations/entries/semantic/18.currency-value-schema-retired.ts new file mode 100644 index 00000000000..7bc7340d5c2 --- /dev/null +++ b/packages/spec/src/migrations/entries/semantic/18.currency-value-schema-retired.ts @@ -0,0 +1,40 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +import type { SemanticMigration } from '../../types.js'; + +export const entry: SemanticMigration = { + id: 'currency-value-schema-retired', + // No backticks in `surface` — build-upgrade-guide.ts renders it inside a + // code span AND a table cell. + surface: + 'data.currencyValue (the whole of CurrencyValueSchema in data/field.zod.ts — 1 def, ' + + 'data/CurrencyValue, and 2 exported names: CurrencyValueSchema and CurrencyValue)', + replacement: + 'a `currency` field\'s value is a BARE NUMBER — `{ value: 1000.5, currency: \'USD\' }` ' + + 'becomes `1000.5`. The currency code is field configuration, not part of the value: ' + + 'declare it as `currencyConfig: { currencyMode: \'fixed\', defaultCurrency: \'USD\' }` ' + + '(CurrencyConfigSchema). To type or check a value, use `valueSchemaFor(field, \'stored\')` ' + + 'from `@objectstack/spec/data` (the ADR-0104 D1 value contract), which answers `number` ' + + 'for a currency field', + reason: + 'ADR-0049 enforce-or-remove; ADR-0104 D1 ("Reality wins": `currency` is a scalar number ' + + 'and CurrencyValueSchema is deleted), carried out as the prerequisite of the multi-currency ' + + 'epic so no author reads the dead shape as the way a record keeps its currency. The schema ' + + 'declared `{value, currency}` and was never consumed: the record validator, the SQL ' + + 'driver\'s `float` column, import coercion and the field-zoo oracle all store and check a ' + + 'bare number, and the value contract REJECTS the object shape. It was `@deprecated` since ' + + 'ADR-0104 and stayed exported only because removal waited for a release. No carrier key and ' + + 'no metadata type ever held it, so there is nothing to tombstone and no seam for a D2 ' + + 'conversion: RETIRED_DEFS_BY_MAJOR plus this entry ARE the declaration. `cloud` and real ' + + 'customer code are UNMEASURED.', + acceptanceCriteria: + 'No code imports CurrencyValueSchema or CurrencyValue from @objectstack/spec or ' + + '@objectstack/spec/data — every such import is TS2305 after upgrade (pinned in ' + + '`data/currency-value-retirement.test.ts`). Code that built or read `{value, currency}` ' + + 'objects for a currency field writes and reads the bare number instead, and takes the code ' + + 'from the field\'s `currencyConfig.defaultCurrency`. CurrencyConfigSchema is unchanged. ' + + '`data/CurrencyValue` is absent from `json-schema.manifest/data.json`, the api-surface / ' + + 'declaration-map / export-origins shards and the generated reference docs. ⚠️ Runtime ' + + 'behaviour is deliberately UNCHANGED: nothing ever parsed with the schema, so removing it ' + + 'removes no behaviour — currency values were bare numbers before and after.', +}; diff --git a/packages/spec/src/type-alias-convention.pin.test.ts b/packages/spec/src/type-alias-convention.pin.test.ts index 644a4a08036..3dbec506362 100644 --- a/packages/spec/src/type-alias-convention.pin.test.ts +++ b/packages/spec/src/type-alias-convention.pin.test.ts @@ -285,7 +285,7 @@ import type * as M194 from './automation/assignment-rule.zod.js'; import type * as M195 from './security/queue.zod.js'; // --------------------------------------------------------------------------- -// 799 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared. +// 798 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared. // // That number is machine-checked, not hand-kept. The runtime companion at the // bottom of this file recomputes the pin count from the source and asserts that @@ -881,7 +881,6 @@ export type Iso_data_fieldValue__ReferenceIdValueSchema = Assert, z.infer< typeof M66.AddressSchema > >>; -export type Iso_data_field__CurrencyValueSchema = Assert, z.infer< typeof M66.CurrencyValueSchema > >>; export type Iso_data_field__FieldMaskingKeepSchema = Assert, z.infer< typeof M66.FieldMaskingKeepSchema > >>; export type Iso_data_field__FieldType = Assert, z.infer< typeof M66.FieldType > >>; export type Iso_data_field__LocationCoordinatesSchema = Assert, z.infer< typeof M66.LocationCoordinatesSchema > >>; @@ -1733,7 +1732,7 @@ describe('ADR-0122 type-alias convention', () => { // this title and the section header above the pin list — are now asserted // against the recomputed count below, so neither can go stale without a red // test naming it. - it('still declares all 799 isomorphic pins', () => { + it('still declares all 798 isomorphic pins', () => { // The truth of each pin is proved by tsc, not here — an `Assert>` // that stops holding is a compile error with the alias named. What tsc // cannot notice is a pin that was DELETED: removing the assertion removes @@ -2664,7 +2663,11 @@ describe('ADR-0122 type-alias convention', () => { // a required id and an optional name, no default and no transform — so it // is pinned here (Iso_api_protocol__MetadataAuthoringClientSchema) rather // than given a `…Parsed` synonym. +1 added. - expect(pins).toHaveLength(799); + // 799 -> 798 is #27182: `CurrencyValueSchema` (`data/field.zod.ts`), the + // never-consumed `{value, currency}` shape a currency value never had (it + // is a bare number, ADR-0104 D1), is deleted, and its pin + // (Iso_data_field__CurrencyValueSchema) goes with it. -1 removed. + expect(pins).toHaveLength(798); // The count is stated in PROSE twice as well — this case's title and the // section header above the pin list — and until commit c6b05c76a nothing read either diff --git a/packages/spec/vitest.repo-tests.json b/packages/spec/vitest.repo-tests.json index 2fb9c1a02f0..a55ddd3ca40 100644 --- a/packages/spec/vitest.repo-tests.json +++ b/packages/spec/vitest.repo-tests.json @@ -42,6 +42,7 @@ "src/data/cube-member-inner-name-retirement.test.ts", "src/data/cube-refresh-key-retirement.test.ts", "src/data/currency-mode-family-closure.pin.test.ts", + "src/data/currency-value-retirement.test.ts", "src/data/document-schemas-retirement.test.ts", "src/data/driver/turso-encryption-key-retirement.test.ts", "src/data/object-external-sharing-model-retirement.test.ts", diff --git a/skills/objectstack-ai/references/_index.md b/skills/objectstack-ai/references/_index.md index c29de5f76a2..06b18a96b71 100644 --- a/skills/objectstack-ai/references/_index.md +++ b/skills/objectstack-ai/references/_index.md @@ -20,7 +20,7 @@ from `node_modules` — there is no local copy in the skill bundle. - `node_modules/@objectstack/spec/src/ai/embedding.zod.ts` — Embedding & Vector Store Primitives - `node_modules/@objectstack/spec/src/data/field-value.zod.ts` — Field runtime VALUE-shape contract (ADR-0104 D1). -- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, CurrencyValueSchema +- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, UniqueScopeSchema - `node_modules/@objectstack/spec/src/data/filter.zod.ts` — Unified Query DSL Specification - `node_modules/@objectstack/spec/src/kernel/metadata-protection.zod.ts` — Metadata Protection Model — Phase 1 (ADR-0010) - `node_modules/@objectstack/spec/src/shared/conditional-formatting.zod.ts` — The **single declaration** of a conditional formatting rule — diff --git a/skills/objectstack-data/references/_index.md b/skills/objectstack-data/references/_index.md index f411956caa4..32bda8f7c56 100644 --- a/skills/objectstack-data/references/_index.md +++ b/skills/objectstack-data/references/_index.md @@ -10,7 +10,7 @@ from `node_modules` — there is no local copy in the skill bundle. ## Core schemas - `node_modules/@objectstack/spec/src/data/datasource.zod.ts` — Exports: DriverType, DriverDefinitionSchema, SchemaModeSchema, ExternalDatasourceSettingsSchema, DatasourceSchema -- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, CurrencyValueSchema +- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, UniqueScopeSchema - `node_modules/@objectstack/spec/src/data/hook.zod.ts` — Exports: HookRefusalSchema, HookEvent, HookSchema, HookContextSchema - `node_modules/@objectstack/spec/src/data/object.zod.ts` — Exports: ApiMethod, ApiOperationSchema, ObjectCapabilities, IndexSchema, TenancyConfigSchema - `node_modules/@objectstack/spec/src/data/seed.zod.ts` — Exports: SeedMode, SeedColumnSchema, SeedSchema, leadSeed diff --git a/skills/objectstack-i18n/references/_index.md b/skills/objectstack-i18n/references/_index.md index ce2cbeff8ba..8afc089eab6 100644 --- a/skills/objectstack-i18n/references/_index.md +++ b/skills/objectstack-i18n/references/_index.md @@ -14,7 +14,7 @@ from `node_modules` — there is no local copy in the skill bundle. ## Transitive dependencies -- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, CurrencyValueSchema +- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, UniqueScopeSchema - `node_modules/@objectstack/spec/src/shared/identifiers.zod.ts` — Exports: SystemIdentifierSchema, SnakeCaseIdentifierSchema, MetadataItemNameSchema ## How to read these diff --git a/skills/objectstack-platform/references/_index.md b/skills/objectstack-platform/references/_index.md index 6d2ef8a89f6..8c6c61b56d9 100644 --- a/skills/objectstack-platform/references/_index.md +++ b/skills/objectstack-platform/references/_index.md @@ -22,7 +22,7 @@ from `node_modules` — there is no local copy in the skill bundle. ## Transitive dependencies -- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, CurrencyValueSchema +- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, UniqueScopeSchema - `node_modules/@objectstack/spec/src/data/hook.zod.ts` — Exports: HookRefusalSchema, HookEvent, HookSchema, HookContextSchema - `node_modules/@objectstack/spec/src/data/object.zod.ts` — Exports: ApiMethod, ApiOperationSchema, ObjectCapabilities, IndexSchema, TenancyConfigSchema - `node_modules/@objectstack/spec/src/security/rls.zod.ts` — Row-Level Security (RLS) Protocol diff --git a/skills/objectstack-ui/references/_index.md b/skills/objectstack-ui/references/_index.md index 22bdd4bfeed..e83ae7f34c1 100644 --- a/skills/objectstack-ui/references/_index.md +++ b/skills/objectstack-ui/references/_index.md @@ -27,7 +27,7 @@ from `node_modules` — there is no local copy in the skill bundle. - `node_modules/@objectstack/spec/src/data/date-macros.zod.ts` — Date Macro Tokens — the declarative placeholders the UI substitutes - `node_modules/@objectstack/spec/src/data/feed.zod.ts` — Activity-timeline UI config enums, and the `sys_activity.type` built-in set. - `node_modules/@objectstack/spec/src/data/field-value.zod.ts` — Field runtime VALUE-shape contract (ADR-0104 D1). -- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, CurrencyValueSchema +- `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, UniqueScopeSchema - `node_modules/@objectstack/spec/src/data/filter.zod.ts` — Unified Query DSL Specification - `node_modules/@objectstack/spec/src/data/hook-body.zod.ts` — Exports: HookBodyCapability, ExpressionBodySchema, ScriptBodySchema, HookBodySchema - `node_modules/@objectstack/spec/src/data/object.zod.ts` — Exports: ApiMethod, ApiOperationSchema, ObjectCapabilities, IndexSchema, TenancyConfigSchema