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

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
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ger — a boot refusal never reaches a wire envelope (objectstack-ai#8035) (objectstack-ai#8239)

* fix(spec): MONGODB_MULTI_TENANT_UNSUPPORTED leaves the error-code ledger (objectstack-ai#8035)

The code was registered under @objectstack/driver-mongodb (objectstack-ai#3724) but no
response envelope can carry it: the CLI boot handler rethrows the tenancy
refusal pre-HTTP and aborts, and the one request-reachable trigger
(assertObjectsNotTenantScoped via syncObjectSchema inside the metadata
protocol's ensureObjectStorage) is swallowed by a documented best-effort
catch. Registered-but-unemittable is the class the ledger header names;
precedent OVERLAY_PERSISTENCE_FAILED / objectstack-ai#5783 — this instance is the sister
shape (never had a wire path, rather than lost it), now documented in the
header.

The boot refusal stays untouched: MULTI_TENANT_UNSUPPORTED_CODE, the error
class, its message, and the CLI's duck-typed literal match. A new
driver-mongodb test pins the code literal (with the ledger row gone it is
the only cross-package guard on the literal serve.ts matches); the ledger
test now asserts the wire vocabulary refuses the retired string. Reference
docs regenerated (ErrorCode enum 264 -> 263).

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

* docs(spec): regenerate references from the merged tree (objectstack-ai#8035)

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: objectstack-ai#8230 retirement state (def names only in retirement
prose + migration entry), objectstack-ai#8232 currency fraction-digit guard, objectstack-ai#8234's
13 comparand-door exports in api-surface/data.json, objectstack-ai#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

---------

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ered/virtualScroll (ADR-0049, objectstack-ai#7176) (objectstack-ai#8252)

* refactor(spec)!: retire pass-through-only list-view keys striped/bordered/virtualScroll (ADR-0049, objectstack-ai#7176)

Maintainer ruling 2026-08-10: every measured reader copies the key forward
and ObjectGrid, where the chains end, never applies any of the three —
copy-without-apply is dead in effect. retiredKey() tombstones on
ListViewSchema (radiating into ObjectListViewSchema), ADR-0087 D2 conversion
view-list-passthrough-keys-removed + D3 chain step + six
RETIRED_KEYS_BY_MAJOR[17] entries, ledger rows flipped to dead with the
retirement note, form inputs pruned, docs updated, changeset with FROM->TO.

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

* test(spec): match the striped prescription's actual casing in the pin test

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

* merge origin/main (os-regen artifacts taken from main; regeneration follows)

* chore(spec): regenerate artifacts after merging origin/main (4dc1c7d relay: objectstack-ai#8230/objectstack-ai#8232/objectstack-ai#8234/objectstack-ai#8236/objectstack-ai#8239)

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
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/m tests tooling

Projects

None yet

2 participants