Skip to content

spec: GlobalFilterSchema gains optional object for i18n label resolution (#7804) - #7892

Merged
os-zhuang merged 10 commits into
mainfrom
claude/issue-7804-globalfilter-object
Aug 12, 2026
Merged

spec: GlobalFilterSchema gains optional object for i18n label resolution (#7804)#7892
os-zhuang merged 10 commits into
mainfrom
claude/issue-7804-globalfilter-object

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#7804

Problem

A dashboard global filter renders its field label (e.g. "Sales Channel:") and its option labels untranslated, and there was no key to fix it with: GlobalFilterSchema declared no object, and neither does DashboardSchema, so the canonical fields.<object>.<field> translation-bundle convention that lists/forms already use has nothing to resolve against. Measured in objectui#4324's implementation, and hit in production on a hotcrm-heimao dashboard.

Fix (Route A, ruled on the triage-seat comment on #7804, 2026-08-11)

Adds an optional authorable object?: string to GlobalFilterSchema in packages/spec/src/ui/dashboard.zod.ts, between field and label. When set, it names the object field lives on, and the filter's field label and option labels resolve through the same fields.<object>.<field> bundle entry lists/forms already use — zero new i18n vocabulary, one resolver path.

Deliberately independent of optionsFrom.object, which names the object dynamic options are fetched from and may differ (e.g. filtering opportunity by owner with options sourced from user).

Rejects Route B (a new dashboards.*.filters bundle node in TranslationData — duplicate vocabulary, no precedence rule) and Route C (inline I18nLabelSchema forms — orthogonal, tracked separately on objectui#4163).

Additive and optional: a filter that omits object renders exactly as it always has. Nothing that parses today stops parsing. Unblocks objectui#4324, the dashboard filter-bar renderer half already landed behind this key.

This PR is a continuation

Branch claude/issue-7804-globalfilter-object was pushed by an earlier dev session that died before opening a PR or reporting (handoff note on #7804). This session fetched the existing branch into a dedicated worktree, reviewed every commit (schema change, tests, changeset, regenerated docs/authorable-surface), merged origin/main (clean, no conflicts), and re-ran full verification from scratch — nothing here was trusted blindly.

Changes

  • packages/spec/src/ui/dashboard.zod.tsGlobalFilterSchema.object (optional string)
  • packages/spec/src/ui/dashboard.test.ts — new describe block pinning: accepts string, optional/absent (no default materializes), rejects non-string, independence from optionsFrom.object, unknown-key strictness unchanged, JSON-Schema pin (string slot, not required)
  • content/docs/references/ui/dashboard.mdx — regenerated (gen:docs)
  • packages/spec/authorable-surface/ui.json — regenerated (gen:schema)
  • .changeset/global-filter-object-i18n-7804.md — minor bump on @objectstack/spec

Verification (this session, re-run in full)

  • pnpm --filter @objectstack/spec build — green, tree clean after (generated artifacts already matched, no diff)
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit, check:scripts-typecheck, check:test-typecheck)
  • pnpm --filter @objectstack/spec test -- --maxWorkers=2379 test files / 9989 tests passed
  • pnpm --filter @objectstack/spec check:generated — all 13 generated artifacts up to date, including check:authorable-surface and check:docs
  • pnpm check:i18n (after building @objectstack/cli) — 9 packages, all bundles in sync, no undeclared authoring keys
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions — green (self-test 24/24, 22 + 9 example sites judged clean)
  • pnpm check:adr-anchors, check:changeset-gate-self-tests, check:docs-audit-scope, check:merge-driver, check:release-body, check:spec-parsed-alias, check:nul-bytes — all green

CI (ESLint job, TypeScript Type Check job, and the rest of the gate farm) has not been waited on from this session per the current reporting contract — the PM reads real gate-job conclusions before any ready-flip.


Generated by Claude Code

os-zhuangand others added 9 commits August 12, 2026 02:57
…l resolution (#7804)
GlobalFilterSchema gains an optional `object?: string` (Route A, ruled on the
triage-seat comment on #7804, 2026-08-11) so a dashboard global filter's field
label (e.g. "Sales Channel:") and its option labels resolve through the same
`fields.<object>.<field>` translation-bundle convention lists/forms already
use -- zero new i18n vocabulary, one resolver path. Rejects Route B (a new
`dashboards.*.filters` bundle node -- duplicate vocabulary, no precedence
rule) and Route C (inline I18nLabelSchema forms -- orthogonal, tracked
separately).
Deliberately independent of `optionsFrom.object`, which names the object
dynamic OPTIONS are fetched from and may differ (e.g. filtering `opportunity`
by `owner` with options sourced from `user`).
Additive optional key: nothing that parsed before stops parsing. Unblocks
objectui#4324, the dashboard filter-bar renderer half already landed behind
this key.
Also: content/docs/references/ui/dashboard.mdx and
packages/spec/authorable-surface/ui.json regenerated to match
(`pnpm --filter @objectstack/spec gen:docs`; check:generated all 13 green).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY2Q5Xto1u8YHADgrZDTnk
…ema.object (#7804)
pnpm --filter @objectstack/spec gen:docs after adding the schema key;
check:generated all 13 artifacts green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY2Q5Xto1u8YHADgrZDTnk
pnpm --filter @objectstack/spec gen:schema; check:authorable-surface green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY2Q5Xto1u8YHADgrZDTnk
…tion (#7804)
The schema-source half of the change: `object?: string` on
GlobalFilterSchema between `field` and `label`, documented as distinct from
`optionsFrom.object`. See the changeset for the full rationale.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY2Q5Xto1u8YHADgrZDTnk
New describe block: accepts string, optional/absent, rejects non-string,
independence from optionsFrom.object, unknown-key strictness unchanged,
JSON-Schema pin (string slot, not required).
pnpm --filter @objectstack/spec test: 378 files / 9954 tests passed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY2Q5Xto1u8YHADgrZDTnk
…e-match local)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY2Q5Xto1u8YHADgrZDTnk
…transcription)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY2Q5Xto1u8YHADgrZDTnk
@vercel

vercelBot commented Aug 12, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 12, 2026 11:18am

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.

@os-zhuang
os-zhuang deleted the claude/issue-7804-globalfilter-object branch August 12, 2026 11:52
os-zhuang pushed a commit that referenced this pull request Aug 12, 2026
…s-regen driver's second half
`authorable-surface/ui.json` carries `merge=os-regen`, so a merge resolves it by
taking a side and leaving it REGEN-PENDING rather than by textually splicing two
generated files. That is the driver working as designed; the half that must
follow is the regeneration, and it is not optional here — measured on the merged
tree before pushing, `check:authorable-surface` fails:
❌ authorable-surface/ is out of date (1 key(s) not recorded).
+ ui/GlobalFilter:object
The missing key is main's own, from #7892 (`GlobalFilterSchema` gains an optional
`object` for i18n label resolution). Nothing of this branch's is involved: the
regenerated diff is exactly that one line, and batch A's five declared keys were
already recorded.
Worth stating because the failure mode is quiet: `pnpm build` REWRITES this
artifact, so a `check:generated` run that happens to follow a build reports all
13 green against the file the build just fixed. Only `check:authorable-surface`
on its own, against the merged bytes, shows the drift — which is how this was
caught before the merge queue caught it.
Merged tree verified: spec 381 files / 10091 tests, lint 71 / 1932,
check:generated 13/13, check:strictness-ledger current (438 sites / 149 strip /
9 authorable — unmoved by the merge). The ledger counts and liveness counts were
regenerated too and came back byte-identical.
Part of #4001
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012NLJ8PWLdwLSyi84LHzrAx
huangyiirene pushed a commit that referenced this pull request Aug 12, 2026
Rebase round for PR #7851 (#7521) after the domain:spec os-regen landing
relay tail landed on main (#7758, #7759, #7763, #7782, #7813, #7892).
Every `merge=os-regen` generated path is taken from origin/main WHOLESALE
(`git checkout origin/main -- <paths>`, the 12 entries .gitattributes names),
so this commit is a known-good base: the `os-regen` merge driver exits 0
without conflict markers while silently dropping one side, so a clean merge is
indistinguishable from a dropped baseline. Regeneration lands as a SEPARATE
commit on top of this one, and asserts the relay PRs' entries survived.
Committed with --no-verify deliberately: the os-regen pre-commit hook wants the
artifacts regenerated into this same commit, which would mix "what main brought"
with "what my change produces" into one indistinguishable blob. The very next
commit regenerates them, so the pushed tip is current.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tmmVmCkr4QtvGKMcn5s96
huangyiirene pushed a commit that referenced this pull request Aug 12, 2026
…ee (#7521)
Step 4 of the os-regen rebase, on top of the committed merge (cbea40d) whose
generated baselines came from origin/main wholesale.
`check:generated` proved exactly 2 of 13 artifacts stale — api-surface/ and
export-origins/, both this PR's own — and the other 11 current, so main's
baselines carried across the merge intact. Regenerated only those two.
The diff is 4 pure insertions and zero removals: the four exports
managed-api-affordance.ts adds. The relay tail's entries are asserted present
in the regenerated tree rather than assumed — the os-regen driver drops a side
silently, so a clean merge is not evidence:
#7763 TranslationBundle `flows` — content/docs/references/system/translation.mdx:161
#7813 Field.number `useGrouping` — packages/spec/authorable-surface/data.json
#7892 GlobalFilterSchema `object` — content/docs/references/ui/dashboard.mdx
#7782 InvitationStatus `canceled` — content/docs/references/identity/organization.mdx
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tmmVmCkr4QtvGKMcn5s96
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:uisize/mteststooling

Projects

None yet

2 participants

@os-zhuang@claude