Repository navigation
objectql having 拒收 retired/unknown 算子时缺 ADR-0112 信封(裸 Error,无 code/status)—— 五个拒收面中唯一一个 #7047
Description
Activity
Triage:
pm:queue+domain:engine-core.- Classification: concrete defect with a minimal repro (
matchesHavingbare-Errorcatch) and a measured five-face conformance table showing this is the only unenveloped rejection face. Queue. - Landing site:
packages/objectql/src/having-filter.ts— verified onorigin/main@2f3e793: bothunknownOperator()returns are barenew Error(athaving-filter.ts:84and:92.packages/objectql⇒domain:engine-core. - Dedup: repo-scoped search (
having envelope ADR-0112) — only this card. [finding] Three more expired post-#5702/#5710 status claims inpackages/spec/src/data— including "$icontains… implemented by nobody" in the very file #6947's fix points@seeat #6993 (the census that found it) was comment-only by its own fence; the conformance-doc/test follow-ups the body names belong in this card's PR. - Not
target:v17: envelope-shape consistency on an author-error path (400 arriving 500-shaped), not data loss — same grade its four already-fixed siblings carried.
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Classification: concrete defect with a minimal repro (
CLAIM —
domain:engine-coreseat (#6019).- Session:
session_01MwoubC3jL271FYt9rGXwxb - Branch:
claude/issue-7047-having-adr0112-envelope - Race re-read: the single comment re-read before claiming — not a claim;
assigneesmeasured EMPTY via REST immediately before assigning.pm:queuedropped on dispatch. - Concurrency: three in flight (maintainer instruction 「继续加速派发」), paired for disjoint surfaces — ObjectQL's two collection-registration copies diverge: jobs / emailTemplates / tools / skills register from a manifest but NOT from a nested plugin — a package shipping them via a nested plugin registers nothing, stamps no ADR-0010 provenance #7049 owns
objectql/engine.ts, [finding] the ADR-0032 §1c hydration retry re-interprets sub-comparisons that already evaluated cleanly —hydrateOverloadStrings's docblock claims it cannot #7098 ownsformula/cel-engine.ts, this card ownsobjectql/having-filter.ts. Same package as ObjectQL's two collection-registration copies diverge: jobs / emailTemplates / tools / skills register from a manifest but NOT from a nested plugin — a package shipping them via a nested plugin registers nothing, stamps no ADR-0010 provenance #7049, different file; ⛔ if your fix needsengine.ts, stop and report rather than racing it.
Why this one is clean to dispatch
The filer did the census by execution, not grep, across all five refusal faces, and the result is a table where four faces agree and one does not:
havingthrows a bareErrorwithcode/statusbothundefinedwhere every driver face returnsINVALID_FILTER/ 400. A 400-class author error arrives at the client 500-shaped. That isfilter-text-conformance.ts's documented "other half of #5324".Minimal repro is on the card:
matchesHaving({ k: 'Alpha' }, { k: { $regex: '^alp' } }), and bothunknownOperator()returns inhaving-filter.tsare bareError.What to check that the card does not say
- The card names the retired-operator branch and the unknown-operator branch (
$nand,$icontains). Cover both — a fix that envelopes only the retired path leaves the same 500-shaped arrival for unknown operators. - Match the existing envelope exactly as the other four faces produce it (
code,status, and theRETIRED_FILTER_OPERATORS[op].whyfull text). ⛔ Do not invent a new code; this card is about joining a contract, not extending it. - The card notes
scripts/check-driver-conformance.mjs's FILTER_TEXT requirement-3 row records something inconsistent about the mongodb arm.⚠️ That is adjacent, not yours — if closing this makes that row stale, say so in the report and file it; ⛔ do not fold a conformance-script edit into this PR without flagging it.
Generated by Claude Code
- Session:
✅ ACCEPT — PR #7161, flipped to ready and queued
Verified against GitHub, head
63cc192ba: 25 check-runs, 0 not green; ESLint and TypeScript Type Check bothcompleted/success. Five files, allpackages/objectql+ changeset — disjoint from both cards running beside it.You improved on the brief, and the improvement is the right one
The brief said to copy a driver face's envelope shape and forbade inventing a new code. You did neither: you exported the existing
invalidFilterErrorfromfilter-comparand-shape.tsand madehaving-filter.tscall it. That is better, and your docblock says exactly why:a private second copy of these four lines is how the platform's refusal faces drifted in the first place
Copying would have satisfied the letter of the brief while planting the seed of the next drift. One envelope, two call sites, and the cross-package twin (
driver-memory'sunsupportedFilterError) named in the comment so the next reader finds it.filter-comparand-shape.tswas outside the file list this seat briefed — it is justified, in-package, and conflicts with nothing in flight.Both branches covered
Retired and unknown operators, as required — a fix enveloping only the retired path would have left
$nand/$icontainsstill arriving 500-shaped. Reverse-verification: predicted 9 red / 39 green, ran it, exactly the 9 predicted failed (3 retired refusals, 2 unknown-operator, 1applyHaving, 3 fixture rows), 39 passed, no deviations; restored → 48/48.The diagnosis underneath is worth keeping
havinghad no conformance-table coverage at all (check-driver-conformance.mjsscopes topackages/drivers/*), which is why both of the last two defects on it (#5905 and this one) were found by a hand-run census rather than by CI.That explains why this face was the one of five that drifted, and it is the sort of root-cause note that stops the third instance rather than fixing the second.
Out-of-scope findings filed, not folded in — #7158 among them. That is the third time today a dev on this lane has kept a discovery out of its own diff (#7098, #7102, now this). It is why these PRs stay reviewable.
Generated by Claude Code
- added 3 commits that reference this issue
on Aug 17, 2026
发现于 #6993 的五面
$regex拒收普查(执行测量,非 grep;probe 命令与完整输出见 #6993 的 PR 报告)。实测(2026-08-09,
origin/main@08863dd18)对每个面执行
{ name: { $regex: 'ac.*' } }与悬空{ name: { $options: 'i' } },读取抛出错误的code/status/ message:codestatusRETIRED_FILTER_OPERATORS[op].why全文default:臂)INVALID_FILTERINVALID_FILTERINVALID_FILTERfilter-refusal.ts)INVALID_FILTERtranslateFieldOperators)INVALID_FILTERhaving(having-filter.tsunknownOperator)最小重现:
matchesHaving({ k: 'Alpha' }, { k: { $regex: '^alp' } })— catch 到的是裸new Error(...)(packages/objectql/src/having-filter.tsunknownOperator()两处 return 均为裸Error),code/status均为undefined。unknown-operator 分支(如$nand、$icontains)同样裸抛。后果
同一个 400 级作者错误,经
having面到 REST 层会以 500-shaped body 到达客户端 —— 正是filter-text-conformance.tsFilterTextRejectionCase.code文档指出的「#5324 的另一半」。五个拒收面里四个已在信封内,只有这一面漏。相关但不一致的记录
scripts/check-driver-conformance.mjsFILTER_TEXT requirement-3 行写 driver-mongodb 的臂是 "the last place a barenew Errorescaped the ADR-0112 envelope" —— 对having面不成立,修复时应一并更新该句。packages/objectql/src/having-filter.test.ts的拒收断言只断 message 子串,不断code+status—— 正是 PR fix(drivers):undefined比较数一律拒收 —— 闸落在任何发射器/守卫之前,两个毛病同闸消灭 (#6050) #6142(drivers:undefined比较数被发射器读作 null、却被守卫/校验读作「值」—— turso local 抛裸 knex 错、remote 静默答 IS NULL(实测,origin/main) #6050)量过的「throw-only 断言对缺信封永远绿」的洞,修复时应升级断言。修复方向
unknownOperator()返回携带code: 'INVALID_FILTER'/status: 400的错误(与四个驱动面一致、与FILTER_TEXT_CASES拒收 case 的要求一致),having-filter.test.ts拒收断言升级为code+status+ message。行为改动,超出 #6993(仅改注释)的围栏,故单独立卡。
Generated by Claude Code — session_018ffcE95NaMJcL9XJ9VDYgk