Skip to content

ci: 第二个声明 Fixes 同一 issue 的 open PR 开出即挂红 —— #4555/#4559 重复开发的三重堵漏 (#4588) - #4589

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-4588-duplicate-fix-guard
Aug 2, 2026
Merged

ci: 第二个声明 Fixes 同一 issue 的 open PR 开出即挂红 —— #4555/#4559 重复开发的三重堵漏 (#4588)#4589
os-zhuang merged 2 commits into
mainfrom
claude/issue-4588-duplicate-fix-guard

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #4588

背景

今天上午 #4551 被两个会话完整实现了两遍(#4555#4559,834 行重复劳动、全套门禁各跑一轮)。重复从第二个 PR 开出那一刻(03:08)起就是机器可判定的——两个 open PR 同时声明了针对 #4551 的关闭关键字——却直到 08:52 才被人工发现。共享 GitHub 身份让 issue 的 assignee 起不到警示作用:"assigned to os-zhuang" 无论认领者是不是你,读起来一模一样。

三个洞,三个对应的堵法,合在本 PR:

A. Duplicate Fix Guard 工作流(新增,挂红的那道闸)

PR opened / edited / reopened / synchronize 时解析正文的同仓库关闭关键字(裸 #N 与限定 objectstack-ai/objectstack#N;跨仓库引用是 cross-repo-issue-closer 的领域,不归它管),逐一比对其它 open PR(含 draft——draft 恰恰是第二个会话最需要看见的在途工作):

B. 认领评论必须带会话 ID(pm-dispatch 模板 + AGENTS.md + CLAUDE.md)

共享身份下,「这条认领是不是我发的」只有评论里的会话 ID 能回答。模板新增一行 会话:session_<id>,race check 的判负条件同步改为「更早且会话 ID 或分支名不同」。AGENTS.md 与 CLAUDE.md 的认领规则补上同一条:认领 = assign 带会话 ID 的评论,动码前必须重读评论区。这一改动同时覆盖此前另一次同根因事故(agent 把共享身份的 draft: false 误读为自己写入失败,反手撤销了维护者的手动操作)。

C. 分支名统一 claude/issue-<n>-<slug>(AGENTS.md 分支纪律)

issue 号进分支名,git ls-remote --heads origin | grep issue-<n> 就是一条命令的预检。#4555claude/issue-4551-…)与 #4559claude/dangling-reference-sweep)互相不可见,一半原因就是后者没带 issue 号。工作流对「声明了 Fixes 但分支名不含任何被声明 issue 号」的 PR 给 warning,不挂红——存量分支不应被追溯打红。

验证

状态
YAML 解析
脚本语法 —— 完整注入标识符集包装(github, context, core, exec, glob, io, fetch, require, octokit, __original_require__),#4573 的教训
关键字正则 16 组样本:冒号形、prefixes #99 不误报、跨仓库排除、大小写、多引用、代码格式剥离 ✅ 16/16
分页(>100 open PRs)用 github.paginate ✅(代码路径,未实测大仓)
端到端真实运行 已在本 PR 上跑过并通过 —— pull_request(不同于 pull_request_target)从 merge ref 读工作流定义,所以新增的闸在自己的 PR 上就会跑。初版 PR 正文断言「合并前不会跑本文件」,是错的,已由第一次运行本身证伪。

首次真实运行立刻暴露了一个真缺陷:日志记下 This PR declares: #4588, #4551——正文里用反引号讨论事故的那句 Fixes #4551 被当成了声明。当时无害(#4551 已关闭、无其它 open PR 声明它),但若某个 open PR 真在修被讨论的 issue,这就是一次冤枉的挂红。第二个 commit 修复:匹配前剥离代码格式,与 GitHub 自身解析行为对齐。修复后的运行应记 This PR declares: #4588——这是可核验的预期,请以该次 Actions 日志为准。

changeset:.changeset/duplicate-fix-guard.md(空 frontmatter,release-nothing)。未触碰 content/docs/releases/

边界

  • 只管同仓库重复。 跨仓库的重复实现(若有)无法靠单侧 CI 挂红解决,不在范围。
  • 不改 objectui。 该仓库的 AGENTS.md/认领约定是独立文件;等本 PR 的形状被真实运行验证过再镜像过去,避免把未经运行的工作流一次铺到两个仓库(cross-repo closer 就是这么放大故障面的)。
  • pm-dispatch SKILL.md 的措辞改动不改变循环的结构,只改认领评论模板与判负条件。

…same issue (#4588)

GitHub lets any number of open PRs declare Fixes #N for the same issue;
#4555 and #4559 proved the cost this morning. Three changes, one per hole:

- duplicate-fix-guard.yml: same-repo closing keywords are checked against
  every other open PR; the LATER PR goes red with a pointer to the earlier
  one (first come, first served, matching the pm-dispatch claim convention).
  Re-runs on 'edited'/'synchronize' so resolving the conflict either way
  clears the red. Branch names that carry no declared issue number get a
  warning, never a failure.
- Claim comments now require a session ID (pm-dispatch template, AGENTS.md,
  CLAUDE.md): under the shared GitHub identity the assignee field cannot
  answer "is this claim mine?" — the comment's session line is what can.
- Branch naming claude/issue-<n>-<slug> documented in AGENTS.md so
  git ls-remote | grep issue-<n> is a one-command pre-check.

Script validated with node --check under the full injected-identifier
wrapper; keyword regex exercised against 10 samples including the
prefixes-#N false-positive and cross-repo exclusions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gEHJN2NFpS9VMeURvakgD
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 2, 2026 9:15am

Request Review

@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 09:14
@os-zhuang
os-zhuang enabled auto-merge August 2, 2026 09:14
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation ci/cd tooling labels Aug 2, 2026
…ns and fenced blocks

The guard's first real run — on its own PR — counted the PR body's
backticked DISCUSSION of 'Fixes #4551' as a declaration. GitHub's own
closing-keyword parser ignores code formatting; a guard stricter than
the linker it protects turns prose mentions of other PRs' fix lines
into spurious reds. Strip ```fences``` and `spans` before matching.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gEHJN2NFpS9VMeURvakgD
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit 6247d7f Aug 2, 2026
19 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-4588-duplicate-fix-guard branch August 2, 2026 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

process: #4551 被两个会话重复实现(#4555 与 #4559)——需要 Fixes 唯一性 CI 闸 + 认领评论带会话 ID + 分支名带 issue 号

2 participants