Skip to content

Commit 4278601

Browse files
committed
docs(spec): the measures.sql ledger note says both expression branches are gone and what still passes a non-column sql through
Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4ec5057 commit 4278601

1 file changed

Lines changed: 1 addition & 1 deletion

File tree

‎packages/spec/liveness/analytics_cube.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"verifiedAt": "2026-10-02",
6464
"evidence": "packages/services/service-analytics/src/strategies/native-sql-strategy.ts#resolveMeasureSql — `measure.sql` is the column the aggregate is applied to (`'*'` the COUNT(*) form), and `qualifyAndRegisterJoin(measure.sql, …)` is what lowers a dotted reference into a LEFT JOIN chain; packages/services/service-analytics/src/strategies/objectql-strategy.ts#resolveFieldName reads `measure.sql.replace(/^\\$/, '')` as the aggregate field for the `engine.aggregate` path; packages/services/service-analytics/src/analytics-service.ts#fieldsOfColumnSql resolves it to the field(s) the analytics door's field-level read gate judges.",
6565
"producer": "packages/cli/src/commands/serve.ts#CAPABILITY_PROVIDERS — the `analytics` entry declares `configKey: 'analyticsCubes'` and the capability resolver threads it into the plugin (`const cubes = (config as any).analyticsCubes ?? (config as any).cubes ?? []; arg = { cubes }`); packages/services/service-analytics/src/analytics-service.ts#registerAll (`if (config.cubes) this.cubeRegistry.registerAll(config.cubes)`) is where the authored array becomes the registry every consumer below resolves through. Without this thread an authored cube reaches no reader at all — the `seed.env` shape (#4837).",
66-
"note": "REQUIRED. NARROWED 2026-09-30 (#20943, maintainer ruling D; ADR-0021 zero raw expressions, ADR-0049 enforce-or-remove): the value is a COLUMN REFERENCE — a bare identifier, a dotted identifier path (relationship hops, then the column), or `'*'` — and any SQL expression is refused at parse with a prescription naming the ADR-0021 dataset form (a measure-scoped `filter`, `derived: { op, of }`). The admitted pattern is the one `IDENTIFIER_PATH` (native-sql-strategy.ts) and the read gate already use to tell a column path from an expression (#4157), so every admitted value other than `'*'` (which reads no field value) resolves to a field the gate can judge. Still LIVE: the key itself is unchanged and read at the three sites above. The runtime's expression branches (verbatim emit on the raw-SQL path, the gate's stand-down) remain for a cube that reaches the service without meeting the parse; their deletion is the services-lane follow-up. The D3 entry is `cube-member-sql-expression-retired`; there is no D2 conversion, because an expression has no mechanical rewrite into a dataset. NARROWED again 2026-10-02 (#21409, the count-only boundary): `'*'` is admitted only under `type: 'count'` — the measure's refinement asks the one predicate it shares with the dataset measure (`data/analytics-column-reference.ts#rowWildcardOutsideCount`), and refuses `'*'` under any other type at `sql`, naming the slot and prescribing a `count` or a column; a dataset `sum` over `'*'`, which compiles to this very member, answered 500 DATABASE_ERROR at `POST /analytics/dataset/query` on both strategies before the rule. Cross-field, so a declared dropped-refinement site (`data/Metric` in `dropped-refinements.baseline.json`). D3 entry `analytics-row-wildcard-outside-count-refused`; no D2 conversion."
66+
"note": "REQUIRED. NARROWED 2026-09-30 (#20943, maintainer ruling D; ADR-0021 zero raw expressions, ADR-0049 enforce-or-remove): the value is a COLUMN REFERENCE — a bare identifier, a dotted identifier path (relationship hops, then the column), or `'*'` — and any SQL expression is refused at parse with a prescription naming the ADR-0021 dataset form (a measure-scoped `filter`, `derived: { op, of }`). The admitted pattern is the one `IDENTIFIER_PATH` (native-sql-strategy.ts) and the read gate already use to tell a column path from an expression (#4157), so every admitted value other than `'*'` (which reads no field value) resolves to a field the gate can judge. Still LIVE: the key itself is unchanged and read at the three sites above. Both runtime expression branches are gone: the field-level read gate's stand-down with #20965, and the raw-SQL path's verbatim emit with #21000. What remains for a cube that reaches the service without meeting the parse is packages/services/service-analytics/src/strategies/native-sql-strategy.ts#qualifyAndRegisterJoin passing a non-column `sql` through as-is, inside the measure's aggregate (`SUM(amount + 1)`, `SUM(COALESCE(account.amount, 0) / 2)`, measured 2026-10-02 through `AnalyticsService#generateSql` with no field reader wired). The D3 entry is `cube-member-sql-expression-retired`; there is no D2 conversion, because an expression has no mechanical rewrite into a dataset. NARROWED again 2026-10-02 (#21409, the count-only boundary): `'*'` is admitted only under `type: 'count'` — the measure's refinement asks the one predicate it shares with the dataset measure (`data/analytics-column-reference.ts#rowWildcardOutsideCount`), and refuses `'*'` under any other type at `sql`, naming the slot and prescribing a `count` or a column; a dataset `sum` over `'*'`, which compiles to this very member, answered 500 DATABASE_ERROR at `POST /analytics/dataset/query` on both strategies before the rule. Cross-field, so a declared dropped-refinement site (`data/Metric` in `dropped-refinements.baseline.json`). D3 entry `analytics-row-wildcard-outside-count-refused`; no D2 conversion."
6767
},
6868
"format": {
6969
"status": "live",

0 commit comments

Comments
 (0)