Repository navigation
Commit 6704717
docs(skills): dashboards.md conditions the measure-currency chain on currencyMode 'fixed' and cites the spec describe (#20256)
Fixes #20196
Clause-②: no
## What
One comment block in `skills/objectstack-ui/rules/dashboards.md` (the
`os:check` dataset snippet under "Server-side date bucketing",
`:304`–`:308` on the base) taught the monetary measure's currency chain
as reading the aggregated field's `currencyConfig.defaultCurrency`
unconditionally and cited ADR-0053 for it. The block now reads:
> It resolves measure `currency` → the aggregated field's
`currencyConfig.defaultCurrency` (only under `currencyMode: 'fixed'`) →
the tenant `localization.currency` (`CurrencyConfigSchema`'s
`currencyMode` describe). Omit it for non-money measures (count,
avg-of-hours).
So the middle step is conditioned on `currencyMode: 'fixed'`, a
`dynamic` field falls straight to the tenant `localization.currency`,
and the citation is the spec describe (navigable from
`references/_index.md`, which lists `CurrencyConfigSchema` in
`field.zod.ts`) instead of the date/datetime ADR. The first two lines of
the block (the `currency` key, its ISO 4217 shape and the example
measure) are unchanged.
## Why
- The contract, verbatim from `packages/spec/src/data/field.zod.ts` at
the base (`:449`; `:447` on `08c8484a`): 「Currency mode. `fixed`: the
field has one currency, `defaultCurrency`. `dynamic` (the default): the
field has no currency of its own — amounts display in the tenant default
currency (the `localization.currency` setting; a plain number when none
is set) and `defaultCurrency` is not read. Neither mode is a per-record
choice: the value is a bare number either way.」
- The runtime implements exactly that chain:
`packages/services/service-analytics/src/analytics-service.ts:1863`–`:1875`
(explicit measure `currency` → `sourceFieldMeta().defaultCurrency` →
`ctx.currency`) with `plugin.ts:1153`–`:1161` relaying `defaultCurrency`
only when `currencyConfig.currencyMode === 'fixed'`; the response
contract says the same at
`packages/spec/src/contracts/analytics-service.ts:79`–`:89`. The skill
text now matches both.
- ADR-0053 is the date / datetime semantics record and never names
currency. The card is the split-out site 2 of the currency-mode family
card; #20126 remains open and carries the family's enumerating pin,
which this PR does not add (spec-lane surface).
## Line budget (the skill token ratchet had headroom 0 on this file)
`skills/**` is priced in tokens by `node
scripts/check-skills-token-ratchet.mjs` (`ceil(utf8 bytes / 4)`), and
the dispatch asked for net ≤ 0 lines and ≤ 0 tokens on the file and on
the package.
| file | before | after | ceiling |
|---|---|---|---|
| `skills/objectstack-ui/rules/dashboards.md` | 468 lines / 6252 tokens
(25006 bytes) | 468 lines / 6245 tokens (24978 bytes) | 6252 tokens
(`check-skills-token-ratchet`) — headroom 0 → 7 |
| `skills/objectstack-ui/**` hand-authored (9 files: `SKILL.md`,
`evals/README.md`, 2 evals JSON, 5 `rules/*.md`) | 2064 lines / 26213
tokens | 2064 lines / 26206 tokens | per-file ceilings; the two
`references/*.md` files are generator-owned and not ratcheted |
- The rewritten block grows from 5 lines / 376 bytes to 6 lines / 448
bytes (+72 bytes, +1 line). The dispatch's expectation that dropping
「(ADR-0053)」 alone pays for the condition did not hold: the tightest
5-line rewrite measured still exceeded the ceiling by 17 bytes, and the
wording above by 70.
- The addition is paid by **deleting content** in the same file, not by
re-wrapping: the report snippet's comment line `// drilldown defaults
true — click a cell to open the underlying records; set false to
disable.` (`:408` on the base, 100 bytes). The same file states that
fact twice in prose — `:378`–`:379` (「A `summary` / `matrix` report
(`drilldown` defaults `true`) opens the identical in-place drawer on
row/cell click」) and `:421`–`:422` (「`drilldown` (default `true`) makes
cells click-through to the underlying records」) — so nothing an author
needs is lost.
- Line wrap of the rewritten block stays at the file's ≤ 85-column
comment width; no other line is reflowed. The ceiling is not raised.
## Verification (all at head `1e5ff84a`, the only commit)
- Gate list from `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` with no paths: the change set was
derived from merge base `14ae40b0` (1 path, +3 / −3, committed 1,
working tree 0, untracked 0). It derived 23 commands (15 matched by
path, 8 whole-tree).
- Result: **23 commands, every one exit 0.** Reconciliation
`dispatch-gates --ran`: `23 derived famil(ies) accounted for — 23 run, 0
NOT-MEASURED (a DERIVED zero — all 23 recorded an exit code and none of
them is 3)`.
- The first run of `pnpm --filter @objectstack/lint run
check:doc-formula-expressions` exited 3 with `PREREQUISITE NOT MET`
(`@objectstack/formula` and `@objectstack/lint` not built); nothing was
measured in that run. Both were built under the verify lock (`turbo run
build --filter=@objectstack/spec --filter=@objectstack/formula
--filter=@objectstack/lint`, `VERDICT command-exit 0`) and the rerun
exited 0: `22 record-scoped formula example(s) across 456 files / 1383
TS blocks judged clean by @objectstack/formula`.
- Verdict lines for the gates this change touches:
- `node scripts/check-skills-token-ratchet.mjs`, exit 0:
`skills/objectstack-ui/rules/dashboards.md is 6245 tokens (ceiling 6252;
headroom 7)`; `54 authored bundle file(s) within their ceilings`.
`--self-test`, exit 0: `65 cases pass`.
- `pnpm check:nul-bytes`, exit 0: `OK (scanned 9707 text file(s) … no
raw ASCII control bytes)`.
- `pnpm check:doc-authoring`, exit 0: `16350 customer-facing string(s)
across 1093 spec sources clean`.
- `pnpm check:skill-identifier-liveness`, exit 0: `Leg 1: 457
citation(s) over 53 published file(s) checked against 108541
implementation word tokens`.
- `pnpm check:skill-frame-sync`, `pnpm check:skill-compatibility`, `pnpm
check:role-word`, `pnpm check:corpus-claim-drift`, `node
scripts/check-doc-route-spelling.mjs --advisory`, `node
scripts/check-comment-mask-corpus.mjs` (`7260 files, 0 disagree`): exit
0.
- Beyond the derived set, because the edited block sits inside an
`os:check`-marked snippet: `pnpm --filter @objectstack/spec
check:skill-examples`. Its first run exited 3
(`packages/client-react/dist holds no .d.ts declarations`; nothing
measured); after `turbo run build --filter=@objectstack/client
--filter=@objectstack/client-react` under the verify lock (`VERDICT
command-exit 0`, 34 tasks) the rerun exited 0: `259 prose examples
type-check across 3 surface(s) — every marked block parsed, so tsc ran
the SEMANTIC pass on all of them` (225 blocks on the skills + docs
surface).
- Not in the derived total, and so not measured locally: the
artifact-roster families, the wide-population families and the CI jobs
these paths schedule. CI runs them.
- `origin/main` moved two commits past the base while this ran
(`e4621867`); neither touches `skills/objectstack-ui/**`, so no merge
was made.
## Changeset
- None, and `skip-changeset` applies: the path is the published skills
catalog (`npx skills add`), not a workspace package.
- Measured: the root `package.json` is `private: true` with no `files`;
no workspace `package.json` has a `files[]` entry that reaches the
repo-root `skills/` tree (grep over every `packages/**/package.json` for
`skills` or a `..` segment: 0). Positive control:
`CurrencyConfigSchema`, a symbol the new text names, is present in 30
files under `packages/spec/dist` (spec's `files[]` starts with `dist`);
the rewritten sentence itself appears in none of spec's published paths
(`dist`, `json-schema`, `prompts`, `llms.txt`, `liveness`,
`api-surface`).
## Acceptance notes
- **Sweep of `skills/**` for the same unconditioned chain, or `ADR-0053`
within five lines of `currenc`** (read at the base `14ae40b0`, before
the edit):
- `git grep -n "ADR-0053" -- skills`: 2 hits —
`skills/objectstack-query/rules/filters.md:251` (the calendar-day rule;
no `currenc` within five lines) and the site `dashboards.md:308`. A
mechanical five-line window check pairs `ADR-0053` with `currenc` only
at the site (`:308` against `:304`–`:307`).
- `git grep -n "defaultCurrency" -- skills`: 6 lines — five in
`skills/objectstack-data/rules/field-types.md` (`:55`, `:183`, `:184`,
`:191`, `:192`), whose resolution paragraph `:189`–`:193` states the
`'fixed'` / `'dynamic'` condition across a wrapped sentence and is not a
hit, plus the site `dashboards.md:307`. `localization.currency`:
`field-types.md:192` and the site only.
- Every other `currenc` line in `skills/**` (case-insensitive, 12 files)
is a field-type table row, an example field (`Field.currency(...)`,
`type: 'currency'`, `format: 'currency'`), a generated `_index.md`
export list, or the word "concurrency" — none is a resolution chain.
- **Hit count outside the site: 0** for both criteria, matching the
dispatch's pre-read. After the edit, `ADR-0053` in `skills/**` is
`filters.md:251` alone.
- **The dispatch's token-budget assumption was falsified** (numbers in
"Line budget" above). The payment line was chosen as the one comment in
the file that restates a fact the file's prose already carries twice.
- **Observation, no card:** the runtime's own comments at
`analytics-service.ts:680`–`:694` and `plugin.ts:1129`–`:1145` and the
`packages/spec/liveness/dataset.json:115` note already describe the
conditioned chain (the liveness note was re-worded on 2026-09-27 under
the family card), so the skill text was the last teaching site with the
unconditioned form. Carrier: none.
- **Observation, no card:** `references/_index.md` for the UI skill
lists `CurrencyConfigSchema` under `field.zod.ts` with no describe text;
a reader following the new citation lands on the schema and reads the
describe there. That is the intended navigation, not a gap.
## 维护者速读(草稿)
**改了什么**:只改 `skills/objectstack-ui/rules/dashboards.md`
里一段注释。原文教「货币度量的币种:先看度量自己的 `currency`,再看字段的 `defaultCurrency`,再看租户默认」,并引用
ADR-0053。现在改成「字段的 `defaultCurrency` 只在 `currencyMode: 'fixed'`
时才算数,否则直接落到租户的 `localization.currency`」,引用改为 spec 里 `currencyMode` 的
describe 原文。
**为什么改**:spec 与运行时都已经是「只有 fixed 模式才读
`defaultCurrency`」,这段技能文字是最后一处还在教旧链的地方;AI 照着旧文字写仪表盘,会以为 dynamic 字段也会用
`defaultCurrency`,与实际显示不符。ADR-0053 讲的是日期语义,和币种无关,引错了。
**风险与代价(含回滚)**:纯文字修正,不动代码、不动 schema、不发包,无需 changeset。该文件的 token
上限本来是零余量,新增的字用删掉同文件里一行重复注释(报表片段里「drilldown 默认为
true」,正文已说过两遍)来抵,行数不变、token 少 7,上限没动。回滚就是 revert 这一个提交。同族的枚举型 pin
按卡片约定不在本 PR 加,留给 #20126(仍开着)。
**席位意见**:
**你要做的**:审阅这段注释改动,同意就在本 PR 上批准(Approve)。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01MjvgiFAmjHqsxy1XLiVYfH)_
Co-authored-by: os-steve <steve@objectstack.ai>
Co-authored-by: Claude <noreply@anthropic.com>1 parent daedf1f commit 6704717
1 file changed
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
304 | 304 | | |
305 | 305 | | |
306 | 306 | | |
307 | | - | |
308 | | - | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
309 | 310 | | |
310 | 311 | | |
311 | 312 | | |
| |||
405 | 406 | | |
406 | 407 | | |
407 | 408 | | |
408 | | - | |
409 | 409 | | |
410 | 410 | | |
411 | 411 | | |
| |||
0 commit comments