test(objectql): two engine fixtures spell the declared aggregation key function, un-erased (#8112) - #8206
Merged
os-zhuang merged 1 commit intoAug 12, 2026
Conversation
…y `function`, un-erased (#8112) `engine-count-read-filter.test.ts` and `engine-filter-tokens.test.ts` each passed `aggregations: [{ func: 'count', field: 'id', alias: 'n' }]`. The declared key on `AggregationNodeSchema` is `function`; `func` exists on no type. Both call sites erased the options bag with `as any`, which is the only reason the wrong spelling compiled. Re-spell to `function:` and drop the `as any` in the same edit — the erasure is what hid the mistake, so removing it is what makes the next one visible. Both bags type cleanly with no erasure at all; the removal surfaced no other error. Neither test's verdict was wrong before, and this was verified rather than inherited: 31/31 green before, 31/31 after. The engine does not validate the member, so the malformed node reached the driver double verbatim (`[{"func":"count",...}]`) and no assertion read it. Each aggregate case now asserts the recorded `aggregations`, so the fixture reads what it constructs — `engine-count-read-filter.test.ts` already carried the comment "groupBy/aggregations survive on the same ast" with only `groupBy` asserted. One correction to the card's premise: the schema does not silently accept the bag. `func` is dropped as an unknown key (the object is not `.strict()`), but that leaves the required `function` missing, so `EngineAggregateOptionsSchema` .safeParse REJECTS it — `invalid_value` at `aggregations.0.function`. Dropped key, rejected bag; the fixture was inert only because the engine seam runs no parse. `check:query-options-erasure` test surface 242 -> 240, baseline ratcheted down in this commit. No open PR rewrites that baseline or moves its count. Fixes #8112 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014C8pAprWdmtecFsEprZax4
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
This was referenced Aug 12, 2026
os-zhuang
marked this pull request as ready for review
August 12, 2026 20:34
os-zhuang
deleted the
claude/issue-8112-aggregation-function-key-fixtures
branch
August 12, 2026 20:50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #8112
Two engine fixtures passed
aggregations: [{ func: 'count', field: 'id', alias: 'n' }]. The declared key onAggregationNodeSchemaisfunction;funcexists on no type. Both call sites erased the options bag withas any.Re-spelled to
function:and dropped theas anyin the same edit, inpackages/objectql/src/engine-count-read-filter.test.tsandpackages/objectql/src/engine-filter-tokens.test.ts. Both bags type cleanly with no erasure at all — the removal surfaced no other error in either file.Before / after, measured per file
The card asserted neither test was wrong in its verdict. Verified, not inherited:
engine-count-read-filter.test.tsengine-filter-tokens.test.tsBoth green, both sides — 31/31 across the two files. No verdict changed, and none should have: the engine runs no validation on this member, so the malformed node simply reached the driver double and nothing read it.
What the double actually recorded
A throwaway probe on the same harness drove both spellings through
ql.aggregateand logged whatdriver.aggregatereceived:The engine passes the array through verbatim — it does not strip the unknown key. So the fixture was inert not because the member was dropped in flight, but because no assertion looked at it.
Each aggregate case now asserts the recorded
aggregations, so the fixture reads what it constructs.engine-count-read-filter.test.tsalready carried the comment "groupBy/aggregations survive on the same ast" with onlygroupByasserted; that is now true as written.One correction to the card's premise
The card says the aggregation schemas are not
.strict(), sofuncis "dropped, never rejected". Measured, the second half does not hold:funcis dropped as an unknown key, but that leaves the requiredfunctionmissing, so the bag is rejected. Dropped key, rejected bag. The fixture survived only because the engine seam runs no parse — not because the schema tolerates it.Reverse verification — the direction inverted, and the reason matters
Predicted before running: restore
func:with the erasure gone andtscgoes red. It did not — typecheck stayed green.packages/objectql/tsconfig.jsoncarries"exclude": [… , "**/*.test.ts"], sotsc --noEmitnever compiles either file. The type can only speak where it is read: the same bag placed in a compiled non-test file gives the card's exact error,so the type is correct and the corrected bags are genuinely well-typed. But the card's rationale — dropping the erasure is what makes the next mistake visible — does not hold for these two files today, because no tsc program reads them. This is known, ledgered debt, not a new finding:
@objectstack/objectqlsits inTEST_DEBTat 355 errors for exactly this hidden test layer, andcheck:type-check-debtreports 20 packages hiding 817 test files repo-wide. No issue filed; it is already tracked.That makes the added assertions the load-bearing half. Second reverse verification, predicted red and observed red —
func:restored in both files, erasure still gone:Restored from the commit, 31/31 green again. The assertions are the only thing in the repo that would now catch a re-introduced
func:here.Ratchet
check:query-options-erasuretest surface fell 242 to 240 — exactly the two removed erasures. Ratcheted down with--updateand committed here; the diff is one line,nonTestuntouched, no key added.Baseline-race check before writing it: no open PR rewrites this baseline, and none moves its count. All 12 open PRs were diffed against their merge base for
scripts/query-options-erasure-baseline.jsonandeslint.config.mjs(zero hits), then the four withas anychurn underpackages/were read line by line — plugin contexts, response bodies, a schema cast,driver.initObjects— none at an engine query-options position.Gates
Derived with
node scripts/pm/dispatch-gates.mjsover the three changed paths, not hand-enumerated.pnpm --filter @objectstack/objectql test(192 files, 3400 tests)pnpm --filter @objectstack/objectql typecheckeslinton both changed filespnpm check:query-options-erasurepnpm check:type-check-debt --re-measurepnpm check:engine-double-contractpnpm check:durability-log-levelscripts/check-engine-split-ratio.mjspnpm check:nul-bytes+ control-byte self-scanNo baseline or ledger entry was raised. The one baseline that moved went down.
check:type-check-debt --re-measurereports 33 entries, none above its recorded number;--lowerwas not run, and the surplus it notes is pre-existing across 9 other entries.Changeset
skip-changeset. The root package owningscripts/isprivate: trueand@objectstack/objectqlpublishes onlydist— neither changed file reaches a consumer, so this releases nothing. That follows #8191 (test-only objectql,skip-changeset) rather than #7846, whose changeset described a correction to matcher behaviour that decided test verdicts; this one changes no verdict, measured above.Generated by Claude Code