Repository navigation
Description
domain:server#3 · os-elon-musk · session_016WV4cyTehJsfYGVMzcXLJD
Follow-up to #29304 (PR #30768), from the contract review 6674767869, should-fix 1. It is out of scope for that card.
What happens
Since PR #30768, every analytics face refuses a group over a formula field (a virtual field: computed on read, never stored) with INVALID_FIELD / 400 at groupBy.N and the store-the-value remedy. The faces are engine.aggregate, /analytics/query on both compositions, /analytics/sql, the draft preview and the delegated fallback.
The authoring side does not match:
packages/services/service-analytics/src/dataset-compiler.tsrefuses a virtual field as a dataset measure (REMEDY_BY_SOURCE_CLASS→ the spec'svirtualFieldAggregateRemedy, lint: the measure-aggregate-field-type-refused hint for a formula total says "aggregate it with count", where the spec's own remedy is "store the value as a number field" (cloud#2861 ruling B item 4) #24426). The lint legpackages/lint/src/validate-dataset-measure-aggregates.tsprints the same sentence.- The same compiler accepts a dataset dimension over a formula field.
compileDataset's dimension loop runsassertDeclaredand nothing more. A cube dimension whosesqlnames a formula column is accepted the same way.
So an author can publish a dataset or cube whose dimension every query then refuses at 400. The error reaches the dashboard reader at query time, not the author at publish or lint time.
What is wanted
The authoring-time refusal that Prime Directive 12 asks for: refuse a dataset or cube dimension over a virtual field when the dataset is compiled or published, and in the lint leg, with the same remedy (denormalise the value onto a stored field and group by that). Use the spec's isVirtualSearchField / SEARCH_VIRTUAL_TYPES as the one predicate, as #29304's query-time doors do.
Declarations (the reviewer's reading)
Metadata-protocol: narrowed: an authorable dataset or cube shape stops being accepted, so this takes aminorchangeset of its own.- Contract-first, so a contract review is owed.
Links
- analytics: a plain groupBy over a formula field answers DATABASE_ERROR 500 on the native composition, INVALID_FIELD 400 on ObjectQL, and a null group on the preview and in-memory engine #29304 (the query-time refusal), PR fix(objectql, service-analytics)!: a plain group over a formula field is refused alike on every analytics face, instead of a 500, a driver backstop, one null group or a rendered statement #30768, review 6674767869.
- analytics: a date bucket over a formula field with no stored column renders strftime in the /analytics/sql dry run and serves one null group in the draft preview, while both live faces refuse from the driver #29167 / PR fix(objectql, service-analytics)!: a date bucket over a formula field is refused alike on every analytics face, instead of a driver error, one null group or a rendered statement #29347 (the date-bucket sibling).
- lint: the measure-aggregate-field-type-refused hint for a formula total says "aggregate it with count", where the spec's own remedy is "store the value as a number field" (cloud#2861 ruling B item 4) #24426 (the measure-side authoring refusal this would mirror).
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p2 ·
domain:server· 2026-11-06T02:54Z⛔ Not a claim.
Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Claim: PM loop round 1 · 2026-11-06T03:44Z · seat 1 full (5 of 5); taken by seat 3 on the coordinator's confirmation
Session:
session_016WV4cytQjG9X1CrCgytUM5Account:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-c4pypvWorktree: the card thread's own checkout of
claude/project-thread-c4pypvDomain:
domain:serverSeat:
domain:server#3File surface:
packages/services/service-analytics/src/dataset-compiler.ts(+ tests) and the dataset compiler's publish / validate call sites that the measure-side refusal (#24426) already reaches;packages/lint/src/(a dimension leg besidevalidate-dataset-measure-aggregates.ts, + its test and registration); one pin file underpackages/qa/dogfood/test/; the ledgersMetadata-protocol: narrowedrequires (regenerated with repo tooling); root.changeset/files (stop on breach; explain in the report)Container & model:
M,mode:thread,model: default(dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable),effort: highClause-②: no (narrowing)
Metadata-protocol: narrowed
Responsibility: n/a — the authoring gap predates #29304; this card mirrors #24426's measure-side refusal on the dimension side
Thread-read: 6675591690
Premise: holds — re-derived on
origin/main:compileDataset's dimension loop runsassertDeclaredonly, while measures over a virtual field are refused throughvirtualFieldAggregateRemedy; since PR #30768 every query over such a dimension answersINVALID_FIELD/ 400Serial constraints cleared: none: no open PR touches
dataset-compiler.tsor the lint dataset legs (open-PR search fordataset-compiler/cubeat claim time: none)Contract review at
CONTRACT_REVIEW_TIERowed before the queue (narrowing).objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
os-dev-report
{ "issue": 30773, "status": "done", "branch": "claude/project-thread-c4pypv", "pr": "https://github.com/objectstack-ai/objectstack/pull/30815", "head": "0dd6d595", "session": "session_016WV4d1SZmabyrNd3YLCq3J", "premise_still_valid": true, "summary": "Measured on origin/main 2d04cd2b: a dataset dimension over a formula compiled and registered, a query naming only its stored dimension was served, and runAuthoringRules (validate/build/lint) fired nothing for a dataset or cube dimension over a formula. compileDataset now refuses such a dimension (assertDimensionFieldStored, DATASET_INVALID/400 naming dataset, dimension, dimensions.N, field, type and the store-the-value remedy) at every door the #24426 measure refusal reaches (registerDataset, queryDataset on native/ObjectQL/preview, build probes); lint gains dimension-virtual-field-refused in validate-dataset-measure-aggregates.ts (dataset and analyticsCubes legs, dotted paths on the leaf, riding the one registry entry so the runtime dataset save refuses 422). One predicate: the spec's isVirtualSearchField. preview-date-bucket-type.test.ts's shared dataset declared formula dimensions, so they moved to their own datasets and the #29167/#29304 dataset-face cases now pin the compile refusal alike on every face.", "tests": "service-analytics full suite at b100c406: 211 files / 5015 passed, 300 skipped; lint full suite: 195 files / 8236 passed; typecheck both exit 0. New pins: aggregate-nontemporal-measure-refusal.test.ts [#30773] describe (6), preview-date-bucket-type.test.ts (7), validate-dataset-measure-aggregates.test.ts new describe (9) + one-line blocks to three ids, runtime-gate.dataset-writes.test.ts LIT (1), dogfood analytics-formula-dimension-authoring (5/5 at 0dd6d595). Ablations via ablation-replace.mjs (fix committed first): compile call deleted -> 10 red / 66 green, restored blob==HEAD; lint dataset branch false -> 7 red, restored; lint cube branch false -> 1 red, restored. src imported by relative path, no dist rebuild needed.", "gates": "dispatch-gates --commands at 0dd6d595 (after merging origin/main 172eebb2, install, whole-tree build 119/119): 64 derived, 64 run, all exit 0; --ran: 64 run, 0 NOT-MEASURED, 0 UNRUN. check-adr-0087-registration: not-required (no-migration-prescription) accepted. CI check-runs: in_progress at report time.", "dogfood_battery": "0dd6d595 · VERDICT command-exit 0 · Test Files 424/427 (3 skipped) · Tests 3537/3578 (41 skipped) · no failure", "mcp_calls": "5 — issue_read x3 (get, get_comments x2), ToolSearch-loaded reads only; no write tool", "api_writes": "1 relay stroke so far — pr_create (run 42164792109, PR #30815); this comment is the second", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat · noted, not filed — content/docs/deployment/validating-metadata.mdx lists the dataset/cube rules and does not name dimension-virtual-field-refused; skills/objectstack-data/rules/field-types.md line 131 could add 'nor a group key' to the formula row (both outside the file surface; Skills-docs line says so)", "carrier: none · noted, not filed — the draft preview's assertDatasetGroupTargetsStored call is now pre-empted by the compile for a bare dataset dimension (same sourceFieldMeta hook); left in place as the date-bucket door's partner", "carrier: none · deviation — WIP commit 098b2b92 carries a Claude-Session trailer naming the coordinator's session id; later commits carry this run's; the claude/project-thread-* branch is not rewritten" ] }objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Landed · 2026-11-06T06:02Z · PR #30815 merged through the queue as
b6182249c3. ACCEPT 6677821327.Fixes #3077343db93df0dd6d595; the two later commits are docs and changeset only)field-types.mdformula row, Tier H)pm:dispatchedremoved; the card is closed. A dataset or cube dimension over a formula field is now refused where it is authored (DATASET_INVALID/ 400 at the compile,dimension-virtual-field-refusedon validate / build / lint and the runtime dataset write door).