/github-audit:GitHub 贡献真实性核验
简历上的"开源贡献"是最容易被误读的一栏:仓库越有名,HR 越容易高估;而 GitHub 的公开数据恰恰能让这件事被精确核实。
本 skill 的核心原则是:看 diff,不看数字。PR 数量、star 数、绿格子密度都可以被廉价地做出来,唯有每个 PR 实际改了什么代码无法伪装。
边界
- 只访问候选人在简历或沟通中主动提供的账号/仓库链接。绝不根据姓名、拼音、邮箱前缀去搜索猜测账号——同名账号极多,误认的后果是把无关的人的行为归到候选人头上。
- 只读公开信息。不尝试访问私有仓库,不通过任何手段推断私有活动。
- 不核验与技术能力无关的内容(候选人 star 过什么项目、follow 了谁、在什么议题下发过言)。这些既不相关也涉及隐私。
- GitHub 活跃度低完全不是负面信号。大量优秀工程师的产出全在公司内网。只有当简历主动声称了开源贡献时,本核验才适用。
核验流程
第一步:确认账号归属
在核验任何内容前,先确认这个账号确实是候选人的。可接受的归属证据:简历中直接写明的链接、账号 profile 中与简历一致的姓名/学校/公司信息、个人网站与账号的互相链接。
归属存疑时停止核验,在报告中写"账号归属无法确认,未做核验"。宁可不查,不可查错人。
第一步半:速查粗筛(先做这个,再决定细看哪些)
逐个开 PR 看 diff 准确但慢。先按 references/quick-metrics.md 花几分钟做量化粗筛,决定把精力投在哪里:
- 先查两项硬证据(若简历声称 Maintainer / 核心作者):目标仓库根目录有无
MAINTAINERS/CODEOWNERS/OWNERS 且名单含候选人;Releases 页有无候选人作为发布者。这两项能最快证实高强度身份主张。
- 按 owner 分叉:在
github.com/pulls?q=is:pr+author:{用户名}+is:merged 里,先剔除打向自己仓库的 PR,剩下的才是可核验的外部贡献。
- 看比例,不看个例:统计外部 PR 中文档类的占比(用 Files changed 的文件后缀机械判定)。
- 蹭明星项目核验:声称贡献过某知名项目时,直接看
/{org}/{repo}/commits?author={用户名} 的 commit 数。
粗筛结果决定细看范围:占比异常或身份主张强的,再进入第二步逐个开 diff。
第二步:贡献类型分布(核心)
先读这条纪律:单个小 PR 不构成任何信号。 实测中 58% 的开发者都至少有一个琐碎的外部 PR,而"多数 PR 都琐碎"的只有 0.4%。任何惩罚"提过小 PR"这个事件的判断,都是为了抓极少数人而误伤绝大多数人。
因此报告里不要写"该 PR 为 T0 级",要写"N 个外部 PR 中 T0/T1 占比 X%"。造假是账号历史的比例属性,不是单个 diff 的事件属性。
打开候选人在外部项目(非自己的仓库)的 PR,查看实际 diff。建议按两个正交轴分类——类型轴(文档 / 表现层 / 核心代码,可按文件路径机械判定)× 深度轴(下表)。把"改 README 里的架构说明"和"改架构代码"放在同一个梯子上会失真:
| 类型 | 判定标准 | 含金量 |
|---|
| T0 文本类 | 错别字、标点、Markdown 格式、坏链接、注释排版 | 正当贡献,但不构成技术能力证明 |
| T1 文档类 | 补充文档内容、示例说明、翻译、README 结构调整 | 说明读懂了项目,有一定理解 |
| T2 配置/构建类 | CI 配置、依赖升级、构建脚本、lint 规则 | 需要一定工程理解 |
| T3 测试类 | 补充测试用例、修复 flaky test | 需要理解被测逻辑 |
| T4 缺陷修复 | 修复实际 bug,含逻辑改动 | 实质技术贡献 |
| T5 特性/架构 | 新增功能、重构模块、性能优化、参与设计讨论 | 强技术贡献 |
关键判断:把统计结果与简历表述对照。
| 简历表述 | 实际分布 | 结论 |
|---|
| "为 XX 项目贡献文档修正" | T0/T1 为主 | 已核实 —— 如实描述 |
| "XX 项目 Contributor" | T0/T1 为主 | 疑似 —— 技术上成立但易致误解,建议面试澄清贡献性质 |
| "XX 项目核心贡献者 / 参与核心模块设计" | 全部 T0/T1 | 部分属实 —— 表述与实际贡献量级存在明显落差 |
| "主导 XX 模块重构" | 有对应 T5 PR 且已合并 | 已核实 —— 核验通过 |
必须写进报告的免责说明:T0/T1 贡献是完全正当且对社区有价值的开源参与,不应被贬低。本核验针对的只是表述与实际的落差,不是贡献本身。
第二步半:领域归属(简历有方向自称时强制)
上一步的类型分级(文档/表现层/核心代码 × T0–T5)测的是贡献分量,测不出贡献领域。.tsx 是"核心代码类"满分——但它是前端。
简历一旦出现方向性自称(AI Infra、推理优化、分布式存储、某某 Runtime Owner),必须按 references/domain-attribution.md 统计改动行数的领域分布,并与自称对照。
速记:按路径判领域,不按语言;.py 可能是训练脚本也可能是 Web 后端,.ts 可能是前端也可能是 Node 服务。
第三步:识别刷量模式
读 references/contribution-red-flags.md,逐条比对。重点看:
- 广度优先型:在大量不同仓库各提 1 个极小 PR,追求"参与项目数"而非深度;
- 知名度导向:所选仓库高度集中在 star 数最高的明星项目,且改动均极小——目标是简历上能写出的仓库名;
- 时间聚集:全部贡献集中在求职季前的短窗口内,此前此后无活动;
- 合并状态混淆:简历写"贡献被采用",但 PR 实际状态是 open 或 closed(未合并)。这一条可以给出较强结论,因为 PR 状态是客观的。
第四步:自有仓库核验
对候选人自己的仓库(简历上作为项目展示的):
- 提交历史形态:是长期渐进式开发,还是少数几个巨型 commit 一次性推上来?后者常见于把已完成代码(含他人代码)一次性导入。这不必然有问题(从私有仓库迁移、初次开源都会这样),但值得追问。
- 首次 commit 时间 vs 简历声称的项目时间:明显矛盾时构成硬证据。
- 是否为 fork:fork 来的仓库若在简历中被表述为自研项目,是明确问题。注意区分:基于开源项目做二次开发并说明来源,是正当行为。
- 代码风格一致性:整个仓库的命名、注释、错误处理风格是否统一。风格断层可能意味着代码来源混杂——但不能据此下结论,团队协作、AI 辅助、不同时期的自己都会造成风格差异。
第五步:Star 与关注度核验(谨慎)
若简历以 star 数作为成果指标:
- 查看 stargazers 列表的账号特征——大量注册时间接近、无任何其他活动、无头像的账号,是刷 star 的信号;
- 查看 star 的增长曲线是否存在异常陡峭的孤立尖峰;
- 注意区分:项目被某个技术周刊、热榜、大 V 转发也会造成尖峰,这是正常的。
这一维度极易误判,结论上限为"疑似",且必须写明其他可能性。
输出
### GitHub 贡献核验
**核验对象**:[账号链接],归属确认方式:[如何确认是候选人本人]
**核验范围**:外部项目 PR N 个(已全部打开查看 diff)、自有仓库 M 个
**贡献类型分布**:
| 类型 | 数量 | 代表 PR |
| T0 文本类 | 12 | [链接](改动:README 3 处错别字) |
| T4 缺陷修复 | 1 | [链接](改动:修复 XX 空指针) |
| ... |
**简历表述对照**:
- 简历原文:"..."
- 实际情况:...
- 结论:[档位]
- 其他可能的解释:...
**其他发现**:[时间聚集 / fork 情况 / 合并状态 等]
**本维度免责**:文档类贡献是正当的开源参与;本核验只针对表述与实际的落差。
常见误判警示
| 观察 | 不能推出的结论 |
|---|
| 绿格子稀疏 | 不能推出"不写代码"——公司代码不在 GitHub |
| 绿格子全绿 | 不能推出"高产"——也不能推出"刷的",需看提交内容 |
| PR 数量少 | 不能推出"能力差"——一个高质量 PR 胜过百个 typo |
| 只有 typo PR | 不能推出"造假"——只能说明表述若为"核心贡献者"则不符 |
| 代码风格不统一 | 不能推出"抄的"——多种正常原因均可致此 |
| 仓库无 star | 不能推出"项目差"——star 与质量弱相关 |
| 深夜/周末提交多 | 不能做任何推断——涉及作息隐私,且与能力无关 |