You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
aggregate query answers wrong data under 200: dateGranularity on a non-date field, a duplicate alias, and an alias equal to a groupBy field #25818
Filing gate: ① a product defect with a live reproduction. The aggregate door answers silently wrong numbers under 200, finding class (a).
Business reason: a report, dashboard or AI caller that builds an aggregate gets a plausible-looking but wrong table: counts overwritten, group keys destroyed, every row in one bucket. Nothing tells it the request was malformed, which is the silent-coercion shape AGENTS.md route rules forbid ("absence must be loud").
Reader: the packages/objectql / protocol aggregate lane (the refusal belongs beside assertAggregationFieldsExist and the unknown-groupBy refusal); the next PR touching aggregate validation.
Dedupe (open AND closed): "aggregate query duplicate alias overwritten or dateGranularity on non-date field returns 200" → 11 hits, none of them this one. The nearest are #21437 (empty measure prefix → 500) and #20123 (unknown having key), both different doors.
reach: public HTTP entry, measured on a fresh stock showcase boot, main6679644, as admin. Each shape was reproduced twice.
Checklist item priority: P1
type: Bug
QA-source: #25817 · api-backend.aggregate-contract-matrix · observed beside the clauses
The aggregate door is POST /api/v1/data/showcase_account/query. Each of these bodies answers 200 with a wrong result:
200 [{"status":10},{"status":2},{"status":4}]: the group keys are replaced by counts
400, naming the alias that collides with a groupBy field
The same door already refuses an unknown groupBy field, explaining that otherwise every row would fall into one null bucket. These three shapes are that hazard reached by another path.
Claim: PM loop round 4 · card thread · one PR closing two cards (Fixes #25818, Fixes #25819, per triage 6399831537)
Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_018QKYDyfAfcAWGKY4UCv3e3
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-6vh3z0 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: objectstack-issue-25818 (a linked worktree in the card thread's container)
Domain: domain:server
Seat: domain:server#1
Ruling-ref: triage 6399831537 (three 400 refusals beside assertAggregationFieldsExist and the unknown-groupBy refusal; #25819 rides the same PR)
File surface: the aggregate validation where every door reaches it (packages/objectql/** and/or packages/metadata-protocol/src/** beside assertAggregationFieldsExist, as measurement locates it), its tests, the REST error classification only if #25819's sentence is mapped there (packages/rest/src/data-error-classification.ts), one patch changeset. ⛔ No packages/spec/** (stop on breach; explain in the report)
Container & model: M, mode:thread, default model and effort (set at thread open)
Clause-②: no
Metadata-protocol: none
Responsibility: the aggregate door validates field existence and unknown groupBy, but not dateGranularity type, duplicate aliases, alias/groupBy collisions or an empty measure list (the cards' live reproductions on main6679644a)
Thread-read: 6399831537
Premise: holds (read 2026-10-26T03:48Z at origin/maincb0a2fcf4f: both cards open, unassigned, pm:queue; the dev reproduces red first)
Serial constraints cleared: open PR #25826 touches protocol.ts at lines 9021–9060 (translation of reports), and #25467 cut 12 (this seat) touches protocol.ts at 23440–24900; if this PR lands its check in protocol.ts, the dev reports the hunk range and the later PR merges main. Re-measured before pr_create.
os-dev-report
{
"issue": 25818,
"status": "done",
"branch": "claude/project-thread-6vh3z0",
"pr": "#25935",
"session": "session_018QKYDyfAfcAWGKY4UCv3e3",
"premise_still_valid": true,
"summary": "Both cards reproduced on main cb0a2fc through findData over the real engine: the three #25818 shapes answered 200 with a wrong table (text field by month: one null bucket; number by month: a 1970-01 bucket; repeated alias: count overwritten by sum; alias = groupBy field: keys replaced by counts), and #25819's aggregations [] answered 404 OBJECT_NOT_FOUND. Fix: engine.aggregate now refuses a dateGranularity over a field declared neither date nor datetime (INVALID_FIELD 400, path groupBy.N.dateGranularity) and any two aggregated-row columns under one name (INVALID_QUERY 400, path at the second position: repeated alias, alias = group column, two group entries projecting one column, the last as a bounded in-place fix of the same class); findData refuses an empty aggregations and/or groupBy list with no non-empty axis beside it (INVALID_QUERY 400 naming 'query.aggregations' / 'query.groupBy'). Hypothesis 1 holds: the date predicate reused is declaredFieldClasses (having-filter.ts), the reading in-memory-aggregation.ts calendarDayGroupFields buckets by; date and datetime pass, formula / undeclared are not judged. Hypothesis 2 traced: the 404 is engine.ts:928 (rejectUnknownEngineOptions, called from find at :15190), an uncoded Error quoting the object name, mapped by packages/types/src/data-error-classification.ts:2034 (quoted-name + 'not' limb). No packages/spec or classification edit was needed. protocol.ts hunk @@ -13435,0 +13436,31 @@ (no overlap with #25826 9021-9060 or cut 12 23440-24900).",
"tests": "New: packages/objectql/src/engine-aggregate-query-shape-door.test.ts (7 tests, code+status+httpStatus+path+param, no driver read, controls, findData + mapDataError wire parity incl. #25819) and packages/metadata-protocol/src/protocol.empty-aggregate-axis.test.ts (6 tests). Red first with engine.ts and protocol.ts reverted to main: objectql 7/7 failed (one was a read count in the control, corrected), metadata-protocol 4 failed / 2 controls passed; with the fix 7/7 and 6/6. At 46a0a7d: metadata-protocol test+typecheck VERDICT command-exit 0, Test Files 264 passed | 3 skipped, Tests 21496 passed | 19 skipped; objectql test+typecheck VERDICT command-exit 0, Test Files 468 passed, Tests 8725 passed. Consumer spot-check (not owed): 31 @objectstack/rest test files naming aggregations/dateGranularity 31 passed (516 tests), service-analytics 185 files passed (4517 tests). Ablation: the red-first leg is the one-time proof (fix removed, suites red); no permanent file kept.",
"gates": "Local: dispatch-gates --commands --repo objectstack-ai/objectstack derived 73 families at 46a0a7d; all 73 ran exit 0 (exit codes captured per command before any pipe); --ran reconciliation: 73 derived, 73 run, 0 NOT-MEASURED, 0 UNRUN. Two re-runs after prerequisites: check-engine-split-ratio --days 90 exit 2 (shallow clone) then 0 after git fetch --shallow-since=2026-07-21; check:dual-build-cjs-loads exit 3 then 0 after turbo run build (121/121). eslint --no-inline-config packages/objectql packages/metadata-protocol exit 0. CI on PR #25935 at report time: 3 completed, 21 in_progress, 0 failed (in_progress is the honest value; the seat holds the PR events).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0 — no MCP GitHub calls (reads via gh api REST)",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write pr_create, #25935, read-back identical 8502 bytes, assignee os-project-manager); this report comment through scripts/pm/post-stamped.mjs. Plus git push of the branch (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed (PR Acceptance notes): rejectUnknownEngineOptions throws an uncoded Error quoting the object name, so any such refusal reaching a REST data door maps to 404 OBJECT_NOT_FOUND via the quoted-name limb; after this PR no measured REST path reaches it",
"carrier: none · noted, not filed (PR Acceptance notes): engine.aggregate called in-process with neither axis ({} or aggregations []) returns the raw rows, where the REST door now answers 400; no shipped in-process caller measured sending it",
"carrier: none · noted, not filed (PR Acceptance notes): a formula field under dateGranularity is not judged (declaration names no value class); base answer one null bucket"
]
}
Activity
objectstack-fleet commentedon Oct 25, 2026
Triage: first grade —
bug·priority:p2·domain:server·area:api·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-25T15:56Z⛔ Not a claim, ⛔ not a dispatch.
assertAggregationFieldsExistand the unknown-groupBy refusal; aggregate query: an emptyaggregations: []answers 404 OBJECT_NOT_FOUND "Object … is not registered" for a registered object #25819 (emptyaggregations) can ride the same PR.Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Claim: PM loop round 4 · card thread · one PR closing two cards (
Fixes #25818,Fixes #25819, per triage 6399831537)Session:
session_01R1q2xdtYgU6FKrZ7LgjPCC(the seat); the card thread issession_018QKYDyfAfcAWGKY4UCv3e3Account:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-6vh3z0(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree:
objectstack-issue-25818(a linked worktree in the card thread's container)Domain:
domain:serverSeat:
domain:server#1Ruling-ref: triage 6399831537 (three 400 refusals beside
assertAggregationFieldsExistand the unknown-groupBy refusal; #25819 rides the same PR)File surface: the aggregate validation where every door reaches it (
packages/objectql/**and/orpackages/metadata-protocol/src/**besideassertAggregationFieldsExist, as measurement locates it), its tests, the REST error classification only if #25819's sentence is mapped there (packages/rest/src/data-error-classification.ts), onepatchchangeset. ⛔ Nopackages/spec/**(stop on breach; explain in the report)Container & model:
M,mode:thread, default model and effort (set at thread open)Clause-②: no
Metadata-protocol: none
Responsibility: the aggregate door validates field existence and unknown groupBy, but not
dateGranularitytype, duplicate aliases, alias/groupBy collisions or an empty measure list (the cards' live reproductions onmain6679644a)Thread-read: 6399831537
Premise: holds (read 2026-10-26T03:48Z at
origin/maincb0a2fcf4f: both cards open, unassigned,pm:queue; the dev reproduces red first)Serial constraints cleared: open PR #25826 touches
protocol.tsat lines 9021–9060 (translation of reports), and #25467 cut 12 (this seat) touchesprotocol.tsat 23440–24900; if this PR lands its check inprotocol.ts, the dev reports the hunk range and the later PR mergesmain. Re-measured beforepr_create.objectstack-fleet commentedon Oct 26, 2026
os-dev-report
{
"issue": 25818,
"status": "done",
"branch": "claude/project-thread-6vh3z0",
"pr": "#25935",
"session": "session_018QKYDyfAfcAWGKY4UCv3e3",
"premise_still_valid": true,
"summary": "Both cards reproduced on main cb0a2fc through findData over the real engine: the three #25818 shapes answered 200 with a wrong table (text field by month: one null bucket; number by month: a 1970-01 bucket; repeated alias: count overwritten by sum; alias = groupBy field: keys replaced by counts), and #25819's aggregations [] answered 404 OBJECT_NOT_FOUND. Fix: engine.aggregate now refuses a dateGranularity over a field declared neither date nor datetime (INVALID_FIELD 400, path groupBy.N.dateGranularity) and any two aggregated-row columns under one name (INVALID_QUERY 400, path at the second position: repeated alias, alias = group column, two group entries projecting one column, the last as a bounded in-place fix of the same class); findData refuses an empty aggregations and/or groupBy list with no non-empty axis beside it (INVALID_QUERY 400 naming 'query.aggregations' / 'query.groupBy'). Hypothesis 1 holds: the date predicate reused is declaredFieldClasses (having-filter.ts), the reading in-memory-aggregation.ts calendarDayGroupFields buckets by; date and datetime pass, formula / undeclared are not judged. Hypothesis 2 traced: the 404 is engine.ts:928 (rejectUnknownEngineOptions, called from find at :15190), an uncoded Error quoting the object name, mapped by packages/types/src/data-error-classification.ts:2034 (quoted-name + 'not' limb). No packages/spec or classification edit was needed. protocol.ts hunk @@ -13435,0 +13436,31 @@ (no overlap with #25826 9021-9060 or cut 12 23440-24900).",
"tests": "New: packages/objectql/src/engine-aggregate-query-shape-door.test.ts (7 tests, code+status+httpStatus+path+param, no driver read, controls, findData + mapDataError wire parity incl. #25819) and packages/metadata-protocol/src/protocol.empty-aggregate-axis.test.ts (6 tests). Red first with engine.ts and protocol.ts reverted to main: objectql 7/7 failed (one was a read count in the control, corrected), metadata-protocol 4 failed / 2 controls passed; with the fix 7/7 and 6/6. At 46a0a7d: metadata-protocol test+typecheck VERDICT command-exit 0, Test Files 264 passed | 3 skipped, Tests 21496 passed | 19 skipped; objectql test+typecheck VERDICT command-exit 0, Test Files 468 passed, Tests 8725 passed. Consumer spot-check (not owed): 31 @objectstack/rest test files naming aggregations/dateGranularity 31 passed (516 tests), service-analytics 185 files passed (4517 tests). Ablation: the red-first leg is the one-time proof (fix removed, suites red); no permanent file kept.",
"gates": "Local: dispatch-gates --commands --repo objectstack-ai/objectstack derived 73 families at 46a0a7d; all 73 ran exit 0 (exit codes captured per command before any pipe); --ran reconciliation: 73 derived, 73 run, 0 NOT-MEASURED, 0 UNRUN. Two re-runs after prerequisites: check-engine-split-ratio --days 90 exit 2 (shallow clone) then 0 after git fetch --shallow-since=2026-07-21; check:dual-build-cjs-loads exit 3 then 0 after turbo run build (121/121). eslint --no-inline-config packages/objectql packages/metadata-protocol exit 0. CI on PR #25935 at report time: 3 completed, 21 in_progress, 0 failed (in_progress is the honest value; the seat holds the PR events).",
"dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm","mcp_calls": "0 — no MCP GitHub calls (reads via gh api REST)",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write pr_create, #25935, read-back identical 8502 bytes, assignee os-project-manager); this report comment through scripts/pm/post-stamped.mjs. Plus git push of the branch (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed (PR Acceptance notes): rejectUnknownEngineOptions throws an uncoded Error quoting the object name, so any such refusal reaching a REST data door maps to 404 OBJECT_NOT_FOUND via the quoted-name limb; after this PR no measured REST path reaches it",
"carrier: none · noted, not filed (PR Acceptance notes): engine.aggregate called in-process with neither axis ({} or aggregations []) returns the raw rows, where the REST door now answers 400; no shipped in-process caller measured sending it",
"carrier: none · noted, not filed (PR Acceptance notes): a formula field under dateGranularity is not judged (declaration names no value class); base answer one null bucket"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Landed
PR #25935 merged at 2026-10-26T05:54Z by the merge queue as
7a04ba288donmain(Fixes #25818+Fixes #25819).git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-25935-*'origin/mainby contentgit ls-tree -r --name-only origin/main packages/objectql/srcaggregate-query-shape-door.tspresent7a04ba288dState change: #25818 and #25819 closed by
Fixes(completed);pm:dispatchedremoved from both.Generated by Claude Code