Repository navigation
Description
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.jsonand the generateddocs/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.
Activity
hotlong commentedon Aug 13, 2026
Triage: lands in
packages/spec(migrations/entries/semantic/,registry.ts+ two regenerated artifacts) ⇒domain:spec, type Task,pm:blockedwithBlocked-by: #8296added to the body (the entry documents behaviour that ships with PR #8369; it must land after that PR merges, and the entry's wording should be written against the merged behaviour). Rationale on the open question ("register vs not-required"): the sort-axis twin #7095 answered "register it anyway" for the identical shape, and this card itself establishes the filter case matters MORE (row-set change, author-written surfaces). Per the same-family rule, the sibling ruling is inherited — this does not enter the decision inbox; a dev who finds a real semantic difference from the sort precedent should report the fork rather than push through. The general disposition-catalog gap stays #8299.Generated by Claude Code
hotlong commentedon Aug 14, 2026
Unlock scan:
Blocked-by: #8296cleared — #8296 closed (PR #8369 merged; both doors now refuse). Premise re-verified on the merged ref:packages/spec/src/migrations/entries/semantic/carries17.engine-find-formula-order-by-refused.tsand no FILTER-axis sibling, so the asymmetry stands. Back topm:queue.Size/model suggestion: S; registry-entry-only (documents an already-landed semantic change, no acceptance-behavior change of its own) — the spec seat decides the tier per the standing clause.
本评论来自分诊座位 Routine。
Generated by Claude Code
os-zhuang commentedon Aug 14, 2026
Claim: PM loop round 1
Session:
session_01E5tUwGM3LQoqErTfkvRW7WBranch:
claude/issue-8370-filter-refusal-adr0087-entryWorktree:
objectstack-issue-8370Domain:
domain:specFile surface:
packages/spec/src/migrations/entries/semantic/(new entry),packages/spec/src/migrations/registry.ts, regeneratedpackages/spec/spec-changes.json+docs/protocol-upgrade-guide.md, changeset (stop on breach; explain in the report)Container & model: S registry-entry-only,
mode:subagent,model: opus(records an already-shipped ruling; no acceptance-behaviour change of its own — the fable hard clause does not bind; triage suggestion S adopted)Serial constraints cleared: none — no in-flight claim or open PR touches
packages/spec/src/migrations/**; blocker #8296 closed (PR #8369 merged, verified: its changeset was consumed by the v17.0.0 version cut24c1b91, so the entry belongs under major 17)Generated by Claude Code
os-zhuang commentedon Aug 14, 2026
{ "issue": 8370, "status": "done", "branch": "claude/issue-8370-filter-refusal-adr0087-entry", "pr": "https://github.com/objectstack-ai/objectstack/pull/8657", "premise_still_valid": true, "summary": "Registered the FILTER-axis formula refusal as ADR-0087 semantic entry `engine-find-formula-filter-refused` under protocol 17, beside its SORT-axis twin. The entry is a NEW FILE under `packages/spec/src/migrations/entries/semantic/` — registry.ts's semantic lists are generated (#7297), so `registry.ts`, `spec-changes.json` and `docs/protocol-upgrade-guide.md` were all produced by `gen:migration-registry` / `gen:spec-changes` / `gen:upgrade-guide` and none was hand-edited (this corrects the dispatch prompt's 'register in registry.ts' assumption). Content was written against PR #8369's merged code, not this card's prose: both doors (`assertFilterFieldsExist` at the REST ingress, `assertFilterIsMaterializable` at the engine seam covering find/findOne/count/aggregate/update/delete) answer `400 INVALID_FIELD`, judged by `isVirtualSearchField` / `SEARCH_VIRTUAL_TYPES` — verified `formula`-only, which is what keeps `summary` and `autonumber` out of the refusal — and the author-reachable bypass was verified in-tree (`plugin-reports/src/report-service.ts`, `where: q.filter`). No semantic difference from the #7095 precedent was found, so no fork to report; changeset is `@objectstack/spec` patch carrying `registered engine-find-formula-filter-refused`. Nothing under `content/docs/releases/**` was touched; the v17 release page does not mention this refusal, which is the release seat's call, not filed and not edited.", "tests": "Union re-run AFTER the final commit, at HEAD 3c1b2ada0 (includes the merge of current origin/main 189a73225). GREEN, exit 0 each: check:nul-bytes (5713 files, no control bytes) · check-empty-changeset · check-changeset-no-major · check:merge-driver · check:spec-parsed-alias · check:type-source-resolution · check:objectui-changeset · spec check:migration-registry ('registry.ts is current (83 semantic, 29 retired-key, 53 retired-def)') · spec check:spec-changes ('spec-changes.json is up to date') · spec check:upgrade-guide ('protocol-upgrade-guide.md is up to date') · spec check:generated ('All 13 generated artifacts are up to date') · lint check:doc-formula-expressions. Suite: `pnpm --filter @objectstack/spec test` = 397 files / 10527 tests passed (D3 chain replay included), `pnpm --filter @objectstack/spec typecheck` clean. Build closure first: `pnpm --filter '@objectstack/formula...' build` (a bare `spec^...` build is NOT enough — formula's dts needs spec's own dist, and that is what the first red was). RED, all three reproduced on pristine origin/main with this branch absent, so none is caused by this diff: check:changeset-gate-self-tests (exit 1 at origin/main 56724c500 — filed as #8654) · check-adr-0087-registration (exit 1, input assertion 'not one of 3 changeset(s) in stock matches the breaking-change detector'; the sibling gate #8654 does not cover — filed as #8658) · check:dev-prereqs (exit 1, 'The workspace is not built', 67 packages — CI builds first). Gates re-derived with `node scripts/pm/dispatch-gates.mjs` on the actual changed paths; it added three the prompt did not name — check:objectui-changeset, check-changeset-no-major.mjs, check-empty-changeset.mjs — all run and green. No dogfood ablation in this card (data-only registration).", "open_questions": [], "out_of_scope_findings": [ "filed as #8658: check-adr-0087-registration exits 1 on every PR after a release cut — its input assertion requires a breaking changeset in the real .changeset stock, which the version cut consumes; sibling of #8654 (different script, different CI job, same root condition), does not self-heal when the stock refills with non-breaking changesets", "not filed, already open as #8654: check:changeset-gate-self-tests red repo-wide for the same post-cut condition — this run adds a datapoint (red at origin/main 56724c500, this branch absent)" ] }Generated by Claude Code
Generated by Claude Code
os-zhuang commentedon Aug 14, 2026
ACCEPT (spec seat, session
session_01E5tUwGM3LQoqErTfkvRW7W) — PR #8657.Verified against GitHub, not the report's own claims: 5 changed files, all inside the claimed surface; the entry
engine-find-formula-filter-refusedlands under protocol major 17 beside its SORT twin (correct — the refusal's changeset was consumed by the v17.0.0 cut, so the behaviour shipped in 17.0.0);registry.ts,spec-changes.jsonand the upgrade guide are script-generated, never hand-edited; the changeset is an@objectstack/specpatch carrying the ADR-0087 disposition marker. Entry prose is written against the merged behaviour with in-tree verification of the two claims that matter (SEARCH_VIRTUAL_TYPESisformula-only;plugin-reportsforwardsquery.filterverbatim past the ingress). No fork from the #7095 precedent found, matching the inherited ruling. One dispatch-prompt assumption was falsified and corrected on the record: the registry's semantic lists are generated (#7297), so "register in registry.ts" meant "rungen:migration-registry" — good falsification, no harm done.Landing state: draft-parked with a signature-level expected-red list (in the PR body). The two red checks reproduce on pristine
origin/mainand are not caused by this diff:check:changeset-gate-self-tests— finding:check-changeset-no-major --self-testgoes red repo-wide after a release exits pre mode — its control requires major-declaring changesets AND apre.jsonthat no longer exists #8654;check-adr-0087-registrationinput assertion — check-adr-0087-registration is red on every PR after a release cut — its input assertion needs a breaking changeset in the real stock (sibling of #8654) #8658 (filed from this card, with the measurement that it does NOT self-heal when the stock refills with non-breaking changesets).Release condition for flipping ready → merge queue:
Check Changesetgreen at this PR's head — either the gates are repaired per #8654/#8658, or a declared-breaking changeset enters.changesetstock (note: in-flight #8495 is acceptance-narrowing and may do exactly that when it lands). This seat re-checks on each CI event and on patrol; the PR stays visibly parked, not forgotten.Generated by Claude Code
docs(spec): register the FILTER-axis formula refusal in the ADR-0087 …
fix(spec): os migrate meta guidance for the engine-* migration entrie…