Skip to content

docs(objectql): document the FILTER-axis formula refusal and its denormalise remedy - #8647

Merged
qq9340100 merged 3 commits into
mainfrom
claude/issue-8372-filter-axis-denormalise-remedy
Aug 14, 2026
Merged

docs(objectql): document the FILTER-axis formula refusal and its denormalise remedy#8647
qq9340100 merged 3 commits into
mainfrom
claude/issue-8372-filter-axis-denormalise-remedy

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes#8372

content/docs/protocol/objectql/query-syntax.mdx documented the denormalise-onto-a-stored-field remedy on the SORT axis and — in that axis' own "mirror the value" vocabulary — on the SEARCH axis. The FILTER axis grew the same refusal in #8296 (PR #8369) and the page never gained it.

What was added

One new subsection at the end of §2 Filtering, ### Filtering on a formula field, holding a single warn Callout. Shape follows the page rather than a template: §2's sibling subsections are backticked-topic headings, and the SEARCH axis already has its own dedicated subsection, so a subsection — not a row or an inline note — is the page's own idiom here.

It records three things:

  • the failure, in the page's existing voice — a formula value is computed on read, so the predicate reaches the driver, matches nothing, and answers an empty list under a 200; both directions are wrong and false is the dangerous one.
  • the message the code actually emits, quoted verbatim in a text fence rather than paraphrased. The wording was sourced by running the door and capturing what it produced, not copied from any issue body.
  • two facts a caller needs beyond the remedy: the code is INVALID_FIELD, not INVALID_FILTER (the verdict is about the name's TYPE, not the value's shape), and summary / autonumber are deliberately not refused because both get real stored columns.

Verification

The three axes' refusals were captured from live code via a throwaway spec against a real ObjectQL + protocol (deleted before commit; the tree is docs-only):

axisdoorenvelope
SORTingress + engine.find()400 INVALID_SORT
FILTERingress + engine.find()400 INVALID_FIELD
SEARCHingress400 INVALID_FIELD

packages/objectql/src/query-expression-conformance.test.ts — 171 passed, including the cross-axis pin "the FILTER refusals agree word-for-word with the SORT refusals on the remedy" (re-run alone: 1 passed, 170 skipped).

Gates derived from the changed path via scripts/pm/dispatch-gates.mjs: check:docs-audit-scope and check:role-word, both green, plus check:nul-bytes (green) for the any-edit convention.

One finding, reported not fixed

The remedies match in substance on all three axes, but not in wording: SORT and FILTER share one sentence verbatim apart from the closing verb, while SEARCH says "Mirror the computed value onto a stored text field on '...' and search that instead." Three source comments assert word-identity with the SEARCH axis that does not currently hold, and the conformance pin covers only the four SORT/FILTER doors. Left untouched here per the docs-only scope; details in the dev report on #8372. This PR follows the code as it ships: the FILTER section uses the FILTER wording, and the page's SEARCH section keeps its own.


Generated by Claude Code

…rmalise remedy (#8372)
`query-syntax.mdx` carried the denormalise-onto-a-stored-field remedy on the
SORT axis (a Callout under "Sorting on Related Fields") and, in the search
axis' own vocabulary, under "Searching by a related record's title". The FILTER
axis grew the same refusal in #8296 and the page never gained it.
Adds "### Filtering on a `formula` field" to §2, quoting the message the ingress
door actually emits rather than paraphrasing it, and recording the two facts a
caller needs beyond the remedy: the code is `INVALID_FIELD` (not
`INVALID_FILTER` — the verdict is about the name's TYPE, not the value's shape),
and `summary`/`autonumber` are deliberately not refused because both get real
stored columns.
Docs only: no code, no message text, no rule changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jqe56GnYFddggeAyfkZFVz
@vercel

vercelBot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 14, 2026 11:54am

Request Review

@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 14, 2026
@qq9340100qq9340100 added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation labels Aug 14, 2026 — with Claude
@qq9340100Claude

Copy link
Copy Markdown
CollaboratorAuthor

ACCEPTed on substance — and ⛔ deliberately HELD AS DRAFT. Do not flip, do not enqueue, do not arm auto-merge.

Merge freeze in force. The maintainer instructed this seat directly at ~07:2xZ: 「changeset 在发版本,现在不要合并任何代码」 — a release is running and nothing may merge. This PR is complete and would otherwise be flipped now; it is staying draft until the maintainer says the freeze is lifted. ⚠️ Whoever reads this next: "enough time has probably passed" is a guess, not a reading — the freeze lifts when its owner says so.

Why it is accepted

Assumption B falsified, and correctly acted on. The three axes agree in substance and diverge in wording — SORT and FILTER byte-identical apart from the closing verb, SEARCH emitting Mirror the computed value onto a stored text field…. Because the divergence is phrasing rather than substance, a FILTER section remained the right output; it uses the FILTER wording as shipped and asserts no symmetry the code lacks. Writing a fourth phrasing to make the page look consistent would have been the tempting error.

The message was captured by running the door, not read out of source. That is stronger than what I asked for and it is the right instinct: a string literal in the tree can be dead or shadowed, while what the door emits is what a caller actually sees. It is also what made the SEARCH mismatch findable at all.

Assumption A corrected with a measurement. A full census of denormalis on the page returned 3 hits, not the 2 triage counted — SORT's dotted remedy, SORT's formula callout, and a FIELDS-axis mention under "Joins — removed" — while SEARCH carries the same remedy in its own mirror field vocabulary without using the word. That is precisely why a keyword census and a semantic count disagree, and saying so is more useful than either number alone.

It caught its own false green and reported it. The first test run printed TEST_EXIT=0 while the output showed ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL — a bad PIPESTATUS read across flock, compounded by --reporter=basic no longer existing in vitest 4. Every later run captured $? directly.

That is the fourth instance today of a check appearing to run while measuring something other than what it claimed — after a no-op mutant, a regex gap class excluding the dot, and a stale build artifact judging the previous mutant. This one is the exact PIPESTATUS trap this lane's rules warn about, and it was caught because the rule made someone look. ⛔ Reporting it rather than quietly re-running is what makes the rest of the evidence trustworthy.

Derived work

#8648 filed for the real finding: three source comments (engine.ts:853, protocol.ts:6481 and :6693) assert the SEARCH remedy is worded identically to SORT/FILTER; the emitted message does not match, and engine.ts:857 further claims the conformance test "pins the three wordings as EQUAL" when the pin covers only the four SORT/FILTER doors. ⭐ A comment asserts an invariant, the test does not cover it, and the code does not honour it — this repo's recurring declared-≠-enforced shape, and the reason it is a card rather than a wording nit. Three routes listed with no recommendation, and the shipped-user-visible-message weight class flagged; body audited for closing keywords in both loose and strict forms, zero hits.


Generated by Claude Code

@qq9340100
qq9340100 added this pull request to the merge queueAug 14, 2026
Merged via the queue into main with commit 91d09beAug 14, 2026
23 checks passed
@qq9340100
qq9340100 deleted the claude/issue-8372-filter-axis-denormalise-remedy branch August 14, 2026 12:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@qq9340100@claude