Skip to content

feat(spec): Field.number gains useGrouping presentation hint (#7768) - #7813

Draft
os-zhuang wants to merge 2 commits into
mainfrom
claude/issue-7768-number-usegrouping
Draft

feat(spec): Field.number gains useGrouping presentation hint (#7768)#7813
os-zhuang wants to merge 2 commits into
mainfrom
claude/issue-7768-number-usegrouping

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #7768

Problem

Field.number's only presentation-adjacent property is scale, which governs
decimal places, not digit grouping. Console number renderers construct
Intl.NumberFormat with grouping unconditionally ON, so an ordinal/identifier
integer authored as Field.number({ scale: 0, min: 1900 }) (a year) renders
2,026 everywhere it is shown. Downstream apps hit this three times
(hotcrm-heimao#35, #40, #59), each time converting the field to Field.text
to escape the comma — trading away numeric semantics (range validation,
sort-as-number, arithmetic) for a display detail unrelated to the field's type.

Ruled direction (provenance)

Option A ruled on #7768, 2026-08-11 (PM triage comment), maintainer veto
window noted and still open: add a narrow useGrouping?: boolean mapping 1:1
to Intl.NumberFormat's useGrouping. Option B (displayFormat, a broader
presentation slot) explicitly rejected as capability surface without demand
per the maintainer's #7496 norm — narrowest shape with measured pull wins.

What changed

  • packages/spec/src/data/field.zod.tsFieldSchema gains useGrouping: z.boolean().optional(), flat alongside precision/scale/min/max
    ("Number Constraints"). Docblock explains the three-valued contract:

  • Tests added to packages/spec/src/data/field.test.ts: accepts explicit
    true/false, absent stays absent (no materialized default), rejects
    non-boolean, confirms Field.number(...) threading, confirms unknown-key
    strictness is unchanged, and pins the JSON-Schema projection (boolean
    type, no default, not in required) the way
    field-autonumber-default-format.test.ts pins autonumberFormat's.

  • Regenerated: authorable-surface/ + authorable-surface.base.json +
    json-schema/ (via pnpm gen:schema) and content/docs/references/data/field.mdx
    (via the docs gate), which now list useGrouping in the data/Field: key
    set / reference table.

  • packages/spec/liveness/field.json — classified the new key planned
    (not live): it has no runtime consumer yet, objectui#4033 is the
    consumer landing next. Not authorWarn'd, per the ledger's own rule —
    unlike a speculative future phase, an author who sets this today loses
    nothing and needs no re-authoring once the objectui half lands.
    packages/spec/liveness/state-counts.md regenerated to match
    (pnpm gen:liveness-counts); check:liveness is green.

Scope note — sibling authoring surfaces deliberately NOT touched

scale/min/precision also travel into two Setup-app admin field-editor
form definitions (packages/spec/src/data/field.form.ts,
packages/spec/src/data/object.form.ts) and into ui/view.zod.ts's
FormFieldBaseSchema (per-view field override for end-user Form views). I
checked all three; none were extended. Exposing useGrouping as a Studio UI
toggle (which would also need pnpm i18n:extract across 4 locale bundles) or
as a per-view override is a UX decision the ruling did not make, and Option A
was explicitly scoped to "the number field's authorable schema" — extending
those surfaces now would be widening past the ruled direction while the
maintainer veto window is still open. Flagging as a candidate follow-up.

Renderer contract (not implemented here)

explicit hint > interim heuristic > locale default. objectui#4033 is the
consumer that reads this key and retires the interim heuristic
(scale === 0 && no currency ⇒ ungrouped).

Gate results

Local, scoped to this surface (full commands/output in the dev report
comment on #7768):

  • pnpm --filter @objectstack/spec test (full package, 378 files): 376
    passed, 1 pre-existing failure (api-methods-batch-conformance.test.ts on
    sys_api_key, introduced by fix(platform-objects,plugin-auth): give API-key revoke/restore a working product route #7769, tracked as Queue-blocking: #7769 opened update on sys_api_key without bulkapi-methods-batch-conformance fails every merge-queue (full-suite) build #7793 — not touched by this
    PR), 1 file transiently red mid-run on my own uncommitted staleness
    (build-schemas-check-mode.test.ts, re-run clean after gen:schema: 60/60).
  • pnpm --filter @objectstack/spec typecheck: clean, zero errors.
  • pnpm --filter @objectstack/spec build: clean.
  • pnpm --filter @objectstack/spec check:generated: all 13 generated
    artifacts current.
  • check:adr-anchors, check:changeset-gate-self-tests (+ real
    empty-changeset/adr-0087-registration runs against the committed diff),
    check:docs-audit-scope, check:driver-conformance, check:merge-driver,
    check:release-body, check:spec-parsed-alias, check:nul-bytes: all
    green.
  • check:i18n — skipped: needs the built @objectstack/cli (prerequisite
    this worktree doesn't carry), and this PR touches no i18n-extraction
    surface (no field.form.ts/object.form.ts/translation file changed) so
    there is nothing for it to see.
  • --filter @objectstack/lint check:doc-formula-expressions — skipped: needs
    the built @objectstack/formula package, unrelated to this schema-only
    change (no formula-expression doc content touched).

Landing

Per the claim comment, this PR is expected to touch content/docs/references/**
and joins the os-regen one-at-a-time landing relay
(#7758#7759#7763#7782). Left as draft — the PM lands it.


Generated by Claude Code

FieldSchema gains an optional `useGrouping: boolean` (Option A, ruled
2026-08-11 on #7768, maintainer veto window open) so an authored number
field can opt out of Intl.NumberFormat's digit grouping without losing
numeric semantics -- the fix for years (Field.number({ scale: 0, min: 1900 }))
rendering as "2,026" that downstream apps have worked around three times by
converting to Field.text (hotcrm-heimao#35/#40/#59).

No default is declared: absent defers to the renderer (interim heuristic
today, locale default eventually -- objectui#4033's contract, not this
package's). Threads through Field.number(...) automatically via the
existing FieldInput shape, same as scale/min.

Also: liveness ledger classifies the key `planned` (objectui#4033 is the
pending consumer); authorable-surface/data.json, field.mdx and
state-counts.md regenerated to match.
@vercel

vercel Bot commented Aug 11, 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 11, 2026 6:14pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

106 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 @objectstack/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/tenancy-modes.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 @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/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 @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/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/permissions/system-context.mdx (via packages/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/http-protocol.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/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/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.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/field-grouping-and-order.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)

7 release-owned page(s) also reference the affected code. These are read-only:

  • 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/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests tooling labels Aug 11, 2026
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 protocol:data size/m tests tooling

Projects

None yet

2 participants