Repository navigation
analytics: a config cube min/max over a text column is served at the cube door under fields[] type number; the dataset door refuses the pair by the compatibility table, the cube door consults nothing #21044
Description
Activity
objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsOne more position for this card's family, from PR #21040's contract review
domain:servicesseat (#6021) ·session_01XY5uCwTjZj7884yYtyur4H· 2026-10-01T03:38Z · ⛔ Not a claim.- Source: the at-tier contract review
5924217364on PR fix(core,driver-sql,service-analytics): the analytics native-SQL path answers measures declared number as numbers (#20889) #21040 ([finding] analytics: on PostgreSQL the native-SQL path answers a measure the response declaresnumberas a string (count: "2"), where SQLite answers 2 — the class #20335 closed at the engine door #20889), boundary flag 5. - Read from source: a
min/maxmeasure whosesqlis a relationship path (a dotted column) over a numeric related field is still declaredfields[] { type: 'number' }. The column type the native strategy can resolve answersundefinedfor a dotted path, so the value is left as the client gave it. This is the same "declared type versus served value" question this card asks for a text column on a config cube, at a second position. - For whoever takes this card: enumerate the relationship-path
min/maxbeside the text column, so one rule covers both.
Generated by Claude Code
- Source: the at-tier contract review
objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·priority:p2·domain:services·area:reports·pm:blocked. Direction: the cube door asks the same compatibility table the dataset door asksTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-01T04:03Z. ⛔ Not a claim, ⛔ not a dispatch.Blocked-by: #20889
Why p2. A config cube's
maxover a text column is served, whilefields[]declares the measurenumber. The dataset door refuses the same pair by the spec table (#16099). It is #16098's residue on the one door it did not cover.Why blocked: the same files as PR #21040 (#20889, re-read open at this write).
Direction: the config cube's measure is judged by
aggregate-field-type-compatibility, the one table, at the cube door, as the dataset door does. ⛔ No second table.buildFieldMetastops mintingnumberfor a non-numericmin/max. Pins:maxover text at the cube door is refused, andmaxover a number is served typednumber(the control).
Generated by Claude Code
- addedarea:reportsBusiness reporting — dashboards, reports, the numbers a manager readsBusiness reporting — dashboards, reports, the numbers a manager readsbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3and removed
on Oct 1, 2026 objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsUnblocked ·
domain:servicesseat (#6021) ·session_01XY5uCwTjZj7884yYtyur4H· 2026-10-01T04:56ZThis card's
Blocked-by: #20889(triage's first grade on this card) has cleared: PR #21040 merged asd1633f3a, andFixes #20889closed that cardcompleted.- The surface this card names,
packages/services/service-analytics/src/strategies/native-sql-strategy.tsand the presenter rule now in@objectstack/core, was re-read on the merged ref, and the card's premise is unchanged there. - State:
pm:blocked→pm:queue, in one label write. ⛔ Not a claim.
Generated by Claude Code
- The surface this card names,
objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 · 2026-10-01T05:00Z
Session:session_01XY5uCwTjZj7884yYtyur4H
Account:os-justin(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-21044-cube-measure-type-table
Worktree:objectstack-issue-21044
Domain:domain:services
Seat:domain:services(seat 1, seat post #6021)
Selection: label order in this lane,priority:p2bug. ItsBlocked-by: #20889cleared when PR #21040 landed asd1633f3a(unlock5925026079).
Direction: triage's grade5924500811. The config cube's measure is judged byaggregate-field-type-compatibility, the one table, at the cube door, as the dataset door does. ⛔ No second table.buildFieldMetastops mintingnumberfor a non-numericmin/max.
File surface, by region:packages/services/service-analytics/src/analytics-service.ts: the cube door's measure judgment inquery()and its field description. ⛔ NotfieldsOfColumnSqlor thequeryObjectshop resolution (analytics: on an inferred cube, a dotted path through a lookup whose name differs from its target object is never served — the door admits (and refuses) the lookup's NAME as if it were an object #20986).packages/services/service-analytics/src/strategies/native-sql-strategy.tsandobjectql-strategy.ts:buildFieldMetaonly. ⛔ Not the hop-object sites (analytics: on an inferred cube, a dotted path through a lookup whose name differs from its target object is never served — the door admits (and refuses) the lookup's NAME as if it were an object #20986),buildFilterClause/ the text-match rendering ([finding]$contains/$notContainson a declared multi-valued or JSON-stored field still answer SUBSTRING on five faces, the analytics RLS read scope among them (u1admits a row storingu10) #20987), orAGGREGATE_SQL(analytics: the native-SQL strategy skips the engine aggregate policies — SUM/AVG exact decimal on PostgreSQL (not #20387's double), and an all-NULL group sums to null where the ObjectQL face folds it to 0 (#15546) #21042).packages/services/service-analytics/src/measure-result-type.tsif the cube door reads the same rule, and a helper beside it if one is needed.- Pins in
service-analytics/src/__tests__/and a route pin besidepackages/rest/src/analytics-*.test.ts. .changeset/21044-*.md.- ⛔ Not
packages/spec/src/**,packages/objectql/src/**or any driver. The table and the predicate are read, never edited.
(stop on a breach outside these; explain in the report)
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate, floor sonnet · default opus · ceiling fable). The contract review runs atCONTRACT_REVIEW_TIER.
Clause-②: no - Why
no(expectedno (narrowing)): a pair the cube door serves today (a config cube'smin/maxover a column the table does not accept) is refused. The dev measures it, and the PR's line 2 carries the measured grammar.
Thread-read: 5925026079
Serial constraints cleared: - PR fix(core,driver-sql,service-analytics): the analytics native-SQL path answers measures declared number as numbers (#20889) #21040 ([finding] analytics: on PostgreSQL the native-SQL path answers a measure the response declares
numberas a string (count: "2"), where SQLite answers 2 — the class #20335 closed at the engine door #20889) has landed asd1633f3a, and PR fix(service-analytics): the ObjectQL strategy hands the engine its null tests as $null, so a $not over a multi-valued lookup gets the engine's rows (#20918) #21036 (analytics: on the ObjectQL strategy a$notover a multi-valued lookup ($contains) is refused 400, because the NULL-safe guard reaches driver-sql as$ne: nullon a JSON column, where the engine answers the rows #20918) as5dbeb7d7. - The same files, other regions, in flight:
- analytics: on an inferred cube, a dotted path through a lookup whose name differs from its target object is never served — the door admits (and refuses) the lookup's NAME as if it were an object #20986 (build): the hop-object sites in both strategies and
analytics-service.ts; - [finding]
$contains/$notContainson a declared multi-valued or JSON-stored field still answer SUBSTRING on five faces, the analytics RLS read scope among them (u1admits a row storingu10) #20987 (build): the filter lowering, the read scope and the native text-match rendering.
This card's sites are separate functions. Each PR mergesmainafter any sibling lands first.
- analytics: on an inferred cube, a dotted path through a lookup whose name differs from its target object is never served — the door admits (and refuses) the lookup's NAME as if it were an object #20986 (build): the hop-object sites in both strategies and
Generated by Claude Code
objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 21044, "status": "done", "branch": "claude/issue-21044-cube-measure-type-table", "pr": "https://github.com/objectstack-ai/objectstack/pull/21128", "session": "session_01XY5uCwTjZj7884yYtyur4H — subagent run, the parent seat's harness-stamped id (the Claude-Session trailer on every commit)", "premise_still_valid": true, "summary": "Premise re-measured and held (H1): at base 2821e9f15b, through the real dispatcher route on SQLite and PostgreSQL 16.13, a configured cube's max / min over text and max over select were served by the native-SQL face with the column's text under fields[] number; the ObjectQL face already answered 400 INVALID_FIELD from the engine's aggregate door (PR #21037), after the strategy began; sum over the same text column answered 0 on SQLite and 500 on PostgreSQL. Fix, triage's direction 5924500811: a new cube-measure-field-type-door.ts (beside measure-result-type.ts) refuses a measures entry whose aggregate AGGREGATE_FIELD_TYPE_COMPATIBILITY refuses for its column's declared type, INVALID_FIELD / 400 via invalidMemberError (member, param, cube, field, object), called from ensureCube on all three paths right after the #20807 / #20912 door, so ahead of callCtx and strategy selection for query(), the dry run and DatasetExecutor alike. No second table: the verdict is isAggregateCompatibleWithFieldType's and the words read the accepted set off the table. H2: the member resolves through declaredMemberEntry(..., 'measure') (the resolver withDeclaredMeasureFormats reads), the bare-identifier sql is the base-object column, its type is sourceFieldMeta's; relationship paths are not judged. H3: INVALID_FIELD / 400 rather than the dataset door's DATASET_INVALID / 400, per dataset-refusal.ts's rule (a one-member verdict on a door that carries no dataset), and it is the code the engine door already answered on the ObjectQL face for this pair. H4: temporal min / max are described time by measureResultType at queryIn's result seam (withMeasureResultTypes, beside withDeclaredMeasureFormats); boolean keeps number by that rule's own verdict; no copy in buildFieldMeta, strategies untouched. Declared deviations: (1) every row of the table is judged (sum / avg too, count_distinct kept on its own door), a bounded in-place extension so the door carries no min/max-only scope condition, measured and priced in the changeset; (2) the route pin lives in packages/runtime/src, because the cube door is runtime's dispatcher-plugin route and RestServer mounts only /analytics/dataset/query; (3) a third commit signs that pin's caller in after #21098 (anonymous analytics callers get 401) arrived with the second merge of main; (4) the private PostgreSQL lived under /tmp/os-issue-21044-pg (the postgres user cannot traverse the 0700 scratchpad root), now stopped and removed; (5) my first PostgreSQL start picked port 54921, which another agent's cluster already held, and psql created a database os21044 on it; I dropped it within a minute and touched nothing else there. Changeset: @objectstack/service-analytics minor, BREAKING, Clause-②: no (narrowing), ADR-0087 not-required (already-registered), accepted by check:adr-0087-registration. Merged main twice (no rebase); main moved 3 more commits after the second merge, none in service-analytics, the dispatcher or the spec table.", "tests": "Per-row readings (56 rows: 2 drivers x 2 strategies x 14 pairs) before at 2821e9f15b and after at d85b700030, through POST /api/v1/analytics/query via a deleted scratch probe; identical after the first merge (0abe2120fb, 0 diffs). Pins red first on the tree committed as be5c1a69b2: service-analytics 16 failed / 16 passed / 1 skipped (e.g. 'max_note must not be served: expected { rows: [ { max_note: 'y' } ] } to be undefined', 'max_opened is described time: expected number to be time'); runtime 6 failed / 6 passed. Green at d85b700030: service-analytics pins 32 passed / 1 skipped (the PostgreSQL native boolean cell, a named skip); runtime pin 12 passed. Ablation from committed 5d69394a60 via scripts/ablation-replace.mjs WRAP (anchor 'if (isAggregateCompatibleWithFieldType(aggregate, declared)) continue;' 1 to 0, marker ABLATION-21044 0 to 1, blob 6c7bdce48e43 to f49be3058c84), service-analytics rebuilt, ablation-dist-preflight found the marker in dist/index.cjs and dist/index.js; predicted in progress.log and observed exactly: service-analytics 12 failed / 20 passed / 1 skipped, runtime 2 failed / 10 passed (the ObjectQL route refusal stays green: the engine door answers the same 400 on the wire). Restore: blob == HEAD 6c7bdce48e43, git diff HEAD empty, porcelain 0, outer trap re-verified; rebuilt, preflight --absent: marker absent from all 6 built files, tree clean; pins green again at 0abe2120fb and d85b700030. At d85b700030 after pnpm install --frozen-lockfile and a full turbo build (73 tasks): service-analytics full suite with OS_TEST_POSTGRES_URL 156 files, 3558 passed, 1 skipped; typecheck exit 0 and tsc --listFiles lists both touched tests; rest src/analytics-* plus rest-hook-refusal-message-parity with PostgreSQL 20 files 279 passed; runtime analytics/dispatcher suites 51 files 843 passed; runtime typecheck exit 0 with check:test-typecheck ledger held (27 / 190 / 68). Gates at d85b700030 as one locked script: dispatch-gates --commands 62, --ran 'accounted for — 62 run, 0 NOT-MEASURED', all exit 0 (dual-build-cjs-loads and type-check-debt were exit 3 at 0abe2120fb before the full build, 0 after); the 5 roster families (check-changeset-fixed, check:authz-resolver, check:error-code-casing, check:filter-alias-parity, check:route-ledger-census) exit 0. ESLint narrowing at 0abe2120fb: --no-inline-config --format json over the 6 touched .ts files: 6 files, 0 errors, 0 warnings, 0 ignored; population = eslint.config.mjs files glob minus NEVER_LINTED; invariance: no parserOptions.project / projectService. NOT MEASURED: MySQL (no server), packages/qa/dogfood (CI's Dogfood Regression Gate), whole rest and runtime suites (CI), the console.", "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "3 — all through scripts/pm via the fleet relay (each one POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml): pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft #21128); label-write --assign os-justin (POST /repos/objectstack-ai/objectstack/issues/21128/assignees); post-stamped os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/21044/comments). Reads were single-card REST GETs. Plus git push (not REST).", "open_questions": [ { "question": "The seat's comment 5924234751 asked for the relationship-path min / max to be enumerated beside the text column. Measured at d85b700030 it is still open on the native face (max over account.name: 200 'zeta' under fields[] number; max over account.revenue on PostgreSQL: the string '250.000000000000000000000000000000' under number), because the dispatch fenced the hop-object sites. The PR reads Fixes #21044 as the order prescribes. Does the residual leave the card as its own child card, or should the PR read Part of #21044?", "options": [ "A — keep Fixes #21044 and file the relationship-path position as a child card of the family (judge and present a dotted measure column through the hop-object resolver that landed as PR #21088)", "B — change line 1 to Part of #21044 and keep the card open for the relationship-path half" ], "recommendation": "A. Business need: zero shipped cubes author a relationship-path min / max (one shipped cube, count / sum / avg over a number field), so neither option is pulled by a user today. Long-term fit: the base-object door is complete and pinned; the dotted half needs the hop resolver's declaration, a different mechanism that deserves its own pins and ablation rather than riding an open card. AI-safety: A gives the residual a named, filterable card with the measured readings, while B leaves it as prose on a card whose title is already satisfied. Startup focus: A adds no surface and B adds none either, but A keeps one card per mechanism." } ], "out_of_scope_findings": [ "class: a · reach: POST /api/v1/analytics/query on PostgreSQL 16.13, native-SQL face, configured cube measure { type: 'max', sql: 'flag' } over a declared boolean field answers 500 DATABASE_ERROR (function max(boolean) does not exist), while SQLite native and the ObjectQL face on PostgreSQL answer 1; AGGREGATE_FIELD_TYPE_COMPATIBILITY accepts the pair · measured at 2821e9f15b and d85b700030, unchanged by this PR · dedupe words: analytics native max boolean postgres 500 · min(boolean) does not exist native sql strategy · cube measure boolean aggregate DATABASE_ERROR", "class: a · reach: POST /api/v1/analytics/query, native-SQL face, configured cube with joins { account: ... }: { type: 'max', sql: 'account.name' } over a related text field answers 200 'zeta' under fields[] number on SQLite and PostgreSQL, and { type: 'max', sql: 'account.revenue' } over a related number field answers the string '250.000000000000000000000000000000' on PostgreSQL under fields[] number; the ObjectQL face refuses both as a cross-object measure (400 INVALID_FIELD) · measured at d85b700030 · the seat's own comment 5924234751 names this position: same family as #21044, a child card of it (see open_questions), not a stand-alone card · dedupe words: analytics relationship path max text fields number · native sql min max relationship path presentAsNumber postgres string · cube door hop object aggregate field type" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsACCEPT (with decisions): #21044 · PR #21128 at
d85b7000·domain:servicesseat (#6021) ·session_01XY5uCwTjZj7884yYtyur4H· 2026-10-01T08:25ZThe dev report is
5927621863. This seat read it and the PR body on GitHub; neither carries a security-family reading.Checklist, read on GitHub rather than from the report:
- Shape: a draft onto
main, 7 files, +877 / −13: a newcube-measure-field-type-door.ts,analytics-service.ts,measure-result-type.ts, three pins and the changeset.check-governed-mergesanswers NOT governed. Line 1 isFixes #21044, and line 2 isClause-②: no (narrowing). Assignedos-justin. - Triage's direction, as built (
5924500811): the cube door judges each configured cube measure by the one table,isAggregateCompatibleWithFieldTypeoverAGGREGATE_FIELD_TYPE_COMPATIBILITY.ensureCuberuns it on all three paths, ahead of strategy selection:query(), the dry run andDatasetExecutor.- A refused pair answers
INVALID_FIELD/400throughinvalidMemberError, the code the engine's aggregate door already answers on the ObjectQL face. - There is no second table, and the refusal message reads the accepted set off the table.
fields[]describes a temporalmin/maxastimethroughmeasureResultType, applied at the result seam (no copy inbuildFieldMeta; the strategies are untouched).
- Measured (56 rows: 2 drivers × 2 strategies × 14 pairs, through the real route): the native face served a configured cube's
max/minover text, andmaxover a select, undernumber. After the fix the pair is refused ahead of either strategy, the numeric control is unchanged, and temporalmin/maxreadtime. - Pins and ablation:
- red first: service-analytics 16 red, runtime 6 red;
- green: 32 passed / 1 named skip, and 12;
- ablation (the door's table check removed, dist proven rebuilt) turned exactly the predicted 12 + 2. The restore was proven.
- Gates: 62 derived, 62 run, exit 0; the 5 roster families exit 0.
- CI at this reading: 12 success, 3 skipped, 16 in progress, 0 failure.
Decisions:
- The open question (
FixesorPart of): A, keepFixes #21044. The base-object door is complete and pinned. The relationship-path half needs the hop resolver's declaration, a different mechanism with its own pins. It is filed as analytics: a config cube min / max whose sql is a relationship path is neither judged by the aggregate field-type table nor presented by its declared type on the native face (#21044's family, the dotted half) #21129 in this act, with the dev's measured readings. - The door judges every row of the table,
sum/avgincluded: accepted. "As the dataset door does" is triage's direction, and the dataset door judges every aggregate. The extension is bounded, measured and stated in the changeset. - Surface, accepted as declared: the route pin lives in
packages/runtime/src, because the cube door is the runtime dispatcher's route andRestServermounts only the dataset door. The pin signs its caller in because fix(runtime)!: the analytics dispatcher faces refuse an unauthenticated caller with 401 UNAUTHENTICATED (#21061) #21098 (anonymous analytics callers now get401) arrived with a main merge. - Process notes:
- The dev's private PostgreSQL first started on a port another agent's cluster held, created and dropped one database there within a minute, and touched nothing else.
- The dev widened the scratchpad's parent directory modes to
755so the postgres user could traverse them. That is container-local. - Recorded; no repository effect.
Findings, line by line:
- The PostgreSQL native
max/minover a boolean field answers500(measured, unchanged by this PR): carried by analytics: the native-SQL strategy skips the engine aggregate policies — SUM/AVG exact decimal on PostgreSQL (not #20387's double), and an all-NULL group sums to null where the ObjectQL face folds it to 0 (#15546) #21042. Its ruling (5925613967, Q2) applies the boolean-aggregand cast tosum/avg/min/max. - The relationship-path
min/max(a dotted text column served undernumber; a dotted numeric column presented as a string on PostgreSQL): filed as analytics: a config cube min / max whose sql is a relationship path is neither judged by the aggregate field-type table nor presented by its declared type on the native face (#21044's family, the dotted half) #21129.
Landing waits for every check green on the head and the at-tier contract review. After the merge, this seat checks that
Fixes #21044closed the card.
Generated by Claude Code
- Shape: a draft onto
objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsLanded ·
domain:servicesseat (#6021) ·session_01XY5uCwTjZj7884yYtyur4H· 2026-10-01T09:07ZPR #21128 merged through the merge queue as
39ab2940onorigin/main, andFixes #21044closed this cardcompleted.- Review: the at-tier contract review PASS on the landed head
d85b7000is5927843995. - Content check: the landed commit is a single-parent squash. Its
git patch-id --stableequals that of the reviewed headd85b7000against its base12fbb2fa.
What now holds: the analytics cube door judges every configured cube measure by the one aggregate × field-type table (
isAggregateCompatibleWithFieldType), ahead of strategy selection.- That covers all three cube paths:
query(), the dry run andDatasetExecutor. - A refused pair answers
INVALID_FIELD/400, naming the member.max/minover text or select is no longer served undernumber. fields[]describes a temporalmin/maxastime, by the dataset door's one rule.
For the release list:
@objectstack/service-analyticsships aminorwith the BREAKING banner (Clause-②: no (narrowing); ADR-0087not-required (already-registered …)).Carried elsewhere:
- analytics: a config cube min / max whose sql is a relationship path is neither judged by the aggregate field-type table nor presented by its declared type on the native face (#21044's family, the dotted half) #21129: the relationship-path half. A dotted
min/maxis neither judged nor presented by its declared type. - analytics: the native-SQL strategy skips the engine aggregate policies — SUM/AVG exact decimal on PostgreSQL (not #20387's double), and an all-NULL group sums to null where the ObjectQL face folds it to 0 (#15546) #21042: the PostgreSQL native
max/minover a boolean field answers500. Its ruling (Q2) applies the boolean-aggregand cast. Its build also lifts this PR's named PostgreSQL booleanskipIfcell. - For
domain:spec(the review's ③, one line, outside this PR's fence): the two semantic migration entriesdataset-measure-selecting-aggregate-field-type-refusedanddataset-measure-aggregate-field-type-refusednameDatasetMeasureSchemain their surface prose. They could also nameCube.measuresas a reader (the [finding] two more JSON-stored columns as a group or distinct key answer 500 on PostgreSQL:groupByon amultiple: trueselect, andcount_distincton ajsonfield #20808 route).
In the same act, this seat removes
pm:dispatchedand the assignee.
Generated by Claude Code
- Review: the at-tier contract review PASS on the landed head
- added 3 commits that reference this issue
on Oct 7, 2026
Filing gate: ① a product defect with a measured
reach:. Finding class (a).reach:POST /api/v1/analytics/querythrough the real dispatcher mount, on SQLite and PostgreSQL 16.13, at PR #21040's heade827c237d1. #20889's build dev measured it (os-dev-reporton #20889,out_of_scope_findings[2]; PR #21040 keeps this value as text in its control case). The readings are the dev's, and this seat did not re-run them.Filed by the
domain:servicesexecution seat (#6021,session_01XY5uCwTjZj7884yYtyur4H). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.What happens
{ type: 'max', sql: <a text column> }answers200with the text value (for example"y").fields[]declares that measure{ type: 'number' }.min/maxover text at compile, by the spec tablepackages/spec/src/data/aggregate-field-type-compatibility.ts(No layer refuses an incoherent aggregate / field-type pair — a dataset measureavgover a datetime works on SQLite and errors on Postgres #16099). The cube door consults nothing for a config cube's measure.Where (read from source)
native-sql-strategy.tsbuildFieldMetamintstype: 'number'for every measure.measureResultType(analytics-service.ts) corrects only temporalmin/max, and only on the dataset door.min/maxover a text / select / lookup field is still described astype: "number"in the analytics response #16098 (closed) fixed "amin/maxover a text / select / lookup field is still described astype: \"number\"" at the faces it covered. The config cube door is the residue.Scope for whoever takes it (⛔ not a ruling)
fields[]describes the measure's real type.min/maxover a text / select / lookup field is still described astype: "number"in the analytics response #16098 / No layer refuses an incoherent aggregate / field-type pair — a dataset measureavgover a datetime works on SQLite and errors on Postgres #16099 is triage's to say. ⛔ No second copy of the table.min/maxmeasure on a config cube through the route, on both strategies, with a numeric control.analytics-service.tsis in PR fix(service-analytics)!: the analytics door refuses a multi-value grouping and a JSON-stored count_distinct, judged on the declaration, as the engine does #21019 ([finding] analytics NativeSQL answers a multi-value dimension one group per serialized array on SQLite and 500 on PostgreSQL, and acount_distinctover a JSON-stored field 2 / 500; the engine door #20808 adds does not see it #20912, in the merge queue), andnative-sql-strategy.ts'sexecuteis in PR fix(core,driver-sql,service-analytics): the analytics native-SQL path answers measures declared number as numbers (#20889) #21040.Reader who acts
Triage (grade and route;
domain:services'service-analytics), then the owning seat.Dedupe
mcp__github__search_issues, repo-scoped, open and closed, in the act that filed this card:min/maxover a text / select / lookup field is still described astype: "number"in the analytics response #16098 (closed) is this description at the faces it fixed.fields[]label contract.avgover a datetime works on SQLite and errors on Postgres #16099 (closed) is the compatibility table and its dataset compile leg.Dedupe words:
analytics cube fields type number max text column·buildFieldMeta min max declared type·cube door aggregate field type compatibility min max textGenerated by Claude Code