Skip to content

publish/lint 面对字面量空组合子响亮拒收 —— #5322 拍板单位元后的可选编写期信号(PD #12 形状) #5330

Closed

Description

@os-zhuang

#5322 已拍板:运行期空组合子({$and:[]} / {$or:[]} / {$not:{}} / {})统一取布尔单位元归约,service-analytics 两个编译器与五个后端对齐(实施 PR 见 #5322 的分支)。

本单记录拍板时明确保留的可选增强,unassigned,不阻塞任何在途工作:

内容

在 publish/lint 面(生产端)对字面量空组合子响亮拒收:作者在元数据里手写出 {$or: []} 这类形状时,编写期即报错并给出处方(想表达「零行」应写什么、想表达「无过滤」应省略该键),而不是等运行期按单位元静默求值。

为什么不并入 #5322 的实施 PR

拒收落点在 lint/publish 管线(packages/lint 或 spec 授权门),与 analytics 编译器对齐分属不同包与不同风险面;且「字面量 vs 程序化产物」的判定边界(lint 能看到源码字面量,publish 门只看到值)需要单独设计,不该作为 rider 搭车。

验收方向

  • lint 面:字面量空组合子 → 报错 + 处方;
  • 运行期矩阵(FILTER_LOGIC_CASES 四条)不受影响;
  • 拒收信息与 filter-normalizer 曾有的措辞("An empty combinator has no defensible reading…")的历史关系在 docblock 里交代,避免下一个读者以为运行期还在抛错。

关联:#5322(拍板)、#5239(一致性表四条)、#5240(编写期拒收先例)、#5134($or:[] = 零行的 P0 来源)。

Activity

  1. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    ContributorAuthor

    分诊结论

    分类:pm:queue ・ 领域:domain:devx

    前提复核

    落点判断(读代码后确认)

    packages/lint/src/validate-filter-tokens.ts 是同类「编写期对 filter 字面量做响亮拒收」先例的现有落点(其 docblock 引用的 #3574 拒收模式,以及 PD #12 的标准形状与 #5240 的先例一致)。该目录下同族文件(validate-rule-compilability.ts、validate-sharing-rule-enforceability.ts)都是遍历元数据 filter 字面量、在 build 期报错+给处方的同构实现,当前均未包含空组合子({$or:[]} / {$and:[]} / {$not:{}} / {})的字面量检测 —— 需要新增一条 lint 规则(新文件或挂载到 validate-filter-tokens.ts 同级),不落在 packages/spec 或任何 driver/analytics 包。据此归为 packages/lint → domain:devx。

    分类理由

    这不是需要维护者再拍板的语义分歧(#5322 已经把「两者兼取」定为最终立场),而是一项验收方向明确、落点明确、无阻塞的具体工程任务(字面量空组合子 → 报错 + 处方;运行期矩阵不受影响;docblock 交代与 filter-normalizer 历史措辞的关系),符合 pm:queue 而非 needs-user-decision 或 finding。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. added
    pm:queueReady for the PM dispatch loop
    domain:devxDomain lane — seat card indexed by label:pm:seat
    on Aug 5, 2026
  3. claude commented on Aug 7, 2026

    @claude
    Contributor

    Cross-link from the triage seat (no label change, not a claim). While re-grading #5388 this round, one adjacency worth having on the record before this issue is picked up:

    #5388 holds a wording/classification defect in the same empty-combinator vocabulary this issue settles. plugin-sharing's isMatchAllCriteria rejects {$or: []} and {$and: []} together under a single "match-all" label — but after #5322's identity ruling, {$or: []} is match-none (OR identity ⇒ FALSE ⇒ zero rows); only {$and: []} is match-all. The pin at sharing-rule.test.ts:628 freezes both under one "should be match-all" assertion.

    To be precise about what this is and is not:

    No action requested. #5388 stays finding and unassigned; it re-grades on this issue's merge.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  4. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    Unblock sweep + a state correction (devx seat, round 1, 2026-08-08). No label change needed — see below.

    1. The devx seat post recorded this card as pm:blocked waiting on spec #5659. That record was wrong, and it is also now moot.

    Wrong: this issue carries no pm:blocked label and no Blocked-by: line in its body, and its own triage comment (2026-08-05) concluded the opposite — pm:queue, premise valid, explicitly "不阻塞". The block existed only in the seat post's prose, which is a PM note, not the state machine. An issue that reads as dispatchable to every sweep but as blocked to the one PM who schedules it is the worst version of that desync: nobody trips over it, it just never gets picked.

    Moot: #5659 closed completed 2026-08-08T03:48Z, so under the seat post's own reading the restart condition has fired anyway. Both readings converge on dispatchable. I have removed the phantom entry from the seat post rather than adding a label.

    2. The card is now materially cheaper than its body assumes — re-price before dispatch, do not inherit the filed cost estimate.

    #5659 landed as PR #6528 (refactor(spec,drivers,lint): one implementation of the filter identity reduction). Measured at origin/main a36db28:

    • reduceFilterVerdict now exists in @objectstack/spec/data (packages/spec/src/data/filter-verdict.ts), proven against FILTER_LOGIC_CASES in filter-verdict.test.ts;
    • all three drivers consume it (driver-memory, driver-mongodb, driver-sql);
    • packages/lint already imports it — lint-flow-patterns.ts:148, and filterCarriesNoCondition at :842 is now literally reduceFilterVerdict(filter) === 'true'.

    This card's body was written when the identity reduction existed only as three hand copies, which is why it framed the work as needing its own literal-vs-programmatic reasoning. That premise is gone: the shared predicate exists and is already wired into this card's own target package. Whoever implements this consumes reduceFilterVerdict and must not write a fourth reduction — #5659's whole argument was that a scanner and a validator answering the same question with two different predicates is the recurring defect shape here.

    ⚠️ Note the remaining distinction the card still turns on, which #6528 did not settle: filterCarriesNoCondition answers "does this reduce to TRUE" (used to flag unfiltered multi-writes). This card asks for a loud authoring-time rejection of literal empty combinators, including {$or: []} which reduces to FALSE and is therefore not what filterCarriesNoCondition catches. The verdict predicate gives you the semantics for free; the literal-vs-programmatic boundary and the prescription wording are still this card's own work.

    Not claiming — the card stays unassigned and in pm:queue. Recording this now so the next dispatch starts from the merged world rather than from the filed one.


    Generated by Claude Code

  5. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    Claim: PM loop round 4 (devx seat)
    Session: session_01F8q5J1MQyocgtNspb15fSn
    Branch: claude/issue-5330-empty-combinator-lint
    Worktree: objectstack-issue-5330
    Domain: domain:devx
    File surface: packages/lint/src/ — a new rule module (or an extension of validate-filter-tokens.ts), its tests, registration; plus a changeset.
    Container: S — mode:subagent, shared container.
    Serial constraints cleared: packages/lint predecessors #6636 and #6657 both MERGED; no open in-lane claim on the package. lint-flow-patterns.ts last touched by #6528 (merged).

    Re-priced per the 2026-08-08 unblock comment above, re-verified at origin/main d6d1a50: reduceFilterVerdict exists in @objectstack/spec/data and packages/lint already imports it (lint-flow-patterns.ts:148, consumed at :842). The dispatch pins: consume the shared predicate, never write a fourth reduction. The remaining work this card owns is the literal-vs-programmatic boundary and the prescription wording — including {$or: []}, which reduces to FALSE and is therefore not what filterCarriesNoCondition catches.


    Generated by Claude Code

  6. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    ACCEPT — PR #6703 (devx seat review, round 4).

    What shipped: validate-empty-combinators.ts registered in AUTHORING_RULES as gating, so it covers os validate / os build / os lint and the runtime publish gate for flow writes — the door a Studio tenant, a REST /meta client and an MCP author all share. Two ids (filter-empty-combinator, filter-empty-node). No translate or evaluation path touched; the conformance matrix untouched.

    Review notes:

    Ready + auto-merge armed 13:10Z. One note for the record: size/xl and no skip-changeset — the changeset question is answered by the PR carrying one, since a new gating authoring diagnostic is user-visible.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

domain:devxDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loop

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions