feat(analytics): an authored cube's measures.format and dimensions.granularities take effect on the query doors (#20282, stage 2) - #20635
Conversation
…anularities reach the query doors (wip) Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…ty at the query doors, with dataset controls Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
… over POST /analytics/query and /analytics/sql Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…es are live; pin the declared narrowing; changeset Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…be-format-granularities
…cribe what the analytics service does with them Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…be-format-granularities # Conflicts: # packages/spec/liveness/README.md
…e-granularity-default-enforced Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 137 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c5adcea116fe2dd0005d0ab8efa1f39e8e36a4d6 && git checkout c5adcea116fe2dd0005d0ab8efa1f39e8e36a4d6
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 3f45b6cc13fb4646fab723a517225aa911cf17b8 257ab1bc9287fb746279ea387a631eb389fb1a67 && git checkout -B drift-repro 3f45b6cc13fb4646fab723a517225aa911cf17b8 && git merge --no-ff 257ab1bc9287fb746279ea387a631eb389fb1a67
node scripts/docs-audit/affected-docs.mjs --json 3f45b6cc13fb4646fab723a517225aa911cf17b8
|
Part of #20282
Clause-②: yes (narrowing)
Stage 2 of #20282, under claim
5886559774(session_014EJ1ED8X4MMrT18BhVx4tx,domain:specseat 2). An AUTHORED analytics cube'smeasures.formatanddimensions.granularitiesnow reach the readers a compiled dataset already reaches.refreshKeyis measured only, and nothing is built for it. The card stays open for stage 3 (descriptions) and for therefreshKeydecision.What changes
One Cube shape has three producers: authored cubes (
AnalyticsServiceConfig.cubes, which the CLI threads fromanalyticsCubes), compiled datasets, and ad-hoc inference. Until now, both keys were read only on the compiled-dataset path.measures.formatanalytics-service.ts#withDeclaredMeasureFormatsruns inqueryIn, beside the SQL-echo gate.formatasfields[].format. This holds for every strategy (NativeSQL, ObjectQL, the delegated fallback) and for both member spellings.format, the same valueenrichResultColumnswrites anyway.GET /analytics/metais unchanged. See the premise checks below.dimensions.granularitiesanalytics-service.ts#withDeclaredGranularityDefaultsruns onquery()and on thegenerateSql()dry run, before the source-field gates and strategy selection.dataset-executor.ts#declaredDefaultGranularity, a new function extracted fromgranularityOf, which now calls it too. Both producers are therefore read by one rule.timeDimensionsentry that carries only adateRange, for a dimension the query does not group by, stays a filter.packages/spec/src/data/analytics.zod.ts, after PR docs(spec): re-anchor the dead tracker citations in stack.zod.ts and data/analytics.zod.ts to the commits that decided them (stage 7) #20616 merged;origin/mainmerged first throughscripts/pm/os-regen-merge.shasd963f30e33)MetricSchema.formatandDimensionSchema.granularitiesgain describes that state the enforcement.fields[].formatslot documents.content/docs/references/data/analytics.mdxis regenerated withgen:docs.packages/spec/liveness/analytics_cube.jsongodead→live. Each cites its readers asfile#symboland the CLI threading producer.state-counts/analytics_cube.mdis regenerated withgen:liveness-counts: live/dead goes from 18/9 to 20/7.analytics_cubeNotes cell inliveness/README.md, which listed both keys among the dead, is rewritten.@objectstack/specminor and@objectstack/service-analyticsminor, with a**BREAKING**sentence.Clause-② (measured arm): yes (narrowing)
fields[].formatis populated for authored cubes. The contract already declares that member.958251b6ac, run once on head and once with the fill ablated throughscripts/ablation-replace.mjs. The mutation landed (blob9d77adcd798f→ee1b928e6f7e) and was restored to HEAD. The probe is not committed.placed_atdeclaresgranularities: ['month']and whoseshipped_atdeclares two intervals.placed_atINVALID_FIELD(the engine path's custom-SQL refusal)queryCapabilitiesoffers raw SQL only (a hand override;AnalyticsServicePluginwires both)countgrouped byplaced_atshipped_at(two intervals)granularity: 'month'stated by hand already got. The pin isDECLARED NARROWINGin the service test.**BREAKING**sentence (the class and its remedy) and the dispositionnot-required (no-migration-prescription).check-adr-0087-registration:✓ 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.Premise checks, against
origin/main7510663c87formatonCubeMeta: not done, because the premise does not hold.formatonly throughfields[]. A compiled dataset'sgetMetaprojection is{ name, type, title }too.AnalyticsMetadataResponseSchemarecords the narrowing for this (#6442).content/docs/api/data-api.mdxalready sends clients tofields[]forformat.contracts/analytics-service.ts,api/analytics.zod.ts) are outside this claim's surface.granularitiesrefusal: none invented.refreshKeycensus (tree958251b6ac;packages/services,packages/drivers,packages/rest, non-test):refreshKey: 0 hits. The repo-wide control finds 9 files.ICacheServiceconsumers: plugin-auth rate-limit and secondary storage, runtime inbound rate limit, dispatcher counter store, sms. None is in analytics.dimension-labels.ts#withLabelFetchCache(the lit control, 1 hit).service-job'sIJobService: cron, interval and db adapters), and nothing in analytics uses it.refreshKey, so building a cache is a separate card.Verification
Final head
d665865d5b, unless a line says otherwise. Builds and test runs went throughos-verify-lock.sh. Thecheck:*gates and eslint ran outside it, as the lock's scope prescribes. So didgen:docs, after two lock acquisitions forcheck:generated --fixtimed out in the queue (exit 99).pnpm --filter '@objectstack/service-analytics...' build: exit 0.turbo run build --filter='@objectstack/runtime^...': 29/29.pnpm --filter @objectstack/spec build, after the describe edit: exit 0.--project local--project repo958251b6ac; service-analytics src is unchanged since)check:test-typecheck, and the new file adds no debt.tsc --listFilesputs the new service test in service-analytics' program.formatand no time dimension:packages/clientanalytics-automation-json-erasure.test.ts, and the dogfood analytics files, which declare neither key.git diff HEADempty):9d77adcd798f→0d48cfde9469)9bf3b3b0b4dist/9bf3b3b0b49d77adcd798f→94b1bc63165a)958251b6acdist/9bf3b3b0b4ablation-dist-preflight(marker present in 2 built files). Each restore leg was rebuilt again and checked--absent, with the tree clean.dispatch-gates --commands: 111 derived.--ranwith exit codes: 111 run, 0 NOT MEASURED. 109 exit 0.1322cc72c:check:platform-checklist:areas/identity-auth.jsoncitesauth-plugin.ts#twoFactor, which is absent;check:docs-transcript-drift: 4 CLI transcripts print "author-time rules (47)", and the count derives to 46.check:liveness:analytics_cube 27 classified (live 20, dead 7), with the state-counts current.check:generated: all 15 artifacts up to date.eslint --no-inline-config --format jsonon the 4 changed.tsfiles: 4 files, 0 errors, 0 warnings..md/.json) are reported by eslint itself as "File ignored because no matching configuration".eslint.config.mjsnever enables type-aware linting (noparserOptions.project), so this diff cannot move a verdict on an untouched file.Acceptance notes
5886559774, each forced by the claim's own items:analytics_cubeNotes cell inpackages/spec/liveness/README.md. It is the prose half of the state table whose shard the claim names, and it named both keys as dead.packages/runtime/src/analytics-authored-cube-format-granularity.test.ts, the REST pin the claim asks for "where the analytics harness reaches". It is a new file, and the runtime harness drives the real dispatcher route.content/docs/references/data/analytics.mdx, which the describes regenerate.packages/services/service-analytics/src/preview-evaluator.tsstill open-codes the single-entry rule (dim.granularities?.length === 1) on the draft-preview path. That makes it a third spelling besidedeclaredDefaultGranularity. It is outside this surface;carrier:承接者:无.examples/app-showcase/src/data/analytics/showcase.cube.tsauthorsdone_rate: { format: 'percent' }. That named style now reachesfields[].formatverbatim, and a numeral-pattern renderer does not read it as a percentage. The spec describe now teaches the pattern vocabulary. The example's value is outside this surface and is reported to the seat.os serveartifact-fallback boot threads noanalyticsCubes.Generated by Claude Code