やり直せば通る問題 — 何回回せば直ったと言えるか
目標
間欠的な失敗の発生率を試行で測り、推定値に区間を付けます。失敗した実行でだけ真になる条件を試行の記録から抜き出し、間隔をあけて測り直して、観測が症状を消すことを確認します。最後に、直したと言うには何回実行すべきかを計算し、その回数を実際に実行して証明します。
なぜ重要なのか
「もう一度やったら動きました」は、調査を終える文のように聞こえますが、実はデータ2件です。1回失敗し、1回成功しました。ここですべきことは、もっと実行して分数を作ることです。 間欠的な失敗が危険な理由は、直ったかどうかを1回の成功で判断させてしまうからです。失敗率10%の問題を直さないまま1回実行して合格する確率は、90%です。そのため、「何回連続で合格させるべきか」を先に計算する必要があります。 このラボで難しいのは、ループではなく判定の根拠です。試行回数なしで比率だけを書くと、20回中2回と200回中20回を区別できず、失敗した実行の証拠をその場で残さなければ、あとから尋ねる相手がいません。 採点ツールは、ランダムさに左右されません。採点ツールが作った決定的なターゲット(ちょうど5回に1回失敗するコマンド)にあなたのツールを実行して数字を照合し、あなたが残した記録と計算は、採点ツールが同じ公式で再計算して突き合わせます。
ステップ
- /root/flaky/gen_flaky.pyを作成して実行し、/root/flaky/job.pyを作ってください。
- /root/flaky/measure.pyでjob.pyを200回以上実行し、/root/flaky/rate.jsonに失敗率とウィルソン区間を書いてください。
- /root/flaky/plan.pyを作り、/root/flaky/runs_needed.jsonに、信頼水準ごとに必要な連続合格回数を求めてください。
- /root/flaky/collect.pyで試行ごとに証拠を残し、/root/flaky/facts.jsonlを作ってください。失敗するときだけ真になるものは、/root/flaky/only_when_fail.jsonに書いてください。
- 試行の間隔をあけて測り直し、/root/flaky/observer.jsonに、2つの測定を並べて書いてください。
- /root/flaky/policy.jsonに、リトライバジェットと隔離の基準、グリーン判定に必要な連続合格回数を、計算で決めて書いてください。
- 修正バージョンを、計算された回数だけ実行して、/root/flaky/proof.jsonに証拠を残してください。
- /root/flaky/summary.jsonを作り、/root/flaky/flaky_report.mdに4つの節で報告してください。
参考
- ジョブの契約:
python3 /root/flaky/job.py [--fixed] [--state <디렉터리>] [--seed <정수>](プレースホルダーはディレクトリと整数です)は、成功すればJSONを1行出力して終了コード0、失敗すれば標準エラー出力に1行出力して終了コード3です。 - 測定の契約:
python3 /root/flaky/measure.py --cmd "<명령>" --trials <횟수> [--gap-ms <밀리초>] --out <json>(プレースホルダーは順に、コマンド、回数、ミリ秒です)は、command・trials・failures・rate・ci_low・ci_high・gap_msを含むJSONを1つ出力します。--gap-msは各試行の前に休む時間です。最初の試行の前でも休みます。直前に何が動いていたかがわからないからです。 - ウィルソンスコア区間(95%、z=1.96): 中心は
(p + z²/2n) / (1 + z²/n)、半幅はz/(1 + z²/n) × √(p(1-p)/n + z²/4n²)です。失敗が0件でも、幅が0になりません。 - 計画の契約:
python3 /root/flaky/plan.py --rate <실패율> --confidence <신뢰수준>(プレースホルダーは順に、失敗率と信頼水準です)は、rate・confidence・runsを含むJSONを出力します。runsは(1-p)^n <= 1-cを満たす最小の整数、つまりlog(1-c)/log(1-p)を切り上げた値です。 - 収集の契約:
python3 /root/flaky/collect.py --cmd "<명령>" --trials <횟수> [--gap-ms <밀리초>] --out <jsonl>(プレースホルダーは順に、コマンド、回数、ミリ秒です)は、1行に1試行ずつ、trial・exit_code・outcome・elapsed_ms・stderr・stdoutを書きます。 - リトライバジェット: もう1回試行するたびに、すべて失敗する確率は、pの累乗です。
p^(r+1) <= 0.01を満たす最小のrを、バジェットとして使います。 - よくあるミスは、試行回数を書かないこと、失敗0件を失敗率0と書くこと、観測を付けたまま測って消えたと報告すること、直した根拠を1回の成功にすることの4つです。
- このラボの前提: 信頼水準95%とリトライバジェットの基準1%は、このラボで決めた値です。現場では、失敗のコストによって変わります。
- 負荷テストを作らないでください。採点1回の予算は60秒で、Podは2コアです。ステップ5の遅い測定は、20回で十分です(間隔があるので、1分ほどかかります)。
間欠的に失敗するジョブを手に入れる
/root/flaky/gen_flaky.pyを作成して実行し、/root/flaky/job.pyを作ってください。そのあと、job.pyを手で何回か実行して、成功したり失敗したりするのを自分で見てください。
このスクリプトをそのまま保存して実行すれば構いません。できたjob.pyを連続で10回ほど実行してみてください。終了コードが0の実行と3の実行が混ざって出ます。何回に1回なのかは、まだ数えないでください。それがステップ2です。
「たまに」を分数に変える
/root/flaky/measure.pyを作成して、job.pyを200回以上実行し、/root/flaky/rate.jsonにcommand・trials・failures・rate・ci_low・ci_high・gap_msを書いてください。区間は、95%のウィルソンスコア区間です。
失敗は、終了コードが0でないものとして数えます。比率だけを書くと、20回中2回と200回中20回を区別できないので、試行回数を一緒に残してください。ウィルソン区間の2つの式は、参考の節にあります。失敗が0件でも幅が0にならないのが、この区間を使う理由です。
何回実行すれば直したと言えるか
/root/flaky/plan.pyを作成し、/root/flaky/runs_needed.jsonに、observed_rateと、信頼水準0.9・0.95・0.99それぞれのrunsを含むtable、そしてchosen(0.95)を書いてください。
直さないままn回すべて合格する確率は、(1-p)のn乗です。その確率を1-c以下に抑える最小のnが答えで、対数を取れば1行で出ます。切り上げを忘れないでください。小数回は実行できません。
失敗したその場で証拠を残す
/root/flaky/collect.pyで60回以上実行し、/root/flaky/facts.jsonlを作ってください。/root/flaky/only_when_fail.jsonには、trials・failures・exit_codes_on_failure・exit_codes_on_success・token・failure_trialsを書いてください。tokenは、すべての失敗の標準エラー出力にあって、どの成功にもない単語です。
間欠的な失敗は、もう一度呼び出せません。試行ごとに終了コードと標準エラー出力をその行に書いておいて初めて、あとから尋ねる相手ができます。tokenは、失敗の記録を目で眺めればすぐに見えます。大文字の1つの単語です。成功の記録にその単語がなければ、tokenになります。
観測が症状を消す
試行の間隔を2000ミリ秒以上あけて20回以上測り直し、/root/flaky/observer.jsonにfastとslowの2つの測定(trials・failures・rate・gap_ms)とchangedを書いてください。遅く測ると、失敗が0件になる必要があります。
ログを付けて1ステップずつ実行すると、症状が消えることがよくあります。タイミングに依存する条件が、遅くなった瞬間に成立しなくなるからです。消えたという事実自体が手がかりです。原因が速度か順序にあるという意味だからです。measure.pyの--gap-msで、同じ状況を作れます。
リトライバジェットと隔離の基準を計算する
/root/flaky/policy.jsonにobserved_rate・confidence(0.95)・green_runs_required・retry_budget・quarantine_afterを書いてください。retry_budgetはp^(r+1) <= 0.01を満たす最小のrで、quarantine_afterは1以上の整数です。
リトライは間違った対応ではありませんが、回数には根拠が必要です。失敗率がわかれば「すべて失敗する確率」を計算でき、そこからバジェットが出ます。隔離しないと、人々は失敗を無視する習慣を身につけ、その習慣は本物の失敗にも適用されます。
直したことを根拠とともに主張する
修正バージョン(--fixed)を、ステップ3で計算した回数以上実行して、/root/flaky/proof.jsonにcommand・required・trials・failuresを書いてください。failuresは0で、trialsはrequired以上である必要があります。
1回合格したことは証拠ではありません。失敗率pの問題を直さないまま合格する確率が、すでに1-pだからです。ステップ3のchosen.runsをそのまま持ってきて、その回数だけ実行し、その記録をファイルに残してください。採点ツールは、同じコマンドを自分でもう一度実行してみます。
確率を1枚で報告する
/root/flaky/summary.jsonにtrials・failures・rate・ci_low・ci_high・token・green_runs_required・proof_trials・observer_changedを書き、/root/flaky/flaky_report.mdに## 얼마나 자주인가、## 실패할 때만 참인 것、## 관측이 바꾼 것、## 고쳤다고 말하려면(韓国語の見出しは、順に「どのくらいの頻度か」「失敗するときだけ真になるもの」「観測が変えたもの」「直したと言うには」という意味です)の4つの節で報告してください。
報告書の価値は、結論ではなく数字にあります。試行回数と失敗回数、区間、必要な連続合格回数を、すべて書いてください。観測を付けたときに消えたという事実も手がかりなので、一緒に書きます。