ci: 第二个声明 Fixes 同一 issue 的 open PR 开出即挂红 —— #4555/#4559 重复开发的三重堵漏 (#4588) - #4589
Merged
Conversation
…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
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
os-zhuang
marked this pull request as ready for review
August 2, 2026 09:14
os-zhuang
enabled auto-merge
August 2, 2026 09:14
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 恰恰是第二个会话最需要看见的在途工作):setFailed,点名对方(链接 + 分支名)。isSystem残留 (#4551) #4559 关闭时抢救出 data: the SQL driver emits thecurrent_userframework token as a literal column DEFAULT, so the database itself writes a non-id into alookup('sys_user')#4560 正是这个动作),或先关掉被弃的早方——检查在edited/synchronize上重跑,冲突消失即转绿。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>就是一条命令的预检。#4555(claude/issue-4551-…)与 #4559(claude/dangling-reference-sweep)互相不可见,一半原因就是后者没带 issue 号。工作流对「声明了 Fixes 但分支名不含任何被声明 issue 号」的 PR 给 warning,不挂红——存量分支不应被追溯打红。验证
github, context, core, exec, glob, io, fetch, require, octokit, __original_require__),#4573 的教训prefixes #99不误报、跨仓库排除、大小写、多引用、代码格式剥离github.paginatepull_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/。边界