TL;DR
- 本記事の「遅くなる」は、1 件が merge されるまでのリードタイム(待ち)が伸びることで、完了件数(throughput)が減ることではありません。
- 検証(レビュー・テスト・merge 判断)は有限の容量 µ を持ちます。生成を増やすと到着率 λ が上がり、稼働率 ρ=λ/µ が 1 に近づきます。
- レビュアー 1 人・到着も処理もランダムという単純化モデル(M/M/1)では、待ち時間 Wq(処理時間を含まない)÷ 平均処理時間 = ρ/(1−ρ) で、ρ=0.8 で 4 倍、0.9 で 9 倍です(
計算値)。 - このリポジトリの 539 PR では、手戻り 0 回の lead p50 が 0.06h、6 回以上は 4.26h でした(
社内データ。相関で、逆向きの関係を含む)。 - λ と µ は PR の本数でなく検証単位で数え、容量計画は queue / batch size / review SLA / test time / decision latency の 5 変数で置きます。
はじめに:Agent を増やしたのに delivery が速くならない
コーディング Agent の席数や並列数は予算を足せば増やせますが、検証する側の容量は人数と時間で上限が決まっています。生成側に投資しても merge までの時間が縮まらない、むしろ伸びる状況は、この非対称から起きることがあります。
体感も当てになりません。METR の 2025 年のランダム化比較試験では、経験のある OSS 開発者 16 名が自分のリポジトリの issue に取り組み、AI ツールを使ってよい条件のほうが完了まで 19% 長くかかりました(公式値)。開発者は事前に 24% 速くなると予想し、終えた後も 20% 速くなったと感じていました(METR, 2025-07-10)。対象は 2025 年前半のツール・熟練者・成熟した大規模リポジトリで、ページ自身が結果は古くなったと注記し、2026-02 の更新に触れています。「AI は遅くする」の証拠には使わず、「体感ではなく測る」という一点だけを借ります。
律速の特定は AI駆動開発で人を律速にしない で扱いました。本記事はその続きで、特定した制約を容量としてモデル化し、生成量を増やしたときに待ちがどう伸びるかを条件付きで示します。
想定読者は、AI を導入済みで席数や並列 Agent 数の投資判断をする EM / VPoE / CTO です。
1. レビュー待ちのボトルネックを「検証容量」として捉える
本記事の「検証」は、生成物を受け入れてよいか確かめる PR レビュー・テスト実行・merge 判断の 3 つで、人か直列の資源が処理します。各変更が検証で過ごす時間は 2 つに分かれます。
- queue(待ち): 検証に入ったが、まだ誰も着手していない時間
- service(処理): 着手してから結果が出るまでの時間
検証容量 µ は単位時間あたりに検証済みにできる検証単位の数、到着率 λ は単位時間あたりに検証に入ってくる検証単位の数です。
flowchart LR
G[生成: Agent / 人] -->|到着率 λ| Q[queue: 検証待ち]
Q --> S[service: レビュー / テスト]
S --> D[decision: merge 判断]
D --> M[merge]
S -->|差し戻し 確率 r| Q
検証単位をそろえる
λ と µ は同じ単位で数えます。chore の一括更新と新機能では 1 本の検証コストが大きく違うので、PR の本数を単位にすると破綻します。数え方は 2 通りです。
- 種別ごとに分ける: 同程度の検証コストの PR だけをまとめ、種別ごとに λ と µ を出す
- 検証時間で数える: ρ = 検証に使った時間 ÷ 検証に使える時間 と置く
傍証として、Google のコードレビュー研究では、初回フィードバックまでの待ちの中央値が小さい変更で 1 時間未満、非常に大きい変更で約 5 時間でした(公式値。Sadowski et al., 2018)。このリポジトリでもサイズの層で lead が大きく違います(4.4)。
成果の数え方は tokenmaxxingを避けるAI開発KPI で「検証済み成果」として整理しました。本記事はその生産側の容量を扱います。
5 つの変数
容量計画で置く変数は次の 5 つです(詳細は 5 章)。
- queue(WIP): 系内の数 L(検証待ち+検証中)
- batch size: 1 回の検証にまとめる変更の大きさ
- review SLA: 初回応答までの上限
- test time: 直列で回るテストの処理時間
- decision latency: merge 判断を待つ時間
制約理論(TOC)の 5 ステップでいえば、まず制約を IDENTIFY し、他をその制約に SUBORDINATE させる順番です(TOC Institute)。
2. 生成量を増やすほど 1 件あたりの待ちが伸びる条件
ρ<1 の間は、待ちが伸びても完了件数は λ に追随して増えることもあります。ρ≥1 では完了件数も頭打ちになり、待ちは際限なく伸びます。
2.1 Little の法則で WIP と滞留時間をつなぐ
Little の法則は L = λW です。L は系内の平均件数(検証待ち+検証中)、λ は到着率、W は 1 件が系内で過ごす平均時間です(Little, 1961)。2 つが分かれば残りを換算できます。
期間 [0, T] の始まりと終わりで系が空なら、定常性を仮定しなくても L = λW が成り立ちます(Little, 2011)。実務では期首と期末に PR が残るので、長い期間で測って端の影響を小さくします。これは近似で、定理の条件を満たすこととは別です。
2.2 稼働率と待ちの非線形性(単純化モデル M/M/1)
M/M/1 は、**レビュアー(サーバ)が 1 人、到着も処理時間もランダム(指数分布)**という単純化モデルで、非線形性を示す例として使います。複数レビュアーが共有キューを処理する場合も ρ→1 で待ちは急増しますが、同じ ρ なら倍率は下の表より小さくなります。
MIT OCW の講義ノートによると、M/M/1 では系内時間 Ws = 1/(µ−λ)、待ち行列での待ち時間 Wq = λ/(µ(µ−λ)) です(MIT OCW 2.854)。平均処理時間は 1/µ なので、次の比が得られます。
Wq ÷ (1/µ) = ρ / (1 − ρ) ただし ρ = λ / µ
| 稼働率 ρ | 待ち時間 Wq ÷ 平均処理時間 |
|---|---|
| 0.5 | 1 倍 |
| 0.8 | 4 倍 |
| 0.9 | 9 倍 |
| 0.95 | 19 倍 |
倍率は上の式からの 計算値 です。ρ/(1−ρ) は系内平均人数 Ls と同じ式ですが、ここでは Wq ÷ 平均処理時間 として読みます(Ws ÷ 平均処理時間 は 1/(1−ρ) で別の数)。
2.3 「遅くなる条件」の定式化
- 生成量: µ を固定したまま、検証単位で数えた λ を上げると ρ=λ/µ が上がり、Wq ÷ 平均処理時間は M/M/1 では ρ/(1−ρ) で伸びます
- 手戻り: r を「1 回の検証が差し戻しになり、同じキューへ戻る確率」とします。各回の処理時間が同じなら、1 件あたりの平均検証回数は 1/(1−r)、実効的な到着は λ/(1−r) です。r=0.2 なら 1.25λ で(
計算値)、同じ生成量でも ρ が上がります。モデル上の導出なので、4 章の rework(作成後のコミット数)とは直接対応させません - batch size: 同じ生成量を k 本ずつ 1 件にまとめると、到着は λ/k、1 件の平均処理時間は k 倍で、ρ は変わりません。それでも Wq = ρ/(1−ρ) × 平均処理時間 なので、Wq も k 倍になります(
計算値、M/M/1)。batch が待ちに効く経路は (1) 1 件の処理時間の増加(この式どおり)、(2) 処理時間のばらつき、(3) 差し戻し確率の 3 つです((2)(3) は経験則)。Faros AI 2025 の PR サイズ +154% / review time +91%(ベンダー調査)はチーム単位の集計(各チームの低採用期と高採用期の比較)による相関なので、1 PR 内のサイズと処理時間の関係は推しません
生成量を増やしても 1 件あたりの待ちを短く保てるのは、ρ に余裕がある間だけです。問題になる ρ の閾値は一般値として決めず、チームが許容できる待ち倍率から逆算します。
3. 外部データ:生成が増えたとき検証側で何が起きているか
どれも調査・相関で、本記事のモデルを証明するものではありません。
| 出典 | 数値 | 条件・注意 |
|---|---|---|
| DORA 2024 | AI 採用の増加に伴い、delivery throughput が推定 1.5%、delivery stability が推定 7.2% 低下(公式値) | 調査データのモデル推定で、因果ではない |
| DORA 2025 | AI 採用と throughput は正の関係に転じ(原文 "Unlike last year")、stability とは負の関係が続いた(公式値) | 数値の年次比較はしない |
| Faros AI 2025 | 高 AI 採用チームの開発者が merge する PR 数 +98%、PR review time +91%、平均 PR サイズ +154%(ベンダー調査) | 10,000 人超の開発者のテレメトリ、相関 |
| Faros AI 2026 | 初回レビューに着手されるまでの待ちの中央値 +156.6%、レビュー中の時間の中央値 +441.5%(平均は +199.6%)(ベンダー調査) | 22,000 人超。各チームの AI 採用が最も低い 2 四半期と最も高い 2 四半期の比較、相関。2025 年版と独立で、年次推移として並べない |
| Sadowski et al., 2018 | 変更行数の中央値 24、レビュー全体の latency 中央値 4 時間未満(公式値) | Google 社内の参照値。理由に小さい変更とレビュー文化の両方が挙がる |
DORA 2025 は "AI accelerates software development, but that acceleration can expose weaknesses downstream." と書き、AI は "amplifies what's already there" ともまとめています。下流の検証が吸収できるかで結果が分かれる、と読むのは本記事の解釈です。DORA の throughput・stability は組織横断の指標で、本記事の 1 件あたりの待ちとは別の量なので、モデルの支持にも反証にも使いません。
Faros 2026 の 2 つの数字は、本記事の queue(初回レビューまでの待ち)と service(レビュー中の時間)に対応します。両方が伸びているなら、手を打つべき段が複数ありえます。ベンダー調査の相関なので、特定の製品や手法の評価には使いません。
4. 自リポで測る:PR のリードタイムを手戻り・同時オープン数・サイズで層別する
このブログを管理しているリポジトリで、PR の lead(作成から merge まで)を測りました。
4.1 測定条件
| 項目 | 内容 |
|---|---|
| リポジトリ | 記事を Markdown で管理する private の Git リポジトリ。PR の作成者は実質 1 人 + AI エージェント。merge には人間の明示承認が必須 |
| 母集合 | PR 番号 ≤ 632 の merged PR のうち author が s977043(筆者のアカウント)のもの = 539 本 |
| ref | PR #632 の merge commit c0fb8b73f3dc5c363d797495746505f4cd032f63(mergedAt 2026-10-06T03:04:54Z) |
| 取得日時 | 2026-10-12T11:58:44Z〜11:59:23Z(UTC) |
| コマンド | python3 verification_queue.py s977043 notionnext-blog s977043 632 |
| 環境 | python3 3.14.7 / gh 2.93.0 |
merged 全体は 558 本で、残り 19 本(Copilot coding agent 14 本、dependabot 5 本)は bot の PR なので除外しました(社内データ。次のコマンドで再現、2026-10-12T11:42:51Z 取得)。
gh pr list -R s977043/notionnext-blog --state merged --limit 1000 --json number,author \
--jq '[.[] | select(.number <= 632)] | length, (group_by(.author.login) | map({(.[0].author.login): length}) | add)'
# => 558 / {"app/copilot-swe-agent":14,"app/dependabot":5,"s977043":539}
番号で上限を切っているので後から作られる PR では母集合は動きませんが、close 済みの PR が reopen・merge されれば変わりえます。定義は次のとおりです。
- lead = mergedAt − createdAt(時間)
- rework(手戻り回数の近似)= PR 作成から 1 分より後の committedDate を持つコミット数。レビュー往復の代理指標
- wip(同時オープン数)= その PR の作成時点で open だった、母集合内(PR ≤ 632・merged・同じ author)の他の PR の数
- size = additions + deletions
lead は queue と service の合計で、待ちと処理を分けていません。 人の検証は PR 作成前のローカル工程で行い、GitHub 上のレビューは主に Copilot が付けるので(社内観測)、PR 上のレビュー開始時刻は人の検証開始を表しません。分けるための時刻は 6 章で示します。
4.2 計測スクリプト
gh(認証済み)と python3 で動き、対象が 0 件なら n=0 を出して exit 1 で終わります。2026-10-12T23:16Z(UTC)に同じ引数で再実行し、出力が下の結果と全行一致しました。
#!/usr/bin/env python3
"""merged PR の滞留時間を、手戻り回数・同時オープン数・差分サイズで層別する。
使い方: python3 verification_queue.py OWNER REPO AUTHOR MAX_PR
MAX_PR 以下の番号の merged PR だけを数える(後から merge された PR で母集合が動かないように)。
要るもの: gh(認証済み)と python3。
「手戻り」は PR 作成から 1 分より後の committedDate を持つコミットの数で近似する。
rebase / amend をすると committedDate が書き換わり、多めに数える。
"""
import json, subprocess, sys
from datetime import datetime, timedelta
QUERY = """query($owner:String!,$repo:String!,$endCursor:String){
repository(owner:$owner,name:$repo){pullRequests(states:MERGED,first:50,after:$endCursor){
pageInfo{hasNextPage endCursor}
nodes{number createdAt mergedAt additions deletions author{login}
commits(first:100){nodes{commit{committedDate}}}}}}}"""
def fetch(owner, repo):
out = subprocess.run(
["gh", "api", "graphql", "--paginate", "-f", f"query={QUERY}",
"-F", f"owner={owner}", "-F", f"repo={repo}",
"--jq", ".data.repository.pullRequests.nodes[]"],
check=True, stdout=subprocess.PIPE, text=True).stdout
return [json.loads(line) for line in out.splitlines() if line]
def ts(s):
return datetime.fromisoformat(s.replace("Z", "+00:00"))
def pct(xs, p):
xs = sorted(xs)
k = (len(xs) - 1) * p
lo, hi = int(k), min(int(k) + 1, len(xs) - 1)
return xs[lo] + (xs[hi] - xs[lo]) * (k - lo)
def to_record(node):
created, merged = ts(node["createdAt"]), ts(node["mergedAt"])
commits = [ts(c["commit"]["committedDate"]) for c in node["commits"]["nodes"]]
return {"created": created, "merged": merged,
"lead_h": (merged - created).total_seconds() / 3600,
"rework": sum(c > created + timedelta(minutes=1) for c in commits),
"size": node["additions"] + node["deletions"]}
def report(label, prs, key, buckets):
print(f"\n{label}\tn\tlead_p50_h\tlead_p85_h")
for lo, hi in buckets:
lead = [p["lead_h"] for p in prs if lo <= p[key] < hi]
if lead:
print(f"[{lo},{hi})\t{len(lead)}\t{pct(lead, .5):.2f}\t{pct(lead, .85):.1f}")
def main(owner, repo, author, max_pr):
nodes = [n for n in fetch(owner, repo)
if n["number"] <= int(max_pr) and (n["author"] or {}).get("login") == author]
prs = [to_record(n) for n in nodes]
if not prs:
print("n=0")
sys.exit(1)
for p in prs:
p["wip"] = sum(o["created"] < p["created"] < o["merged"] for o in prs)
lead = [p["lead_h"] for p in prs]
print(f"n={len(prs)} lead_p50_h={pct(lead, .5):.2f} lead_p85_h={pct(lead, .85):.1f} "
f"lead_mean_h={sum(lead) / len(lead):.1f} over_24h={sum(x > 24 for x in lead)}")
report("rework", prs, "rework", [(0, 1), (1, 3), (3, 6), (6, 10**6)])
report("wip", prs, "wip", [(0, 1), (1, 3), (3, 6), (6, 10**6)])
report("size", prs, "size", [(0, 100), (100, 500), (500, 2000), (2000, 10**9)])
if __name__ == "__main__":
main(*sys.argv[1:5])
4.3 結果
スクリプトの出力をそのまま載せます(社内データ)。
n=539 lead_p50_h=0.31 lead_p85_h=5.8 lead_mean_h=17.5 over_24h=35
rework n lead_p50_h lead_p85_h
[0,1) 302 0.06 1.0
[1,3) 164 0.88 7.6
[3,6) 57 1.80 36.1
[6,1000000) 16 4.26 35.5
wip n lead_p50_h lead_p85_h
[0,1) 306 0.13 2.2
[1,3) 164 0.75 12.3
[3,6) 57 1.19 9.8
[6,1000000) 12 0.70 3.4
size n lead_p50_h lead_p85_h
[0,100) 170 0.09 1.1
[100,500) 223 0.32 6.0
[500,2000) 137 0.97 9.0
[2000,1000000000) 9 0.87 5.5
lead の平均 17.5h は p85 の 5.8h より大きく、少数の長く滞留した PR が平均を引き上げています。以下では主に p50 と p85 を見ます。
4.4 読み取り
- 手戻り: 作成後のコミットが多い PR ほど lead p50 が長くなっています(0.06h → 0.88h → 1.80h → 4.26h)。open が長いほどコミットが積まれる逆向きの関係を含みます。他の PR の待ちを伸ばしたか(共有キューの混雑)は測っておらず、2.3 の「差し戻しで実効到着が増える」とは別の現象です
- サイズ: [500,2000) の層まで lead p50 が伸びています(0.09h → 0.32h → 0.97h)。lead は待ちを含むので、1 本の重さがそろわないことの傍証に留めます。[2000,∞) は n=9 なので判断しません
- 同時オープン数: [6,∞) の層で p50 が 0.70h に下がり、単調ではありません(n=12)。WIP 単独の効果としては読みません
このデータは稼働率の効果(ρ が上がると待ちが伸びる)を示していません。示すのは lead が手戻りとサイズの層で大きく違うことだけで、「1 本の重さがそろっていない」ことを自分のデータで確かめる手順の例です。
4.5 この測定で言えないこと
- lead からは queue と service のどちらが伸びたか分かりません
- 1 リポジトリ、実質 1 人 + AI の運用です。lead には PR 作成前の人の検証が入らず、一方で誰も触っていない放置時間(24h 超が 35 本)は入ります。lead は検証時間の推定には使えず、層別の比較に使います
- 相関であり因果ではありません。rework・wip・size は互いに相関しえて、rework と lead には逆向きの関係も入ります
- rework は committedDate による近似で、rebase / amend で多めに出ます。
commits(first:100)のため、100 コミットを超える PR は切り捨てて数えます
手戻りの定義で数字が大きく動くことは AI Codingの費用はOutcome単位で測る でも同じリポジトリで確かめています。rework の数字は定義とセットで扱ってください。
5. 容量計画に入れる 5 つの変数
| 変数 | 測り方 | 設計レバー | 根拠 |
|---|---|---|---|
| queue(WIP) | 系内の数 L(検証待ち+検証中)の推移 | WIP 上限 | Little の法則、M/M/1、TOC |
| batch size | 差分サイズ別の lead・差し戻し | 分割 | Sadowski 2018、Faros 2025、4.3 |
| review SLA | 依頼→初回レビューの上限と中央値 | 上限の宣言と実績の分離 | Google eng-practices、Sadowski 2018 |
| test time | 直列テストの処理時間 | 直列資源の処理時間を先に測る | 社内観測 |
| decision latency | 承認→merge の時間 | 委譲できる判断の切り分け | 社内観測 |
5.1 queue:WIP の目安を検証容量から見積もる
条件: 系内の数 L が増え続けているなら、生成の投入を検証が処理できる量に制限します(TOC の SUBORDINATE)。
例で計算します(例示。このリポジトリの数値ではなく、M/M/1 を仮定)。
- 検証容量 µ = 6 検証単位/稼働日
- 目標: Wq を平均処理時間の 4 倍以内に収める
- 表から ρ ≤ 0.8 なので、λ ≤ 0.8 × 6 = 4.8 単位/稼働日
- このとき Ws = 1/(µ−λ) = 1/1.2 ≈ 0.83 稼働日、Little の法則で L = λ × Ws = 4 件
この 4 件は平均で、上限ではありません。M/M/1 では系内が n 件以上になる確率は ρ^n で、5 件以上は 0.8^5 ≈ 0.33 です(計算値)。WIP 上限を平均値の 4 に置くと約 1/3 の時間で上限に当たり、その状態では Wq の式(表の倍率)は当てはまりません。上限は平均より上に(例: 系内の数の分布の裾を見て)置き、当たった頻度を記録します。止めた分は生成側で待つので、待ちが消えるわけではありません。
5.2 batch size:大きな変更を分割する
条件(経験則): サイズの層で lead が伸び、大きい PR ほど差し戻しが多いなら分割を検討します。分割で ρ は下がりませんが、2.3 の 3 経路で待ちは短くなりえます。逆に、まとめて 1 本ごとの固定作業(文脈の把握など)が減れば、合計の検証時間が減って ρ が下がります。どちらが勝つかは測って決めます。参照値として、Google の変更行数の中央値は 24 行です(Sadowski 2018)。
1 PR あたりの検証コストを下げる書き方(意図・影響範囲・証拠)は AI生成PRでレビューが詰まる本当の理由 に、巨大な PR の分割手順は AI生成の巨大PRをStacked PRに分解する にまとめています。
5.3 review SLA:上限と実績を分けて置く
review SLA は上限、実績は中央値として別々に置きます。Google の eng-practices はレビュー依頼への応答時間の最大を 1 営業日としています(公式値。Speed of Code Reviews)。一方、同社の研究での初回フィードバックの中央値は、小さい変更で 1 時間未満でした(Sadowski 2018)。
条件: SLA を宣言しても実績の中央値が上限に張り付いているなら、ρ が高い可能性を疑う材料になります(経験則。締め切りまで着手しない運用など、ほかの原因もありえます)。SLA を守れと言う前に、容量か到着のどちらを動かすかを決めます。
5.4 test time:並列化できない検証資源を数える
このリポジトリでは pnpm test を同一マシンで並列に走らせるとネットワーク依存のテストがストールするため、ワーカーが何本いても最終テストは直列です(社内観測)。生成側の並列度を上げても µ が増えない例です。処理時間が一定に近く M/M/1 の前提から遠いので、倍率の表はそのまま当てはめません。
条件: 直列の検証資源があるなら、その処理時間を容量の上限として先に測ります。
5.5 decision latency:判断を 1 人に集める構造を可視化する
このリポジトリでは merge にリスクの大小に関係なく人間の明示指示が必要で、decision latency は 1 人に集まります(社内観測)。
条件付きの提言: 判断者が 1 人なら、その人を単一サーバとみなして稼働率 ρ を見積もり、委譲できる判断(低リスク)と人に残す判断を分けます。委譲の可否はリスクの許容度で決まるので断定しません。委譲のパターンは AI駆動開発で人を律速にしない で扱っています。
6. 導入手順
- lead を層別して測る: 4.2 のスクリプトで層ごとの lead を出し、PR 番号の上限で母集合を閉じて取得日時を記録します
- queue と service を分けたいなら時刻を取る: PR ごとにレビュー依頼・初回レビュー・承認・merge の時刻を記録します。依頼→初回レビューが queue、承認→merge が decision latency です。初回レビュー→承認には差し戻し時の修正と再レビュー待ちが入るので、分けるならラウンドごとに時刻を取ります。人の検証が PR の外にある運用では、ローカル工程の開始と終了も記録します
- 検証単位を決めて ρ を見積もる: µ と現状の ρ を見積もり、2.2 の表で待ち倍率を読みます
- 1 つだけ選ぶ: 5 変数のうち、待ちを最も押し上げているものに手を打ちます
- 同じ条件で再測定する: 母集合の切り方・定義・取得方法を変えずに測り直します
改善対象を 1 つ選ぶループは Cycle Time の定義と改善:境界を引く改善ループ に書いています。
7. この測り方で解けないこと
- 検証の質(見逃し)は容量モデルに入りません。DORA の stability のような安定性の指標で別に見ます
- M/M/1 は単純化です。レビュアーの人数や処理時間のばらつきが前提と違えば倍率は変わるので、表は倍率の傾向として使います
- 1 人運用の実測を多人数チームの数値として使わないでください。4 章の数値は手順の例です
FAQ
検証容量(verification capacity)とは何ですか
単位時間あたりに検証済みにできる検証単位の数(µ)です。PR レビュー、テスト実行、merge の判断を含みます。1 件あたりの待ちを左右するのは生成量そのものではなく、この容量と到着率の比(稼働率)です。
稼働率はどう見積もればよいですか
ρ = λ/µ で、λ(検証待ちに入る量)と µ(処理できる量)は同じ検証単位で数えます。差し戻しがあるなら、λ の代わりに実効的な到着 λ/(1−r) を使います(r は同じキューへ戻る確率)。処理時間が取れない場合は、検証者が検証に手を動かしている時間の割合で見積もります。単一サーバでは、処理中の平均件数 = λ × 平均処理時間 = ρ になるからです。Little の法則(L = λW)は L・λ・W のうち 2 つから残りを換算する式で、lead(W)を測るだけでは ρ は出ません。
PR の本数で検証負荷を測ってはいけないのですか
PR の種別やサイズで 1 本の検証コストが大きく違うため、本数では λ と µ の単位がそろいません。このリポジトリでも差分サイズの層で lead p50 が 0.09h から 0.97h まで違いました(社内データ。相関で、lead は待ちも含むため傍証です)。種別ごとに分けるか、検証時間で数えてください。
AI レビューを入れれば検証容量は増えますか
1 件あたりの処理時間を下げる範囲では µ を上げえます。ただし merge の判断が 1 人に集まる構造(decision latency)は残ります。どの段の待ちが長いかを先に測ってから判断してください。特定の製品の効果はここでは評価しません。
まとめ
- 本記事の「遅くなる」は 1 件あたりの待ちが伸びることで、完了件数が減ることとは別です
- 検証を容量 µ として置くと、ρ が 1 に近づくにつれて待ちは処理時間に対して非線形に伸びます(M/M/1 では ρ/(1−ρ) 倍)。差し戻しは実効的な到着を λ/(1−r) に増やします
- λ と µ は検証単位でそろえ、queue / batch size / review SLA / test time / decision latency の 5 変数を容量計画に置きます
- このリポジトリの 539 PR は稼働率の効果を示すものではなく、1 本の重さが層によって大きく違うことを示しています
次の一手として、4.2 のスクリプトを自分のリポジトリで回し、手戻りとサイズの層で lead がどれだけ違うかを確かめてください。違いが大きければ、PR の本数で容量を語るのをやめ、検証単位を決めるところから始めます。
References
- John D. C. Little, A Proof for the Queuing Formula: L = λW, Operations Research 9(3), 1961(2026-10-12 確認)
- John D. C. Little, Little's Law as Viewed on Its 50th Anniversary, Operations Research 59(3), 2011(2026-10-12 確認)
- MIT OpenCourseWare 2.854, M/M/1 Queue(2026-10-12 確認)
- Google Cloud Blog, 2024 Accelerate State of DevOps Report の発表(2026-10-12 確認)
- Google Cloud Blog, 2025 State of AI-assisted Software Development の発表(2026-10-12 確認)
- Sadowski et al., Modern Code Review: A Case Study at Google, ICSE-SEIP 2018(2026-10-12 確認)
- METR, 早期 2025 年の AI ツールと熟練 OSS 開発者の RCT(公式ブログ, 2025-07-10)(2026-10-12 確認)
- Faros AI, AI Productivity Paradox Report 2025(2026-10-12 確認)
- Faros AI, AI Engineering Report 2026: The Acceleration Whiplash(PDF、2026-03 版)(2026-10-12 確認)
- TOC Institute, Five Focusing Steps(2026-10-12 確認)
- Google Engineering Practices, Speed of Code Reviews(2026-10-12 確認)
