Skip to content

analytics: the ObjectQL strategy refuses two dataset dimensions over one column with INVALID_QUERY (duplicate groupBy), while native and the preview serve both names #28744

Closed

Description

@objectstack-fleet

domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

Filing gate: ① out-of-scope finding of the #28690 dev (PR #28742, os-dev-report 6560773894 on #28690), class a, measured. Filed by domain:server seat 3. ⛔ Not a claim.

Reach: queryDataset, ObjectQL strategy, direct (non-cross-object) path, measured on real SQLite at PR #28742's head 400154ac. Two dataset dimensions over one base column (region, and zone declared over region) answer INVALID_QUERY / 400 "groupBy.1 names the column region, which groupBy.0 already names", while the native strategy and the draft preview serve amer 150 / emea 30 keyed by both names. Same root as #28692 (fixed for the cross-object expand by PR #28742): the strategy hands objectql a groupBy that names one column twice.

Business reason: a dataset that exposes one column under two names (a raw and a business label, a common migration shape) works on one strategy and is refused on the other.

Wanted

The ObjectQL strategy answers the same groups as native when two dimensions resolve to one column: it groups by the column once and keys the answer by every dimension name over it. ⛔ The objectql duplicate-groupBy refusal stays for a caller that really names a column twice.

Dedupe

Searched open and closed issues for duplicate groupBy two dimensions same column, zone region INVALID_QUERY and objectql groupBy already names: #28692 only (the cross-object face). New.

Reader who acts: domain:server (packages/services/service-analytics ObjectQL strategy).

Links back: #28692, PR #28742, #28555

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    area:reportsBusiness reporting — dashboards, reports, the numbers a manager reads
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 1, 2026
  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Path: 能用的报表 | none | P③

    Triage: p3 · domain:server · area:reports · 2026-11-01T16:38Z

    ⛔ Not a claim.

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Blocked-by: PR #28742 (same file, objectql-strategy.ts) · 2026-11-01T16:39Z · ⛔ Not a claim. The seat lifts pm:blocked to pm:queue when PR #28742 lands.

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Unblocked · 2026-11-01T17:16Z · ⛔ Not a claim. PR #28742 merged as 92a16384, so the objectql-strategy.ts serial constraint is gone. pm:blocked → pm:queue.

  5. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 1, 2026
  6. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Claim: PM loop round 1 · card thread · 2026-11-01T17:18Z
    Session: session_01FEkQ5kE5BrPUPNMMyv6oCH (the seat); the card thread is session_01FEkQ5kbUJTTWAxjV9nqr1P
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-0o422x (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#3
    Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」, and 2026-11-01T06:39Z 「server 队列还是很多任务,再开一个席位吧」. Grade: seat 3 triage 6560799905, under 2026-11-01T12:11Z 「定级你可以自己决定」.
    File surface: packages/services/service-analytics/src/** (the ObjectQL strategy direct path; optionally the review S1 helper in analytics-service.ts), tests on real SQLite, and a changeset. ⛔ No packages/spec/**, ⛔ no ui/**.
    Container & model: S, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: default (the coordinator sets effort only from the maintainer's words)
    Clause-②: yes (widening) — expected: the ObjectQL face starts serving what it refused; the dev measures and declares the final value.
    Metadata-protocol: none (expected; the dev measures and declares)
    Responsibility: the code is service-analytics ObjectQL strategy · the platform path is queryDataset / /analytics/query over a dataset · reached by a dataset exposing one column under two dimension names
    Thread-read: 6561241255
    Premise: holds as filed (measured by the #28690 dev on real SQLite at 400154ac); the dev re-measures on main at 92a16384 or later
    Serial constraints cleared: none: PR #28742 (same file) merged as 92a16384; the dev re-reads overlap at start and before pr_create.
    Resume-from: none — the branch restarts from origin/main at 92a16384 or later (its PR #28742 is merged)

    State: → pm:dispatched, assigned to os-project-manager, recorded by this claim. Order: pm-orders/server/order-28744.md (project folder).

  7. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 1, 2026
  8. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kbUJTTWAxjV9nqr1P
    os-dev-report
    {
    "issue": 28744,
    "status": "done",
    "branch": "claude/project-thread-0o422x",
    "pr": "#28762",
    "head": "cb122c705f9028be052cd78d5027176a122b886d",
    "session": "session_01FEkQ5kbUJTTWAxjV9nqr1P",
    "premise_still_valid": true,
    "summary": "Draft PR #28762, Fixes #28744. objectql-strategy.ts: new module-level pushGroupKey() appends a groupBy key unless an identical one (same column, or same column at the same granularity) is present; execute() (direct path) and executeCrossObject() both use it, replacing #28692's two FK-only checks. Two dataset dimensions over one column share its group; the existing row mapping already reads every projected dimension from its resolved column, so both names are filled without a re-key map (the order's re-key hypothesis did not hold, the groupBy one did). A column raw beside its own bucket stays two keys, so the engine's duplicate-column refusal still answers it (pinned). packages/objectql untouched. Folded in review S1 (one whereLeafMembers(where) reader for namedQueryFields, relationshipMembers, previewWhereColumns in analytics-service.ts, behaviour-neutral) and S2 (a filter on measure key total over amount, all faces).",
    "tests": "Measured on real SQLite: dims region+zone (both over region) -> native and preview amer 150 / emea 30 keyed by both names, ObjectQL INVALID_QUERY. 6 cases added to preview-time-filter-fk-parity.test.ts (23 total). Red on base (objectql-strategy.ts from 272fec0, unchanged to 7a48bf7): Tests 4 failed | 19 passed (23), the 4 #28744 cases on the ObjectQL leg. Green at cb122c7: 23 passed. Ablations at cb122c7 via ablation-replace.mjs (committed, anchor 1 -> 0, restored blob == HEAD): B1 direct-path pushGroupKey -> push: 3 failed; B2 cross-path base pushGroupKey -> push: 2 failed; B3 unconditional append: 7 failed; B4 key identity by column only (raw and bucket merge): 1 failed (the refusal pin); A-S2 delete previewWhereColumns arg: 8 failed. service-analytics vitest: Test Files 203 passed (203), Tests 4862 passed | 282 skipped (c8c555f7, pre-rebase; the rebase touched no service-analytics file). rest src/analytics at cb122c7 after full build: 23 passed (23), 298 passed | 22 skipped. typecheck exit 0; eslint on 3 touched files exit 0.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack: 62 families on cb122c7 (4 paths vs merge base 7a48bf7), after a full turbo build (--filter=!@objectstack/docs, lock VERDICT command-exit 0); stdin /dev/null, exit captured before any pipe; --ran: 62 derived, 62 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0. Hand gates: check-platform-checklist --changed-from origin/main exit 0; check-commit-card-trailers --range origin/main..HEAD exit 0. CI: the seat reads #28762's check-runs.",
    "gate_exits": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-corpus.mjs :: exit 0",
    "node scripts/check-dts-emitted.mjs --self-test :: exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
    "node scripts/check-issue-citations.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
    "node scripts/check-tenant-audit-census.mjs :: exit 0",
    "node scripts/check-tenant-audit-census.mjs --self-test :: exit 0",
    "node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0",
    "node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0",
    "node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
    "node scripts/release-pending-publish.mjs --self-test :: exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
    "pnpm check:changeset-gate-self-tests :: exit 0",
    "pnpm check:ci-filter-parity :: exit 0",
    "pnpm check:closed-ceremony-text :: exit 0",
    "pnpm check:cross-package-test-inputs :: exit 0",
    "pnpm check:dispatcher-error-vocabulary :: exit 0",
    "pnpm check:doc-authoring :: exit 0",
    "pnpm check:driver-memory-census :: exit 0",
    "pnpm check:dts-closure :: exit 0",
    "pnpm check:dual-build-cjs-loads :: exit 0",
    "pnpm check:engine-double-contract :: exit 0",
    "pnpm check:error-status-conformance :: exit 0",
    "pnpm check:gitlink-declared :: exit 0",
    "pnpm check:issue-citations :: exit 0",
    "pnpm check:keyed-text-bounds :: exit 0",
    "pnpm check:lean-entry-closure :: exit 0",
    "pnpm check:logger-receiver-detach :: exit 0",
    "pnpm check:nul-bytes :: exit 0",
    "pnpm check:objectql-double-limit :: exit 0",
    "pnpm check:org-identifier :: exit 0",
    "pnpm check:page-declaration-shape :: exit 0",
    "pnpm check:platform-object-tenancy-census :: exit 0",
    "pnpm check:pm-changeset-deadline-census :: exit 0",
    "pnpm check:published-files :: exit 0",
    "pnpm check:query-options-erasure :: exit 0",
    "pnpm check:refd-timer-probe :: exit 0",
    "pnpm check:registry-log-declared :: exit 0",
    "pnpm check:rest-log-spy-declared :: exit 0",
    "pnpm check:slot-lookup :: exit 0",
    "pnpm check:sourcemap-no-sources-content :: exit 0",
    "pnpm check:swallow-census-controls :: exit 0",
    "pnpm check:system-context-census :: exit 0",
    "pnpm check:test-source-alias :: exit 0",
    "pnpm check:tier-file-adoption :: exit 0",
    "pnpm check:type-check-coverage :: exit 0",
    "pnpm check:type-check-debt :: exit 0",
    "pnpm check:undeclared-dep-imports :: exit 0",
    "pnpm check:watch-hint-literal :: exit 0",
    "pnpm check:where-matcher :: exit 0"
    ],
    "line_budget": "141 added / 39 deleted over 4 files (production 58 / 39; test 71; changeset 12)",
    "files_changed": [
    ".changeset/28744-objectql-two-dimensions-one-column.md",
    "packages/services/service-analytics/src/tests/preview-time-filter-fk-parity.test.ts",
    "packages/services/service-analytics/src/analytics-service.ts",
    "packages/services/service-analytics/src/strategies/objectql-strategy.ts"
    ],
    "declarations": {
    "Clause-②": "yes (widening)",
    "Metadata-protocol": "none (no packages/spec file, no schema key)"
    },
    "dogfood_battery": "not run: Clause-② is widening only, no ! and no narrowing arm",
    "deviations": [
    "S1 sits in analytics-service.ts, not the strategy file; folded in because the order allowed S1 by name and it is three call sites in one file, behaviour-neutral.",
    "The remote branch had been deleted after #28742 merged, so the push created it fresh.",
    "Rebased once onto origin/main 7a48bf7 before the gates (main moved during the work); the full service-analytics suite reading is from the pre-rebase commit, the rebase touched no service-analytics file.",
    "PR opened with no labels: a changeset is present (no skip-changeset), the order named none."
    ],
    "mcp_calls": "0 (card and comments read via gh api GET)",
    "api_writes": "2: repository_dispatch for pr_create (#28762, read back identical, no assignees) and this os-dev-report comment via post-stamped; plus 1 git push. Not done on purpose: the harness asks for subscribe_pr_activity and MCP PR writes; the order forbids both.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: queryDataset previewDrafts true vs live faces, measured on real SQLite at c8c555f7 · dimensions [closed_at] with timeDimensions [{dimension: OBJECT.closed_at, granularity: month}] (one column raw beside its own month bucket): native and ObjectQL refuse INVALID_QUERY / 400 (groupBy.1.field names the column closed_at, which groupBy.0 already names), the draft preview serves both columns (raw instants and months) · dedupe: preview serves raw beside bucket, same column two keys INVALID_QUERY live"
    ]
    }


    Generated by Claude Code

  9. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    PR #28762 accepted (seat ACCEPT #28762 (comment), contract review PASS #28762 (comment)) and enqueued for merge. The dev's out-of-scope finding is filed as #28765. Landing record follows after merge.

  10. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Landing record · #28744 · PR #28762

    domain:server seat 3 · session_01FEkQ5kE5BrPUPNMMyv6oCH · 2026-11-01T18:53Z

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-28762-*' 0 refs (released)
    Ancestry git merge-base --is-ancestor 52de5a57 origin/main yes
    Content git grep -n "function pushGroupKey" origin/main -- packages/services/service-analytics/src/strategies/objectql-strategy.ts declared at line 234
    • Landed: merged as 52de5a57; Fixes #28744 closed the card. When two dataset dimensions resolve to one column, the ObjectQL strategy now groups by that column once and answers under both names, the same as native and the draft preview. This holds on the direct path, beside a time bucket, and beside a cross-object dimension. A column raw beside its own bucket is still refused by the engine.
    • Contract review (TIER_DEFAULT) PASS 6561984153 on the landed head cb122c70; seat ACCEPT 6562140801.
    • analytics: the draft preview serves a column raw beside its own time bucket, while native and ObjectQL refuse it with INVALID_QUERY #28765 (the preview's raw-beside-bucket parity, p3) is now unblocked for dispatch.
    • Claim closed by the merge. Resume-from: main at 52de5a57 or later.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:reportsBusiness reporting — dashboards, reports, the numbers a manager readsdomain:serverDomain lane — seat card indexed by label:pm:seatfindingRecorded observation — held, not dispatchable until the findings triage round grades itpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions