0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

同じ Python 60 本に検出器を 2 つ当てたら、拾えた欠陥が 0/4 → 4/4 に裏返った——検出器が見ていた場所が違った

0
Posted at

「AI が書いたコードは失敗を握り潰すか」を測った前の記事で、当方の検出器は 4 件を挙げて、当たり(真の握り潰し)は 0 件でした。公開後に読者が公開リポの gt.csv を数え直し、「成績表の片側しか書いていない」と指摘しました。当方の検出器は、コーパスに在った真の握り潰し 4 件を 1 件も拾っていなかったのです。

同じ読者が 30 行の別の検出器を提案しました。同じ Python 60 本に当てた結果を、今度は両側そろえて書きます。

結果を先に書きます(母集団=Python 60 本・公開リポ ai-silent-defect-scanner・results/gt.csv から再集計)。

出荷版の検出器 読者提案の検出器
見る場所 except の中の return <既定値> except の外の return <既定値>
在った欠陥 4 件のうち拾えた数(再現率) 0 / 4 4 / 4
挙げた中で当たりだった数(精度) 0 / 2 4 / 17
  • 真の握り潰し 4 件(py_fetch_json_s2/s3/s7/s9)は、全部 if ガードの中で既定値を返していました。try/except の中には 1 件も無かったのです
  • 読者の検出器は 4 件を全部拾い、代わりに 13 件を一緒に拾いました。13 件の内訳は、対照課題 9・正当な既定値 2・適切に処理済み 2 です。対照課題 9 本を「外れ」と数える根拠は下に書きます
  • 前の記事の「4 件 flagged」は Python 2 件+TypeScript 2 件で、真の 4 件は Python だけです。言語を混ぜた「0/4 と 0/4」は同じ 2×2 ではありません。この記事は Python 60 本に揃えます

用語は 2 つだけ使います。再現率=在った欠陥のうち拾えた割合。精度=挙げたもののうち当たりだった割合。英語では recall と precision です。

同じ Python 60 本・検出器 2 つの成績表: 出荷版(except の中)は挙げた 2・当たり 0・精度 0/2・再現率 0/4。読者提案(except の外)は挙げた 17・当たり 4・外れ 13(人手 4+設計上の対照 9)・精度 4/17・再現率 4/4。当たり/外れの根拠は人手の裁定 8 本と課題の設計 9 本の 2 系統

この記事の位置づけ(2026-09-26 追記)

  • この記事で新しく示すこと: 同じ 60 本に、見る場所の違う検出器を当てると再現率が 0/4 から 4/4 に変わったこと(代わりに精度は 4/17)。
  • 当てはまる範囲: ローカル LLM に書かせた Python 60 本(公開リポの gt.csv)です。

何を測っていたか

コーパスは、小さなモデル(Qwen2.5-Coder 1.5B)に生成させた 120 本です。言語ごとに 6 課題 × 10 本で、Python 60・TypeScript 60。6 課題のうち 5 つは失敗経路のある入出力課題(JSON の取得・整数の変換・環境変数の読み取りなど)、1 つは失敗経路の無い純粋な計算課題(平均値)で、対照群として設計したものです。各本に、当方が読んで付けた裁定(human_verdict)と、機械で付けた形の列(subtype など)が gt.csv に入っています。

裁定の内訳(Python 60)です。

裁定 本数 意味
loud_fail 14 失敗を raise で外へ出す
proper 9 try/except で受けてログか再送出をする
problematic_fallback 4 失敗の区別を消して既定値を返す(真の握り潰し)
legit_fallback 2 既定値を返すが、docstring やコメントで契約として書いてある
not_adjudicated 31 当方が個別に裁定していない(うち 22 は既定値を返さない bare・9 は対照課題の既定値)

「握り潰し」の真の 4 件は、fetch_json 課題の 4 本です。HTTP が 200 でなければ None を返します。404・500・204 などの区別が呼び出し側から消えます(ネットワーク断は、requests.get が try の外で例外を上げるので、握り潰されません)。コメントには「失敗時は None」と書いてあるので、構文だけでは正当な既定値と区別できません。ここは前の記事の主題で、今回も変わりません。

検出器 1: 出荷版は「except の中」を見ていた

出荷版の規則は、except の本体が return <既定値> の 1 文だけのときに挙げます(厳格アンカー)。Python 60 本で挙がったのは py_parse_int_s3 と py_parse_int_s9 の 2 本。2 本とも docstring かコメントで「変換できなければ None」と書いてあり、裁定は legit_fallback です。精度 0/2。

真の 4 件はどれも try/except の外に居るので、この規則の射程に最初から入っていません。再現率 0/4。前の記事は精度の側だけを書き、再現率を書いていませんでした。読者の指摘はここです。

厳格アンカーそのものは、読者の再導出でも「残す価値がある」と出ました。アンカーを「本体のどこかに既定値の return がある」まで緩めると 5 本増えます(py_fetch_json_s6・py_first_line_s2・py_load_json_s4・py_load_json_s8・py_parse_int_s2)。5 本とも has_log=Y で、裁定は 5/5 proper でした。つまりアンカーは「ログが無ければ無言」を見分けるフィルタとして働いています。射程の穴とアンカーは別の境界です。

検出器 2: 読者の提案は「except の外」を見ていた

読者が提案した規則は 1 行で言えます。「except の中に無い return <既定値> を全部挙げる」。Python の標準 ast で 30 行です。

同じ 60 本に当てた結果が 17 本。当方も同じ規則を 30 行で書き直して再現し、読者の挙げた 4 件の行番号が 4 つとも一致しました。

17 本の内訳 本数 当たり/外れ 根拠
problematic_fallback 4 当たり 人手の裁定
legit_fallback 2 外れ 人手の裁定(契約として書いてある既定値)
proper 2 外れ 人手の裁定(try/except で受けた上で、外側でも既定値を返す)
対照課題 9 外れ 課題の設計(下記)

対照課題の 9 本を「外れ」と数える根拠

9 本は gt.csv では not_adjudicated(個別に裁定していない)です。それでも外れと数えるのは、この課題が「失敗経路の無い純粋な計算」として実験設計の時点で対照群に置かれているからです(公開リポの PROVENANCE.md「純計算対照 1 課題×10 本」)。9 本の既定値はすべて if not numbers: return 0 の形で、空リストの平均を 0 と定義しているだけです。失敗を隠す経路がそもそも無い課題なので、握り潰しにはなりません。

つまりこの表の「当たり/外れ」は 2 系統の根拠で決まっています。8 本は人手の裁定、9 本は課題の設計です。9 本を「未確定」と読むなら、精度は「当たり確定 4・外れ確定 4・未裁定 9」と書くことになります。当方は設計上の対照群として外れに数え、精度 4/17 としました。どちらの読みでも再現率 4/4 は変わりません。

精度 4/17。1 件の当たりを得るのに、人が 4.25 本読む計算です。

対照課題 9 本は、前の記事で「try/except も候補も 0」と書いた対照群(両言語で 20 本)のうち、Python 10 本の中の 9 本です。「候補 0」は出荷版の射程の中での話でした。射程の外には、同じ形が 9 本ありました。

成績表を両側そろえて置く

出荷版 読者提案
母集団 Python 60 Python 60
挙げた数 2 17
当たり 0 4
外れ 2 13(うち 9 は対照課題)
精度 0/2 4/17
再現率 0/4 4/4

前の記事の「4 flagged・0 TP」は、この表の左の列の上半分だけでした。下半分(再現率)を書かないと、「拾うものが何も無かった」と読めてしまいます。実際は「拾うべき 4 件が射程の外に居た」でした。

読者の検出器が正しい、という話でもありません。13 件の巻き添えがあります。2 つの検出器は「try/except の中を見るか、外を見るか」で射程が違い、片方の穴がもう片方の得意領域です。

この 60 本から直接言えるのはここまでです。except の中だけを射程にした検出器は、ガード側に在った 4 件を全部落とした。 そこから設計に持ち帰るなら、失敗経路は複数の構文位置に現れる前提で、検出器の射程を決める、までです。

TypeScript 60 本はなぜ載せないか

TypeScript 側で出荷版が挙げた 2 本(ts_load_config_s0/s2)は、ファイル末尾のデモ用ブロックにあるコメントだけの catch {} で、裁定は偽陽性です。読者の規則を TypeScript に当てると if ガードの既定値は 11 本あります。9 本(ts_get_item_*)は「catch が log か throw をする」という機械の判定のままで、人は裁定していません。残る 2 本(ts_parse_int_s0/s5・catch なし)は 2026-09-18 に人が legit_fallback と裁定しました(docstring が「失敗なら null/undefined」と書いている=Python の py_parse_int_s3/s9 と同じ規則)。裁定した正例(欠陥)は 0 本なので、再現率は「0/4」のような値ではなく定義できません(分母が 0)。「2 本開いて 2 本とも文書化されていた」が正確な読みです。

前の記事のテーゼは「構文では裁定できない。裁定は人の仕事」です。著者が慌てて残り 9 本を裁定して数字を作るのは、そのテーゼに反します(2 本を裁定したのは、読者が docstring という根拠を示したからで、数字を作るためではありません)。TypeScript 側は対照群として読み、この記事の表には入れません。

この 1 本から言えること/言えないこと

言えること:

  • Python 60 本で、出荷版は精度 0/2・再現率 0/4、読者提案は精度 4/17・再現率 4/4 でした
  • 真の握り潰し 4 件は全部 try/except の外に居ました
  • 精度の分母 17 のうち 9 本は、人手の裁定ではなく課題の設計で外れに数えています
  • 厳格アンカーを緩めると増える 5 本は 5/5 proper で、アンカーは精度側のフィルタとして働いていました

言えないこと:

  • 「120 本で比較した」とは言いません。比較したのは Python 60 本です
  • 「AST 検出器のほうが正しい」とは言いません。外れ 13 です
  • 「try/except を見る検査は無意味」とも言いません。射程が違うだけです
  • 一般の AI 生成コードについては何も言えません。1.5B の 1 モデル・6 課題・60 本です

再現したい人へ

  1. git clone して results/gt.csv を開く。列は sample_id, task_id, language, seed, handling, subtype, returns_default, has_log, has_raise, intent_disclosed, human_verdict, review_note
  2. Python 60 本で subtype in (guard_default, both) を数えると 17。human_verdict で割ると 4/2/2/9(9 は task_id が py_avg_control)
  3. handling == swallow_cand を数えると 2(出荷版の flagged)
  4. 読者の検出器は「except 節の外にある return で、値が None / 0 / [] / {} / "" / False のもの」を ast.walk で拾うだけです。同じ 17 本と同じ行番号が出ます

数字は手で写さず、上の集計をそのまま載せています。

持ち帰り: 検出器の成績表(1 枚)

列 書くこと
母集団 何本・どの言語・どの課題
挙げた数 検出器が候補にした本数
当たり/外れ 根拠の系統も書く(人手の裁定か・設計上の対照か)
精度・再現率 両方。片方だけの成績表は「無かった」と読まれる

AI の利用について

再集計・検出器の再現・この記事の下書きは AI(Claude Code)が行い、裁定と公開の判断は人が行っています。読者の検出器は読者のものです。本人の希望で名前は出しません。

関連

この記事は「固定する → 測る → 道具を選ぶ → 公開後に伝播する」の 4 本のうち、測るの回です。


この記事は Zenn にも同じ内容を掲載しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?