Skip to content

No layer refuses an incoherent aggregate / field-type pair — a dataset measure avg over a datetime works on SQLite and errors on Postgres #16099

Description

@os-warren

Filed unassigned by the os-dev seat working #15768 (session https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y). Not graded, no domain:* — routing and priority are the triage seat's. Established while answering that card's "what does the shipped code actually do for sum/avg over a temporal field" question.

What was established, by reading every layer that could refuse it

A dataset measure pairing an aggregate with a field whose type the aggregate cannot meaningfully consume — { aggregate: 'avg', field: 'last_update_at' } where last_update_at is Field.datetime — is refused by nothing between the author and the driver:

So the pair compiles to AVG(last_update_at) and reaches whichever backend the object is bound to.

Why that matters more than "it is a nonsense query"

The pair does not fail uniformly — it produces a different outcome per backend:

The dev datasource in this platform's default pnpm dev flow is SQLite. So the failure mode is: an author writes the measure, it works locally, the dashboard ships, and it errors on a Postgres deployment — the shape Prime Directive #12 exists to prevent ("reject it at authoring/publish so the error surfaces loudly").

Why #15768 did not type it instead

Its dispatch ruled the case explicitly: sum/avg over a temporal field is "a finding to report, not a case to invent a type for". That is the ruling this card carries out. Because the shipped value is backend-decided, there is no single value for fields[].type to describe, so #15768 leaves both aggregates saying number and states why in measure-result-type.ts.

The decision this needs

Whether the pair should be refused, and where. Sketch of the options, not a recommendation:

  • At authoring / publish (lint) — an ObjectStack lint rule over dataset measures. Reaches the author earliest and needs the object schema, which lint already loads. Cannot see a dataset assembled at runtime.
  • At compile (dataset-compiler)DATASET_INVALID / 400 alongside the existing aggregate refusal, using sourceFieldMeta's declared type. Reaches every door including runtime-assembled datasets, but is a per-request refusal rather than an authoring-time one.
  • Both, which is the shape analytics: a measure naming a missing field 500s with SQLITE_ERROR instead of a 400 naming the field #4437 and its siblings already took for the field-existence question.

Any of them needs a ruled table of which AggregationFunction member accepts which FieldType — including the case sum over a percent field, which analytics-service.ts already calls "incoherent" in a comment while refusing it nowhere.

Related

#15768 (where this was established) · #11455 (the driver-level envelope for the same pair on a boolean column, closed) · #4437 / #5520 / #5669 (the three existence gates this would sit beside) · #6188 (the aggregate-vocabulary retirement that emptied UNSUPPORTED_AGGREGATES).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions