Skip to content

The ADR-0087 ledger entry for the aggregate x field-type refusal says "no non-temporal pair changes behaviour" — PR #17559 makes that false, and objectstack migrate meta / the upgrade guide are its only readers #17561

Description

@claude

Filed by the os-dev seat delivering #16099's residual 2 (PR #17559), session https://claude.ai/code/session_01ToDPcx9AESFubJkDiFMtKW. Unassigned, not graded, no domain:* set by me. Measured on origin/main @ ad715aca5.

⚠️ Activates when PR #17559 merges. It is true of that PR's landing, not of main today. Filed rather than fixed because packages/spec is fenced out of that card by its dispatch (「凡触 packages/spec 一律转 domain:spec 座位」), so the correction has to be a domain:spec stroke.

The stale sentence, quoted

packages/spec/src/migrations/registry.ts, ADR-0087 entry dataset-measure-aggregate-field-type-refused (around :6490), in its surface field:

dataset measure aggregate × field pairs … over a TEMPORAL field — date, datetime, time — whose aggregate that declared FieldType cannot carry: avg and sum over any of the three. ⛔ The compile leg is scoped to that class and to nothing else: the table's string rows are under #16785 (ruled C …) and its sum × percent row is not executed here either, so no non-temporal pair changes behaviour

PR #17559 makes the final clause false in two places at once. It re-cuts assertAggregateFieldTypeCompatible's scope from the temporal FIELD class to the DERIVING AGGREGATE class (sum / avg), so:

  • every non-temporal sum / avg pair the table refuses now changes behaviour — 75 pairs, measured and enumerated on that PR;
  • sum × percent is executed there, which the entry names specifically as one that is not.

(The entry also cites #16785, which does not resolve — HTTP 404, with its dense neighbours #16783/#16784/#16786/#16787 all resolving. That is the separately-filed #17512 class and is not what this card is about; the real tracker for those rows is #17513. Worth correcting in the same stroke since the text is being touched.)

Why it is a defect and not a nit — the consumers are named

ADR-0087 ledger entries are not commentary. They are the sole data source for objectstack migrate meta, for packages/spec/spec-changes.json, and for the generated docs/protocol-upgrade-guide.md. So an author upgrading across this change is told, by the channel built to tell them, that no non-temporal pair changed — while 75 of them did, including the sum × percent row the text singles out as safe. A migration record that understates what was withdrawn is the failure Prime Directive #10 names, pointed the other way: the runtime enforces more than the contract record admits.

⭐ It is also what #16778 itself treated as load-bearing. That PR shipped a dedicated follow-up commit, docs(changeset,spec): scope the breaking declaration to the temporal class it actually withdraws, whose own reason reads: 「A breaking-change record that overstates what changed tells every consumer reading the release notes that behaviour was withdrawn which was not.」 ⇒ The same standard in reverse is what this card asks for.

What a taker does

  1. Widen the entry's surface to the population actually withdrawn — the temporal rows plus every sum / avg pair the table refuses — and drop the 「no non-temporal pair changes behaviour」 clause and the sum × percent exemption with it.
  2. Widen replacement correspondingly: it currently prescribes only the temporal remedy (min / max for an instant, store a duration as a number). The non-temporal shapes need the rest — count / count_distinct for a non-numeric column, avg instead of sum for a percent, the formula field's numeric input column instead of the formula. PR feat(service-analytics)!: refuse a deriving aggregate over a field type that cannot carry it, for every field type and not only the temporal class #17559's changeset carries a FROM → TO table that can be lifted verbatim.
  3. Re-point the #16785 citations at AGGREGATE_FIELD_TYPE_COMPATIBILITY refuses min/max over the string classes while 15 shipped end-to-end cases depend on them working — the table or the uses must give #17513.
  4. ⚠️ Regenerate, never hand-edit the artifacts: pnpm --filter @objectstack/spec gen:migration-registry, then check:generated. feat(service-analytics)!: refuse an aggregate a datetime measure's field type cannot carry, and reconcile the storage-form annotations to one measured statement #16778's own landing notes say two consecutive runs must be byte-identical and the diff confined to this entry's block.
  5. acceptanceCriteria gets the same treatment — it is qualified to a measure over a date / datetime / time field and says outright that a field of any other class is 「neither refused nor certified by this leg」.

Precedent for the shape of this card

#11950 — 「spec: register the #11566 maxLength narrowing in the ADR-0087 migration ledger (deferred from the enforcement PR — registry.ts was held)」. Same situation: an enforcement PR that could not touch registry.ts, with the ledger work carved into its own domain:spec card. This is that card for #16099.

Lane

packages/spec/src/migrations/registry.tsdomain:spec.

Refs: PR #17559 (the change that falsifies the sentence) · #16099 · #16737 / PR #16778 (wrote the entry) · #17513 (what #16785 should have been) · #17512 (the unresolvable-citation class) · #11950 (precedent)

Blocked-by: #16099


Generated by Claude Code

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions