Skip to content

finding(devx): #5186 读接缝规则的「编造空答案」词表看不见「原样返回入参」这一形状 —— #6116 是实证样本 #6451

Closed

Description

@baozhoutao

发现于 #6116(PR 见下)实施期,按 Prime Directive #10 只记录不修,未认领。严重度不自评,交分诊。#6116 的分诊评论明确要求实施方对这个问题表态、且不得夹带进那条 PR(闸门在 scripts/,devx 车道),故独立立单。

事实

scripts/check-durability-degradation-log-level.mjs 的读接缝编造规则(#5186)判红需要四个条件同时成立,其中第三条是:

some path out of the catch returns an EMPTY/ZERO value for that method ([], false, null, undefined, {}, '', 0, 1)

packages/objectql/src/engine.ts 的 resolveFileReferences 里,sys_file hydrate 的批量读故障走的是 catch { return records } —— 返回的是入参本身,不在上面这张值表里。实测:该接缝在 65 个被发现的读接缝里被正常计入普查,但从不判红,#6116 的缺陷因此在闸门下存活到人工清扫才被看见(闸门在修复前后都报 ✓ … none invents an unreported empty answer)。

为什么值得单独裁

支持扩的一面。 危害轴与 []/null 完全同族:读没发生,调用方却拿到一个与「合法的空/无」不可分辨的答案(ADR-0110 D3)。#6116 的具体形态是消费方把裸 id 当「无附件」渲染。规则的名字叫「invention」,但它真正保护的是可分辨性,而不是「返回值字面上是不是空」。

需要审慎的一面(也是我不敢在实施单里顺手扩的原因)。 「原样返回入参」与「返回空字面量」有一处不对称:对 resolveFileReferences 这类富化/装饰函数,原样返回是它 happy path 上的已声明契约(inline blob、外部 url 字符串本来就原样穿过),不是编造。要把「作为契约的穿过」与「吞掉故障的穿过」分开,需要知道函数的声明语义,而这条语法规则看不到 —— 这与脚本头部自陈的局限 1(信封形状 { data: null, … } 判不了)是同一类盲区,不是同一个盲区。

所以我的倾向是「该扩,但要作为一条新判据而不是往 EMPTY 值表里塞一项」:判据是「catch 返回了本函数的某个形参(identity 穿过)」,并且仍受原有两条豁免约束(catch 内有任意级别日志 ⇒ 豁免;按错误类型判别 ⇒ 豁免)。#6116 修好之后这两条豁免都命中,所以扩了也不会把已修的点判红 —— 但扩之前必须先量三个 scan root 的假阳性面并落 baseline,这正是脚本自己对「收窄先行」的纪律要求(维护者 2026-08-06 裁定)。是否值得做、按什么优先级,交分诊。

处置方向(供分诊定价,不预判)

  1. 在 READ_SEAM_SCAN_ROOTS 三个包上先做一次测量:有多少 catch 返回形参、其中多少已有日志或类型判别(即扩了之后的真实红集大小);
  2. 若红集可控,加 identity-穿过判据 + 自测用例 + durability-read-invention.baseline.json 的初始条目;
  3. 若红集过大或大量落在「穿过即契约」的富化函数上,则记录为 honest limitation(与信封局限并列写进脚本头部),不扩规则。

⚠️ 与 #5981 不同:那条是 AGENTS.md 散文没跟上 #5186,这条是规则判据本身的覆盖面。

Refs:#6116(实证样本 + 修复 PR)、#5186(读接缝规则)、#5108 / #4825 / #4728(族形来源)、ADR-0110 D3、#5981(同闸门的散文单,不同面)。

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 7, 2026
  2. added
    domain:devxDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 7, 2026
  3. claude commented on Aug 7, 2026

    @claude
    Contributor

    Findings triage — verdict: PROMOTE. finding → pm:queue + domain:devx.

    Why promoted: the rule has a demonstrated escape, not a hypothetical one — #6116 was a real read-seam defect that lived under a gate reporting ✓ … none invents an unreported empty answer, and the seam was counted in the census the whole time. A gate that surveys a seam and then cannot fail on it is the "excluded without a reason vs. never looked at" indistinguishability this family exists to remove; that is a restore-invariant card, not an observation.

    Scope as queued — the measurement is the card, and its outcome may legitimately be "do not extend": the body's step 1 (measure catch-returns-a-parameter across the three READ_SEAM_SCAN_ROOTS, minus the two existing exemptions) is the deliverable, and it decides step 2 vs step 3 from data. Both endings are acceptable completions: extend with an identity-pass-through criterion + baseline entries, or record it as an honest limitation in the script header alongside the envelope-shape one. An implementing seat must not treat "extend" as the required outcome — the maintainer's 2026-08-06 收窄先行 ruling is what makes the measurement mandatory and the extension conditional.

    The body's own caution is the sharpest part of the card and survives promotion intact: for enrichment functions like resolveFileReferences, pass-through is the declared happy-path contract (inline blobs, external URL strings), so a syntactic rule cannot separate "pass-through as contract" from "pass-through swallowing a fault". That is why this must be a new criterion rather than another entry in the EMPTY value table — as the body says.

    Routing: domain:devx. The fix lands in scripts/check-durability-degradation-log-level.mjs (plus a baseline JSON and self-test), and scripts/ gate scripts ⇒ domain:devx per the domain table. Not domain:engine-core: packages/objectql/src/engine.ts is only the sample, and #6116 already fixed it.

    Stale-premise check: catch { return records } in resolveFileReferences is verbatim on origin/main (engine.ts:4727 in that block, with the guard-style return records at :4560/:4561/:4565 in the same function), and nothing has touched the gate script since filing. Premise holds; the distinction it draws against #5981 (that card is AGENTS.md prose lagging #5186; this one is the rule's own coverage) also holds and needs no cross-link beyond the one in the body.

    No target:<major>: internal gate tooling, nothing on a shipped surface.

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


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 8, 2026
  5. self-assigned this
    on Aug 8, 2026
  6. hotlong commented on Aug 8, 2026

    @hotlong
    Contributor

    认领 — devx 车道执行座位。 pm:queue → pm:dispatched,assignee 已置。

    交付物是「测量」,不是「扩规则」(分诊已明确,维护者 2026-08-06「收窄先行」裁定使测量成为强制、扩展成为条件):先在三个 READ_SEAM_SCAN_ROOTS 上量清楚 —— 有多少 catch 返回本函数形参、其中多少已被现有两条豁免(catch 内有日志 / 按错误类型判别)吃掉,即扩了之后的真实红集大小。两种结局都算完成:红集可控 ⇒ 加 identity-穿过判据 + 自测 + baseline 初始条目;红集过大或大量落在「穿过即契约」的富化函数上 ⇒ 写成 honest limitation 进脚本头部,与信封形状那条并列,不扩规则。把「扩」当成必须达成的结果就是把这张单做错了。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

domain:devxDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions