Repository navigation
Commit 5b9402d
fix(spec,objectql)!: retire
Fixes #19629
Clause-②: no (narrowing)
Executes maintainer ruling `5791803339` (batch #215 item 1, letter B,
「215 同意」): `scale` is retired from the `currency` field type. Its
refusal remedy and its ADR-0087 migration entry are worded by maintainer
ruling 乙 `5805782503` (batch #218 item 2, 「其他同意」), item 1:
> PR #19909's refusal remedy and ADR-0087 migration entry are reworded:
delete `scale` on a currency field; the currency's ISO 4217 minor unit
decides its display, and its write allowance stays unconstrained
(today's contract). ⛔ No pointer to `currencyConfig.precision`.
The consumer half is objectstack-ai/objectui#10221 and is not in this
diff: the field designer, the grid summary footer, and, under ruling 乙
item 2, the dashboard `ObjectMetricWidget`. B′ (enforcing a currency
width on writes) was not taken and is not here.
## Landing order (ruling 乙 item 2)
This PR lands **after** objectstack-ai/objectui#10221 has landed
(widened to `ObjectMetricWidget`) **and after** this repository's
`.objectui-sha` pin bump has moved past it. That order keeps any
zero-decimal window from opening on the grid summary footer or the
dashboard metric widget. At this writing the pin is `62597c588072` and
objectui#10221 is open with no PR (both re-read in round 3). Holding the
landing to that order is the seat's.
## What changes
1. **`@objectstack/spec`, `FieldSchema`**
(`packages/spec/src/data/field.zod.ts`): `scale` on a `type: 'currency'`
field is refused at parse, with one `custom` issue at `scale` (the
file's per-type `superRefine` house pattern). No alias and no grace
window. The remedy's first sentence is "`scale` is not valid on a
`currency` field — delete the key." It goes on to say that the
currency's ISO 4217 minor unit decides how the amount displays, and that
the field's write allowance stays unconstrained. It names no other key
to carry the value. The `scale` describe names the set the key still
applies to: `number`, `percent`, `rating` and `slider`, enforced on
writes, and `formula`, rounded. On `currency` it now reads "REFUSED on a
`currency` field — delete it there".
2. **`@objectstack/objectql`, record validator**
(`packages/objectql/src/validation/record-validator.ts`): the
`max_scale` branch no longer reads `def.scale` for `currency`, so the
type leaves the enforced set. `min`, `max` and the finite-number check
still apply to currency. `percent`, `number`, `rating` and `slider` are
unchanged. Nothing else is read in its place: a currency's write
allowance stays unconstrained.
3. **ADR-0087 semantic entry** `field-currency-scale-refused`
(`packages/spec/src/migrations/entries/semantic/18.field-currency-scale-refused.ts`).
Its replacement is "DELETE the key — that is the whole migration", and
it says nothing replaces the key. It is deliberately not a mechanical
conversion: a conversion that dropped the key would accept it on every
load, which is the grace window ruling B refused. `registry.ts` is
regenerated with `gen:migration-registry`, never hand-edited.
4. **Shipped examples** that the refusal would reject. `scale: 2` was
deleted from each, and nothing was added:
- `examples/app-crm/src/objects/account.object.ts`,
`opportunity.object.ts`, `opportunity-line-item.object.ts` (×2)
- `examples/app-showcase/src/data/objects/account.object.ts`,
`client-brief.object.ts`, `expense-report.object.ts`,
`external/customer.object.ts`, `external/order.object.ts`,
`field-zoo.object.ts`, `invoice.object.ts` (×3), `project.object.ts`
(×2)
5. **Documentation examples.** `scale: 2` was deleted from 13 currency
examples in `content/docs/concepts/architecture.mdx` (×2),
`concepts/metadata-driven.mdx` (×2), `data-modeling/fields.mdx`,
`data-modeling/objects.mdx`, `data-modeling/schema-design.mdx`,
`protocol/kernel/plugin-spec.mdx`, `protocol/objectql/schema.mdx` (×4)
and `protocol/objectql/types.mdx`. The `schema.mdx` property table's
`scale` row no longer lists `currency`. It now says "Refused on
`currency` — delete it there".
6. **Generated**, never hand-edited:
`content/docs/references/data/field.mdx`,
`content/docs/references/data/object.mdx` and
`content/docs/references/system/migration.mdx` (the `scale` describe).
`authorable-surface`, `api-surface`, `json-schema.manifest`,
`spec-changes.json` and the upgrade guide did not move, because no key
or export was added or removed. The nine `*.metadata-forms.generated.ts`
i18n bundles did not move either: round 3 changes a `visibleWhen`, not a
label or help text, and those bundles carry only label and help text.
7. **`packages/spec/src/data/field-scale.ts`**: the docblock's
`currency` bullet records the retirement and ruling 乙's remedy. It no
longer names `CurrencyConfigSchema.precision` as the money faces'
override; that claim was false at the pin.
8. **`packages/spec/src/data/object.form.ts`** (round 3): the object
designer's quick-add fields grid, `objectForm`, is the form
`METADATA_FORM_REGISTRY` serves for the `object` metadata type. Its
`scale` row's `visibleWhen` was `"data.type in
['number','currency','percent']"` and is now `"data.type in
['number','percent']"`, with a one-line comment citing this card and
ruling `5791803339` B. The `precision`, `min` and `max` rows are
unchanged.
## Measured first, on `origin/main` `1f89ba0d70` (built `dist`)
- A currency field with `scale: 2` **parsed**: `FieldSchema.safeParse`
succeeded. Control: the same with `type: 'number'` also succeeded.
- The record validator **refused** a currency write over `scale`:
`scale: 2`, write `1.234` → `max_scale {"scale":2,"actual":3}`. A
currency field without `scale` accepted `1.23456`.
- `max_scale` read `def.scale` on **all four** controls. Each was given
`scale: 2` and the write `1.23456`. `number`, `rating` and `slider`
answered `{scale:2, actual:5}`. `percent` answered `{scale:4,
actual:5}`, because of the fraction-storage derivation.
- **Population census**, a TypeScript AST sweep over every tracked
`.ts`/`.tsx`/`.mjs`/`.js` file (7,036 files): **15 example sites**, all
listed above, and **7 test fixtures**, listed below. A JSON walk over
556 tracked `.json` files found 0 currency-typed objects with `scale`. A
windowed scan of 831 `.md`/`.mdx` files found the 13 documentation
examples. The one surviving AST hit is
`packages/spec/src/data/inline-related-columns.test.ts:103`. It is
`InlineGridColumnSchema.scale`, a different schema that the ruling does
not cover.
## Readings the round measured, and where each went
1. **`currencyConfig.precision` has no reader.** No face in the pinned
console (`.objectui-sha` `62597c588072`) reads it, and no non-test code
in this repository does. The cell uses the currency's ISO 4217 minor
unit, and the edit widget reads the **field-level** `precision`. →
Ruling 乙 item 1: the remedy and the migration entry no longer point to
that key. Two findings follow from ruling 乙 item 3:
`currencyConfig.precision` is declared and read by nothing, and
objectui's `CurrencyField` reads the field-level `precision` as decimal
places. Both are filed by the `domain:spec` seat, as #19992 and
objectstack-ai/objectui#10276, ⛔ not riders here.
2. **Ruling B's control reading undercounted the examples.** Fifteen
`Field.currency` declarations in `examples/` declared `scale: 2`. →
Corrected on the card by `5805294161`.
3. **A fourth face.** The dashboard `ObjectMetricWidget`'s currency arm
reads `valueFieldDef.scale ?? 0`. → Ruling 乙 item 2: objectui#10221 is
widened to it and lands first (see the landing order above).
4. **Direction of the validator half.** It moves writes from refused to
accepted. → Ruling 乙 item 4: `Clause-②: no (narrowing)` stays as ruled.
The widening reading from the #19320 precedent is noted and ⛔ not
re-declared.
## Round 3, on top of `40ef043003`
**Why.** The at-tier contract-review record `5818558748` on this PR
(head `40ef043003`) read **VERDICT: FAIL** with one required fix:
`packages/spec/src/data/object.form.ts:190` still offered `scale` on a
currency row of the object designer's fields grid, the form registered
in `packages/spec/src/system/metadata-form-registry.ts`. After this PR
an author using that form is shown a `scale` input on a currency field
and is refused at publish, which is the offer-vs-door shape this
retirement removes.
- **`d7740c324e`**: the fix exactly as the record states it. The `scale`
row's `visibleWhen` is now `"data.type in ['number','percent']"`, with
the one-line comment. The row was not widened to any other type, and the
`precision`, `min` and `max` rows were not touched. The same commit adds
the offer-side pin and one changeset sentence (both below).
`origin/main` was not merged: the PR reads `mergeable_state: clean`, and
no file main changed since the merge base `c8399867b8` is a file this
branch changes (`comm` of the two name lists is empty), so CI's merge
ref needs nothing from a merge here.
**Sweep of `packages/spec/src/**` for any other surface offering `scale`
on `currency`.** All 17 `*.form.ts` files were read for `scale` rows,
and every non-test source file naming both `scale` and `currency` was
read at the hit.
| file:line (HEAD `d7740c324e`) | what it is | changed? |
|:--|:--|:--|
| `data/object.form.ts:191` | the `objectForm` fields-grid `scale` row
(it was `:190`) | **yes**, the record's fix |
| `data/field.form.ts:79` | the `fieldForm` `scale` row, `"data.type ==
'number'"` | no; it does not offer the key on currency (the record's own
control) |
| `data/field.zod.ts:1235-1236` | `FieldSchema.scale` and its describe,
"REFUSED on a `currency` field" | no; that is the door, from round 2 |
| `data/field.zod.ts:1025` | `FieldSchema` aliases `decimals` /
`decimalPlaces` → `scale` | no; on currency the renamed key lands on the
same refusal (acceptance note below) |
| `data/field.zod.ts:420` | `CurrencyConfigSchema` alias `scale` →
`precision`, inside `currencyConfig` | no; a different schema,
pre-existing, and the surface of #19992 (acceptance note below) |
| `data/field.zod.ts:931` | `InlineGridColumnSchema.scale` | no; a
different schema, left alone as instructed |
| `ui/view.zod.ts:3338` | `FormFieldSchema.scale`, a form-view row's
widget override with no type gate by design (a form row usually omits
`type`) | no; a different schema, and its describe names no field type |
| `ui/view.zod.ts:1600` | the timeline view's `scale` (`hour` … `year`)
| no; unrelated |
| `ui/bulk-action.zod.ts:157` | `scale` in
`BULK_PARAM_WIDGET_CONFIG_KEYS`, a list of keys bulk params REFUSE | no;
a refusal list, not an offer |
| `data/field-scale.ts:101` | `ABSENT_SCALE_BY_TYPE`, whose one row is
`percent` | no; there is no currency row |
| `data/numeric-column-representation.ts:49-52` | a dated measurement
docblock that names a `currency` field with `scale: 2` refused at the
write seam | no; a record of a reading, not an offer (acceptance note
below) |
| `studio/**` | designer hints | 0 `currency` hits |
|
`packages/platform-objects/src/apps/translations/*.metadata-forms.generated.ts`
(outside `packages/spec/src`) | the generated form bundles;
`fields.scale` carries only its label and help text (`en` `:147-150`) |
no; no predicate lives there, and `check:i18n` reads all nine packages'
bundles in sync |
A quoted-exact `git grep -n -F "['number','currency','percent']"` over
the whole tree now answers one line, the `precision` row at
`object.form.ts:189`, which the record says to leave. Before the fix it
answered that row and the `scale` row.
**The new pin**
(`packages/spec/src/data/field-currency-scale-refused.test.ts`, final
block). It evaluates each row's `visibleWhen` the way
`form-delete-behavior-options.test.ts` already does: a fail-closed
reader of the `data.type` spellings these forms use (`==` and `in
[...]`, joined by `||`) that throws on anything else, so a predicate it
cannot read fails the test instead of being assumed visible or hidden.
- **CONTROLS** (lit): the walk over every form in
`METADATA_FORM_REGISTRY` finds exactly two `scale` rows, `field:scale`
and `object:fields.scale`. `METADATA_FORM_REGISTRY.object` is
`objectForm`. The reader lights on a row that does name `currency`.
- **Firing case**: the `objectForm` `scale` row is not offered when
`data.type` is `currency`.
- **Dark controls**: it is still offered for `number` and `percent`, and
the door agrees on both types (`FieldSchema.safeParse` with `scale: 2`
succeeds).
- **Class guard**: no registered form offers `scale` on a currency
field.
**Old-row pins.** Nothing pinned the old row: before the fix, the
quoted-exact `git grep` above found the predicate only in
`object.form.ts` itself, and none of the tests that read `objectForm` or
`METADATA_FORM_REGISTRY` mention `scale`. There was nothing to reverse.
## Round 2, on top of `7c0a33c6ad`
- **`07c9be36bf`**: a merge of `origin/main` `c8399867b8`, run through
`scripts/pm/os-regen-merge.sh`. `registry.ts` text-merged, and
`gen:migration-registry` then wrote no change. `check:generated` read
"All 15 generated artifacts are up to date".
- Main changed none of the three reference pages this branch changes, so
the script kept the branch's bytes for them. The three reference pages
main did change (`api/package-api.mdx`, `security/permission.mdx`,
`system/translation.mdx`) are byte-identical to `origin/main` (`git
diff` empty).
- Quoted-exact `git grep` survival checks:
- Each of the 7 semantic entries main added since the merge base appears
exactly once in both `origin/main`'s and HEAD's `registry.ts`:
`admin-scope-business-unit-blank-refused`,
`filter-equality-array-comparand-refused`,
`flow-predicate-slot-blank-string-refused`,
`package-api-contracts-unmounted-entries-retired`,
`rls-predicate-array-comparand-refused`,
`translation-per-app-settings-platform-only` and
`view-filter-rule-absent-value-refused`.
- Main's added reference line "Required and non-blank: an empty or
whitespace-only value names no business unit" appears 2 times in
`permission.mdx` on both sides.
- Main's deleted line "POST /api/v1/packages/upgrade" appears 0 times on
both sides.
- **`e2c5077421`**: the rewording to ruling 乙, across the refusal
message, the describe, the migration entry (with `registry.ts`
regenerated), the validator's comments, the `field-scale.ts` docblock,
the `schema.mdx` row, the changeset and the spec pins. What is refused
and what is accepted did not change.
- **`40ef043003`**: `gen:docs` regenerated the three reference pages. A
later `gen:schema && gen:docs` produced no further diff, and
`check:docs` read "225 generated files in sync with packages/spec".
## Tests, on HEAD `d7740c324e`
Every command went through `scripts/pm/os-verify-lock.sh`. Each count is
the runner's own summary line.
- Build: `turbo run build` over `./packages/*`, `./packages/*/*` and
`./examples/*` gave **73 successful, 73 total**.
- `@objectstack/spec`: `vitest run --project local` gave **532 files,
15667 passed, 2 todo** (round 2: 15663; the 4 new offer-side tests).
`--project repo` gave **35 files, 602 passed**.
- `field-currency-scale-refused.test.ts` alone: **12 passed** (8 from
round 2, 4 new).
- `@objectstack/spec` `typecheck` exited 0. `check:test-typecheck` held
53 files, 255 errors and 142 pinned signatures, the same as rounds 1 and
2. `check:type-check-coverage` exited 0, so the package's `tsconfig`
reaches the edited test file.
- Consumers that read the registered forms:
`@objectstack/platform-objects` translation suites gave 6 files, 137
passed; `@objectstack/lint` `validate-predicate-path-refs.test.ts` gave
1 file, 54 passed; `@objectstack/metadata-protocol`
`protocol.meta-types-*` gave 3 files, 38 passed.
- NOT re-run this round: `@objectstack/objectql` (on `40ef043003`: 309
files, 5196 passed; 1 file, 5 passed; `typecheck` exit 0 with 40 files,
234 errors and 65 pinned signatures held), `@objectstack/example-crm`,
`@objectstack/example-showcase`, and round 1's `platform-objects`,
`metadata-core`, `driver-sql` and `service-automation` suites. No file
in those packages changed since `40ef043003`. They are declared to CI.
## Reverse verification
All legs are one-shot proofs run from the committed state, each with a
trap on EXIT/INT/TERM. No rebuild was needed, because the test file
resolves `./object.form`, `./field.zod` and
`../system/metadata-form-registry` through relative `src` imports.
**Round 3, the offer.** `scripts/ablation-replace.mjs` restored the old
row, `visibleWhen: "data.type in ['number','currency','percent']"`, on
`object.form.ts`. The landing was proved on disk: new-row anchor 1 → 0,
old row 0 → 1, blob `6e87b93283` → `295afbe69f`. Then
`field-currency-scale-refused.test.ts` ran: **2 failed | 10 passed**.
The two failures are the firing case ("expected true to be false") and
the class guard (it received `object:fields.scale` where it expected
none). The lit CONTROLS, the `number` and `percent` dark controls and
all 8 round-2 tests stayed green. Restored: blob `6e87b93283` == HEAD,
`git diff HEAD` empty, and `git status --porcelain` empty.
Round 2's two legs, on `40ef043003`:
- **The ruled wording.** `field.zod.ts` was restored to its round-1 blob
`0c24baa382`, which carries the old remedy naming the other key. Main
changed nothing in this file across the merge, so that blob differs from
HEAD only by the round-2 rewording. The landing was proved by blob hash,
with the old-remedy anchor ×1 and the new one ×0. Then
`field-currency-scale-refused.test.ts` ran: **4 failed | 4 passed**. The
three message pins went red on the first-sentence assertion, and the
describe pin went red on its new clause. The firing control (every
declared value refused) and the three dark controls stayed green.
Restored: blob `d6ada97894` == HEAD, and `git diff HEAD` is empty.
- **The absence half.** `scripts/ablation-replace.mjs` appended "Move
the value to `currencyConfig.precision` instead." to the new message.
Anchor 1 → 0, blob `d6ada97894` → `017fdba420`. Result: **3 failed | 5
passed**. All three failures read "not to match
/currencyConfig|precision/", and the describe pin and every control
stayed green. Restored: blob == HEAD, and `git diff HEAD` is empty.
## Test pins of the old remedy, reversed
A repo-wide grep finds the old remedy pinned in one file only,
`packages/spec/src/data/field-currency-scale-refused.test.ts`. It had a
message `toContain` on the other key and a control named "the remedy
target parses". Here is what replaces them:
- One helper asserts the message's first sentence verbatim, the two
ruled clauses, and that the message names neither `currencyConfig` nor
`precision`. It runs on all three firing paths: the designer shape, the
shape beside a `currencyConfig` block, and the `Field.currency()` +
`ObjectSchema` path.
- The control is now "following the remedy parses". It takes each
refused shape, deletes `scale`, adds nothing, and the result is
accepted.
- The describe pin asserts the new clause and the absence of
`currencyConfig`.
- `packages/spec/src/data/currency-precision-iso4217.test.ts:293` names
that key only as `CurrencyConfigSchema`'s ISO-contradiction issue path.
It is not a remedy pin and is unchanged.
## `currencyConfig` hits that remain (`git grep` on HEAD `40ef043003`,
unchanged at `d7740c324e`)
- **In the branch's added lines** (`c8399867b8..HEAD`): 7 hits. None
names that key as a remedy or as a decimal-places carrier.
- The changeset's FROM → TO row 2 shows a field that declares a
`currencyConfig` block. Its fix is still the deletion.
- `field-zoo.object.ts:53` is in the diff only because `scale: 2` was
deleted from that line. Its `currencyConfig: { …, precision: 2 }` is
`origin/main`'s, unchanged.
- `field-currency-scale-refused.test.ts` has 5 hits: two absence
assertions, one test title, and two fixtures with a `currencyConfig`
block and no `precision` (the firing case and the remedy-follow
control). Round 3 added none.
- **In the touched files, pre-existing** (the same count on `c8399867b8`
and HEAD):
- `fields.mdx` 1, `types.mdx` 2 and the three reference pages 2 each.
The reference hits are generated from `CurrencyConfigSchema`.
- Showcase `account.object.ts` 2, `field-zoo.object.ts` 1.
- `field.test.ts` 34 and `field.zod.ts` 10: the `CurrencyConfigSchema`
definition and tests, the ISO check, and the
`currency`-is-not-a-field-key refusal.
- `registry.ts` 1, in another entry.
- These stay because this PR did not write them. The key's own
disposition is ruling 乙 item 3's first finding, for the `domain:spec`
seat.
## Test fixtures re-judged (round 1)
These fixtures pinned a currency field with `scale`, or `max_scale` on
currency:
- `packages/spec/src/data/field.test.ts`: "should accept **number**
field with precision and scale" spelled `type: 'currency'`. It now
spells `number`, a spelling change only.
- `packages/spec/src/data/object.test.ts`: the account fixture's
`annual_revenue` lost `scale: 2`.
- `packages/spec/src/data/field-scale.test.ts`: the resolver's "declared
scale wins" example moved from `currency` to `slider`.
- `packages/objectql/src/validation/record-validator.test.ts`: the
#19320 CONTROLS loop dropped `currency`. A new #19629 block holds the
three ruled pins, and its header now cites ruling 乙 for the
unconstrained write allowance.
-
`packages/services/service-automation/src/flow-field-expression-scale.integration.test.ts`:
the #11060 oracle needs a live `scale` gate, so its `total` field moved
from `currency` to `number`.
-
`packages/drivers/driver-sql/src/sql-driver-external-unprovisioned-sort-anchor.test.ts`
and `packages/metadata-core/test/injected-column-provenance.test.ts`
mirror the showcase external customer. Both lost `scale: 2`.
## Changeset
`.changeset/19629-currency-scale-retired.md` sets `@objectstack/spec:
minor` and `@objectstack/objectql: minor`, with a **BREAKING** banner.
Per AGENTS.md, `Clause-②: no (narrowing)` is breaking, and
`check-changeset-no-major` refuses `major`. Round 2 reworded it to
ruling 乙:
- Its remedy sentence and FROM → TO table now prescribe deletion only.
- Its write sentence says the allowance stays unconstrained.
- Its console bullet says both faces derive from the currency in the
console this release bundles, because of the landing order above.
Round 3 added one sentence to its `@objectstack/spec` paragraph, because
the form change is visible in Studio: "Studio's object editor no longer
offers `scale` on a currency field: the fields grid of the `objectForm`
this package registers in `METADATA_FORM_REGISTRY` now shows it only for
`number` and `percent`." It names no key to carry the value, so it holds
under ruling 乙.
It carries the ADR-0087 marker `registered
field-currency-scale-refused`. `check-adr-0087-registration` reads
"`[BREAKING+bang+clause-②-narrowing]` registered
field-currency-scale-refused". The test-only packages (`driver-sql`,
`metadata-core`, `service-automation`) ship nothing that changed, and
the examples are private.
## Acceptance notes
- `docs/qa/platform-checklist/areas/records-forms.json`: the field-zoo
fixture line still reads "f_currency scale 2". Its `knownGaps` text,
which says `scale` is not enforced on write, has been stale since #7501.
This is checklist-owned text and is left for that seat.
- Four documentation YAML examples keep `precision: 18` on a currency
field (`schema.mdx` ×3, `types.mdx`). They are meant as DECIMAL(18,2)
total digits, but the pinned edit widget reads field-level `precision`
on currency as fraction digits. This predates the PR. It is the surface
of ruling 乙 item 3's second finding.
- `data-modeling/fields.mdx` ("Currency Configuration") and
`protocol/objectql/types.mdx` show `currencyConfig: { precision: 2, … }`
as a currency's configuration. This predates the PR and is the surface
of ruling 乙 item 3's first finding.
- `FieldSchema`'s alias table renames `decimals` / `decimalPlaces` to
`scale`. On a currency field that rename now leads to this refusal, and
its remedy tells the author to delete the key.
- hotcrm declares `scale: 2` on a currency quote field (hotcrm#1206,
cited by the flow oracle). That becomes a refused parse downstream, and
the migration entry prescribes the deletion.
- objectui#10221's title still says "derive the summary footer's
fraction digits from `currencyConfig.precision` / ISO minor units",
which is ruling B's wording. Under ruling 乙 only the ISO half holds.
Rewording that card belongs to the `domain:ui` seat.
- Round 3 sweep: `CurrencyConfigSchema` (`field.zod.ts:420`) accepts
`currencyConfig: { scale: … }` and renames it to
`currencyConfig.precision`, the key #19992 records as read by nothing.
This predates the PR and is not `FieldSchema.scale`; it goes wherever
#19992's enforce-or-remove decision takes that key.
- Round 3 sweep: the field editor form's `precision` row
(`field.form.ts:78`) is shown on currency with the help text "Decimal
places (e.g., 2 for $10.50)", while `FieldSchema.precision`'s describe
(`field.zod.ts:1211`) says "Total digits" and `objectForm`'s own
`precision` row says "Total digits". That is a `precision` row, which
this PR does not touch; it is the spec-side neighbour of
objectstack-ai/objectui#10276.
- Round 3 sweep: `numeric-column-representation.ts:49-52` records a
write-seam measurement in which a `currency` field declaring `scale: 2`
was refused. After this PR the seam no longer reads `scale` on currency,
so the docblock describes a past reading. It is an internal comment, not
an offer, and it is left alone.
## Gates, on HEAD `d7740c324e`
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` derived **120** families from this worktree. Every one was
run with its exit code captured before any pipe, and **all 120 exited
0**. The `--ran` reconciliation read: "120 derived famil(ies) accounted
for — 120 run, 0 NOT-MEASURED (a DERIVED zero — all 120 recorded an exit
code and none of them is 3)". The derivation warned of a stale tree:
`origin/main` `e8f163fc3a` is 23 commits past the merge base, and 18
derivation inputs changed in that range (among them
`.github/workflows/lint.yml` and `package.json`). CI runs the PR's merge
ref with the current copies.
- `pnpm --filter @objectstack/spec check:generated`: "All 15 generated
artifacts are up to date".
- `check:i18n`: "OK (9 package(s) — all bundles in sync, no undeclared
authoring keys)". `check:nul-bytes`: OK, no raw ASCII control bytes.
- `check-changeset-no-major`: no `major` bump. The level axis reads this
PR body, so it is NOT MEASURED locally.
- CI on `d7740c324e`, read at 2026-09-24T18:25Z: 35 check-runs, 33
`success` and 2 `skipped` (`Console Pin Gate`, `Packed-tarball smoke
(opt-in)`), none failed. All seven required contexts and `Check
Changeset` read `success`.
- Lint was narrowed to the diff and was not run repo-wide. `eslint
--no-inline-config --format json` over the 25 changed `.ts`/`.mjs` files
(`c8399867b8..HEAD`, round 3 adds `object.form.ts`) reported 25 files, 0
errors, 0 warnings and no ignore notices. The narrowing holds because
`eslint.config.mjs` never enables type-aware linting (its own comment at
lines 326-328: no `parserOptions.project`, no typed rules), so this diff
cannot move any untouched file's verdict. The full `pnpm lint` belongs
to CI.
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: Claude <noreply@anthropic.com>scale from the currency field type — refused at parse, no longer enforced on writes (#19909)1 parent 3557f85 commit 5b9402d
37 files changed
Lines changed: 573 additions & 63 deletions
File tree
- .changeset
- content/docs
- concepts
- data-modeling
- protocol
- kernel
- objectql
- references
- data
- system
- examples
- app-crm/src/objects
- app-showcase/src/data/objects
- external
- packages
- drivers/driver-sql/src
- metadata-core/test
- objectql/src/validation
- services/service-automation/src
- spec/src
- data
- migrations
- entries/semantic
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
118 | 118 | | |
119 | 119 | | |
120 | 120 | | |
121 | | - | |
122 | 121 | | |
123 | 122 | | |
124 | 123 | | |
| |||
426 | 425 | | |
427 | 426 | | |
428 | 427 | | |
429 | | - | |
430 | 428 | | |
431 | 429 | | |
432 | 430 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
450 | 450 | | |
451 | 451 | | |
452 | 452 | | |
453 | | - | |
454 | 453 | | |
455 | 454 | | |
456 | 455 | | |
| |||
515 | 514 | | |
516 | 515 | | |
517 | 516 | | |
518 | | - | |
519 | 517 | | |
520 | 518 | | |
521 | 519 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
| 65 | + | |
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
436 | 436 | | |
437 | 437 | | |
438 | 438 | | |
439 | | - | |
440 | 439 | | |
441 | 440 | | |
442 | 441 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
290 | 290 | | |
291 | 291 | | |
292 | 292 | | |
293 | | - | |
294 | 293 | | |
295 | 294 | | |
296 | 295 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
117 | | - | |
118 | 117 | | |
119 | 118 | | |
120 | 119 | | |
| |||
161 | 160 | | |
162 | 161 | | |
163 | 162 | | |
164 | | - | |
165 | 163 | | |
166 | 164 | | |
167 | 165 | | |
| |||
291 | 289 | | |
292 | 290 | | |
293 | 291 | | |
294 | | - | |
| 292 | + | |
295 | 293 | | |
296 | 294 | | |
297 | 295 | | |
| |||
383 | 381 | | |
384 | 382 | | |
385 | 383 | | |
386 | | - | |
387 | 384 | | |
388 | 385 | | |
389 | 386 | | |
| |||
914 | 911 | | |
915 | 912 | | |
916 | 913 | | |
917 | | - | |
918 | 914 | | |
919 | 915 | | |
920 | 916 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
28 | 27 | | |
29 | 28 | | |
30 | 29 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| |||
0 commit comments