Skip to content

ci(doc-symbol-pins): 从 qa.yml 拆成无 paths 的独立 workflow —— 它从来不在该触发的时候触发 - #1002

Merged
vansin merged 1 commit into
mainfrom
ci/doc-symbol-pins-standalone
Aug 18, 2026
Merged

ci(doc-symbol-pins): 从 qa.yml 拆成无 paths 的独立 workflow —— 它从来不在该触发的时候触发#1002
vansin merged 1 commit into
mainfrom
ci/doc-symbol-pins-standalone

Conversation

@vansin

@vansin vansin commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

#1001 里报的那个结构性缺口,按当时说的方向②做,单独一条。

缺口

这道门原来是 qa.yml 的一个 step(qa.yml:309)。而 qa.yml 的 paths 是:

server/** · docs/stale-issue-review.md · scripts/check-doc-claims.py ·
tests/test846-doc-claims/** · agent-network/** · agent-node/** ·
tests/qa-*/** · scripts/qa.sh · docs/qa/** · .github/workflows/qa.yml

docs/architecture.md 不在里面。 于是改 architecture.md 的 PR 从来不跑这道 pin 门,
那个文件里的行号锚点可以自由漂 —— #1001 一次就抓到三处(URL cli.ts#L1569、锚文本
cli.ts:347、真值 1585;另一处 cli.ts:2386 声称是 sub === "dashboard" 分支,真值 6279)。

它只在被指向的文件agent-network/**)变动时才有机会红,而那时红的是别人的 PR、
理由却在 architecture.md 里。门存在、也挂上了,但不在该触发的时候触发 —— 三件事里
它只做到了前两件。

为什么拆出来,而不是给 qa.yml 的 paths 加 docs/**

  • qa.yml 很重(跑多个 docker 构建的测试套件),为一个几百毫秒的 python 检查把它整个
    拉起来不划算;
  • paths 的 workflow 在不匹配的 PR 上不产生 check-run,永远做不了 required check
    (卡在 Expected — Waiting for status)。这道门应当能进 required。

no-memory-slugs / public-script-safety 这些守卫保持同构。

验证

结果
绿起点 SYMBOL-PIN: OK(扫到 15 个 pin,判定 5 个,跳过 10 个,漂移 0 个) rc=0
见红 #1001 修的三处退回(git show 8937065f^:docs/architecture.md)→ SYMBOL-PIN: RED(… 漂移 1 个) rc=1
还原 rc=0

qa.yml 那一步摘除后留了去向注释,不是静默删掉。

workflow-structure / action-pins / qa-trigger-coverage / l1-paths-sync /
no-escaped-comments 全部 rc=0;job name doc-symbol-pins 经核全仓唯一(required
check 只能按这个名字写,此前有过四个 workflow 的 job 都叫 scan 的教训)。

覆盖面净增

原来只有命中那 10 条 paths 的 PR 才跑,现在每个 PR 都跑。合并后这条 PR 自己的 check
列表里应当出现 doc-symbol-pins —— 我会在合并前确认它真的产生了 check-run,而不是只
存在于文件里。

#1001 里报的那个结构性缺口,按当时说的方向②做,单独一条。

这道门原来是 `qa.yml` 的一个 step(qa.yml:309)。而 qa.yml 的 paths 是:

    server/** · docs/stale-issue-review.md · scripts/check-doc-claims.py ·
    tests/test846-doc-claims/** · agent-network/** · agent-node/** ·
    tests/qa-*/** · scripts/qa.sh · docs/qa/** · .github/workflows/qa.yml

**`docs/architecture.md` 不在里面。** 于是改 architecture.md 的 PR 从来不跑这道
pin 门,那个文件里的行号锚点可以自由漂 —— #1001 一次就抓到三处
(URL 写 `cli.ts#L1569`、锚文本写 `cli.ts:347`、真值 1585;另一处写 `cli.ts:2386`
声称是 `sub === "dashboard"` 分支,真值 6279)。

它只在**被指向的文件**(`agent-network/**`)变动时才有机会红,而那时红的是别人的
PR、理由却在 architecture.md 里。**门存在、也挂上了,但不在该触发的时候触发。**

拆出来而不是往 qa.yml 的 paths 里加 `docs/**`,两个理由:
  - qa.yml 很重(跑多个 docker 构建的测试套件),为一个几百毫秒的 python 检查
    把它整个拉起来不划算;
  - **带 paths 的 workflow 在不匹配的 PR 上不产生 check-run,永远做不了
    required check**(卡在 Expected — Waiting for status)。这道门应当能进 required。
和 no-memory-slugs / public-script-safety 这些守卫保持同构。

验证:
  绿起点   python3 scripts/check-doc-symbol-pins.py .   rc=0
           SYMBOL-PIN: OK(扫到 15 个 pin,判定 5 个,跳过 10 个,漂移 0 个)
  见红     把 #1001 修的那三处退回(git show 8937065^:docs/architecture.md)
           SYMBOL-PIN: RED(… 漂移 1 个)   rc=1
  还原后   rc=0

qa.yml 那一步摘除后留了去向注释,不是静默删掉。
workflow-structure / action-pins / qa-trigger-coverage / l1-paths-sync /
no-escaped-comments 全部 rc=0;job name `doc-symbol-pins` 经核全仓唯一。

覆盖面净增:原来只有命中那 10 条 paths 的 PR 才跑,现在每个 PR 都跑。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vansin
vansin merged commit 1355e56 into main Aug 18, 2026
23 checks passed
@vansin
vansin deleted the ci/doc-symbol-pins-standalone branch August 18, 2026 14:07
vansin added a commit that referenced this pull request Aug 18, 2026
…1004)

* fix: fail closed on broken Grok CommHub MCP

* test: exercise Grok CommHub MCP readiness handshake

* test: add isolated Grok MCP readiness gate

* test: exercise the real Grok MCP doctor

* docs: report Grok vendor MCP readiness

* test: gate Grok readiness on product startup path

* test: keep Grok gate dependency layers source-independent

* test: anchor Grok readiness to runtime events

* docs: record exact Grok MCP readiness evidence

* fix(grok): 把 #825 的 MCP 就绪 fail-closed 落到 main(rebase + 补两处今天新门抓到的)

#825(`fix(grok): fail closed when CommHub MCP is not ready`)从 2026-08-15 起是
draft,落后 main 120 个提交,上次 CI 只跑了 10 个 check(今天一个 PR 跑 13–23 个)。
它是 grok 栈 `#825#826#830 → {#836,#867}` 的**唯一出口**,它不落地,
上面四条谁都到不了 main。

**没有 force-push 那条共享 draft 分支** —— 本 PR 从我自己的分支发,内容是它那 9 个
补丁 rebase 到 `origin/main`(`rc=0`,0 冲突)再加下面两处修补。

## 今天新合的两道门抓到了它两处

上一轮我测过「#825 引入新失败 0」,那句话当时是真的 —— 但那两道门是**今天晚些时候**
才合进 main 的,门槛抬高之后它就红了:

  1. `test-suite-registration`(#1003)
     `tests/test813-grok-mcp-readiness/` 是新增套件,没有任何 CI 会跑它。
     🔴 这条特别值得修而不是豁免:**#825 的目的就是「MCP 没就绪时 fail closed」,
     而验证这件事的套件如果不进 CI,fail-closed 这个保证就没有任何东西持续守着。**
     照 test831 的同构做法接进 qa.yml:两处 `paths` + build/run 两个 step。
     ⚠️ 它的 Dockerfile 收的 build-arg 叫 `SOURCE_COMMIT`(不是 831 的
     `TEST831_SOURCE_COMMIT`),容器里由 `ENV TEST813_SOURCE_COMMIT` 承接 ——
     照抄 831 的参数名会静默拿不到值。

  2. `doc-symbol-pins`(#1002)
     `docs/message-lifecycle.md` 把 `shouldSkipMessage` 钉在 `cli.ts#L4639`,
     而 #825 给 cli.ts 加了 54 行,真值现在是 **4662**。
     文本 `cli.ts:4639` 和 URL `#L4639` 是同一句话的两副面孔,两处都改 ——
     只改 URL 会留下渲染出来给人读的那个错数字。

## 验证

    rebase 到 origin/main            rc=0,0 冲突,9 个补丁
    test-suite-registration          rc=0   suites=198 registered=34 orphans=164 new=0
    doc-symbol-pins                  rc=0
    l1-paths-sync / qa-trigger-coverage / workflow-structure / docs-integrity /
    no-escaped-comments              全部 rc=0

`registered` 从 33 变 34、`orphans` 仍是 164 —— 新套件是接进 CI 了,不是塞进基线蒙混。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(test813): 一条从写下起就是空的变异 —— 接进 CI 的第一次运行就把它照出来了

把 test813 接进 CI(本 PR 上一个提交)之后,它在 GitHub runner 上第一次运行就红:

    MCP_READINESS_PASS tools=commhub_get_all_status,commhub_send_message,commhub_send_task,commhub_upload_file
    FAIL: mutation survived: upload-tool-removed
    MCP_READINESS_PASS tools=…(同一份列表,commhub_upload_file 仍在)

不是产品没拦住,是**变异根本没发生**:

    sed -i '/^[[:space:]]*"commhub_upload_file",[[:space:]]*$/d' agent-network/src/node-server.ts

那个模式要求整行只有 `"commhub_upload_file",`,而真实那行是
`      name: "commhub_upload_file",`(对象字面量的字段)。实测命中 **0** ——
在 origin/main 上也是 0,**它从写下那天起就没匹配过任何一行**。
套件此前不在任何 CI 里(#861 说的 164 个孤儿之一),所以没人见过它红。

删整行会破坏对象字面量语法,改成改名:

    sed -i 's/name: "commhub_upload_file"/name: "commhub_upload_file_MUT"/' …

干跑验证:文件确实变了(`243:      name: "commhub_upload_file_MUT",`),已还原。

## 顺带堵住这一类,不只这一条

给 `expect_red` 加空变异防护:跑完变异命令后,若两个源文件**都**没被改动就直接判红,
并说清楚是「sed 模式和源码对不上」而不是「产品没拦住」。

这两种结论指向完全不同的下一步 —— **去改产品 vs 去改测试** —— 而它们在没有这道防护
时打印出来是同一句 `mutation survived`。

同一个套件里另外三条 sed 都逐条查过,各自命中 1(其中打 fake-grok.mjs 那条还自带
`grep -Fxc … -eq 1` 基数守卫),只有这一条是空的。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: t <internlmorg@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant