You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 12cc227
Browse filesBrowse the repository at this point in the historyBrowse files
docs(adr): ADR-0144 separates ruled decisions from cited context, and 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>
`currency`). It has tenant scope, no platform default and `valueDomain: 'iso_4217_currency'`. It may be unset. It is mutable and keeps no history: probe B
77
-
of the measurement round saw a change relabel every stored `dynamic` amount.
77
+
`currency`). It has tenant scope, no platform default and `valueDomain: 'iso_4217_currency'`. It may be unset. It is
78
+
mutable and keeps no history: probe B of the measurement round saw a change relabel every stored `dynamic` amount.
78
79
-**The ISO 4217 value domain exists** (`packages/spec/src/shared/value-domain.zod.ts#isValueDomainMember`). It checks
79
-
membership in `CURRENCY_FRACTION_DIGITS` (`packages/spec/src/data/currency-fraction-digits.ts#CURRENCY_FRACTION_DIGITS`). Only that table's key set is
80
-
read. Its fraction-digit values have no reader.
80
+
membership in `CURRENCY_FRACTION_DIGITS`
81
+
(`packages/spec/src/data/currency-fraction-digits.ts#CURRENCY_FRACTION_DIGITS`). Only that table's key set is read.
lines. Control: `git grep -c currencyConfig -- packages/spec/src/data/field.zod.ts` prints 13.
84
86
-**The CEL standard library is pure.** Its header says: "Nothing registered here may be handed a resolver, a lazy
85
87
getter or any other callback into the host" (`packages/formula/src/stdlib.ts`). That purity keeps
86
88
`objectstack build` byte-stable, so a formula function cannot read a rate table.
87
-
-**`CurrencyValueSchema` is still exported**, marked `@deprecated` (`packages/spec/src/data/field.zod.ts#CurrencyValueSchema`, its type `#CurrencyValue`), although
88
-
ADR-0104 D1 says it "is deleted". #27182 retires it.
89
+
-**`CurrencyValueSchema` is still exported**, marked `@deprecated`
90
+
(`packages/spec/src/data/field.zod.ts#CurrencyValueSchema`, its type `#CurrencyValue`), although ADR-0104 D1 says it
91
+
"is deleted". #27182 retires it.
89
92
-**Today's numbers are silently wrong** (from the measurement round's probes over a real ObjectQL engine; the scratch
90
93
files were run and deleted and are not re-run for this record). The probes model a record currency the way authors
91
94
do today, as a sibling text field. `sum` over a USD row of 100 and an EUR row of 100 answers `200 "USD"`. A `summary`
@@ -102,10 +105,9 @@ One named overseas port and terminal customer (2026-08) needs three things:
102
105
3. consolidate in one home currency.
103
106
104
107
In-tree author pull is zero. The measurement round counted 17 currency fields in `examples/**` at `3d9188502e`, and
105
-
none has a record currency. The hold of
106
-
2026-10-08 ended with this ruling (乙-现在: now, as an epic). The commitment, as ruled: "R1 (about 4–5 agent-days) is
107
-
the delivery the customer can rely on; R2 starts after the customer confirms the consolidation terms (home currency,
108
-
rate source, which date drives the rate)."
108
+
none has a record currency. The hold of 2026-10-08 ended with this ruling (乙-现在: now, as an epic). The commitment,
109
+
as ruled: "R1 (about 4–5 agent-days) is the delivery the customer can rely on; R2 starts after the customer confirms
110
+
the consolidation terms (home currency, rate source, which date drives the rate)."
109
111
110
112
### 3. The shapes considered
111
113
@@ -119,6 +121,8 @@ again against how Dynamics 365, Odoo, NetSuite, SAP, Salesforce and Airtable mod
119
121
| B | Dated rates and a CEL `convertCurrency()`| Rejected. It conflicts with the stdlib purity invariant. A formula is virtual and aggregates refuse it, so the converted amount can never be totalled. |
120
122
|**C′**| A′, plus `sys_exchange_rate` and a home amount computed at write and stored with its rate. No formula function. |**Ruled.** It meets all three needs. Existing aggregate readers total the stored home field without any change to the reader. |
121
123
124
+
The ruling chose C′. The reasons in the Outcome column are the analysis', not the ruling's.
125
+
122
126
Q0, where the record currency lives, had four options of its own:
123
127
124
128
-**A, a sibling code field.** Ruled.
@@ -129,7 +133,8 @@ Q0, where the record currency lives, had four options of its own:
129
133
130
134
## Decision
131
135
132
-
Every item in this section comes from the ruling. Its words are quoted wherever the reading matters.
136
+
Every decision in this section comes from the ruling, and its words are quoted wherever the reading matters. A line
137
+
that cites the design record, a workload row or a card is context for the decision above it, and names its source.
133
138
134
139
### D1 — Shape C′
135
140
@@ -151,8 +156,8 @@ pairing.
151
156
### D3 — Q1: dated rates live in `sys_exchange_rate` (letter A)
152
157
153
158
-`sys_exchange_rate { currency, rate, effective_date, source }` is a platform system object.
154
-
- In v1, rows come from manual entry and import. A provider feed is "by an app flow" that writes rows. The platform
155
-
ships no feed.
159
+
- In v1, rows come from manual entry and import. Provider feeds come "by an app flow", which writes rows; the
160
+
platform ships no feed.
156
161
- A missing rate refuses (D5).
157
162
158
163
### D4 — Q2: the home currency is `localization.currency`, locked once used (letter A)
@@ -210,9 +215,9 @@ pairing.
210
215
`skills/**`, "never a contract".
211
216
3.**"Enabled currencies" are derived, not a setting.** They are the home currency, plus every currency with a rate
212
217
row, plus the codes already used.
213
-
4.**The form pre-fills the organization's currency at the renderer, and the stored value is always explicit.**The
214
-
organization's currency reaches a new record only as a pre-filled value the user submits. The server never fills
215
-
in the code.
218
+
4.**The form pre-fills the organization's currency at the renderer, and the stored value is always explicit.**Read
219
+
plainly, the organization's currency reaches a new record only as a pre-filled value the user submits, and the
220
+
server never fills in the code.
216
221
5.**Metadata never names the home currency.** "the home field is a `dynamic`-mode currency field", so it displays in
217
222
`localization.currency`, as every `dynamic` field does.
218
223
@@ -249,7 +254,8 @@ Version Packages, and the epic body says that happens only when a pair is comple
249
254
These are outside this decision, and each would need a decision of its own. The first eight are the workload rows'
250
255
"What is not in this list", each "a capability with no pull in tree". The last comes from the design record §13.
251
256
252
-
- A CEL `convertCurrency()`. The shape rules it out (D1), and it conflicts with the purity rule in the header of `packages/formula/src/stdlib.ts`.
257
+
- A CEL `convertCurrency()`. The shape rules it out (D1), and it conflicts with the purity rule in the header of
258
+
`packages/formula/src/stdlib.ts`.
253
259
- Read-time conversion.
254
260
- A built-in provider feed (ECB or similar). An app flow writes rows instead (D3).
255
261
- N×N pair rates. Every rate is against the home currency.
@@ -267,11 +273,11 @@ D8 already excludes a switch, injected columns, fixed field names and a setting
267
273
-**The change is additive.**`record` is a new mode, `dynamic` and `fixed` keep their meaning and stored rows are not
268
274
touched. An app that never writes `record` sees no change. The two spec cards that add keys (#27184, #27191) declare
269
275
`Metadata-protocol: added`.
270
-
-**Two steps cannot be undone once used.**The home-currency lock is one. The other: an object with record-mode
271
-
amounts and a home field returns to a single currency only through a data migration (design record §13).
272
-
-**Today's relabel hazard closes where the feature is used.**Once the lock holds, a change to `localization.currency`
273
-
can no longer relabel stored amounts. An organization with no rate row and no home-amount declaration keeps today's
274
-
behaviour.
276
+
-**Two steps cannot be undone once used**(design record §13). One is the home-currency lock. The other: an object
277
+
with record-mode amounts and a home field returns to a single currency only through a data migration.
278
+
-**Today's relabel hazard closes where the feature is used**(the measurement round's Q2 recommendation). Once the
279
+
lock holds, a change to `localization.currency`can no longer relabel stored amounts. An organization with no rate
280
+
row and no home-amount declaration keeps today's behaviour.
275
281
-**Every converting write adds a rate lookup.**
276
282
-**The fraction-digit values may get their first reader.** That depends on [Open item](#open-items) 3.
277
283
-**The docs start from a true baseline.**#27158 (closed) removed the two docs claims of exchange rates and a stored
@@ -299,8 +305,8 @@ Where a source leans one way, the lean is quoted here, not adopted. This record
299
305
says money is computed in minor-unit integers or decimals, not floating point (「浮点算钱用最小单位整数或 decimal」).
300
306
Neither point is in the ruling.
301
307
4.**A home-amount declaration or a converting write while no home currency is set** (#27192, #27198).
302
-
`localization.currency` may be unset (its manifest entry says `required: false`, and there is no platform default). The
303
-
ruling locks the setting once used. It does not say what happens while the setting is unset. The sources rule out a
308
+
`localization.currency` may be unset (its manifest entry says `required: false`, and there is no platform
309
+
default). The ruling locks the setting once used. It does not say what happens while the setting is unset. The sources rule out a
304
310
silent default (design record §9: no CNY default).
305
311
5.**The unit of parameter 4** (#27185). "12 significant decimals" can mean 12 significant digits or 12 digits after
306
312
the decimal point. The precision and scale of the `rate` column follow from the choice.
0 commit comments