Filed from PR #8369 (#8296). Unassigned; the fix lands in packages/spec, which that card's dispatch deliberately fenced off ("if implementation requires a change — not just a read — to packages/spec, stop and route that slice to the spec seat").
Blocked-by: #8296
The asymmetry
PR #8369 gives the FILTER axis its unmaterializable verdict at both doors: a where on a formula field is now 400 INVALID_FIELD instead of 200-with-zero-rows, at the REST ingress and at the engine seam that saved reports / flows / dashboards reach directly.
Its SORT-axis twin, #7095, made exactly the same kind of change — an engine-boundary refusal for a formula field that used to answer 200 — and paired it with an ADR-0087 semantic migration entry:
packages/spec/src/migrations/entries/semantic/17.engine-find-formula-order-by-refused.ts- registered in
packages/spec/src/migrations/registry.ts - surfaced through
spec-changes.json and the generated docs/protocol-upgrade-guide.md
The FILTER refusal has no such entry. Its entry would be id: engine-find-formula-filter-refused (or similar) with the same three fields the sort entry carries — surface (a where naming a formula field, at both doors), replacement (denormalise onto a stored field, written when the source changes, and filter that; summary / autonumber need no action), and acceptanceCriteria (grep saved reports, flows, dashboards and view filters for a filtered field whose object declares it as a formula).
Why it matters
That entry is the only notification channel for this class. The sort entry says so in as many words: this is a code-path API with no sys_metadata row for the D2 chain to rewrite, so the ledger IS the notification. objectstack migrate meta, spec-changes.json and the upgrade guide all read the registries, so an unregistered behaviour change is a silent gap on the upgrade path — the #6148 shape.
It matters slightly MORE here than on the sort axis: a refused sort returns the same rows in a different order, while a refused filter changes the row SET, and the surfaces that break are author-written (sys_saved_report.query.filter, flow node filters, dashboard widget filters), not code.
Why PR #8369 did not include it
Not an oversight and not a judgement that it is unnecessary — the dispatch fenced packages/spec changes to the spec seat, and adding an entry means touching entries/semantic/, registry.ts and two regenerated artifacts. The changeset there is therefore minor for both packages with no **BREAKING** declaration (the launch-window convention, and what #6994 — the same refusal class at ingress — shipped as), so the ADR-0087 changeset gate is not triggered and nothing currently asks the question.
Not for this issue to decide
Whether the entry is genuinely required, or whether not-required (no-migration-prescription) is the honest disposition, is a real question: no key, symbol or stored value moves, and no mechanical rewrite exists in either direction (the platform cannot invent the stored column, and it must not filter post-hoc — driver.find has already applied limit / offset, so a post-hoc predicate would filter an arbitrary PAGE). The sort axis answered "register it anyway" for the identical shape, which is the strongest available precedent.
Related: #8299 (the disposition catalog has no category for published runtime surfaces with no metadata surface) is the general form of the same question.
Filed from PR #8369 (#8296). Unassigned; the fix lands in
packages/spec, which that card's dispatch deliberately fenced off ("if implementation requires a change — not just a read — topackages/spec, stop and route that slice to the spec seat").Blocked-by: #8296
The asymmetry
PR #8369 gives the FILTER axis its unmaterializable verdict at both doors: a
whereon aformulafield is now400 INVALID_FIELDinstead of 200-with-zero-rows, at the REST ingress and at the engine seam that saved reports / flows / dashboards reach directly.Its SORT-axis twin, #7095, made exactly the same kind of change — an engine-boundary refusal for a
formulafield that used to answer 200 — and paired it with an ADR-0087 semantic migration entry:packages/spec/src/migrations/entries/semantic/17.engine-find-formula-order-by-refused.tspackages/spec/src/migrations/registry.tsspec-changes.jsonand the generateddocs/protocol-upgrade-guide.mdThe FILTER refusal has no such entry. Its entry would be
id: engine-find-formula-filter-refused(or similar) with the same three fields the sort entry carries —surface(awherenaming aformulafield, at both doors),replacement(denormalise onto a stored field, written when the source changes, and filter that;summary/autonumberneed no action), andacceptanceCriteria(grep saved reports, flows, dashboards and view filters for a filtered field whose object declares it as aformula).Why it matters
That entry is the only notification channel for this class. The sort entry says so in as many words: this is a code-path API with no
sys_metadatarow for the D2 chain to rewrite, so the ledger IS the notification.objectstack migrate meta,spec-changes.jsonand the upgrade guide all read the registries, so an unregistered behaviour change is a silent gap on the upgrade path — the #6148 shape.It matters slightly MORE here than on the sort axis: a refused sort returns the same rows in a different order, while a refused filter changes the row SET, and the surfaces that break are author-written (
sys_saved_report.query.filter, flow node filters, dashboard widget filters), not code.Why PR #8369 did not include it
Not an oversight and not a judgement that it is unnecessary — the dispatch fenced
packages/specchanges to the spec seat, and adding an entry means touchingentries/semantic/,registry.tsand two regenerated artifacts. The changeset there is thereforeminorfor both packages with no**BREAKING**declaration (the launch-window convention, and what #6994 — the same refusal class at ingress — shipped as), so the ADR-0087 changeset gate is not triggered and nothing currently asks the question.Not for this issue to decide
Whether the entry is genuinely required, or whether
not-required (no-migration-prescription)is the honest disposition, is a real question: no key, symbol or stored value moves, and no mechanical rewrite exists in either direction (the platform cannot invent the stored column, and it must not filter post-hoc —driver.findhas already appliedlimit/offset, so a post-hoc predicate would filter an arbitrary PAGE). The sort axis answered "register it anyway" for the identical shape, which is the strongest available precedent.Related: #8299 (the disposition catalog has no category for published runtime surfaces with no metadata surface) is the general form of the same question.