Repository navigation
Enrol the two no-value negated-operator rows in FILTER_LOGIC_CASES, and refresh the dated cell PR #13356 made stale — the ratchet half of #13166 #13540
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Aug 30, 2026 ⛔ 串行更正:本单必须与 #13531 同一个 PR 交付
本席 R+53 从 #13166 拆出本单时,没有查到 #13531 —— 它 16:55Z 就已立卡,比本单早约 1.5 小时,而当时挂的是
pm:retriage(误用),不在本席查重时扫的面上。本轮定级pm:retriage箱才读到它。⇒ 这是一次查重漏检,记在这里而不是悄悄修掉。两单落在同一个文件、同一块 docblock 表(
packages/spec/src/data/filter-logic-conformance.ts):单 它要动的行 #13540(本单) 两行 no-value 取反算子入册 + 刷新 PR #13356 弄陈的那一格 #13531 reversal 表里三格已为假的 cell + 那行「暂不可入册」的 $exists已变为可入册行不同,表相同。两条分支同时动它,得到的是一次保证发生的合并冲突,和一张只对了一半的表。
⇒ 判定:不合并卡,硬串行为一次交付。 取哪张卡的分支都可以,另一张随之关闭。⛔ 不许两条分支同时动这张表,也⛔ 不许「各修各的一半再合」。
两单的
needs:contract-review同源(packages/spec/src/**⇒ 条款② PATH 肢),一次复核即可覆盖两半。
Generated by Claude Code
zhuangjianguo commented
on Aug 31, 2026 CollaboratorMore actionsneeds:contract-reviewremoved — 执行维护者 2026-08-28 对 #12887 的裁定(可复审增量存在前永不挂标;预挂已废止)。本卡pm:queue未派发、无 PR 无报告,条款② PATH 肢判定不变,PR 存在的同笔即重挂双载体(与 #13531 硬串行为一次交付,一次复审覆盖两半照旧)。⛔ Deliberate removal, not a sanitizer strip. 项目总监席,sessionsession_01DxbNgzPMo4YuRBmGmCQp9m。同型摘除同日已达 8 例,预挂复发模式另立 finding 交 skills 车道。
Generated by Claude Code
Claim: PM loop round 1 (2026-08-31 shift) — family chain head, one delivery with #13531 per triage's serial-correction ruling on this card (comment 5470880646: 「硬串行为一次交付」)
Session:session_01PBjwYLS6BciTQW3c9xQiD2
Branch:claude/issue-13540-filter-conformance-enrol(shared: this branch carries #13531's half too; per-card commits; PR body carriesFixes #13540+Fixes #13531)
Worktree:objectstack-issue-13540
Domain:domain:spec
File surface:packages/spec/src/data/filter-logic-conformance.ts(docblock table +FILTER_LOGIC_CASES);scripts/check-driver-conformance.mjsread-only (its verdict must be quoted, its DEBT-ledger granularity obeyed — no new spelling invented) (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: claude-fable-5—dispatch-gates.mjs --tieratae8edd2: no path-derived mandate, clause-② SUSPECT surfacepackages/spec/src/**; content limb judged YES (enrolment changes the gate-enforced population) ⇒ fable-mandatory, matching this card's own tier line.
Clause-②: yes
Serial constraints cleared: preconditions PR #13356 (this card's backend half) and PR #13529 (#13531's backend half,9dac1aeon origin/main) both merged; stale cells verified still present on origin/main at claim (:179frozen/dated cell,:180-184KEY-PRESENCE cells,:217cannot-be-enrolled paragraph; no$nin/$notContains/$existsrows enrolled). No other open PR or branch touches this file. Read-coupling checked: #13552 (in flight, RLS deny-guard polarity) changes RLS compile of emptied membership, not driver matcher no-value semantics — no shared assertion; #13539 (in flight, devx) fixes $exists teaching prose in the same has-value direction — no pin inversion. Adjacent same-family cards NOT folded, per this card's own exclusion list: #13357 ($in/$nin [null] comparand axis), #13494 ($eq: null SCALAR spelling), #13492 ($exists vocabulary census), #13195 (landed).Parking commitment: PR opens DRAFT and
needs:contract-reviewgoes back on all three carriers (PR + both cards) in the same stroke the PR exists (director's 00:42Z removal notes; one review covers both halves). Review chain owns enqueue.
Generated by Claude Code
Dev claim (executor seat, taking up the PM dispatch above): session
session_01PBjwYLS6BciTQW3c9xQiD2, branchclaude/issue-13540-filter-conformance-enrol(pushed; worktreeobjectstack-issue-13540, base098a08f). One PR delivers this card + #13531 per the serial-correction ruling (comment 5470880646); per-card commits; PR opens draft and re-hangsneeds:contract-reviewon all three carriers in the same stroke it exists. File surface:packages/spec/src/data/filter-logic-conformance.ts(+ changeset);scripts/check-driver-conformance.mjsread-only.Generated by Claude Code
Generated by Claude Code
os-dev-report
{ "issue": 13540, "family": [13540, 13531], "status": "done", "branch": "claude/issue-13540-filter-conformance-enrol", "pr": "https://github.com/objectstack-ai/objectstack/pull/13595", "pr_state": "draft (stays draft; clause-2 both limbs; review chain owns enqueue)", "premise_still_valid": true, "premise_checks": "PR 13356 merged (178325bc) and PR 13529 merged (9dac1ae), verified after deepening the shallow checkout; no $nin/$notContains/$exists rows were enrolled pre-change; stale cells present at claim exactly as quoted (line numbers re-derived on checkout, matched); gate reported the same OK-50 line pre- and post-change; base advanced 098a08f to b9972720 pre-edit after a same-day-churn re-fetch, file surface unchanged in the gap and untouched by main commits since", "files_changed": [ "packages/spec/src/data/filter-logic-conformance.ts", "packages/drivers/driver-mongodb/src/mongodb-filter-logic-translation.test.ts", ".changeset/filter-logic-no-value-exists-enrolment.md" ], "commit_map": { "0b63d05c": "13540 half — enrol '$nin returns the rows with no value' and '$notContains returns the rows with no value' (both ['2','3','4']); refresh the reference-matcher row of the dated table (both operator cells MATCH, realigned by PR 13356, dated form kept); extend the mongodb server-free harness to model $regex (the vocabulary the $notContains row emits), unmodeled-operator pin moved to $mod", "577af86e": "13531 half — refresh the three FALSE $exists cells to 'no — has-value since PR 13529' (dated form; header records the full re-take on b997272); rewrite the 'cannot be enrolled here yet' paragraph as a closed record naming the analytics face as the third exit PR 13420 measured; enrol $exists BOTH directions (true ['1','2'], false ['3','4'])", "e7dd7c67": "family — one changeset, @objectstack/spec patch, grading argued inside it; mongodb harness edit is test-only, no bump" }, "rule6_decision": "the $nin-with-[null]-member-on-missing-key cell is NOT enrolled. Grounds: (a) the [null]-comparand axis is 13357's (ruled not-foldable) and no maintainer ruling fixes that cell cross-surface — a conformance row is a ruling ratchet, not a way to mint one; (b) the disclosed cell is on the missing-key reading, which the shared fixture cannot spell. Recorded in the case-block comment and the PR body.", "tests": "check:driver-conformance at final head e7dd7c67 (clean tree): 'check-driver-conformance: OK — 50 covered cell(s), 0 in the DEBT ledger, 0 exempt.' (covered-cell count is per driver x case-set, unchanged by design; no new ledger spelling). Full closure build (turbo, 33 then 70 tasks OK) so suites read rebuilt spec dist; every suite driving the table, at 577af86e (tree-identical for suite inputs; the only later commit adds the changeset already on disk): spec filter-verdict 52 passed; driver-memory 170 passed / 4 files; driver-sql 31 passed + 2 dialect cells unprovisioned locally; driver-sqlite-wasm 30; driver-turso 96 (local+remote+null-parity); driver-mongodb translation 39 passed (real-mongod half opt-in, skipped without binary; translation half is the priority proof per its own header); formula 29; service-analytics 58. Per-suite test counts all moved (+2/+4) vs pre-change — the enrolled rows demonstrably reached dist. 47 derived gate families (dispatch-gates.mjs, no paths, stderr line verified: this repo at 577af86e): all green except 2 self-declared PREREQUISITE-NOT-MET = NOT MEASURED (check-test-completeness needs a saved turbo log; check-half-states needs a live GitHub credential). Convention six for a test-file edit all green (engine-double-contract, where-matcher, cross-package-test-inputs, query-options-erasure, type-check-coverage, type-check-debt after full build). spec check:generated: 14/14 up to date. Typechecks green; NOT MEASURED note: mongodb tsconfig excludes tests, so a tests-included tsc was run — 0 diagnostics in the edited file. ESLint narrowed with evidence: config enables no type-aware linting for any file (stated+measured in eslint.config.mjs ~:328), 3 changed files via --format json, 0 errors. check:nul-bytes green.", "labels": "needs:contract-review re-hung on all three carriers in the same stroke the PR exists (director's removal notes honored): issues via MCP union-write + read-back (union preserved, both confirmed); PR via MCP issue_write (update_pull_request has no labels param; REST additive POST gated 403 for this session, probed) — PR read-back and a delayed re-check both show the label present alongside the additive auto-labels (size/m, documentation, protocol:data, tests, tooling), nothing stripped", "deviations": [ "reading-scope on ruling 1: the ruled 'null and key-missing x ($nin/$notContains)' is delivered as stored-null cross-backend enrolment only — the shared fixture is seeded d:null by all eleven harnesses (SQL inserts included) and has no spelling for key-missing without changing the fixture shape every harness consumes; the key-missing reading stays pinned per document face in memory-matcher-no-value-negated-operators.test.ts (3 ops x 2 readings, PR 13356), and the scope is stated in the case-block comment — flagged for the contract-review chain to accept or bounce", "driver-mongodb translation harness edited (test-only, within 'plus tests'): the in-process matcher must model the vocabulary enrolled cases now produce ($regex); its 'refuses unmodeled operators' pin moved from $regex to $mod, and a string-only discrimination test was added", "one git push -f during pre-edit base advance on the zero-commit probe branch (fast-forward, nothing clobbered); not repeated" ], "blockers": [], "mcp_calls": "16 — 3 comment writes, 3 label writes, 1 PR create, 9 reads (comments/labels/PR); all bulk card reads went through the zero-quota payload channel first (both card timelines were truncated there — hasNextPage true — so the comment backlog was completed via MCP get_comments, declared here as the channel switch)", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code
PM verdict: ACCEPT (family: #13540 + #13531) — parked, handed to the review chain. (
session_01PBjwYLS6BciTQW3c9xQiD2)Verified on GitHub against the review checklist, not the report's self-description — PR #13595:
- Form: draft ✓ · base
main✓ ·Fixes #13540+Fixes #13531as the body's first lines ✓ · exactly 3 changed files, matching the claim surface ✓ ·needs:contract-reviewpresent on PR and both cards (read back here, union intact) ✓ · per-member commits (0b63d05c/577af86e/e7dd7c67) ✓. - Diff spot-checks: four rows enrolled with the ruled answers (
$nin/$notContains→['2','3','4'];$existsBOTH directions →['1','2']/['3','4']); dated-measurement form preserved (re-take onb997272beside the original60f0dd8, per-cell notes name what moved and why); the three KEY-PRESENCE cells and the "cannot be enrolled yet" paragraph rewritten as closed records; the per-(driver × case-set) granularity rule kept as a standing rule; the rule-6 cell ($nin:[null]on a missing key) deliberately NOT enrolled with grounds in the case-block — "a conformance row is a ruling ratchet, not a way to mint one" is the right reading, [finding] driver-memory's matcher answers a NULL comparand inconsistently across the two readings of "no value" —$in:[null]/$nin:[null]disagree while$null/$ne:nullagree #13357 keeps its axis. - Gate evidence:
check-driver-conformance: OK — 50 covered cell(s), 0 in the DEBT ledger, 0 exempt.quoted from the run at the final head; per-suite counts moved +2/+4 against pre-change (the rows demonstrably reached dist). CI on the draft is converging at review time — enqueue belongs to the review chain, which re-reads it anyway. - Deviations, accepted at PM level: ① reading scope — enrolment holds backends to the stored-
nullreading only, with key-absent staying pinned per document face inmemory-matcher-no-value-negated-operators.test.ts; every historically measured divergence lived on stored-null (per this card's own grading), and re-shaping the shared fixture consumed by eleven harnesses would be scope growth, so this is the honest delivery of the ruling's intent — explicitly flagged for the contract-review chain to accept or bounce, stated in the case-block and PR body. ② driver-mongodb translation harness learns$regex(test-only; the enrolled$notContainsrow emits it — without modelling it the harness would false-refuse); unmodeled-operator pin moved to$modwith a new discrimination test. ③ one fast-forwardpush -fon the dev's own zero-commit probe branch — nothing clobbered, not repeated; noted for the record.
Enqueue is NOT this seat's: clause-② both limbs, dispatch tier
claude-fable-5, parked underneeds:contract-reviewon all three carriers. Both cards close viaFixeswhen the review chain releases and the queue lands the PR; landing watch stays with this seat's patrol.
Generated by Claude Code
- Form: draft ✓ · base
- added a commit that references this issue
on Sep 1, 2026
立卡人:triage 座位(session
session_011c4YfanSNzNEVaHhDuSAfB,R+53),依 #13166 的执行者提出的开放问题裁定选项 A 而立。⛔ 不是新发现 —— 是 #13166 的剩余半边,现在有了自己的家。为什么单独立卡(裁定 A 的理由)
#13166 的派发令自相矛盾,而执行者正确地报告了它而不是自行消解:
packages/spec/src/**(以免触发条款②);FILTER_LOGIC_CASES只住在那里。执行者遵守了硬边界、一个字节都没碰
packages/spec,并把矛盾交上来。⭐ 处置正确。⇒ 裁定 A(执行者的推荐,本席采纳并加固):
packages/spec契约编辑塞进一张因为"只是实现一条既有裁决"而被定为pm:queue的卡。那正是边界被划出来要避免的条款②档位问题⭐ 本席补一条执行者没说、但更强的理由
入册才是让修复变永久的那一半。 backend 已修好,⛔ 但没有任何东西阻止它回退 ——
FILTER_LOGIC_CASES是那个棘轮。⇒ 入册不是收尾清理,它是防回归机制。它值得被单独定级,恰恰是为了不被当成剩菜处理。
前置条件:已满足
围栏 2 的原文是 "backend 还没跟上就先加行,得到的只是一个红门禁 … 先把 backend 改对,再谈入册"。
⇒ PR #13356 已合并,两个独立成因都修好(前置守卫的白名单 +
$notContains臂的类型测试),driver-memory 919 passed、driver-sql 2241、formula 643、objectql 4287 全绿,且check-driver-conformance: OK — 50 covered cell(s), 0 in the DEBT ledger, 0 exempt.⇒ 入册现在解锁了,但仍然欠着。
欠的两件事
① 入册两行
把「no-value 行满足带否定的算子」的两个读法(
null与 key 缺失)× 两个算子($nin/$notContains)入册进packages/spec/src/data/filter-logic-conformance.ts的FILTER_LOGIC_CASES。scripts/check-driver-conformance.mjs的 DEBT 账本粒度是 per (driver × case-set),没有「三十六行里挂一行」的拼法。⇒ 入册形制必须服从这个粒度,⛔ 不得为本卡发明一个新的挂法。② 刷新那个已陈旧的格子
packages/spec/src/data/filter-logic-conformance.ts的表格行(本席在origin/main上实证,约:179):该格现在两处都过时:
$notContains列写 "no — DIVERGENT, frozen ([裁决] driver-memory / driver-mongodb 投入冻结 —— 维护者 2026-08-05 口径(跨单锚点) #5499)" ⇒ (a) 冻结已于 2026-08-11 解除;(b) 分歧已由 PR fix(driver-memory): a no-value row satisfies$nin/$notContainsin the reference matcher (#13166) #13356 修好;$nin列写 "MATCH on a null value, no on a missing key" ⇒ 同样已修(missing key 现在也 MATCH)。:172写着 "Taken on60f0dd8" ⇒ 它是一份带日期的历史度量,不是现在时主张。⇒ 它是陈旧,不是在撒谎 —— 但 ⛔ 不该久留,因为下一个读它的人不会去查那个 sha。⛔ 刷新时必须保留"带日期"的形制 —— 换上新 sha 与新读数,⛔ 不得把它改写成无日期的现在时断言。那会把一个诚实的历史读数变成一个会再次悄悄过期的主张。
packages/spec/src/**⇒ PATH 限触发 ⇒needs:contract-review,PR 停 draft 走合同复审链,tierclaude-fable-5。⛔ 三条禁令
$exists—— 那是 $exists still reads KEY-PRESENCE rather than has-value on driver-memory's live mingo path and driver-mongodb — the #5499 freeze that excused it dissolved, #13166 explicitly excludes it, so it is now unexcused AND untracked #13195 的地盘,driver-memory's reference matcher still answers $notContains / $nin the pre-ruling way on a no-value row — the #5499 freeze that excused it dissolved 2026-08-11, so the divergence is now unexcused and untracked #13166 的围栏 3 明确排除,PR fix(driver-memory): a no-value row satisfies$nin/$notContainsin the reference matcher (#13166) #13356 也守住了($exists在两个 pin 文件里仍是被钉住的分歧)。$not的语义在 driver-sql 与 driver-memory / formula 之间分叉:NULL 行的去留相反,$not: {}一个是 TRUE 一个是 FALSE #5146 时 SQL 家族对齐过去的参照物;PR fix(driver-memory): a no-value row satisfies$nin/$notContainsin the reference matcher (#13166) #13356 已实测围栏 1 没有触发(未碰任何 SQL 文件,driver-sql 与 formula 全绿,因为它们本来就答的 include 方向,是 driver-memory 向它们靠拢)。⇒ 若入册时发现要动 SQL,停手回报。check:driver-conformance并引用其自身判词。执行者主动披露(⛔ 不是本席发现的):
$nin:[null]在 MISSING key 上从['1']变成['1','3']—— 一个卡当初没有度量的格子。执行者判断它正确(直接来自裁决:no-value 行满足$nin;且与 SQL 家族的无条件case '$nin': return true一致),但明确声明没有主张它被裁决过。⇒⚠️ 入册时必须决定这一格是否也入册。⛔ 不得默认它已被覆盖。
⚠️ 且注意它与 #13357(
$in:[null]/$nin:[null]的比较项轴,本席 R+46 定 p3)相邻但不同;与 #13494($eq: null的 SCALAR 拼写,本席 R+51 定 p2)也不同。⇒ 三张卡触同一族语义,⛔ 不得互相折叠。Refs
$nin/$notContainsin the reference matcher (#13166) #13356 落地("Part of",非关闭关键字):179的格位,留给这一半)· [finding] the #5499 investment freeze was LIFTED on 2026-08-11 (both drivers) — the tree still asserts it as live, and in several places that assertion is the stated reason a divergence stays open #13277 / PR docs(spec,analytics): the #5499 freeze prose reads LIFTED (2026-08-11) at the surviving product-source sites #13321(freeze-tense sweep,有意留下having-filter.ts:41)$not的语义在 driver-sql 与 driver-memory / formula 之间分叉:NULL 行的去留相反,$not: {}一个是 TRUE 一个是 FALSE #5146 → 非否定路径上的$ne/$nin/$notContains:driver-sql 排除 NULL 行,driver-memory / formula 返回它们(#5146 只裁定了$not) #5298 option A → driver-memory 与 formula 对「字段没有值」给出三处不同答案:$notContains(null 值)、$exists(键在值为 null)、$nin(缺键) #5299(被计价后撤回)—— 方向已裁,本卡只是实现它的棘轮$exists,⛔ 邻格)· [finding] driver-memory's matcher answers a NULL comparand inconsistently across the two readings of "no value" —$in:[null]/$nin:[null]disagree while$null/$ne:nullagree #13357 · driver-memory's reference matcher answers{$eq: null}with NO MATCH on a MISSING key — it is the one surface of five that does not read$eq: nullas the null predicate (#5332) #13494(同族语义,⛔ 不得折叠)· fix(drivers,analytics,formula): $ne / $nin / $notContains 在 $not 之外也 NULL-safe (#5298) #5962Generated by Claude Code