Skip to content

chore(spec): regenerate the api-surface baseline for the percent-scale exports (#4442) - #4523

Merged
os-zhuang merged 2 commits into
claude/percent-scale-3136from
claude/pr-4442-fix-5o08wm
Aug 1, 2026
Merged

chore(spec): regenerate the api-surface baseline for the percent-scale exports (#4442)#4523
os-zhuang merged 2 commits into
claude/percent-scale-3136from
claude/pr-4442-fix-5o08wm

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Fixes the failing TypeScript Type Check job on #4442. Targets that PR's branch, so merging this turns #4442 green in place.

What was red

Every job on #4442 passed except TypeScript Type Check, and that job did not fail on a type error — all 117 turbo typecheck tasks, the four examples, and downstream-contract were clean. It failed on its last step, pnpm --filter @objectstack/spec check:api-surface:

  ./data
    + PercentScale (type)
    + PercentScaleFieldMeta (interface)
    + emptyGroupValueFor (function)
    + percentScaleOf (function)

@objectstack/spec public API changed: 0 breaking (removed/narrowed), 4 added.
If intentional, run `pnpm --filter @objectstack/spec gen:api-surface` and commit the updated snapshots.

api-surface.json is a committed snapshot of every export reachable from a @objectstack/spec entry point, and the gate fails whenever the built surface and that list disagree — in either direction. That is the point: it makes an unintended public-API change impossible to land silently. #4442 added four exports to ./data and never refreshed the baseline, so the gate did exactly its job.

What lands

packages/spec/api-surface.json — regenerated. The additions are deliberate: percentScaleOf is the single place the percent-scale question is answered, emptyGroupValueFor states which aggregates have an identity over the empty set, and the Console half (objectui#3140) consumes the percentScale annotation they produce. The report itself says 0 breaking — nothing removed, nothing narrowed, so no downstream consumer loses anything. Four lines, matching the four names CI listed:

+    "PercentScale (type)",
+    "PercentScaleFieldMeta (interface)",
+    "emptyGroupValueFor (function)",
+    "percentScaleOf (function)",

Generated by pnpm --filter @objectstack/spec gen:api-surface, not hand-edited. api-surface-signatures.json came back byte-identical — no factory signature moved — so it is not in the diff.

An empty-frontmatter changeset. The first push turned Check Changeset red: the gate requires every PR to add a .changeset/*.md, counted by diffing against the PR base rather than globbing the directory (in RC pre-mode changeset version retains consumed files, so a global count can never go red). An empty changeset is the sanctioned "this PR releases nothing" declaration, and that is the honest answer here — api-surface.json is a build-time snapshot the gate diffs against, not shipped code, and the four exports it records already ship under dataset-percent-scale-chain.md on the base branch. Declaring a bump would double-count that same release. check-changeset-no-major.mjs passes for the same reason: no bumps declared at all.

Verification

Check Result
spec check:api-surface public API surface + factory signatures unchanged ✓ (was exit 1)
spec typecheck (tsc --noEmit) clean
spec percent-scale + aggregation-policy tests 12 passed
service-analytics query-dataset + granularity-postprocess tests 41 passed
check-changeset-no-major.mjs exit 0
merge against current main (fd3013a) clean — no conflicts

Note on CI scope: ci.yml triggers only on PRs whose base is main, so the TypeScript Type Check job carrying the api-surface gate does not run on this PR — it re-runs on #4442 once this merges. The gate was verified locally against a real spec build.

main has moved 3 commits since #4442 was opened; the branch still merges without conflict, so no rebase is needed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S9TVFwXGsXqR3SD5e2qAU8

…e exports

`check:api-surface` is a snapshot gate: every export reachable from a
`@objectstack/spec` entry point is listed in `api-surface.json`, and the
check fails when the built surface and the committed list disagree — in
either direction. It is what makes an unintended public-API change
impossible to land silently.

The percent-scale work added four exports to `./data` —
`PercentScale`, `PercentScaleFieldMeta`, `percentScaleOf` and
`emptyGroupValueFor` — without refreshing the baseline, so the gate
reported them as 4 unrecorded additions and failed the TypeScript Type
Check job. They are additions, deliberately: `percentScaleOf` is the
answer-in-one-place the service reads, and the renderer half of
objectui#3136 consumes the annotation it produces. Nothing was removed
or narrowed, so this is not a breaking surface change.

Regenerated with `pnpm --filter @objectstack/spec gen:api-surface`;
the diff is exactly those four lines. `api-surface-signatures.json`
is untouched — no factory signature moved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S9TVFwXGsXqR3SD5e2qAU8
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 1, 2026 4:16pm

Request Review

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/claude/percent-scale-3136 → pass the list as args.docs.

The changeset gate requires every PR to add a `.changeset/*.md`, counted
by diffing against the PR base rather than globbing the directory — in RC
pre-mode `changeset version` retains consumed files, so a global count can
never go red. This PR added none and the gate failed, correctly.

An empty-frontmatter changeset is the sanctioned "this PR releases
nothing" declaration, and that is the honest answer here. `api-surface.json`
is a build-time snapshot the `check:api-surface` gate diffs against, not
shipped code — regenerating it changes no runtime behavior and publishes
no new API. The four exports it now records already ship under the
percent-scale changeset on the base branch, so declaring a bump here would
double-count that same release.

`check-changeset-no-major.mjs` is satisfied for the same reason: an empty
changeset declares no bumps at all, least of all a `major`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S9TVFwXGsXqR3SD5e2qAU8
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling and removed size/xs labels Aug 1, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 1, 2026 16:17
@os-zhuang
os-zhuang merged commit bb79c30 into claude/percent-scale-3136 Aug 1, 2026
7 checks passed
@os-zhuang
os-zhuang deleted the claude/pr-4442-fix-5o08wm branch August 1, 2026 16:17
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 2, 2026
…report an empty filtered group as zero (objectui#3136) (objectstack-ai#4442)

* fix(spec,service-analytics): carry a percentage measure's SCALE on the result column (objectui#3136)

A `%` format string says how to print a number, not what scale it is on, and
the two readings collide at exactly 1 — both "100%" (a 0-1 ratio) and "1%" (one
percentage point). Renderers guessed from the value's magnitude and resolved it
the wrong way, so an SLA rate of full compliance displayed as "1.0%".

The scale was answerable from metadata all along; it just never left the
server. `derived: { op: 'ratio' }` is a 0-1 fraction by definition, and a
measure over a `percent` field has that field's scale. Both are now resolved in
the measure-column enrichment pass, next to the ADR-0053 currency chain that
already walks back to the source field for exactly this kind of display fact.

- `percentScaleOf(field)` (spec/data) — the one rule: a `percent` field stores
  a fraction unless it declares `max > 1`, matching what the edit widget
  writes. Non-percent fields get no opinion.
- `AnalyticsResult.fields[].percentScale` — 'fraction' | 'whole', absent when
  the column is not a percentage. `currency` (emitted since ADR-0053 through a
  cast) is declared on the same interface.
- `measureCurrency` → `sourceFieldMeta`, now returning `max`. The old name had
  outgrown itself: date bucketing already read `type` through it, and the
  percent chain is its third consumer.
- Showcase: a `paid_rate` ratio measure + KPI/table widgets on Revenue Pulse.
  Grouping by status pins the Paid bucket at exactly 1 — the repro value.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(spec,service-analytics): an empty filtered group is a measured zero, not missing data (objectui#3136)

A measure-scoped filter can exclude every row of a group the grid still lists,
and the database reports that by omitting the group from the supplementary
result — after the merge, indistinguishable from "never measured". For a COUNT
or a SUM it IS measured: the answer is 0.

So "0 of 12 paid" rendered as a blank cell and every ratio built on it went
null — a compliance dashboard silently dropping the row it exists to show. On
the showcase's Paid-Rate table the Sent bucket read "—/—" where the truth is
"0 / 0.0%".

- `emptyGroupValueFor(aggregate)` (spec/data/aggregation-policy) states which
  aggregates have an identity over the empty set. avg/min/max keep their null:
  there is nothing to average, and a zero there would invent a measurement.
- `queryDataset` fills it in after ALL supplementary merges, not inside the
  loop — a later measure's merge can append rows for dimension keys no earlier
  query saw, and those rows need the same fill.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(spec): regenerate the api-surface baseline for the percent-scale exports (objectstack-ai#4523)

Regenerates `packages/spec/api-surface.json` so the committed baseline records
the four `./data` exports the percent-scale chain adds — `PercentScale`,
`PercentScaleFieldMeta`, `percentScaleOf` and `emptyGroupValueFor` — plus an
empty-frontmatter changeset declaring that this releases nothing.

The api-surface gate is a snapshot check: it fails whenever the built public
surface and the committed list disagree, in either direction, which is what
makes an unintended public-API change impossible to land silently. objectstack-ai#4442 added
the exports without refreshing the baseline, so `check:api-surface` reported 4
unrecorded additions and failed the TypeScript Type Check job. Nothing was
removed or narrowed — 0 breaking.

The changeset is empty on purpose: `api-surface.json` is a build-time snapshot,
not shipped code, and the exports it records already ship under
`dataset-percent-scale-chain.md` on this branch. A bump here would double-count
that release.

* fix(showcase): translate the two percent-scale widget titles at birth

`check-i18n-coverage` failed the TypeScript Type Check job: showcase's
untranslated declared strings grew 452 → 454. The two new strings are the
Revenue Pulse widgets this branch adds — `kpi_paid_rate` ("Paid Rate") and
`table_rate_by_status` ("Paid Rate by Status") — declared with English
titles and no zh-CN, a locale the example claims to support.

This defect was always here; it was simply unreachable. The job used to die
one step earlier on `check:api-surface`, so it never got as far as the i18n
gate. Fixing the baseline uncovered it.

Translated rather than baselined. The ratchet tolerates the debt that
predates it and refuses growth, so the honest remedy for a string this
branch introduces is to translate it — and the convention is already
written down two lines above, where `showcase_chart_gallery`'s newest widget
is translated at birth while its older siblings stay frozen. Revenue Pulse's
other eight widget titles predate the ratchet the same way and are left
alone; cleaning those up is not this branch's business.

Terminology follows the existing zh-CN invoice bundle (发票 / 状态 / 付款).

Count returns to exactly 452, so `scripts/i18n-coverage-baseline.json` needs
no edit — no ratchet-down, no baseline churn.

Verified: `check-i18n-coverage` OK (12 configs, none new); `check-i18n-bundles`
all in sync; showcase `tsc --noEmit` clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S9TVFwXGsXqR3SD5e2qAU8

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: os-zhuang <jack@objectstack.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants