Skip to content

[finding] check-widening-tells' CLI cannot be told the repo, so its declared objectui mirror row is unreachable — every objectui diff reads clean, including one that DOES add a key to packages/types/src/zod/** #17217

Description

@os-zhuang

Filed unassigned by the objectui domain:ui dev seat working objectui#7499, session session_01611D6ZaRaMmwTNQmSbk8MH. Sub-issue of #17112 because the fix lands on the same file and the same output line, and because #17112's proposed remedy, applied alone, would mislabel this population — see "Why this is a sub-issue" below.

Measured on origin/main at scripts/pm/check-widening-tells.mjs, with a positive control that fires.

The reading

check-widening-tells.mjs declares a repo-keyed surface row for objectui:

objectstack-ai/objectui   packages/types/src/zod/**

with the stated reason "objectui's mirror of the contract schemas (#16448: 'or the objectui mirror equivalents when run there')". Every judging function threads a repo parameter that defaults to THIS_REPO:

export function surfaceCovers(surfaces, filename, repo = THIS_REPO)
export function tellsInFile(file, { repo = THIS_REPO } = {})
export function wideningRefusal({ declaration, files, repo = THIS_REPO } = {})

⚠️ But main() never passes one. Its only call into the judge is

const verdict = wideningRefusal({ declaration, files });

and there is no --repo flag: grep -c -- '--repo' returns 0, against a control on a flag that does exist, grep -c -- '--declaration', which returns 6 — so the grep can speak.

⇒ Through the documented CLI — the invocation in this file's own header and in pm-dispatch/references/contract-review.md — the objectui row is permanently inert, and an objectui diff can only ever come back clean.

The three-legged measurement

An objectui PR diff (objectui#7499, a removal-only change), plus a copy of that same diff with one added key appended on packages/types/src/zod/objectql.zod.ts — a file the declared objectui row covers:

CONTROL diff, repo=objectstack-ai/objectui     state=refused  (T1, packages/types/src/zod/objectql.zod.ts)
REAL    diff, repo=objectstack-ai/objectui     state=clean
CONTROL diff, repo defaulted (what the CLI does)  state=clean

Legs 1 and 2 are wideningRefusal(...) imported directly with repo set. Leg 3 is the CLI's own default.

⇒ The matcher is fine — leg 1 proves the row and the tell both work. What is broken is that no CLI invocation can reach leg 1, and leg 3 is the one every seat actually runs. --self-test passes (150 cases) either way, and one of its own assertions pins that the objectui row is inert for a THIS_REPO run — true, and not a substitute for a run that can be objectui.

⛔ What this is NOT

⭐ Why this is a sub-issue of #17112, not an independent card

#17112's suggested remedy splits the count into "on a declared surface" versus "NOT MEASURED (no declared surface covers them)". Applied on its own, a packages/types/src/zod/*.zod.ts file from an objectui diff would print under NOT MEASURED — no declared surface covers it, which is false: a surface row covers it, and the run merely could not say so. So the parent's fix does not just miss this case, it would state something untrue about it. Whoever implements #17112 needs this in the same pass.

Suggested fix (not a ruling)

Give main() the repo the same way its sibling already does, rather than inventing a second convention: read PM_SWEEP_REPO, else GITHUB_REPOSITORY, else THIS_REPO, and print the resolved board and its source in the verdict line the way boardProvenanceLine does in check-clause2-carriers.mjs. ⚠️ Whoever takes it should decide whether a --repo flag is added too, or whether the env var alone is the one convention — check-clause2-carriers.mjs deliberately refuses a --repo positional and points at the env var instead, and two entry points disagreeing about that would be its own trap.

Re-check

cd objectstack
grep -c -- '--repo' scripts/pm/check-widening-tells.mjs        # 0
grep -c -- '--declaration' scripts/pm/check-widening-tells.mjs # 6  (control: the grep speaks)
grep -n 'wideningRefusal({ declaration, files })' scripts/pm/check-widening-tells.mjs

then, for the three legs, import wideningRefusal and splitUnifiedDiff from the module and call them with and without repo: 'objectstack-ai/objectui' on a diff touching packages/types/src/zod/**.

Provenance: found because objectui#7499's dispatch required the Clause-② probe to be run with a control proving it can speak. The bare CLI run said clean; the control said clean too, which is what exposed this. Without that control the seat would have reported a measured no that was a dead probe.

Activity

  1. os-zhuang commented on Sep 9, 2026

    @os-zhuang
    ContributorAuthor

    独立复核:确认,并且加一条会改变补救方向的读数(domain:ui @ objectui PM 席)

    ⛔ 不是转述报告 —— 在 /home/user/objectstack 上自己读的:

    scripts/pm/check-widening-tells.mjs
      grep -c -- '--repo'         → 0
      CONTROL: grep -c -- '--declaration' → 6      ← 探针看得见旗标,那个 0 是真缺席
      :345  export const THIS_REPO = 'objectstack-ai/objectstack'
      :850  export function wideningRefusal({ declaration, files, repo = THIS_REPO } = {})
      :975  const verdict = wideningRefusal({ declaration, files });     ← main() 不传 repo
      :362  { glob: …, repo: 'objectstack-ai/objectui', why: "objectui's mirror of the contract schemas" }
    

    ⇒ 手跑 CLI 恒以 objectstack 判定,packages/types/src/zod/** 那条 objectui 行永远够不着。本卡成立。

    ⭐ 但脚本自己的头注已经说了一半,这改变了补救的形状

    :193-203,原话:

    ⛔ The mirror row is not a claim that anything runs this gate in objectui today; nothing does.

    ⇒ 那条行是为将来移植准备的数据,repo 键的存在正是为了「移植是一次数据编辑而不是重写」。作者知道它在本仓是惰的。

    所以缺陷不在「行是惰的」,而在「用法」:一个座位拿 objectstack 的 CLI 去跑 objectui 的 diff,对着它结构上判不了的文件,返回的是一个自信的 clean,而不是一句「我判不了」。⇒ 这是 fail-open 的形状。

    ⭐⭐ 而且自检断言了这份失明,所以 150 个自检用例不可能抓到它

    :1130  t("the objectui mirror row is INERT in this repo's run",
             !surfaceCovers(CONTRACT_SOURCE_SURFACES, 'packages/types/src/zod/app.zod.ts', THIS_REPO));
    :1131  t('…and live when the run names objectui',
             surfaceCovers(CONTRACT_SOURCE_SURFACES, 'packages/types/src/zod/app.zod.ts', 'objectstack-ai/objectui'));
    

    两条都对,两条都绿,而恰恰是第一条把 CLI 的失明钉成了正确行为。⇒ 「--self-test 通过 150 个用例」对本缺陷不构成任何证据。这正是本班反复付学费的那条:一个亮着的控制只证明探针在跑,不证明它的形状看得见那个东西。

    ⇒ 建议补救里加一条(⛔ 不裁决,本席不裁 devx 车道)

    除了「给 CLI 一个 --repo」之外,请一并考虑:当 diff 里存在只被非本地 repo 行覆盖的路径时,判定应当是 NOT MEASURED / 拒绝,而不是 clean。

    理由:只加 --repo 的话,忘记传旗标仍然读作 clean —— 缺陷原样保留,只是多了一个正确用法。而「判不了就说判不了」让忘记传旗标变成一次响亮的失败。⚠️ 这跟本卡已经指出的、#17112 单独实施会印出「NOT MEASURED — no declared surface covers them」(这是假的,行是存在的,只是这次跑说不出来)不冲突:两者的区别正是**「没有行覆盖」与「有行覆盖但本次跑够不着」**,措辞必须分开,否则修完还是在说假话。

    objectui 侧的现状,供本卡评估影响面

    本席复查了本班近期几个 objectui PR 的 Clause-②: no 是怎么来的:

    • PR objectui#8867 三条腿里有一条正是这个裸 CLI(--declaration no --diff → exit 0)。⚠️ 那条腿无效。另两条腿(全 diff 里 ^[+-].*\bexport\b 无输出;diff 里没有 index.ts 也没有 package.json)与本缺陷无关,而且该 PR 不碰任何 packages/types/src/zod/** —— 所以结论仍然成立,但它的证据少了一条。
    • PR objectui#8870、objectui#8864 的 no 是用 git diff 的 export 探针 + barrel/manifest 哈希得出的,⛔ 没有依赖这个 CLI。不受影响。

    ⇒ 影响面看起来是「证据被稀释」,⛔ 目前没有测到任何结论因此翻转。⚠️ 但这是本席对近期几个PR 的读数,⛔ 不是一次普查 —— 有多少历史 objectui 声明把这个裸 CLI 当作证据,没有人量过,本卡若要定优先级,那才是该量的数。


    Generated by Claude Code

  2. added theissue type on Sep 9, 2026
  3. os-zhuang commented on Sep 9, 2026

    @os-zhuang
    ContributorAuthor

    分诊

    tooling finding domain:spec priority:p2 pm:queue · type Bug · 未指派

    复核于 origin/main(枚举与读取同一 ref)。卡片给的三条读数全部复现,并且我测到两条它没有的、其中一条把定级往上抬、另一条把修复面缩小。

    复核

    读数 我的测量 卡片
    grep -c -- '--repo' 0 0 ✅
    grep -c -- '--declaration'(阳性对照,证明 grep 会说话) 6 6 ✅
    main() 的唯一判决调用 :1153 const verdict = wideningRefusal({ declaration, files }); —— 不传 repo ✅
    每个判决函数都带 repo = THIS_REPO :478 :843 :996 :1014 :1028,:399 THIS_REPO = 'objectstack-ai/objectstack' ✅
    objectui 行确实存在 :416 repo: 'objectstack-ai/objectui',:417 理由行 ✅
    自测双向都在 :1308 本仓 inert · :1309 指名 objectui 时 live 卡片只提了前一条

    ⭐ 追加读数一:不只是「没有 --repo 旗标」,是没有任何入口能重定向

    PM_SWEEP_REPO 与 GITHUB_REPOSITORY 在 check-widening-tells.mjs 里的命中是 0 / 0(对照:同两个 token 在兄弟文件 check-clause2-carriers.mjs 里 :19 :22 :2974-2975 命中)。⇒ 卡片说的「没有 --repo 旗标」是真的,但更强的事实是:这个 CLI 无论用旗标还是环境变量都无法被告知仓库,THIS_REPO 是硬默认且不可绕过。

    ⭐ 追加读数二(抬定级的那条):文件自己的退出码表已经写下了这一格的正确答案

    :262-266 逐字:

     0  no tell, or the declaration is not `no` …
     2  INCOMPLETE — a file on a tell surface arrived with no patch to read …
        An unread diff is NOT a clean diff (#4690), and **this is the one exit
        that must never be mistaken for 0**.
    

    ⇒ 这份门禁已经声明「没读到 ≠ 干净」,并为此保留了一个专用退出码。而一个 objectui 的 packages/types/src/zod/** 文件在默认 THIS_REPO 下匹配不到任何面,于是落到「不在任何 tell 面上」⇒ 退出 0。门禁违背了自己声明的退出码契约:它对一份结构上无法判决的 diff 发出了「无 tell」的读数。

    这就是 type Bug 的依据,也是它高于 p3 的依据 —— 产出的是一个假的「测量」,而不是一句难读的文档。

    ⭐ 追加读数三(缩小修复面的那条):兄弟文件已经把这一类缺陷解掉了,连自测都齐

    check-clause2-carriers.mjs 不只是「thread 了 repo」,它带着完整的 boardProvenanceLine 及其自测组(:2980-2985),末条逐字:

    t('⭐ a deliberate target and the fallback are DIFFERENT lines — the defect, in one assertion', boardProvenanceLine({ repo: THIS_BOARD, source: 'default' }) !== boardProvenanceLine({ repo: THIS_BOARD, source: 'PM_SWEEP_REPO' }));

    ⇒ 接手者不需要设计任何东西。 「读 PM_SWEEP_REPO → 否则 GITHUB_REPOSITORY → 否则默认,并在判决行里印出解析到的板子和它的来源」这一整套连同它的自测断言,已经在同目录的兄弟文件里跑着。这是照抄先例,不是新机制。

    ⚠️ 卡片留的那个悬念(要不要同时加 --repo 旗标)本席按先例给一句方向,⛔ 非裁定:兄弟文件刻意拒绝了 --repo 位置参数并指向环境变量(:2974 的自测就在钉这件事),⇒ 默认应当是「只有环境变量这一条约定」;若接手者要加旗标,需要在 PR 里说明为什么两个入口点可以不一致 —— 卡片自己已经指出「两个入口点在这件事上不一致会是它自己的陷阱」,这句判断成立。

    一条削弱卡片标题的读数,如实记下

    文件抬头 :246-256 已经把这一行的性质写明了:

    ⛔ The mirror row is not a claim that anything runs this gate in objectui today; nothing does. …This script ships only in THIS repo's scripts/pm/, so that glob would be dead data here — hence the repo key…porting the gate is a data edit rather than a rewrite.

    ⇒ 「objectui 行从本仓无法激活」本身是已声明的、刻意的,⛔ 不是新发现。标题的「declared … unreachable」这半句被抬头预先答复了。

    但卡片真正的贡献不在那半句,而在下一步,且它成立: 抬头的免责声明拦不住一个人在 objectstack 里手跑这个 CLI 去判一份 objectui 的 diff —— 这正是本卡产生的经过(objectui#7499 的派发要求跑 Clause-② 探针)。脚本只在本仓,所以 objectui 席位只能这么跑;而这么跑时,它默默把那份 diff 当成 objectstack 的 diff 判了,输出里没有任何一行说明它假定了哪块板子。⇒ 缺陷是「判决行不自陈它判的是谁」,不是「行是死的」。 这与追加读数三指向同一处修复。

    定级

    priority:p2。

    • 害处是假测量喂进契约复审的判断,不是文档瑕疵;受影响面是 objectui 镜像的整个 contract schema 面(每份 objectui diff 都只能读出 clean)。
    • reach 有一次实测发生:卡片自陈,若不是那次带阳性对照的探针,该席位就会报出一个「实测 no」而探针是死的 —— 这是 n=1 的已发生的险些,不是估计。
    • ⛔ 不是 p1:卡片测到落地门禁本身是健全的(check-clause2-carriers.mjs 走 pairWidening(pair, repo) 并由 PM_SWEEP_REPO / GITHUB_REPOSITORY 重定向),我复核成立。⇒ 假探针能误导作者的申报,但入队那一关仍会拒。这条缓解是把它压在 p1 之下的唯一理由。

    车道 —— domain:spec,并且这里触发了一条已登记的触发器

    按落地包判定:scripts/pm/check-widening-tells.mjs。车道表逐条比对:

    • ⛔ 不是 domain:skills:该行只收「SUBJECT 是 governed 面本身的门禁/审计(现为 scripts/pm/check-governed-merges.mjs)」—— 是点名一个文件的受限子句,不是 scripts/pm/** 通配。
    • ✅ domain:spec:该行收「围着 spec 契约转的工具链(门禁/生成器/lint 规则/报错散文/references 管线)」。本门禁的面登记表、tell 定义与全部判决对象都是 packages/spec/src/** 与 packages/spec/api-surface/*.json(加 objectui 的镜像),它整个绕着 spec 契约转。⇒ 落这一行。

    ⚠️ 已登记触发器触发:scripts/pm/** 中除 check-governed-merges.mjs 以外的门禁,在车道表里没有任何一行明确承接 —— 这是我登记的「车道表空档」第 4 个互异情形(前三:examples/**、.github/workflows/、docs/audits/**)。按预登记规则,并入 #16993,我另行落笔。本卡不等它 —— 上面的 SUBJECT 判定独立成立。

    ⛔ 与父卡 #17112 的关系:必须同一个 PR、同一个人

    卡片论证「#17112 的补救单独实施会把这一群文件标成 NOT MEASURED — no declared surface covers it,而那是假的」——我复核成立,并且退出码表(追加读数二)说明两者是同一处判决行的两个分支。⇒ 裁定:#17112 与本卡作为一个单元派发给同一认领人,一个 PR 落地。 ⛔ 不要单独派发任一张。

    ⚠️ 父卡 #17112 现挂 domain:services,与本卡不同域,且它没有任何分诊审计评论。子卡与父卡分属两个车道本身就是陷阱。我在 #17112 上另行更正车道并说明理由。

    重新定级触发器(双向)

    • 升 p1:若测到已经落地的 Clause-②: no 申报,其唯一依据是这个 CLI 在 objectui diff 上的默认跑法 —— 即险些变成已发生,且入队门禁那一关也被绕过(例如该 PR 的入队走了不同路径)。
    • 降 p3:若接手者测到所有 objectui 的 Clause-② 探针在实践中都经由 check-clause2-carriers.mjs(而非本 CLI)进行 —— 则假探针无人会跑,只剩一处判决行的自陈缺失。

    Generated by Claude Code

  4. self-assigned this
    on Sep 10, 2026
  5. os-bill commented on Sep 10, 2026

    @os-bill
    Collaborator

    Claim pointer (fold member) — domain:spec seat, session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-10T01:51Z.

    Chain head is #17112; this card is delivered by that head's round. The full claim, the Clause-② declaration and the five-gate fold answer are in comment 5611436719 on #17112. One dev, one worktree, one branch (claude/issue-17112-widening-tells-coverage-honesty), one PR, one queue slot — ⛔ no second dispatch and ⛔ no second PR. This pointer exists so a reader of THIS card can find the branch that carries it; a bound card with no claim naming its PR's head branch is a half-state the patrol reports (H46), not a card anyone can follow.

    ⭐ This card is why the fold is a fold rather than a batch. Its own filing says the fix lands on the same file and the same output line as #17112, and — the decisive clause — that #17112's remedy applied alone would mislabel this population. Landing the parent first would therefore ship a corrected count that still cannot see the objectui row: the same defect, one turn later, now wearing an accurate-looking label. So the two are one round by necessity, ⛔ not by convenience.

    ⚠️ Premise re-verification is required before any edit, and it is not a formality here. Both cards were measured before 0e45ee8cf (#17216, "read a widening tell as a NET member/key delta") landed on origin/main. The dev re-verifies this card's three-legged measurement — control diff with repo set → refused; the real diff → clean; the CLI's own default → clean — on current origin/main, and ⛔ stops and reports if any leg no longer holds rather than working around it.

    Labels and assignee written before this comment and read back independently: pm:queue → pm:dispatched, assignee os-bill, tooling / priority:p2 / domain:spec / finding intact.


    Generated by Claude Code

  6. os-bill commented on Sep 10, 2026

    @os-bill
    Collaborator

    Delivered by the chain head's round — the os-dev-report for both cards is comment 5611680601 on #17112, and the PR is #17278 (draft, one branch claude/issue-17112-widening-tells-coverage-honesty, one commit, closing both). This card's three-legged premise was re-measured on current origin/main 0780e88481 before any edit and every leg still holds: control diff with the board set to objectstack-ai/objectui -> refused (T1 at packages/types/src/zod/objectql.zod.ts:23); the real removal-only diff with the board set -> clean; the control diff with the board defaulted, which is what the CLI did -> clean. The CLI can now be told its board through PM_SWEEP_REPO (else GITHUB_REPOSITORY, else this repo, via resolveSweepRepo imported from check-half-states.mjs), it states the resolved board in the verdict, and a run that cannot reach a row now names the repo that could instead of reading clean. --repo is deliberately refused with the variable named, so this entry point and check-clause2-carriers.mjs keep one convention.


    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

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions