Skip to content

spec-loop: 想定外の例外を 2(判定していない)に寄せ、読めなさの原因を取り違えない(#286) - #486

Open
hdknr wants to merge 5 commits into
mainfrom
issue/286-unexpected-error-exit-2
Open

hdknr wants to merge 5 commits into
mainfrom
issue/286-unexpected-error-exit-2

Conversation

@hdknr

@hdknr hdknr commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Fixes #286

spec-loop のスクリプトは、終了コード 1(違反)と 2(判定していない・書いていない)を分けると約束している。ところが想定外の例外は、トレースバックになって 1 で終わっていた。この PR で、12 本すべての CLI の入口で想定外の例外を 2 に寄せた。あわせて、捕まえてはいるが原因を取り違えていた箇所を直した。

計画と受入基準(I1〜I9)、各パスの採否の表: docs/plans/issue-286.md

不在の周(/dev-loop:cruise 474 --absent)。このリポジトリではマージがサイトを再デプロイするので、不在の線「マージ」が効かない(#476)。PR までで止める。

🤖 Generated with Claude Code

hdknr and others added 5 commits October 28, 2026 10:34
- 12 本の CLI の入口で、想定外の例外(csv.Error・RecursionError など)を 2 にする。
  SystemExit・KeyboardInterrupt は寄せない。読み込まれた関数は例外をそのまま返す
- -OO(docstring が無い)でも使い方・argparse の説明でトレースバックにしない
- 2 で前の出力を消すと約束しているもの(merge-versions・schedule-to-gantt・build-proposal)は、
  想定外の例外でも消す/書きかけを残さない。scaffold は判定の外では本文を消さないと docstring に名指し
- build-proposal: git の起動・手書き部分の読み・出力の書き込みを別の文言で、strerror とパスつきで報告
- check-signoff: removed.csv の読めなさを常に「UTF-8 として読めない」と言っていたのを、Unreadable の文言に
- 試料(128KB 超のセル・深い入れ子・読めない手書き部分・-OO の引数なし)と、捕捉を外す変異を各テストに
- spec-loop 0.30.0

Fixes #286

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
python 3.12 の Path.resolve は自分を指すリンクで RuntimeError を投げ、入口の想定外の例外に落ちて
前の出力が残っていた(docstring は「入力が読めないときは前の出力を消す」)。resolve を分けて捕まえる。
試料と、3.12 でだけ死ぬ変異を足した。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…の 2 パス目)

1 パス目の修正は resolve の例外で早く消していたので、3.12 では docs を含む印つきの場所を丸ごと消した
(docstring は「docs/ を含む場所は消さない」)。realpath はリンクの輪でも投げないので、出力先の検査と
「ディレクトリが無い」の後始末が版によらず同じ順で走る。試料を足し、3.12 でだけ死ぬ変異を付け替えた。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hdknr

hdknr commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

レビュー結果(dev-loop 手順 6)

直す線: 既定(出所: cruise の確かめた線。台帳 issue-474)

関門

関門 パス 結果
Verifier(dev-loop:dev-loop-verifier・sonnet) 1 パス目 反証 0 件(見てほしい点 3 件)
/code-review(high) 1 パス目 指摘 10 件——直したのは CR2 の 1 件
Verifier 2 パス目 反証 0 件(気づいた点 1 件。P2-1 と同じ)
/code-review 2 パス目 指摘 6 件——直したのは P2-1 の 1 件
Verifier(狭いパス 28fdff4..6abb359) — 挙動の反証 0 件・テストの穴 1 件(NP-1)
  • CR2(1 パス目で直した): merge-versions.py で、docs が自分を指すリンクのとき、python 3.12 では 2 なのに前の出力が残っていた(docstring は「入力が読めないときは前の出力を消す」)。著者が 3.12 で再現してから直した。
  • P2-1(2 パス目で直した): CR2 の直し方では、出力先の検査より前に消していた。そのため 3.12 では、docs を含む印つきの場所を丸ごと消していた(docstring は「docs/ を含む場所は消さない」)。著者が 3.12 で再現した(keep.txt が消えた)。os.path.realpath で辿るように直し、3.12 でも 3.14 と同じ「docs を含む場所には書かない」で止まる。
  • 狭いパスの陽性対照: Verifier が設計した 9 通りの配置で、3.12 と 3.14 の rc・文言・残ったファイルが一致した(docs がリンク・.. を含む・互いを指す 2 本のリンク・存在しないパスなど)。
  • 歯止め: python3 scripts/check-all.py 52/52 が緑。test-merge-versions.py は python 3.12 で 66 試料・61 変異、3.14 で 66 試料・60 変異(3.14 では当てていない 1 件——下の P2-4)。
  • 生成物: なし(skill-metrics.py --check は緑)

証明できないもの・BLOCKED

なし。

人間に判断してほしいこと(狭いパス・2 パス目の残課題)

  1. NP-1(狭いパス): out_real だけを out.resolve() に戻す変異を、どの試料も殺さない。試料はリンクの輪を docs 側にしか置いていない。挙動は正しく、どちらの形でも rc=2 になる。違うのは文言だけ(「想定外の例外」か「書けない」か)。試料を足すかどうかを決めてほしい。
  2. P2-4: python 3.13 以降では、試料「入力が自分を指すリンクでも前の出力を消す」は修正の有無によらず通る。修正を確かめているのは CI(3.12)の変異 1 本だけで、手元の 3.14 で緑でも修正の証拠にならない。
  3. P2-6: only_312 は、変異の名前の部分一致(「3.12 でだけ」)で決めている。同じ判定が test-build-proposal.py(spec-loop: build-proposal.py の remove_owned が unlink の失敗で traceback・1 になり、古い出力が残る #440)にも写してある。名前を変えると、黙って当てなくなる。

残課題(1 パス目。既定の線では受入基準を破らないので直していない)

  • CR5: schedule-to-gantt.py で前の出力を消せないと、決まりの違反も 2 になり、古い svg が残る。docstring の「消せないときは理由を出して 2」の範囲ではある。ただし文言は「前の出力が残っている」と言わない(著者が 3.12 で走らせて確かめた)。
  • CR1: build-proposal.py で手書き部分のディレクトリが読めないと、glob が空を返し、「無い」(1)になる。この周より前からの挙動。
  • CR3: CLI から git を起動できないときに出る文言は check-signoff.py のもので、新しい run_git の文言は CLI からは届かない。
  • CR4: check-spec-exit.py の rglob は、読めないサブディレクトリを黙って飛ばす。この周より前からの挙動。
  • CR6: init-mkdocs.py で想定外の例外が起きると、写したファイルの一覧が出ない。
  • CR7: build-proposal.py の残りの except OSError のコメントが不正確。
  • CR8: check-signoff.py の新しい文言で、パスが 2 度出る。
  • CR9: test-init-mkdocs.py の -OO の試料は何も判別しない。
  • CR10: 同じ入口の形を 12 本に写していて、テストはその文言を錨にしている。
  • V2: init-mkdocs.py を引数なしで走らせると rc=0 で書く。既存の設計どおり。
  • V3: 終了コードの表を持つ SKILL.md は proposal だけ(そこは直した)。
  • 計画の訂正(V1): 計画の「merge-versions.py は権限エラーを UTF-8 と言う」は誤りだった。I6 で実際に直したのは check-signoff.py のほう。
  • 実装役の自己申告: KeyboardInterrupt には専用の試料が無い。ただし SystemExit の試料が BaseException への広げすぎを赤にする。build-proposal.py の一時ファイルの読み書きの OSError の文言にも試料が無い。

各行の「示せるか」「破る受入基準」は、計画ファイルの採否の表にある。

この周の起票

0 件。不在の周なので、手順 8 の起票は訊いていない。

マージ

不在の周で、このリポジトリのマージはサイトを再デプロイする。そのため、マージは利用者の判断を待つ(#476)。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec-loop: 想定外の例外がトレースバックで 1 になり、1(違反)と 2(検査していない)の区別が崩れる

1 participant