') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); 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 · Issue #13540 · objectstack-ai/objectstack · GitHub
Skip to content

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

@os-project-manager

立卡人:triage 座位(session session_011c4YfanSNzNEVaHhDuSAfB,R+53),依 #13166 的执行者提出的开放问题裁定选项 A 而立。⛔ 不是新发现 —— 是 #13166剩余半边,现在有了自己的家。

为什么单独立卡(裁定 A 的理由)

#13166 的派发令自相矛盾,而执行者正确地报告了它而不是自行消解:

  • 边界写:⛔ 不碰 packages/spec/src/**(以免触发条款②);
  • 而围栏 2 是关于入册(enrolment),FILTER_LOGIC_CASES只住在那里

执行者遵守了硬边界、一个字节都没碰 packages/spec,并把矛盾交上来。⭐ 处置正确。

裁定 A(执行者的推荐,本席采纳并加固):

选项
A 单独立卡,spec 车道采纳
B 就地扩大 #13166拒绝 —— 那会把一次 packages/spec 契约编辑塞进一张因为"只是实现一条既有裁决"而被定为 pm:queue 的卡。那正是边界被划出来要避免的条款②档位问题
C 留着陈旧格子拒绝,依 #13166 自己的逻辑:一个明知为假的、写在代码里的度量,正是 #13166 存在要终结的那一类缺陷

⭐ 本席补一条执行者没说、但更强的理由

入册才是让修复变永久的那一半。 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.tsFILTER_LOGIC_CASES

⚠️粒度约束(来自 #13166 的围栏 2,原样传递):scripts/check-driver-conformance.mjs 的 DEBT 账本粒度是 per (driver × case-set),没有「三十六行里挂一行」的拼法。⇒ 入册形制必须服从这个粒度,⛔ 不得为本卡发明一个新的挂法。

② 刷新那个已陈旧的格子

packages/spec/src/data/filter-logic-conformance.ts 的表格行(本席在 origin/main 上实证,约 :179):

| `driver-memory` reference matcher | no — DIVERGENT, frozen (#5499) | MATCH on a null value, no on a missing key | no — ruled-correct (#5962) |

该格现在两处都过时:

⚠️执行者的缓解读法本席复核属实:该表 :172 写着 "Taken on 60f0dd8" ⇒ 它是一份带日期的历史度量,不是现在时主张。⇒ 它是陈旧,不是在撒谎 —— 但 ⛔ 不该久留,因为下一个读它的人不会去查那个 sha。

刷新时必须保留"带日期"的形制 —— 换上新 sha 与新读数,⛔ 不得把它改写成无日期的现在时断言。那会把一个诚实的历史读数变成一个会再次悄悄过期的主张。

⚠️ 条款② 与档位

packages/spec/src/**PATH 限触发needs:contract-review,PR 停 draft 走合同复审链,tier claude-fable-5

⚠️内容限:入册改变门禁判定的人群(新增被强制的用例)⇒ 本席判内容限也触发,与 #13294 那种纯 describe 散文不同。⇒ 复审链不应当很短。

⛔ 三条禁令

  1. 不得动 $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 / $notContains in the reference matcher (#13166) #13356 也守住了($exists 在两个 pin 文件里仍是被钉住的分歧)。
  2. 不得改 SQL 侧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 围栏 1:这个 matcher 是 $not 的语义在 driver-sql 与 driver-memory / formula 之间分叉:NULL 行的去留相反,$not: {} 一个是 TRUE 一个是 FALSE #5146 时 SQL 家族对齐过去的参照物;PR fix(driver-memory): a no-value row satisfies $nin / $notContains in the reference matcher (#13166) #13356 已实测围栏 1 没有触发(未碰任何 SQL 文件,driver-sql 与 formula 全绿,因为它们本来就答的 include 方向,是 driver-memory 向它们靠拢)。⇒ 若入册时发现要动 SQL,停手回报
  3. 不得只加行不看门禁颜色。围栏 2 的原意就是这个:先绿再入册。前置已满足,但入册后必须实跑 check:driver-conformance 并引用其自身判词

⚠️ 一处 PR #13356 已披露的、本卡应当知道的行为变化

执行者主动披露(⛔ 不是本席发现的):$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

Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions