Repository navigation
feat(spec)!: refuse a homeAmount rateField declaring scale below 12; document CURRENCY_FRACTION_DIGITS as CLDR fraction digits - #30644
Conversation
…ocument CURRENCY_FRACTION_DIGITS as CLDR fraction digits Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
… rateField scale floor Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
…te-field-scale-floor
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3cbe1a1fb6f87c73cb6711a28417be8dc1a8ac27 && git checkout 3cbe1a1fb6f87c73cb6711a28417be8dc1a8ac27
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin af8aab1b1c4f479b9b102da9227279534b4d27cd fcb86f79a42b967c781e8ae92ab9c4e17eeb8c3e && git checkout -B drift-repro af8aab1b1c4f479b9b102da9227279534b4d27cd && git merge --no-ff fcb86f79a42b967c781e8ae92ab9c4e17eeb8c3e
node scripts/docs-audit/affected-docs.mjs --json af8aab1b1c4f479b9b102da9227279534b4d27cd
|
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P Contract reviewServed-tier: Inputs read: card #30103 body (Ruling-ref 6469382727, read on #27185: "scale 12 — twelve digits after the decimal point, total precision 24"), triage 6632541832, claim 6665552839, os-dev-report 6668122247, amendment 6668151276; PR #30644 body, its 6-file list, the net diff Check-runs on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Should-fix summary (none blocks): ④ 3 semantic entry's stored-metadata and built-artifact legs; ③ Implemented-by: VERDICT: PASS Generated by Claude Code |
… rateField scale floor's upgrade entry Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P Head What changed. The entry's (a) Older built artifacts, verified in the tree.
(b) Stored
Checks on fcb86f7 (exit codes captured before any pipe):
The container restarted twice during the run. Commands 1-85 kept their first recorded codes. Two of them ( |
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P Contract reviewServed-tier: Re-review after one patch round. Inputs read: card #30103 body and all five comments (triage 6632541832, claim 6665552839, os-dev-report 6668122247, amendment 6668151276); PR #30644 body (patched), its 6-file list, the net diff against Check-runs on Unchanged ① Derived judgments
② Semver levelUnchanged axis: ③ Boundary flags
④ Design judgment
Should-fix summary: none new. The first record's ④ 3 is closed by this delta; its other three are dispositioned by the seat (one as card #30648). No must-fix. Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P 维护者速读
席位核对ACCEPT · head
Generated by Claude Code |
Requested by Sales · project thread
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
Fixes #30103
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: none —
skills/objectstack-data/rules/field-types.md(L175-178) teachesrateFieldas a readonlynumberwith noscale, which this diff still accepts; the floor ships in the refusal text, the changeset's FROM → TO and the upgrade-guide entryhome-amount-rate-field-scale-floor.维护者速读
homeAmount.rateField指向的数字字段若声明scale小于 12(汇率的小数位,裁决 6469382727),建模时拒收,错误点名字段、下限 12 和改法;未声明scale照常通过。同时把CURRENCY_FRACTION_DIGITS与币种文档改写为 CLDR 小数位(不是 ISO 4217 最小单位),并列出实测不同的 16 个币种。os validate/保存时报错,改法一行(改成scale: 12或删掉scale);已存的记录数据不受影响。已构建的旧产物若含此类字段,加载时整份被拒,需修源后重建;sys_metadata里已存的对象行照常加载注册,启动日志打[metadata_spec_invalid],下次保存被 422 拒收,直到把 scale 提到 12 以上或删掉。回滚即撤销本 PR。packages/spec/src/data/object.zod.ts的rateField分支(新增 scale 判断);②packages/spec/src/data/currency-config-home-amount.test.ts末尾新 describe;③.changeset/30103-home-amount-rate-field-scale-floor.md。pnpm --filter @objectstack/spec exec vitest run src/data/currency-config-home-amount.test.ts,预期 38 条全过,其中 scale 4/0/11 被拒、12/14/未声明通过。What changes
refuseDishonestHomeAmount, therateFieldarm (packages/spec/src/data/object.zod.ts). After the existing target and writer checks, a rate field declaringscalebelow 12 is refused atfields.AMOUNT.currencyConfig.homeAmount.rateField. The message names the field, itsscale, the floor 12 and the fix (scale: 12or more, or deletescale). The floor is a module-privateHOME_AMOUNT_RATE_SCALE = 12citing ruling 6469382727. It restates platform-objects'EXCHANGE_RATE_SCALEbecause spec cannot import that package. A rate column shared by consistent amounts is judged once, like the readonly mark.Undeclared
scaleis accepted, and here is the reading behind it. Atorigin/main1c5cee67:packages/objectql/src/home-amount-projection.tsL38-44).numbercolumn is one exact decimal,NUMERIC_COLUMN_PRECISION 65/NUMERIC_COLUMN_SCALE 30(packages/spec/src/data/numeric-column-representation.tsL174/L181;driver-sqltable.decimal(name, 65, 30)), whateverscalethe field declares.sys_exchange_rate.rate).scaleon a non-percent numeric type declares no fixed width.resolveFieldScaleanswersundefinedfor it, and the console's number formatter then usesmaximumFractionDigits: 20. So an undeclared rate field shows all twelve stored digits.This follows from the existing field contract. It needs no choice beyond the ruling.
CURRENCY_FRACTION_DIGITSTSDoc (packages/spec/src/data/currency-fraction-digits.ts). It now opens "CLDR currency fraction digits — NOT ISO 4217 minor units" and carries a measured table of the 16 differing codes.content/docs/data-modeling/currency.mdx. The fraction-digits sentence now lists the same 16 codes.Changeset (
@objectstack/specminor,**BREAKING**, FROM → TO). It has a semantic upgrade-guide entry18.home-amount-rate-field-scale-floor.ts(dispositionregistered).The 16 codes, measured. The table's 162 entries were compared with SIX's ISO 4217 List One, published 2024-06-25: the
iso-4217-list-one.xmlthat[email protected]ships, sha2562dea9812…71b8b. The cross-read used thedatasets/currency-codescodes-all.csvactive rows (sha256c4b6829a…7407f). Both give the same set:Not comparable: XDR and XSU (ISO
N.A., table 2); HRK, SLL and ZWL are withdrawn and absent from List One. XCG is absent from the 2024-06-25 XML and equals 2 in the CSV. ANG, BGN and CUC are absent from the CSV's active rows and equal in the XML. SIX's own host (www.six-group.com) was refused by this container's egress proxy, so the list was read from those two copies. The triage's "about seventeen" included SLL. SLL is withdrawn, so no current ISO minor unit exists to compare it against.Verification
Census: in-repo
homeAmount.rateFieldtargets declaringscale< 12 — 1 found, not changedI ran
git grep -n "rateField:"over the whole tree and read every rate field definition:content/docs,skills/, objectql, cli, plugin-audit, service-analytics, service-settings, dogfood and the spec tests.examples/declares nohomeAmount.packages/objectql/src/engine-home-amount-projection.test.tsL331,invoice({ rate: { scale: 4 } }). It is an engine pin that a scale-4 rate field still stores the full rate (from PR feat(objectql): store a record-mode amount converted into the home currency on every write (multi-currency M2-2) #28302). It registers the object throughengine.registry.registerObject, which does not runObjectSchemaparse, and it stays green (below). It pins what the engine does with an object stored before this release (stored rows are kept as authored). It is outside this PR's file surface (objectql) and is left as is.Field.number({ readonly: true })) and is accepted.Pins (
ObjectStackDefinitionSchema.safeParse, the parseos validateandos compilecall)There is one new top-level
describein the existing harness filepackages/spec/src/data/currency-config-home-amount.test.ts:scale: 4is refused. The pin assertscode: 'custom', pathobjects.0.fields.amount.currencyConfig.homeAmount.rateField, the message's first sentence (field,scale: 4, floor 12), the prescription, and that the message has no tracker number.scale0 and 11 are refused at the same path.scale12 and 14 are accepted, and an undeclaredscaleis accepted.scale: 4gets exactly one issue.File: 38/38. Full
@objectstack/specsuite: 816/816 files, 25671 passed, 1 todo.Ablation
node scripts/ablation-replace.mjsreplaced the arm's condition withif (false && …). The anchor went x1 → x0 and the blob7f70cb81→c41206f1. Result: 3 red (thescale: 4, the 0/11, and the shared-column pins) and 35 green. The preservation pins stayed green. The tool restored the file: blob == HEAD7f70cb81,git diff HEADempty.Dogfood battery and consumer tests
pnpm --filter @objectstack/dogfood teston997cb02d30, after a build of the@objectstack/dogfood^...closure (exit 0): VERDICT command-exit 0, 420 passed / 3 skipped of 423 files, 3500 passed / 36 skipped of 3536 tests. No failure.homeAmountobjects: each exit captured separately, all 0: objectqlengine-home-amount-projection+home-amount-projection+home-amount-write-paths3/3 files, 73/73 (the scale-4 engine pin among them); plugin-audithome-amount-recompute-audit.integration1/1; service-analyticshome-amount-consolidated-measure18 passed / 18 skipped (PostgreSQL legs, noOS_TEST_POSTGRES_URL); service-settingslocalization-currency-lock24/24; clirecompute-home-amounts9/9.Gates on
997cb02d30(exit code captured before any pipe)pnpm --filter @objectstack/spec buildpnpm --filter @objectstack/spec check:generated(14/14 up to date,--fixnot needed)dispatch-gates --commandsderived set: 103 commandsdispatch-gates --ranreconciliationpnpm check:adr-0087-registrationregistered home-amount-rate-field-scale-floor, new here)pnpm check:doc-authoringnode scripts/check-nul-bytes.mjs--no-inline-configon the 4 changed.tsfilesSix derived commands first exited 3 (PREREQUISITE NOT MET: unbuilt dists). Each was re-run after the closure build, and that re-run is the exit recorded for
--ran:check:doc-formula-expressions,check:doc-security-posture,check:skill-examples,check:docs-transcript-drift,check:lean-entry-closure,check:dual-build-cjs-loads, all 0.check:generatedwas run at--max-old-space-size=6144(CI's figure). Under the default heap,check:test-typecheck's tsc ran out of memory: no verdict, not a finding.Acceptance notes
registered, because a FROM → TO body refusesno-migration-prescription, and every specno (narrowing)changeset in stock is registered. So the diff addspackages/spec/src/migrations/entries/semantic/18.home-amount-rate-field-scale-floor.ts, which the generated registry picks up. Nothing else outside the claimed surface is touched.Metadata-protocol: narrowed, read from the diff: the change refuses a value an author could write before (scale0–11 on the named rate field). The card body saysnone, and the claim already saysnarrowed.git grep -n -i "ISO 4217 minor unit" -- packages/spec/src ':!**/*.test.ts'gives 20 lines. They are infield.zod.tsdescribes and refusals, five ADR-0087 migration entries, andregistry.ts.template;field-types.mdxL237/L248/L596 andvalidation-rules.mdxL160 say the same. They describe how a currency amount's decimals display, and the console reads those fromIntl(CLDR). Several quote ruling 5805782503's own remedy words. Noted, not filed. carrier: domain:spec seat.HomeAmountSchema.rateField.describe()(field.zod.tsL657) does not mention the floor. It is outside this surface. The refusal carries the prescription. carrier: domain:spec seat.ObjectStackDefinitionSchemaparse at load (packages/metadata/src/plugin.ts_parseAndRegisterArtifact, a throwing.parsebefore any registration, reached fromstart), so it is refused whole and must be rebuilt; a storedsys_metadataobject row registers anyway with a[metadata_spec_invalid]line (packages/objectql/src/registry.tsregisterItem→validate→ObjectSchema.parse, caught and logged) and its next save is refused422 INVALID_METADATA(packages/metadata-protocol/src/protocol-save.ts, theobjectschema isObjectSchema). Stored data rows are unaffected.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P