Skip to content

fix(spec): EngineAggregateOptions.groupBy declares the GroupByNodeSchema union the engine already reads (#8032) - #8236

Merged
huangyiirene merged 7 commits into
mainfrom
claude/issue-8032-groupby-declared-union
Aug 13, 2026
Merged

fix(spec): EngineAggregateOptions.groupBy declares the GroupByNodeSchema union the engine already reads (#8032)#8236
huangyiirene merged 7 commits into
mainfrom
claude/issue-8032-groupby-declared-union

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #8032

What

EngineAggregateOptionsSchema.groupBy declared z.array(z.string()) while the engine has always read the structured { field, dateGranularity, alias } bucket form on the same key (date bucketing, and the credential-aggregation guard walks both spellings) — so every correct caller had to lie to the type. The canonical union already shipped in the same package (GroupByNodeSchema in query.zod.ts; QuerySchema.groupBy uses it), making EngineAggregateOptionsSchema the one outlier face. This PR is the declaration catching up to the enforced contract — no engine/runtime behavior change.

The three landed cast sites (acceptance)

  1. packages/objectql/src/internal-fields.test.tsas unknown as EngineAggregateOptions removed from the structured-bucket credential case. Reverse-verified the case still fails for its ORIGINAL defect (see Verification, RV1).
  2. packages/objectql/src/engine-filter-array-lowering.test.ts — the whole-options cast was doing double duty: it also covered the deliberately off-contract FilterArray where this file exists to drive (its own module note says so). The as unknown as EngineAggregateOptions on the options object is gone; the remaining cast is scoped to the one slot whose contract is deliberately bypassed (where), per the file's own documented convention. groupBy and aggregations now type-check honestly.
  3. packages/mcp/src/stdio-data-bridge.ts — both casts (groupBy, aggregations) removed; @objectstack/mcp typechecks with the honest code.

Addendum item measured (bridge function: string → enum)

Pure declaration catch-up, included: the aggregate_records tool's zod schema already enforces exactly the six-name enum (and the five-name granularity vocabulary) before any value reaches the bridge, and the runtime HTTP bridge implementation types its opts parameter as any, so no accepted input changes on any path. The only behavioral delta is compile-time: a caller who read the old wide interface and passed distinct: true (silently dropped before) is now refused by tsc with the tombstone's prescription — the fix the issue thread asked for.

#4918 check:query-options-erasure ratchet

Direction observed: no movement. The ratchet holds at its exact baseline (67 non-test sites / 17 files; test surface at main's own ceiling). The two as any groupBy casts removed from engine.ts were evidently not among the rule's counted shapes, and the removed test casts were as unknown as, which the rule deliberately does not count — so the baseline needed no --update. Verified on both pre- and post-merge states.

Changesets

  • @objectstack/spec minor — the declared accept-set widens on the engine-options face (a request surface gains a declared form it always executed). Not breaking: every previously-valid payload validates byte-identically, so no ADR-0087 disposition is required (not a declared-breaking changeset).
  • @objectstack/mcp patch — interface declaration catch-up; runtime acceptance unchanged on every path; body carries the distinct FROM → TO prescription (delete the key; count_distinct is the deduplicating spelling).

Verification (all local, full farm is CI's)

Round 1 (merged main @ 30536e3): spec build/typecheck green; spec 10199 tests / 385 files passed; check:generated — exactly 1 stale (gen:docs), regenerated, gen:openapi restored after gen:schema cleanup; downstream consumers (prefix direction — dependents of @objectstack/spec): objectql 3400/192, mcp 138/13, rest 1731/103, runtime 2261/146, all typechecks green; examples validate ×3 green; gate farm green (adr-anchors, changeset-gate-self-tests, cross-package-test-inputs, doc-formula-expressions, docs-audit-scope, i18n, merge-driver, release-body, spec-parsed-alias, nul-bytes).

Round 2 (after re-merging main @ fa48973 family): spec 10199/385, objectql 3401/192 (+1 = #8206's merged test), mcp 138/13, check:generated green, erasure ratchet holds.

RV1 (guard walk, runtime) — predicted: blinding rejectCredentialAggregation's structured-bucket read turns exactly the un-cast credential case red. Observed: Tests 1 failed | 17 passed, the failing case being "rejects the flagged field as a structured {field} groupBy bucket". The case is not vacuous.

RV2 (type direction, rebuilt .d.ts) — predicted: an off-vocabulary dateGranularity: 'decade' in a compiled consumer goes red naming the enum. Observed via @objectstack/mcp typecheck: TS2345 … Type '"decade"' is not assignable to type '"year" | "month" | "day" | "week" | "quarter" | undefined' — the error text quotes the new union from the freshly built spec declarations. Note: objectql's own typecheck cannot carry this proof — its tsconfig excludes **/*.test.ts (known, margin-carrying entry in the type-check debt ledger), which is why the proof runs through the mcp seam.

Known-red on main, not this diff: check:type-check-debt reports @objectstack/service-analytics DEBT 10 → 14 (+4); the four errors reference CROSS_FIELD_OPERAND_NAMES / diagnosticIncludes — surfaces PR #8198 changed today. Filed as #8235; every PR merging today's main will see the same red until stanched.


Generated by Claude Code

claude added 4 commits August 12, 2026 19:01
…chema union (#8032)

The engine has always read structured { field, dateGranularity, alias }
buckets on this key (date bucketing, credential-aggregation guard); the
declaration said string[], so every correct caller had to cast. Catch the
declaration up to the enforced contract:

- spec: EngineAggregateOptionsSchema.groupBy -> z.array(GroupByNodeSchema),
  pin tests in both directions (structured buckets parse; plain strings
  parse byte-identically; bad dateGranularity / field-less bucket rejected)
- objectql: engine drops its own groupBy casts; the two landed test casts
  removed (internal-fields structured-bucket case now type-checks honestly;
  filter-array-lowering cast narrowed to the deliberately off-contract
  where slot)
- mcp: McpDataBridge.aggregate retyped onto the engine's own
  EngineAggregateOptions slices - closes function:string vs the six-name
  enum, dateGranularity:string vs the five-name vocabulary, and
  distinct?:boolean vs the #6815 retiredKey tombstone; stdio bridge
  compiles with zero casts

No engine/runtime behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
…pBy union (#8032)

check:generated proved exactly one artifact stale (gen:docs); regenerated
that one only. gen:openapi restored after gen:schema's cleanup (untracked,
kept for the local rest runs).

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

vercel Bot commented Aug 12, 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 13, 2026 1:19am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/mcp, @objectstack/objectql, @objectstack/spec.

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

  • content/docs/ai/actions-as-tools.mdx (via @objectstack/mcp)
  • content/docs/ai/agents.mdx (via @objectstack/mcp, @objectstack/spec)
  • content/docs/ai/connect-mcp.mdx (via @objectstack/mcp)
  • content/docs/ai/index.mdx (via @objectstack/mcp)
  • content/docs/ai/natural-language-queries.mdx (via @objectstack/mcp)
  • 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/mcp, @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 @objectstack/objectql, 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 packages/objectql, @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/environment-variables.mdx (via @objectstack/mcp)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • 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/deployment/vercel.mdx (via @objectstack/objectql)
  • 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/objectql, @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 packages/objectql, @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/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/permissions/authorization.mdx (via @objectstack/mcp, @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/mcp, packages/objectql, 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/objectql, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/mcp, @objectstack/objectql, @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/objectql, @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/mcp, @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via packages/objectql, @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/objectql, @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/mcp, @objectstack/objectql, @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.

claude added 3 commits August 13, 2026 01:01
…merge (#8032)

os-regen-merge took main's side of references/**; gen:docs re-applies the
three EngineAggregateOptions.groupBy rows on top of the merged state.
check:generated: all 13 artifacts up to date.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
@huangyiirene
huangyiirene marked this pull request as ready for review August 13, 2026 01:38
@huangyiirene
huangyiirene added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit 3f7b4ff Aug 13, 2026
27 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-8032-groupby-declared-union branch August 13, 2026 01:55
huangyiirene pushed a commit that referenced this pull request Aug 13, 2026
os-regen merge lap for landing: merge origin/main (committed first, per
scripts/pm/os-regen-merge.sh), then wholesale regen of the os-regen'd
references/api pages from the merged tree. Sibling assertions on the
regenerated tree: #8230 retirement state (def names only in retirement
prose + migration entry), #8232 currency fraction-digit guard, #8234's
13 comparand-door exports in api-surface/data.json, #8236's groupBy
union row all survive; MONGODB_MULTI_TENANT_UNSUPPORTED stays absent
from the ledger and the references ErrorCode union reads main-minus-one
(+265 -> +264; the union grew by 2 on main since the previous lap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
huangyiirene pushed a commit that referenced this pull request Aug 13, 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