B18 · Day 177OSS 收口 + 英文 + 全局 SOTA 复核
真实 OSS PR 实现
B18 的主线是「把私有资产变成外部可验证的工件」,今天是这条主线上的关键一跳:
阶段: B18 · OSS 收口 + 英文 + 全局 SOTA 复核(Day 171-180) 标签: #oss-contribution #fix-plus-test #contributing-conventions #regression-test
今日导引(由浅入深)
B18 的主线是「把私有资产变成外部可验证的工件」,今天是这条主线上的关键一跳:
- Day 176 把 agent-evals 切成了独立公开 repo(自己的代码、自己的 CI);
- 今天更进一步——向别人的活跃 OSS 项目提交一个真实修复,这是「外部可验证」的最高形式:不是自己给自己 review,而是上游 maintainer 的红绿门和人工审查;
- Day 174 已经在 smolagents / DeepEval / Inspect AI 三个 repo 各筛了一个
good-first-issue并本地复现了其中一个; - 今天就针对那个选定 issue 写出 fix + 配 1 个单测,本地全套绿,push 到 fork branch;
- 明天(Day 178)才是把它正式提成 PR 并用英文说服 reviewer。
今日最小可判定产出:fork branch 上一个带单测的 commit,本地全套测试绿,通过测试数记录在案。
1. 机理精读
「fix 配单测」是 OSS 接受率的硬门槛,不是礼貌。
- 一个没有测试的纯逻辑改动 PR,几乎一定会被 reviewer 退回——maintainer 无法判断你的 fix 是否真修了 bug、是否引入回归。
- 配套单测必须覆盖 bug 的触发路径:即一个在打 patch 前会失败、打 patch 后会通过的测试。
- 这条测试本身就是「这个 bug 确实存在过」与「这个 fix 确实有效」的可执行证据。
- 依据:目标 repo 的 CONTRIBUTING(2026)。
小而聚焦的 PR 接受率最高。
- 一个 PR 只改一件事:修一个 bug、改一处错误信息、补一段文档。
- 把多个无关改动塞进一个 PR 会大幅增加 review 成本与被要求拆分的概率。
- Day 174 之所以优先选「文档修复 / 错误信息改进 / 边界 bug」类,正因它们改动面小、语义清晰、回归风险低——是 good-first-issue 的典型形态。
三件套:fix + test + changelog。
- (1) fix 本身;(2) 覆盖触发路径的单测;(3) changelog 条目(很多 repo 要求每个面向用户的改动都登记一条)。
- 还要符合该 repo 的 commit 规范(Conventional Commits、DCO
Signed-off-by、或 CLA)。 - 这些都在 CONTRIBUTING.md 里写明,Day 174 已读过——动手前先把硬约束列成清单。
为什么参照本仓已验证模式?
- seed 让 fix 逻辑参照本仓
src/agent/runtime/resilience.ts的测试写法。 - 原因:resilience 这类「重试 / 退避 / 熔断」逻辑是 OSS 里 bug 高发区(边界多:attempt=0、max 截断、jitter 边界、连续失败计数、冷却恢复)。
- 本仓已用「时钟 / sleep / rng 全部可注入」的方式把它做成无真实定时器、无 key 的确定性单测。
- 这套写法直接可迁移到上游 PR 的测试里,让测试快、稳、可重放。
与相邻概念的边界。
- 今天不是「提 PR」(那是 Day 178 的事,状态 open + 英文正文)。
- 今天的产出止于「本地 push 到 fork branch」——一个可独立判定的中间里程碑:代码写完、单测写完、本地全套绿。
- 是否被上游接受是后续不可控的外部事件,不在今天的判定范围内。
2. 代码走读:可类比的已测产物
seed 点名两个本仓「已测、可作为 fix 写法范式」的纯函数模块。逐一走读真实符号(均已 Read):
src/agent/runtime/resilience.ts(retry/backoff/熔断已测):backoffDelay(attempt, opts)— 第 0-based attempt 的延迟:min(base·factor^attempt, max)再叠±jitter分数,Math.max(0, Math.round(...))兜底非负。典型边界 bug 区:attempt=0、命中 max 截断、jitter 把值推到负数(已被Math.max(0, ...)防住)。retry(fn, opts)— 最多retries(默认 3)次重试,shouldRetry(err)决定是否继续,sleep可注入(测试里换成立即 resolve,无真实定时器)。触发路径测试范式:注入一个前 N 次抛错、第 N+1 次成功的 fn,断言总调用次数与最终返回。CircuitBreaker类 —getState()在open且超cooldownMs后转half-open;exec(fn)成功归零失败计数并关断、失败累加并在达threshold(默认 5)时开断。now()可注入 → 用假时钟测试冷却恢复,不靠真实时间。withFallback(primary, fallback)— primary 抛错则跑 fallback,返回{value, usedFallback}。- 迁移要点:上游若有类似重试/退避 bug,照搬「把 sleep/now/rng 注入成确定性桩」的写法,测试就能稳定覆盖触发路径。
src/agent/train/grpo.ts(纯函数已测):groupRelativeAdvantage(rewards, eps=1e-8)— 组内标准化(r-mean)/(std+eps),无 critic。exactMatchReward(output, target)/formatReward(output, pattern)/composeRewards(parts)(加权平均,totalW===0返回 0)。grpoScore(group)— 给每个样本挂advantage与reinforce = advantage>0。- 迁移要点:这类纯数学函数是「输入→输出确定」的理想被测对象,fix + 单测一对一,最易被 reviewer 接受。
走读结论:上游 fix 若落在「重试/边界/纯计算」类,本仓 resilience.ts / grpo.ts 的「依赖全注入 + 触发路径单测」写法可直接迁移。
3. 今日实战
- 在 Day 174 选定的 issue 所属 repo(smolagents / DeepEval / Inspect AI 之一)的 fork 上开新 branch。
- 重读该 repo CONTRIBUTING.md,确认:测试目录约定、commit 规范(DCO/CLA/Conventional Commits)、changelog 是否必填。
- 实现 fix:聚焦单一改动,覆盖 Day 174 本地复现里「预期 vs 实际」的偏差点。
- 加 1 个单测,覆盖 bug 触发路径(patch 前红、patch 后绿)——写法参照
resilience.ts的依赖注入式确定性测试。 - 若 repo 要求,补 changelog 条目。
- 本地跑该 repo 全套测试,确认绿;
git push到 fork branch。记录通过测试数。
4. 今日实测 / 产出
- fork branch + 通过测试数 committed:外部动作(seed 状态「外部动作 → 将产出 fork branch + 通过测试数 committed」)。未完成、不升级为已完成。注意 Day 174 已明确「merged OSS PR 不算已完成」,今天止步于 fork branch,更不算合入。
- 本仓可类比的已测产物(可立即引用的硬资产):
resilience.ts(retry/backoff/熔断已测)、grpo.ts(groupRelativeAdvantage/exactMatch/composeRewards/grpoScore纯函数已测)。 - Block 里程碑参照:上游 OSS PR = 外部动作(未完成,状态待 open/merged,正文须含 before/after eval 数字)。
5. 常见误区 / 陷阱
- 无测试的纯逻辑 PR:最常见的退回理由。哪怕只改一行逻辑,也要附一个覆盖触发路径的测试。
- PR 范围发散:顺手「再优化一下」其他代码 → review 成本飙升、被要求拆分。一个 PR 只做一件事。
- 忽略 commit / 签署规范:DCO 缺
Signed-off-by、commit 不符 Conventional Commits、漏 CLA 签署,都会卡在 CI 或机器人检查上。动手前把 CONTRIBUTING.md 的硬约束列清单。 - 测试依赖真实定时器/网络/key:会让上游 CI 变慢变 flaky。照搬本仓「sleep / now / rng / fetch 全注入」的确定性写法。
- 具体到 resilience:测
retry时把sleep注入成立即 resolve,测CircuitBreaker冷却时把now注入成假时钟,绝不靠真实时间。
- 具体到 resilience:测
- 把 push 到 fork 当成「已贡献」:今天只是中间里程碑,merge 与否是 Day 178 之后不可控的外部事件。
- 改动越界改了无关代码:顺手「格式化整个文件」会让 diff 噪声淹没真正的 fix,reviewer 难以聚焦——保持 diff 最小。
6. 学习资源(每条带 YYYY-MM)
- 目标 repo(smolagents / DeepEval / Inspect AI)各自的 CONTRIBUTING.md,2026 当周版本需复验(测试要求/commit 规范可能更新)。
- GitHub「Creating a pull request from a fork」官方文档,2026。
- Conventional Commits 规范 v1.0.0(多数活跃 repo 采用),规范本身长青。
- DCO(Developer Certificate of Origin)说明,linuxfoundation,长青。
- 本仓
src/agent/runtime/resilience.ts(backoffDelay/retry/CircuitBreaker/withFallback,依赖注入式确定性测试范式,seed 依据)。 - 本仓
src/agent/train/grpo.ts(groupRelativeAdvantage/exactMatchReward/composeRewards/grpoScore纯函数,fix+test 一对一范式,seed 依据)。
SOTA检查 (2026-06 更新)
- fix + test + changelog 三件套 为长青 OSS 规范,仍 SOTA。
- 当前主流实践:小而聚焦 PR + 触发路径回归测试 + Conventional Commits / DCO 签署,是 2026 活跃 Python/TS repo 的通行门槛。
- 过时黑名单:
- 避免无测试的纯逻辑改动 PR(会被 reviewer 退回);
- 避免针对已 stale/锁定的旧 issue 提 fix(Day 174 已警示 good-first-issue 会被他人抢先)。
- 当周需确认:
- 所选 repo 未冻结分支(freeze 期间不接 PR);
- 目标 issue 仍 open 未被他人认领;
- CONTRIBUTING.md 的测试/签署要求未变。
- 下次复查点:Day 178 提 PR 前,再刷一次目标 repo 的 open PR 列表,确认没有人已提交同一 fix。
衔接
- 昨天:Day 176 — 抽独立公开 repo 工程化(agent-evals 切成独立 repo,确定性 CI,≥18 passing 目标)
- 今天:针对 D174 选定 issue 写 fix + 1 单测,本地全套绿,push fork branch
- 明天:Day 178 — 提 PR + 英文沟通(向上游提 1 个 open PR,正文贴 before/after 可核验数字)