news 2026/9/21 20:29:47

opencodex 贡献者署名修复机制:CREDITS.md 与 Co-authored-by 自动化门禁的完整实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
opencodex 贡献者署名修复机制:CREDITS.md 与 Co-authored-by 自动化门禁的完整实现

【免费下载链接】opencodex

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载

opencodex(Universal provider proxy for OpenAI Codex & Claude Code)的维护者在落地他人 Pull Request 时,常采用重新实现(reimplement)、携带(carry)或变基(rebase)的方式,导致最终提交的作者是维护者,贡献者的名字只能通过Co-authored-by尾注存活。本文以仓库根目录的 CREDITS.md 为主体,剖析该文档的诞生背景、证据边界、完整署名记录表,以及从源码到工作流的自动化防护体系,帮助贡献者、维护者和开源社区读者理解"git 历史不重写"原则下的前瞻性修复方案。


一、问题起源:为什么需要一份独立的 Credits 文件

1.1 署名只存在于尾注,而尾注是可选的

opencodex 的合入流程中,当维护者以"重新实现、携带或变基"的方式落地另一位作者的 Pull Request 时,最终提交的作者是维护者。贡献者的名字只能通过Co-authored-by尾注(trailer)存活——而 GitHub 正是读取这个尾注来生成贡献者图表、仓库贡献者列表和作者的个人主页活动。

问题在于:两条同样真诚的声明,只有一条是可被机器读取的数据。文档开头给出了仓库中的真实对照:

53c09a247 "Clean reimplementation of #3193" Co-authored-by: alan7629 ... 5734a1caf "Reimplements #2797 by @rrmlima." (no contributor trailer)

第一条在提交体里写了Co-authored-by尾注,能被 GitHub 的工具链识别;第二条只在散文(prose)中陈述了债务,任何自动化工具都读不到。两条句子同样真诚,但只有第一条是数据

1.2 为什么不能回填尾注:git 历史不可重写

这些提交位于已发布的 release 标签内部,并且位于阻止强推(force-push)的分支规则集(branch rulesets)之后,因此无法追溯性地补上尾注——那会令每一个标签和克隆失效。与此对应,MAINTAINERS.md 第 26 行从另一个方向陈述了同一原则:

Authorship credit in git history, release notes, and code comments is not rewritten when a maintainer steps down.

(维护者卸任时,git 历史、发布说明和代码注释中的作者署名不会被重写。)

正是"历史不可重写"这一约束,催生了CREDITS.md这个**前瞻性修复(forward repair)**文件。

1.3 CREDITS.md 不是什么

文档明确声明:这个文件不是贡献者名单。绝大多数贡献以正常的、作者身份完整的方式合并,不需要任何条目。不出现在本页意味着"常规路径正常工作了"。CREDITS.md只为那些署名在工具层丢失的落地记录而存在。


二、证据边界:每条记录都必须有出处

CREDITS.md的可信度建立在严格的证据规则上:

  • 只引维护者自己的话:每个条目都引用维护者在关闭评论(closing comment)、Pull Request 描述或落地提交(landing commit)中的原话;
  • 绝不从 diff 推断:"Nothing here is inferred from a diff."——哪些代码、设计或测试被采纳,必须以维护者的文字陈述为准;
  • 两种等级分开记录:因为混在一起会同时误报两种事实。

这一规则在配套的开发计划文档 devlog/_fin/260903_contributor_credit_restoration/010_credits_file.md 中被复述为"Row selection rule"(行选择规则):行存在的唯一条件,是维护者自己的文字(关闭评论或落地提交体)陈述了贡献者提供了什么,每个"what landed"单元格都是该句子的引用或贴近的转述,绝不来自对 diff 的推断

三、Carried work:被携带的代码、设计与测试

3.1 主表:从 #1801 到 #3284

下表记录了被携带的 Pull Request。所谓"携带",指原作者的代码、设计或测试被维护者采纳并落地:

Pull requestAuthorLanded asWhat landed
#1801@jonathanli12cb48c2e11"carries all three of its unique tests" — the Cursor code-mode contract
#2123@chilung-cguef7b3c9cf"Your account loop and the reuse ofgetTokenForAccountQuotaProbeare what shipped"
#2655@TooSpace607042b02"re-implemented on currentdevfrom your design"
#2693@yxr1995-makerd829215af,bdc1e97bb"carries your fix forward with the three review blockers closed"
#2734@TooSpace88c427522"That carry keeps the adaptive effort-mode design"
#2744@yxr1995-maker8877df0ee"Your diagnosis held up"; the landed fix reimplements it narrowly
#2796@rrmlimabb3321ca8"Reimplements #2796 by @rrmlima"
#2797@rrmlima5734a1caf"Reimplements #2797 by @rrmlima"
#2812@gaoran1209c986d1d20"Reimplements #2812 by @gaoran1209 with the maintainer's blocker addressed"
#2867@Ingwannu8d1dc1f5d"That landed change includes this PR's strict LoadState parsing"
#2870@luvs01de91dfde4"the coalescing design here is right, and it is carried forward"
#2884@chilung-cgueb52973c5"Completes contributor PR #2884"; the exact-name approach carried as-is
#3000@MarcTCruzfecb77a91"Your central insight" — the refresh lock and the file it protects live under different homes
#3039@ntdatt812b14b741dc"keeps your production logic exactly as written — the Windows budget, thewaitedguard, and the grace probe"
#3041@ntdatt812b46164e78"carries your three merge-loop tests … they came from this PR"
#3067@ntdatt812b14b741dc"keeps your diagnosis and your relocation", with the remedy narrowed
#3078@Veritas-70ef04e640"reimplements both of your production hunks ondev"
#3142@olddonkey52d941640"That carry keeps the measurement/refusal work and ships the guard default-off"
#3300@S0RYUASUKA15b43e51cthe same two test files made hermetic
#3284@mdwsk883d3c4fe26"Core implementation is already ondevvia #3286 (3d3c4fe26), including the suffix wire ladder, picker collapse, Google adapter coverage"

一个值得注意的细节:#2123 中被携带的getTokenForAccountQuotaProbe函数在真实源码中依然可查——它出现在 src/providers/quota.ts、src/providers/quota/account-cache.ts 和 src/providers/quota/vendor-probes-key.ts 中,对应账户配额探测的实现正是这条"carried work"的落点。这印证了文档记录与代码库的对应关系。

3.2 2026-09-07 跟进:缺失或畸形的尾注

在审计的 3,000 提交窗口中又发现了一批落地记录,其落地描述或提交信息标明了被采纳的内容。完整清单涵盖 #1748(outbound Fake-IP discovery 修复的限定范围重新实现)、#1842(Public OAuth 错误投射与类型化认证失败保留)、#1896(functions 命名空间解析器扁平化)等共 40 余条。这里特别说明几类关键形态:

  • 跨 PR 落地:#2077 与 #2100 均以f9c224b70落地,维护者原话为 "Both patches are @ntdatt812's work from #2100 and #2077, applied unchanged";#2109 与 #2110 的共享 base-URL 覆盖实现合并在d2493a147落地;
  • 合并落地:#2027 以两个提交5445ce3e6293494cfa落地,标注 "Absorbed from #2027";
  • 在落地过程中修正归属:#1748 落地信息中的源 PR 作者被纠正为 @Blushyes。

3.3 2026-09-07 跟进:未链接的尾注

某些提交包含贡献者名字,但 GitHub 的提交作者映射(commit-author mapping)无法将该尾注解析为源 PR 作者。仓库不在此复现任何个人地址,前瞻性修正使用与账号关联的 noreply 身份。该类包含 #2817(opt-in 上游 Responses WebSocket 传输及六个被携带提交)、#3148(两个订阅启动准入密钥修复)、#3293(缺失的 claude-fable-5-1 模型元数据及配套用量成本测试)。修正提交把这些贡献者及前表作者记录为 co-author——这是前瞻性归属(forward attribution):旧的提交对象、原始日期和发布标签均未改变。

3.4 2026-09-07 跟进:四轨 source-to-landing 归属

应项目所有者要求,审计对 #3771 之后的四条跟进轨道,把原始 PR 标题、作者和被交付的切片(delivered slices)明确化。所有链接的落地提交都是5759d9ea2f1e7281cdc01eb9628f2e0a123fb59c的祖先。值得强调的几行:

  • #3769(@ideabib)仅交付"配额/不完整归属"部分,native compact 404 fallback 不在本次落地范围内
  • #3736(@Hylouis233)只交付了"无内容的缓冲压缩进度",提议的全局 600 秒默认值未被采纳
  • #3383(@x3M3x)交付 picker 排序控制与隔离保存,源 PR 中无关的 Windows 变更不被计入该层归属

表尾的说明至关重要:"交付了切片"不等于"原始 PR 或总括 issue 的每个需求都完成了"。表格刻意保留了未采纳的范围,避免夸大。

3.5 2026-09-13 跟进:合入时尾注丢失

最近一次审计以相同方式扫描了当前dev可达的最后 3,000 个提交:先看落地处的 carry/reimplement 语言,再看实际落地提交,最后对照 GitHub 的提交作者映射。发现一处新遗漏:#4031 自己的描述中写明了尾注,但合并提交没有保留它——cherry-pick 的对象以未映射的机器身份署名,GitHub 无法将其映射到任何账号,仅剩的尾注是自动化产生的。

该行记录的是 #3988(@rrmlima),以e2bf1672c/14ce693e5落地:"Carries #3988 by @rrmlima (cherry-pick -x)"——即 Gemini/CCA/Vertex/AI Studio 模型尾部的(continue)提示,位于messagesToGeminiFormat中。


四、Report and diagnosis:报告者的独立归属

4.1 主表:修复因报告而存在

有一类贡献必须与"carried code"严格区分:修复之所以存在,是因为报告本身,而分支自己的方案并未成为载体,作者在当时就被告知了原因。若把这些记录为被携带的代码,就会误述另一方向的事实:

Pull requestAuthorFix landed asMaintainer's words
#2925@ncepuee1d9b389c1"Credit to @ncepuee, whose #2925 identified this and argued the split"
#3006@Ingwannu870a2adb6"your PR correctly identified the broken invariant and verified the target was unused"
#3038@L-Y-Je9d198a3c"the defect is real and #3107 exists because you found it"
#3040@ntdatt812330470e74"The defect you found is real"
#3117@olddonkeyb46164e78"Thank you for the focused report and tests"
#3143@Ingwannu408652698"The diagnosis here was yours and it was right"
#3223@alex-jordan547d23eab43a"The report itself was what made the fix quick; the wire capture pointed straight at the cause"

4.2 四轨报告与诊断证据

还有一类 issue 作者提供了被后续工作使用的报告或观察,他们作为**报告者(reporters)**被单独致谢,与 carried PR 作者分开。例如 #3746(只读容器 Codex-home 持久化失败)对应 #3788、#3770(JSON-to-SSE 完成语义丢失)对应 #3803、#3522(同进程 Windows spill 失败证据)对应 #3790 等八条。表尾的免责声明很关键:仅交付诊断不意味着报告中的运行时故障已被解决

五、Closed as landed:诚实记录"未言明的落地"

有两起 PR 以落地提交关闭,再无其他说明。落地被记录,但被采纳的内容未声明——凭空编造答案,正是这个文件要纠正的不准确

  • #3020 by @luvs01 — closed "Landed via #3119 ata73a4c998"。
  • #2675 by @Ingwannu — closed "Landed via #2677 at8412fe156"。

另有 #2360(@chilung-cgu)与 #3621(@yansigit)以落地引用关闭但未明确声明携带内容,其作者在此被致谢,但仅凭该关闭行为不计入被携带代码


六、如何保持准确:从修复到自动化门禁

CREDITS.md是一个修复(repair),而不是流程(process)。真正的流程是missing_coauthor_credit检查,位于 .github/scripts/pr-hygiene.cjs:一个 PR 只要在自身文本中声明它重新实现、取代、携带或变基了另一位作者的 PR,就会在卫生门禁(hygiene gate)上失败,直到一个Co-authored-by尾注点名该作者。理想状态下,本页的新条目应当不再出现。

6.1 工作流触发:PR 卫生检查

.github/workflows/pr-hygiene.yml 定义了PR hygiene工作流:

  • 使用pull_request_target事件,类型包括opened, reopened, synchronize, edited, labeled, unlabeled。其中edited只为 carry-attribution 检查存在——其补救措施是在描述中加尾注,无需触碰分支,若无edited,修复要到一次无关的 push 才可见;
  • 最小权限原则permissions: {}默认无权限,hygiene job 只授予contents: readissues: writepull-requests: write
  • 只从 PR base 的修订版本检出可信脚本ref选择main(当 base 是main)否则dev,并启用sparse-checkout: .github/scriptsPR head 代码从不被检出或执行
  • 通过github.paginate读取 PR 文件和提交,把标题、描述与全部提交信息交给resolveReferencedAuthors解析被引用的作者;
  • 关键设计:异常批准是 head 特定的——synchronize事件会清除test-exception-approvedattribution-approved等标签,防止贡献者拿到一次窄豁免后推入未审变更;而maintainer-sponsored与 head 无关,不受同步清除影响。

6.2 门禁实现:读文本,不读 diff

.github/scripts/pr-carry-attribution.cjs 是 carry 归属检查的核心实现,注释中直接引用53c09a2475734a1caf的对照作为设计动机,并说明"对dev的扫描发现了 27 处署名只存在于散文、工具读不到的地方;CREDITS.md 是这些的记录,而这个检查是这份清单不应再增长的原因"。其关键机制:

  • CARRY_VERB_RE:匹配re-implementsupersedecarry/carries/carrying/carriedrebase/rebasingadopts the design from等携带动词(re-?implement同时覆盖带连字符与不带连字符的拼写);
  • REF_RE(?:([\w.-]+\/[\w.-]+))?#(\d+)——捕获可能存在的 owner/repo 限定符,限定引用(如other/project#2797)会被丢弃而不是误读,避免拿本仓库的同号 PR 与尾注比对;
  • carryWindow:携带动词管辖的窗口是"到句末、上限 80 字符"。句末边界让"Supersedes #3193. Fixes #3192."只报告 #3193(这正是53c09a247的真实提交体);宽度上限防止动词跨段落扫进无关的引用列表;
  • strippedText:围栏代码块、内联代码和 HTML 注释内的 carry 语言是引用材料而非声明——一个解释门禁本身的 PR(例如本检查的实现 PR)不得触发它;
  • trailerNamesGitHub 登录名不是 git 身份。扫描曾因此产生十一个假阳性(如登录名asmith92不会出现在A. Smith <a@example.com>尾注中)。检查对引用的 PR 实际携带的三种标识符(登录名、git 名字、git 邮箱)逐一匹配,并对users.noreply.github.com邮箱做数值 ID 前缀剥离后按登录名匹配。

6.3 引用解析:失败开放、有界、按身份匹配

.github/scripts/pr-referenced-authors.cjs 把 carry 声明点名的 PR 解析为作者身份,让门禁能区分"你携带了别人的工作"与"你变基了自己的分支"。它必须满足三个性质:

  • 失败开放(fail open):限流、已删除账号或指向其他仓库的引用解析为 null,而 null 作者即通过——因 API 调用失败而阻止合并,比这个门禁要防止的遗漏更糟;
  • 有界(bounded):最多解析MAX_LOOKUPS = 5个引用,避免一个讨论二十个历史 PR 的描述把一次 hygiene 运行变成四十次 API 调用;
  • 身份而非登录名:被引用 PR 自己的提交提供 git 作者名和邮箱,因为尾注通常由人复制 git 身份而非 GitHub 句柄。

6.4 门禁的已知盲区与防线

文档以真实案例说明了门禁的两个局限及相应防线:

盲区一:尾注存在 ≠ 尾注可解析。2026-09-04 积压审查发现 carry PR #3374 携带 #3333(@blackjune67),尾注是Co-authored-by: hajune <contributor@work-domain.example.test>(地址已在仓库中被掩码,因为privacy:scan会阻止真实贡献者邮箱出现在树中)。这是贡献者自己提交上的 git 身份,形态上看起来完全正确——但 GitHub 按账号关联邮箱归属 co-author,该地址未关联任何账号,尾注将无法给任何人记名。门禁放过了它(因为有尾注),好在合并前被纠正为账号关联的users.noreply.github.com地址,因此上表没有它的行。

盲区二:门禁只看"文本说了什么",看不到"独立工作超越了开放提案"。#4077(@laerad777)提议向service_tier: "priority"开放 xAI Grok OAuth 通道并修正 Fast-tier 目录文案。注册表一半经 #4431 在7ca00ffe7独立落地——它来自自己的 live probe,未引用 #4077、无尾注;且落地范围在证据上更窄(grok-4.20-multi-agent-0309仍被排除,因为网关在收到priority时回答service_tier: "default")——所以这是真正的独立工作而非静默携带。文案修正部分(#4077 首先指出的部分)则经 #4474 落地并带有点名作者的Co-authored-by尾注。一般化的结论是:"独立"和"首先"是不同的声明,只有后者从开放队列可见。

盲区三:门禁也会对"描述携带的散文"开火。匹配器读取描述,因此一个仅仅描述了 carry 链条、实际没有源作者的 PR 也会触发missing_coauthor_credit。#4499 是一个没有源分支的普通实现,但 "contributor-carry train" 与 "Head commit carries[skip ci]" 两个短语足以让它失败。改写措辞后通过。这是误报(false positive),但文档明确认为不值得为此放宽匹配器:"一个偶尔要求作者说明措辞的门禁,比一个漏掉真实未署名携带的门禁便宜得多"——后者正是整页文档记录的失败。

核心建议(对携带者):携带他人工作时,尾注地址应从作者的 GitHub 账号获取(数字 ID 形式的users.noreply.github.com永远安全),而不是从他们分支的提交元数据里复制——用工作邮箱提交的贡献者是常态而非边缘情况。

6.5 验证落地提交,而不只是提案

2026-09-07 审计精确读取了从7d8523eed75a67f7a4a15b533744fcd0e6059aa8可达的 3,000 个提交,止于53130de4e540fbfcf2629079effb851af54e989e,并对照源 PR 描述、关闭评论和 GitHub 提交作者映射。PR 描述或中间分支提交可以包含正确的尾注,却在自定义 squash 信息替换该文本时丢失。在宣布一个 carry 已获得署名之前,必须检查实际落地提交:其最终Co-authored-by尾注必须仍然存在,并且能解析到源作者的 GitHub 账号——现有的"存在性"门禁单独无法确立这两点中的任何一点。


七、从设计到验证:CREDITS.md 的工程生命周期

devlog/_fin/260903_contributor_credit_restoration/010_credits_file.md 记录了该文件的完整切片设计,可与仓库根文件互相印证:

  • 为什么是文件而非历史重写:提交在已发布标签内、位于防强推规则集之后,且MAINTAINERS.md已禁止重写历史中的作者身份;
  • 文件形态# Credits→ 存在原因 → 非贡献者名单声明 →Carried work表 →Report and diagnosis表 → 未言明落地段落 →How this is maintained(指向 hygiene 门禁);
  • 链接编辑README.md的贡献区块与CONTRIBUTING.md顶部的文件清单(与MAINTAINERS.mdstructure/docs/并列)都增加了指向CREDITS.md的入口;
  • 可复现的验证方式
for sha in <every sha in both tables>; do git merge-base --is-ancestor "$sha" origin/dev || echo "NOT AN ANCESTOR: $sha" done

静默即通过。这个检查是真实起作用的——起草期间它捕获了d975feaa4这个来自过期扫描的引用。


八、实践要点总结

对贡献者、维护者与开源读者,CREDITS.md及其配套门禁给出了三条可操作的结论:

  1. 散文不是数据:提交体里写"Reimplements #2797 by @rrmlima"和写Co-authored-by: rrmlima ...同样真诚,但只有后者会被 GitHub 的贡献者图谱、仓库列表与个人主页读取。署名必须落在尾注上;
  2. 尾注地址要用账号关联身份:复制贡献者分支上的工作邮箱可能让尾注"看起来正确"却解析不到任何账号,数字 ID 形式的users.noreply.github.com才是永远安全的形态;
  3. 验证落地而非提案:一个 carry 只有在实际落地提交的最终尾注存在且能解析到源作者账号时才算完成署名——自定义 squash 信息随时可能吞掉它;PR hygiene工作流只保证尾注存在,不保证它可解析。

这个文件的特殊价值在于其诚实边界:它拒绝为"落地但未声明内容"的 PR 编造答案(Closed as landed一节),拒绝把"报告者"夸大为"被携带代码的作者"(Report and diagnosis一节),也拒绝把"独立工作"误记为"静默携带"(2026-09-13 两条跟进)。在 git 历史不可重写的前提下,CREDITS.md用"前瞻性归属"的方式,为每个在工具层丢失署名的贡献者保留了可检索、可引用、有证据的公共记录。

【免费下载链接】opencodex

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 20:26:02

金融风控Excel公式自动化验证方案设计与实现

1. 金融风控平台Excel风险公式验证方案设计在金融风控领域&#xff0c;Excel作为最常用的数据分析工具之一&#xff0c;承载了大量核心风险模型和计算公式。传统验证方式依赖人工核对&#xff0c;效率低下且容易出错。我们基于WordPress构建的自动化验证平台&#xff0c;完美解…

作者头像 李华
网站建设 2026/9/21 19:39:31

OpenClaw 不走 Ollama/混元,模型通道改到 TaoToken 通道行不行?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/21 19:38:27

Anaconda环境管理全攻略:从入门到实战

1. Anaconda环境管理入门指南作为一名长期使用Python进行数据分析的从业者&#xff0c;我深刻体会到环境管理的重要性。Anaconda作为Python生态中最流行的环境管理工具&#xff0c;其核心价值在于能够创建相互隔离的Python环境&#xff0c;避免不同项目间的依赖冲突。对于刚接触…

作者头像 李华