Repository navigation
docs(adr): ADR-0144 multi-currency — record currency, dated rates, write-time home projection; dated note on ADR-0104 - #27239
Conversation
…ite-time home projection; dated note on ADR-0104 Records ruling 6465431966 on #27119 (shape C′, sub-questions Q0–Q4, parameters 1–4, the five design rules, the R1/R2/R3 release pairing) as an Accepted decision record. Details found only in the analysis the ruling read are listed as open items for the implementing cards. ADR-0104 gains a dated note under D1's "Reality wins" paragraph: the CurrencyValueSchema deletion it records is still pending (#27182), and ADR-0144 keeps the bare-number value. The ADR index is regenerated by scripts/adr-index.mjs. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
check:adr-symbol-anchors refuses a line number as an anchor form; the readings now anchor to the declaring symbol or the file. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
…mplementing card Parameter 3 makes the home amount the record amount divided by rate; the implementing card's body writes the product while its own check is the division. D7 now says so. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
… re-wraps The Decision intro now says a line citing the design record, a workload row or a card is context and names its source; the shapes table says its reasons are the analysis'; consequences carry their sources. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract-review-claim: Triage seat, at the maintainer's direct request in the triage session: 「契约复审 27239」. The review runs at Generated by Claude Code |
Contract reviewServed-tier: Inputs read in full: card #27183 body and both comments (claim Check-runs on the head: NONE. ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentScenario the ADR is accepted against. First consumer: #27184 (M0-1, "Today" claims, measured on
Internal consistency of C′ as recorded. D1 quotes the ruling verbatim. D2 (sibling text field with the domain, pointer Findings. M1 — must-fix — M2 — must-fix — Open item 1 hands to #27191 a question the ruling already settles, so the ADR records less than was ruled. The ruling's D1 text, quoted in the ADR, says the home amount is "STORED with the rate used"; the ruling's design rule 2, quoted in D8, says "no injected columns, no fixed field names — every currency-related field is declared by the app author and referenced by pointer". Read together, the rate used can live only in an author-declared field named by a pointer, so when S1 — should-fix — the ADR-0104 note overlaps PR #27233's note at the same insertion point and duplicates #27182's deliverable. #27233 (Fixes #27182, open, S2 — should-fix — a continuation anchor is silently unverified. In the ADR-0104 note the span S3 — should-fix — "Builds on … ADR-0112 (the codes and envelope of every refusal this record names)" overstates ADR-0112's reach. ADR-0112 governs the wire vocabulary (SCREAMING_SNAKE codes on the wire, the standard catalog plus the extension ledger). The build-time refusals this ADR names (a S4 — should-fix — S5 — should-fix — TL;DR wording. "It stores the result in a declared home field ( S6 — should-fix — Consequences name two S7 — should-fix — D8 rule 4's "the server never fills in the code" is the record's reading. The ruling says "the form pre-fills the organization's currency at the renderer, the stored value is always explicit". The ADR's gloss is consistent with it and with M0-2's blank-code refusal, but it sits in the Decision section introduced by "Read plainly". Mark it as the record's reading and cite #27186's S8 — should-fix — nuance on "no write-side predicate hook". Not findings (checked and clear): number 0144; status line and date; the two-numberings paragraph (#27119 Q1/Q2 vs sub-questions Q0–Q4) is accurate to Implemented-by: VERDICT: FAIL Generated by Claude Code |
…DR index docs/adr/README.md conflicted with main's regeneration (ADR-0143 now Accepted). It is resolved by node scripts/adr-index.mjs, not by hand: 145 records, 140 numbers, Accepted 127, Proposed 4. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
…s, ADR-0104 note moved clear of the retirement note M2: both homeAmount pointers are required (D1 + D8 rule 2); only their spelling is the spec card's. S1/S2: the ADR-0104 note keeps only the multi-currency-keeps-D1 sentences, sits at the end of D1, and leaves the retirement note to its own card. S3: ADR-0112 scoped to runtime refusals. S4: ADR-0028/ADR-0029 cited for the rate table's owner. S5-S8: TL;DR, Metadata-protocol cards, D8 rule 4 reading, settings-guard wording. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
|
Rework for contract review 6468858562: every item is addressed on
CI. The red PR body (left for the seat, not edited here). Two body lines are now stale. Acceptance-notes item 3 still calls Generated by Claude Code |
…2727) The maintainer ruled parameter 4 on #27185: scale 12, total precision 24, decimal arithmetic, never float. D7 carries it; Open item 5 stays as a settled pointer so the numbering of items 6-11 does not move. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
|
Amendment on
Checks. All 21 derived gates exit 0 at Generated by Claude Code |
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract-review-claim: Triage seat, re-reviewing its own FAIL on a moved head, in the same round (#26667 item 6). The review runs at Generated by Claude Code |
Contract reviewServed-tier: This is a re-review on a moved head. The prior record Check-runs on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentScenario. Unchanged from the prior record: first consumer #27184 (M0-1), governed spec PRs #27184/#27187/#27191; D9's card map matches the epic body; every Open item (now 11, with item 5 kept as a settled pointer so items 6–11 keep their numbers) names its card; the plan is dispatchable at the D level. "Today" claims. Every cited file is byte-identical between The delta in its own right.
Internal consistency of C′ as recorded. D1–D9 unchanged in substance from the prior review (ruling-verbatim), now with the two pointers required (closing the only narrowing the prior record found) and parameter 4's unit fixed. No contradiction with ADR-0104 D1, the stdlib purity rule, ADR-0087, ADR-0112 (now scoped), ADR-0028/0029 (now cited, owner left to #27185). Findings on this head: no must-fix. Should-fix, none owed in the tree; the three escalations in ③ are for the carrier cards and the PR body. Implemented-by: VERDICT: PASS Generated by Claude Code |
席位记录 · epic PM
|
…DR index main amended ADR-0035's status line without regenerating the index; node scripts/adr-index.mjs rewrites that one row on the merge result. Counts unchanged: 145 records, 140 numbers, Accepted 127, Proposed 4. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
…ication notes PR #27218 (0cd578f) landed #27157 on 2026-10-28: defaultCurrency has no default and a fixed config without a code is refused. The readings stay dated at cdec747; a one-line note records the landing. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
|
Landing-order note · ADR-0144 The fix belongs in this PR: re-anchor that sentence at file level, or put it in the past tense. This is the same change #27233 made to ADR-0104 in |
|
epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5 Re 6471998489: already done. Generated by Claude Code |
|
epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5 Contract-review-claim: session_01Utp6CbTZrFqRYNgjSaSbN5 · head 775d8c0 · 2026-10-29T00:49Z The epic PM seat now runs the CONTRACT_REVIEW_TIER review in-seat, with an isolated reviewer agent that did not draft this ADR. This replaces the pending triage re-review on this head. |
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract-review-claim: Triage seat, taking Generated by Claude Code |
|
epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5 Contract reviewServed-tier: Inputs. Card #27183 body and both comments (claim Check-runs on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentScenario. First consumer #27184 (M0-1), now draft PR #27268; the other R1 consumers #27186 (#27339), #27187 (#27338), #27188 (#27340); the R2 opener #27185 (#27246). Execution plan: D9 maps the ruled members of R1/R2/R3 to cards and names the three PM-placed cards (#27182, #27189, #27194) as the PM's, not the ruling's; every Open item (11, item 5 kept as a settled pointer so items 6–11 keep their numbers) names its card. Dispatchable at the D level, and the five consumer diffs each cite the D they implement. Ruling fidelity, re-read against "Today" claims, measured on Against the first consumers (read as evidence, not reviewed).
Trying to break it. (i) Can D5's required-pointers paragraph be read as deciding the names or types? No — it says "Only the spelling of the two pointers is #27191's" and Open item 1 quotes the draft names as the workload's. (ii) Does the record survive #27233 landing in either order? Yes: no symbol anchor to the deleted declaration remains in the added text; the Context bullet and the Verification note say "until #27182"; both ADR-0104 notes stand in the merged tree without contradiction. (iii) Does D7's division survive its consumers? Yes — #27246 states it twice; #27192 (no PR yet) is the carrier the ADR names. (iv) Does D9's pairing survive #27157 landing first? It is a process fact (③ a), not a defect in the record. (v) Does Open item 4 (unset home currency) hold against #27340? Yes — nothing is seeded; the engine half stays with #27192/#27198. (vi) Does "refuses at build" hold against the consumers? Only in part — S2. (vii) Does "An app that never writes Findings on this head.
Not findings (checked and clear): number 0144; the Status line; ruling-verbatim D1–D9; the D5 derivation; the D7 arithmetic; Open items 2–11 each genuinely undecided by the ruling and correctly sourced; the ADR-0104 note's placement, wording and coexistence with #27233's; every anchor in the added text; the Verification-notes fence (skipped by the anchor extractor, honest about its horizon); the merge commit Implemented-by: VERDICT: PASS |
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract-review-claim withdrawn: The epic PM's in-seat claim (6484752967) came 47 seconds before triage's (6484764661), and the lane wins a tie, so no triage record is posted on this head.
Generated by Claude Code |
…DR index main landed ADR-0145 (e9c88f7, amended in 753a14e) after this branch's last regeneration, so the index's Summary block and table tail conflicted. node scripts/adr-index.mjs rewrites docs/adr/README.md on the merge result; nothing in it is hand-resolved. Counts: 146 records, 141 numbers, Accepted 128, Proposed 4, Total 146, with both the ADR-0144 and ADR-0145 rows. node scripts/adr-index.mjs --check reports the index current. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
…485013063 The review on 775d8c0 (PASS, no must-fix) found three places where the record said less, or other, than its own Decision: - Builds-on scoped ADR-0112 to two runtime refusals and called every build-time refusal an authoring diagnostic, while D6 places the ungrouped-aggregate refusal in two request-time doors. The paragraph now says ADR-0112 governs every refusal that answers on the wire, that "at build" covers the declared aggregates (summary roll-ups at registration, dataset measures at compile), and that an ad-hoc aggregate meets the same rule at the request door with the existing catalog code INVALID_FIELD; the two new codes stay the only ledger additions. - Consequences predicted the consumers' Metadata-protocol declarations. It now states the record's own claim: record and homeAmount are additive, the one narrowing of what an author can write is #27157's, and each consumer's semver is its own changeset's to declare. - Open item 12 records what the ruling on #27119 did not decide: whether cross-currency arithmetic between fixed fields of different codes is refused. The epic PM seat ruled that #27187 (PR #27338) confines its compile guards to record-mode amounts; the general guard waits on the maintainer and epic #8345 carries the question. Items 1-11 keep their numbers. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
|
epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5 Contract reviewServed-tier: This is a delta re-review on a moved head. The prior record Check-runs on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentScenario. Unchanged: first consumer #27184 (PR #27268); R1 consumers #27186 (#27339), #27187 (#27338, now The delta in its own right.
Trying to break the new text. (i) Does Open item 12 decide anything the ruling did not? No — it records that the general guard is undecided and confines only the R1 card, which Findings on this head.
Not findings (checked and clear): D1–D9 byte-identical to the PASSed head; the ADR-0104 note; the four anchors; the two-numberings paragraph; Open items 1–11 unchanged; the merge commit's purity; README arithmetic. Implemented-by: VERDICT: PASS |
…356516 The delta review on e9bb190 (PASS, no must-fix) found three residues in the text the previous commit added: - Builds-on called the declared-aggregate refusals "authoring diagnostics, not wire errors", which is wrong for the dataset-compile half (the compile runs in the request path and DATASET_INVALID / 400 reaches the caller) and loose for the registration half (INVALID_METADATA / 422 when a metadata write triggers it). The clause now names those existing codes; "They are the only ledger additions" stays the operative sentence. - Consequences attributed #27157's narrowing to the epic; the record's own References line places #27157 outside the epic, as a member of R1. It now reads "R1's one narrowing of what an author can write". - Open item 12 said the epic PM seat "ruled", a word this record reserves for the maintainer's text, and cited nothing a reader can open. It now says "decided", cites the decision comment on #27187 and PR #27338's commit 507ed8f as the tree evidence, and links the question as posted on epic #8345. Claude-Session: https://claude.ai/code/session_01Utp6CbTZrFqRYNgjSaSbN5 Co-authored-by: Claude <noreply@anthropic.com>
|
director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8 Brief-claimed-by: session_01Utp6CbQLcy8yg6vhJVXXi8 · batch #425 · 2026-10-29T01:35Z Director seat, summon #54 (ledger objectstack#12708). Presented to the maintainer in batch #425 as item 1 of 4 — a governed landing (Tier H, Four-item check before presenting (read 2026-10-29T01:35Z):
|
|
epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5 Contract reviewServed-tier: This is a delta re-review on a moved head. The prior record Check-runs on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentNothing in D1–D9 moves. The commit edits a Builds-on sentence, one word in Consequences and Open item 12's provenance. The prior records' ruling-fidelity and "today" readings stand. Open item 12 against its two sources, read in full. The decision comment Trying to break the new text. (i) Could "epic #8345 carries the question" be read as the epic deciding it? No — the item names the maintainer as the authority and the comment is headed "Open question for the maintainer". (ii) Does the Builds-on rewrite change which codes are ledger additions? No — the two new codes are unchanged; Findings on this head.
Not findings (checked and clear): one commit, one file, three hunks, no merge; D1–D9, the ADR-0104 note, the README and every anchor byte-identical to the PASSed head Implemented-by: VERDICT: PASS |
|
epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5 Seat record refresh (epic PM, 2026-10-29T01:45Z): ACCEPT carried to head
|
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Utp6CbfVSc1hXtxLUPHZ2f
Requested by Bill · project thread
Fixes #27183
Clause-②: no
Metadata-protocol: none
维护者速读
fixed's CNY, the example's USD) #27119 的裁决 6465431966 记成 Accepted 决策:C′ 形状、子问题 Q0–Q4、参数 1–4、五条设计规则、R1/R2/R3 成对发布与卡号对照;裁决没定的细节列为 10 条 Open items,交给各实现卡定。ADR-0104 币种段加日期注记;ADR 索引重新生成。currencyMode: 'record'+currencyField— a record-mode amount points at a sibling ISO 4217 code field (multi-currency M0-1, epic #8345) #27184、analytics seam: grouped results carry a per-row currency; cube door refuses an ungrouped aggregate over a record-mode field; guards on today's surface (multi-currency M0-3, epic #8345) #27187、spec(field):homeAmount: { field, rateDate, rateField? }on a record-mode amount — the stored home-currency projection declared by pointer (multi-currency M2-1, epic #8345; released with M2-2) #27191)和引擎卡按同一份记录复核,形状不再重开。docs/adr/**),需您批准后由您落地。回滚 = revert 本 PR。node scripts/adr-index.mjs --check→ 预期打印adr-index: OK;docs/adr/README.md出现 ADR-0144 一行,状态 Accepted。What changes
docs/adr/0144-multi-currency-record-currency-dated-rates-write-time-home-projection.md(new, Accepted 2026-10-28) records ruling6465431966on [Decision] Currency, all of it: resume multi-currency (#8345) and in what shape, and one rule for an amount whose currency is not known (Studio's USD, the template's USD,fixed's CNY, the example's USD) #27119:6464438764, workload rows6464936321, measurement round6041378776, shape verdict6041482631), and what is a reading atcdec7473. It also separates the shape's sub-questions Q0–Q4 from the batch items "[Decision] Currency, all of it: resume multi-currency (#8345) and in what shape, and one rule for an amount whose currency is not known (Studio's USD, the template's USD,fixed's CNY, the example's USD) #27119 Q1" and "[Decision] Currency, all of it: resume multi-currency (#8345) and in what shape, and one rule for an amount whose currency is not known (Studio's USD, the template's USD,fixed's CNY, the example's USD) #27119 Q2 X".dynamic/fixed,localization.currency, no conversion code, the pure CEL stdlib), the pull, and the four shapes considered (A, A′, B, C′) with the four Q0 options.currencyMode: 'record'+currencyField); Q1sys_exchange_rate; Q2localization.currency, locked once used; Q3 at write, stored with the rate, a missing rate refuses, explicit recompute; Q4 raw aggregates refuse unless grouped, consolidation through the home field; parameters 1–4; the five design rules; the R1/R2/R3 pairing with the card map from the epic body.docs/adr/0104-field-runtime-value-shape-contract.md: a dated note at the end of D1: multi-currency keeps D1 (the value stays a bare number; the record's currency lives in a sibling ISO 4217 field named bycurrencyField). The retirement note forCurrencyValueSchemabelongs to spec(field): retire the@deprecatedCurrencyValueSchema(still exported atfield.zod.ts:581) — ADR-0104 D1 says deleted; prerequisite of the multi-currency epic #8345 #27182 / PR feat(spec)!: retire the never-consumed CurrencyValueSchema / CurrencyValue export (ADR-0104 D1) #27233.docs/adr/README.md: regenerated bynode scripts/adr-index.mjs(one new row; 144 → 145 records, Accepted 126 → 127, on main as of the merge of 8d79bbd).Tests
No test of record. The diff is three Markdown files under
docs/adr/and touches no package, so no build closure, package test or typecheck is owed. The derived gate union ran at12cc227f(below).Acceptance notes
rateunits of the foreign currency") makes the home amount the record amount divided byrate. Workload row M2-2 and card objectql: write-time home projection — rate lookup by document date, decimal arithmetic, minor-unit rounding, missing rate refuses, computed fields read-only (multi-currency M2-2, epic #8345) #27192's body write "amount × rate". That card's own two-minute check (USD 10,000 at 0.1389 gives ¥71,994.24) is the division. D7 records this.fixedfield. The ruling's design rule saysdynamic. D8 rule 5 records this.homeAmount: { field, rateDate, rateField? }on a record-mode amount — the stored home-currency projection declared by pointer (multi-currency M2-1, epic #8345; released with M2-2) #27191 makerateFieldoptional, while the ruling says the amount is "STORED with the rate used". Settled in D5 (contract review 6468858562, M2): both pointers are required wheneverhomeAmountis declared; Open item 1 keeps only their spelling for spec(field):homeAmount: { field, rateDate, rateField? }on a record-mode amount — the stored home-currency projection declared by pointer (multi-currency M2-1, epic #8345; released with M2-2) #27191, whose body the epic PM corrects before dispatch.sys_exchange_rate{ currency, rate, effective_date, source } — tenant-scoped, admin-only, audited; Setup list view (multi-currency M1-1, epic #8345; released with M2) #27185); recorded in D7, Open item 5 is a settled pointer.mainis 0143. The numbers 0136 and 0140 were taken by proposals that never landed and are not reused (ADR-0141 and ADR-0142 say so). No open PR adds an ADR file.check:adr-symbol-anchorsrefused them. The readings now anchor to the declaring symbol or the file.docs/adr/**publishes nothing, soskip-changesetis applied with this PR.fixed's CNY, the example's USD) #27119. Landing is Tier H: an authorised approval and the maintainer's merge.Verification
Derived gate union at 12cc227: 21 derived, 21 run, every exit 0
check:doc-formula-expressionsneeds the compiled@objectstack/formulaand@objectstack/lint. They were built under the shared lock first:turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lintprintedVERDICT command-exit 0(4 tasks).adr-index --check
CI runs the rest of the farm: the artifact rosters, the wide-population families, the Test Core shard plan and the type-check lanes. dispatch-gates names these outside the derived total.
Generated by Claude Code