Skip to content

fix(ci): ReproSpec.ci.skip —— 让 Windows-only / 手工预置类 spec 在 Ubuntu CI 上自报豁免 (closes #3) - #4

Merged
libz-renlab-ai merged 4 commits into
mainfrom
feat/spec-ci-skip
May 15, 2026
Merged

fix(ci): ReproSpec.ci.skip —— 让 Windows-only / 手工预置类 spec 在 Ubuntu CI 上自报豁免 (closes #3)#4
libz-renlab-ai merged 4 commits into
mainfrom
feat/spec-ci-skip

Conversation

@libz-renlab-ai

Copy link
Copy Markdown
Owner

fix(ci): ReproSpec.ci.skip —— 让 Windows-only / 手工预置类 spec 在 Ubuntu CI 上自报豁免

关闭 issue #3 Gap 1。

背景

PR #2 落地远程评审 workflow 后,首次 dogfood 跑出 verdict=fail —— 因为唯一现存 spec fixtures/repro-specs/hook-moment-block.ts 是「数据驱动差异」(baseline.ref="HEAD",两侧靠 env 切的 $TA_DEMO_STAGE/home-empty|loaded 切知识库),Ubuntu runner 上既没那俩目录也没 TA_DEMO_STAGE,必然 fail。本 PR 让这类 spec 自报「我在 CI 上跑不了」,被 list-specs job 显式过滤掉,verdict 把它当豁免。

变更

文件 内容
scripts/verify/list-specs-core.ts(新) 纯函数 filterCiSpecs(specs) —— 按 ci.skip 把 spec 列表分成 includedexcluded。Functional Core,严禁 IO import
scripts/verify/list-specs-core.test.ts(新) node:test 7 个 case:空数组 / 无 ci / ci.skip=false / 仅 reason / skip+reason / skip 无 reason 默认值 / 混合保序
scripts/verify/repro-types.ts ReproSpec 加 optional ci?: SpecCi({skip?, reason?})
scripts/verify/list-ci-specs.ts(新) IO 壳:readdirSync(fixtures/repro-specs)pathToFileURL + 动态 import → 抽 spec.cifilterCiSpecs → JSON to stdout
fixtures/repro-specs/hook-moment-block.ts ci: { skip: true, reason: "需 $TA_DEMO_STAGE 下两份知识库目录预置 + 录 GIF 仅 Win32 可行" }
.github/workflows/pr-review.yml list-specs job 拆 label-shortcut step(skip-repro label 早退,不必装 pnpm/node)+ setup-repo + npx tsx scripts/verify/list-ci-specs.ts;新加 excludedSpecs output;verdict job 把豁免列表附在 repro_summary 后,verdict comment 上一眼可见哪些 spec 被豁免

架构遵守

  • Functional Core, Imperative Shell:list-specs-core.ts 纯函数,严禁 import fs;IO 在 list-ci-specs.ts
  • TDD:list-specs-core.test.ts 先写,跑红 → 实现 → 跑绿(7/7)。每个 commit 都跑得通、测试绿。
  • 小 commit 4 个:list-specs-core 红→绿、ReproSpec.ci 类型、list-ci-specs IO 壳 + spec 标记、pr-review.yml 接入。

验证

$ tsx --test scripts/verify/list-specs-core.test.ts
# tests 7 / pass 7 / fail 0

$ tsx scripts/verify/list-ci-specs.ts
{"included":[],"excluded":[{"file":"fixtures/repro-specs/hook-moment-block.ts","reason":"$TA_DEMO_STAGE ... 录 GIF 仅 Win32 可行"}]}

预期 dogfood 表现

本 PR 一开,会触发的 pr-review.yml 跑应该:

  1. list-specs job —— 读 spec ci.skip=truespecs=[] + excludedSpecs=[{...}] + skipReason="all-specs-ci-skip: ..." + 注解 warning
  2. repro matrix —— specs=[] → 整个 job skipped
  3. tests job —— 预期仍 fail(21 个 Matrix baseline 预存失败,不在本 PR 范围,issue [follow-up] PR #2 dogfood 揭示两个预存问题:CI repro 豁免 + Matrix baseline pnpm test 失败 #3 Gap 2)
  4. verdict job —— repro_ok=true(豁免)+ tests_ok=falseverdict=fail,但只挂 tests-and-merge-clean 一条,不再因 repro 错挂

把「repro 不该挂」的部分修干净,留 Gap 2 作下一个独立 PR。

合并方式

无 Visual proof of work 章节 → can-auto-merge.ts 不会因此豁免;但 tests-and-merge-clean 还会 fail → can-auto-merge.ts:52 仍会因 reviewVerdictState !== "success" 拒绝自动合 → 回落到 human-merge(等 Gap 2 修了之后,本类纯 CI fixup PR 才能享受全自动)。

关联

🤖 Generated with Claude Code

liboze2026 and others added 4 commits May 15, 2026 15:08
issue #3 Gap 1 的纯函数:把发现的 ReproSpec 按 ci.skip 分桶,
included 喂 pr-review.yml 的 repro matrix,excluded 喂 verdict
job 的豁免列表(让 hook-moment-block 这类需手工预置的 spec
在 CI 上被显式豁免,而不是 fail)。

TDD 红→绿 7 个 case 覆盖:空数组 / 无 ci / ci.skip=false /
仅 reason / skip+reason / skip 无 reason / 混合保序。

下一步:repro-types.ts 加 ReproSpec.ci 字段、list-ci-specs.ts
IO 壳、pr-review.yml list-specs job 调用。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
issue #3 Gap 1 类型层:加 optional ci?: SpecCi 字段到 ReproSpec,
让 spec 自报「在 CI 上能不能跑」,而不是 CI workflow 硬 grep 文件。

SpecCi 与 scripts/verify/list-specs-core.ts 的 SpecCi 是同构(后者
在 functional core 不能依赖 ReproSpec 全部类型),behaviorally 等价。

无功能影响 —— 现有 spec 不带 ci 字段 = 行为不变。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
issue #3 Gap 1 IO 壳 + 首个真受益 spec:

  scripts/verify/list-ci-specs.ts:
    readdir fixtures/repro-specs/*.ts → 动态 import → 抽 spec.ci →
    调 list-specs-core.filterCiSpecs → 把 { included, excluded } JSON
    打到 stdout。给 pr-review.yml 的 list-specs job 读。

  fixtures/repro-specs/hook-moment-block.ts:
    加 ci: { skip: true, reason: '需 $TA_DEMO_STAGE 下两份知识库目录
    预置 + 录 GIF 仅 Win32 可行' }。本地 Windows 手工跑仍然有效;CI 上
    会被 list-specs 过滤掉,verdict 把它当显式豁免。

Smoke-test:
  $ tsx scripts/verify/list-ci-specs.ts
  {"included":[],"excluded":[{"file":"fixtures/repro-specs/hook-moment-block.ts",
   "reason":"需 $TA_DEMO_STAGE ... 录 GIF 仅 Win32 可行"}]}

下一步:pr-review.yml 改用此 CLI。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
issue #3 Gap 1 最后一拼:把 list-specs job 从「inline bash find」改成
「调 scripts/verify/list-ci-specs.ts 读 spec.ci.skip 分桶」。

变更:
  - 拆出 label-shortcut step:skip-repro label 命中即早退,不必再装
    pnpm/node 跑 list-ci-specs(优化)
  - 没命中标签 → 跑 setup-repo composite 装依赖 → npx tsx list-ci-specs.ts
    → 解析 JSON 输出 specs/excludedSpecs/skipReason 三个 output
  - verdict job 拿 excludedSpecs 拼成 `显式豁免: file (reason); ...`
    附在 repro_summary 后,verdict comment 上一眼可见哪些 spec 被豁免

行为差异(对 hook-moment-block 这种 ci.skip=true 的 spec):
  before: list-specs 把它放进 matrix → repro job Ubuntu 上跑 → fail →
          verdict=fail
  after:  list-specs 把它放进 excluded → repro matrix 为空 → repro job
          skipped(skipReason 非空) → repro_ok=true → verdict 不再因它 fail

skip-repro label(PR 级豁免)语义不变;新增的 spec.ci.skip(spec 级豁免)
是 PR 级豁免的补集。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

❌ 远程评审 verdict: fail

commit 07052d2 · workflow run · 2026-05-15T07:20:19Z

标准 结果 简述
repro-pass 豁免 — all-specs-ci-skip: fixtures/repro-specs/hook-moment-block.ts (需 $TA_DEMO_STAGE 下 home-empty/home-loaded 两份知识库目录预置 + 录 GIF 仅 Win32 可行)
tests-and-merge-clean tests failed or tree dirty (TESTS_OUTCOME=failure)

要修这个失败,请在本地按 docs/plans/2026-05-15-local-review-loop.mdloop-driver.ts,push 修复 commit 即可触发本评论刷新。

@libz-renlab-ai
libz-renlab-ai merged commit ed54a27 into main May 15, 2026
4 of 7 checks passed
@libz-renlab-ai
libz-renlab-ai deleted the feat/spec-ci-skip branch May 15, 2026 07:34
libz-renlab-ai pushed a commit that referenced this pull request May 15, 2026
PR #7 v2 dogfood 第三个 sub-gap:tests + tree-clean 都修过后,verdict
job 在 'Post comment + set status' step 仍崩:

  Error: update comment 失败: gh: Not Found (HTTP 404)

根因(本 session PR #2 引入的 post-pr-comment.ts bug):
  - line 71: `gh pr view --json comments` 返回 GraphQL node ID(IC_kwDOI...)
  - line 81: `gh api repos/.../issues/comments/{id}` PATCH 要 REST integer id
  - 不匹配 → PATCH 404

为什么 PR #2 / #4 没炸:每个 PR 只跑过一次 verdict → 没现成评论可更新 →
只走 CREATE 路径(line 87 `gh pr comment`)→ 没暴露。PR #7 是本仓库
第一个 multi-commit PR:v1 (2798a32) 创了评论 → v2 (1aa98e3) 想更新 → 404。

修复:
  - 列评论改用 `gh api repos/.../issues/{pr}/comments` —— 返回 REST id,
    跟 PATCH 端点格式一致
  - CREATE 也改走 REST POST(对称;新评论的 id 直接是 REST 制式,下次能
    正确 UPDATE)

这是 dogfood 的核心价值 —— 第一次真有 multi-commit PR 跑流水线就揪出了
首次 ship 时遗漏的 code path bug。

Co-Authored-By: Claude Opus 4.7 (1M context) <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.

2 participants