Repository navigation
Commit b94a2a7
Fixes #21183
Clause-②: no
This PR writes the protocol-text half of the maintainer's ruling **A
(deferred)** on objectstack-ai/objectui#11254 (ruling record 5933283974,
batch 261 item 4, 「其他四张同意」).
The A′ paragraph of `packages/spec/src/data/field-scale.ts` stated a
rule as protocol: "a computed result over a no-fixed-width column rounds
to the widest decimal count among the values that entered it". A
server-side `sum` / `avg` does not deliver that. The diff changes one
comment and nothing else: ⛔ no schema, key, export or runtime change.
## What changes
One paragraph changes in place, in the `number` bullet of the module
docblock and in the same voice. It now says four things.
- **Which computed results the rule binds today.** Only those whose
inputs the renderer sees: the grid summary footer, which computes over
the rows it holds, and the `object-metric` tile's `min` / `max`, whose
answer is itself one of the inputs.
- **What a server `sum` / `avg` over a `number` with no declared `scale`
shows instead.** It does not get that width yet. The tile receives one
number, and `AnalyticsResultResponseSchema`'s column metadata carries
`format` / `currency` / `percentScale` and no width. The paragraph also
says what each face shows at the objectui pin.
- **The ruled end-state and its trigger.** End-state: the analytics
result reports the width, which is the widest decimal count among the
values the server read, or the declared `scale` when there is one.
Trigger: the first first-party `object-metric` tile or dataset measure
doing `sum` / `avg` over such a `number` with no `format`. A is then
built in one go.
- **The two declared channels an author has today.** One is the field's
`scale`, which the `object-metric` tile reads through
`resolveFieldScale`. The other is a `format`: the tile's own, or the
dataset measure's on a dataset-bound tile.
## Readings (each measured before writing)
1. **Spec, at base `d7d5b4f96a`.** The paragraph stated the rule with no
server-aggregate exception. `AnalyticsResultResponseSchema`'s
`data.fields[]` declares `name`, `type`, `label`, `format`, `currency`,
`percentScale` and `builtinAggregate`, and no width member. The schema
now sits at about `analytics.zod.ts:94-130`, not the card's `:94-125`.
Its content is as the card says.
2. **objectui, read at this repo's `.objectui-sha` pin `89cad75d5570`.**
- `ObjectMetricWidget.tsx`, `inferredFormat`: an authored `format` wins.
Otherwise a declared `scale` goes through `widthPattern`. With no width,
`min` / `max` take the answer's own decimal count (`ownFractionDigits`),
and `sum` / `avg` fall through to `'0,0'`. That is line 354, the same
line the card cites on `8001068b9c`. The whole-number reading is
confirmed.
- `useColumnSummary.ts`, `widestFractionDigits`: the footer rounds a
no-fixed-width `number` result to the widest decimal count among the
values it read. Confirmed.
- objectstack-ai/objectui#11375 (merge `b149617e6f`) **is** an ancestor
of the pin. The objectui sibling clone is shallow, and its first reading
answered exit 1, with the merge commit below the shallow boundary. After
the pin's history was deepened into a private ref, `git merge-base
--is-ancestor` answered exit 0, which proves ancestry on its own.
- **Where the pin differs from the card.** The card says a server `sum`
/ `avg` "still shows a whole number". That is true of the
`object-metric` tile only.
- The dataset-bound tile (`DatasetWidget`, then `formatMeasure` in
`@object-ui/core` `dataset-format.ts`) behaves differently when the
measure has no `format`. It prints an integer as it is and rounds any
other value to at most two decimals (`maximumFractionDigits: 2`).
- A field's `scale` never reaches that tile. `service-analytics` copies
only the measure's `format` into the column metadata
(`analytics-service.ts`: `if (f.format == null && m.format) f.format =
m.format`).
- The docblock says what the pin does on each face.
3. **No generated page lifts the docblock.** `check:docs` is green. The
reference pages come from `FieldSchema.scale`'s `.describe()`, which is
unchanged and makes no claim about computed results.
4. **objectui citations.** objectui is cited by file and symbol, with no
line numbers, in the historical `.objectui-sha` pin spelling.
`check:objectui-pin-citations` is green: 49 asserting citations match
the pin, and 73 historical ones are recorded.
## Changeset: none, `skip-changeset` (a measured deviation from the
dispatch)
The card and the dispatch asked for one `@objectstack/spec` `patch`
changeset, "since the docblock ships in the published types". Measured
after `pnpm --filter @objectstack/spec build`, it does not ship. A
module-level docblock is attached to no exported declaration, so it
reaches none of the paths in spec's `files[]`: `dist`, `json-schema`,
`liveness`, `prompts`, `llms.txt`, `README.md`, `src/**/*.zod.ts`,
`api-surface` and `spec-changes.json`. (`field-scale.ts` is not a
`*.zod.ts` file.)
- The new text (`binds TODAY`) is in 0 files.
- The module docblock that was already there (`What an ABSENT`, `Why a
resolver and not a Zod default`) is in 0 files.
- Positive control: `resolveFieldScale`'s own TSDoc (`The decimal places
this field displays`) is in 2 files, `dist/data/index.d.ts` and
`dist/data/index.d.mts`.
A diff that publishes nothing takes `skip-changeset` (AGENTS.md,
Post-Task Checklist step 3). The changeset was written first, in commit
`80ae4f4cb3`, and commit `97a757c216` removed it, with this measurement
in its message. To reverse: restore
`.changeset/21183-field-scale-server-aggregate-width.md` from
`80ae4f4cb3` and remove the label.
## Tests and gates (head `97a757c216`)
- `pnpm --filter @objectstack/spec exec vitest run --project local
--maxWorkers=2`: 600 files, 17684 passed, 1 todo.
`src/data/field-scale.test.ts` alone: 13 passed.
- `pnpm --filter @objectstack/spec run typecheck`: exit 0 (tsc, the
scripts typecheck and `check:test-typecheck`).
- `pnpm --filter @objectstack/spec check:generated`: all 15 artifacts
are up to date. This was taken on `80ae4f4cb3`; `97a757c216` changes
only `.changeset/`, and `check:docs` / `check:api-surface` /
`check:authorable-surface` were re-run green on `97a757c216`.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands`, with no paths, derived 73 commands. All 73 ran and 72
exited 0. `--ran` reconciliation: `73 derived, 72 run, 1 NOT-MEASURED, 0
UNRUN`.
- `check:doc-formula-expressions` and `check:lean-entry-closure` first
refused with exit 3, because their prerequisites were not built. After
`@objectstack/formula`, `@objectstack/lint` and `@objectstack/objectql`
were built, both re-ran green.
- **Lint, narrowed.** The population is read from eslint itself:
`isPathIgnored: false` for the one changed file. `eslint
--no-inline-config --format json` on it: 1 file, 0 errors, 0 warnings.
Invariance: the config resolved for this file sets `parserOptions` to
`ecmaVersion` / `sourceType` only, with no `project`, so no type-aware
linting runs and this diff cannot move a verdict on an untouched file.
The repo-wide `pnpm lint` is CI's run.
## NOT MEASURED
- `check:dual-build-cjs-loads`: exit 3, PREREQUISITE NOT MET. It needs
every workspace package built (`pnpm build`), which does not fit this
container's foreground budget. Invariance: the diff is a comment that
reaches no emitted file (measured above), so no package's CJS output
differs from base. CI runs it.
## Acceptance notes
- **The dataset-bound tile's `min` / `max`.** Over a no-fixed-width
`number` with no measure `format`, they also round to at most two
decimals, through the same `formatMeasure` arm. So "a `min` / `max`
keeps its own decimal count" holds on the `object-metric` tile only, and
the docblock names only that tile's `min` / `max` as bound. Not filed:
there is no producer. No example dataset or metric in this repo
aggregates `min` / `max` (grep on `d7d5b4f96a`), and no carrier touches
`formatMeasure`. When A is built, a width on the analytics column would
cover this face too.
- **Trigger reading, on `d7d5b4f96a`.** All 11 dataset `sum` / `avg`
measures in `examples/` carry a `format`. The one `object-metric` `sum`
KPI (`app-showcase` `command-center.page.ts`, `cc_k6`) carries `'0.0a'`.
Within these spellings, no first-party producer has fired the trigger.
- **objectui sibling checkout.** The pin's history was deepened into a
private ref, `refs/os-dev/issue-21183/pin`, for the ancestry reading,
and the ref was deleted afterwards. objectui's working tree and its
branch refs were not touched.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 086ad0a commit b94a2a7
1 file changed
Lines changed: 25 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
72 | 96 | | |
73 | 97 | | |
74 | 98 | | |
| |||
0 commit comments