記事Bの本文と examples/sample-b/ に対応。実行記録は evidence/rev1-2026-09-18/sample-b/run_log.md(初版は evidence/sample-b/run_log.md)。
「修正前の結果」は説明用の失敗例 v1 を実行した結果であり、実際のAI出力を観測したものではない。
1. 検証の対象
| 項目 | 内容 |
|---|
| 対象の処理 | 依頼の承認・差戻し(approve / send_back) |
| 対象の版 | 修正前 approval_v1.py(説明用の失敗例)/修正後 approval_v2.py(rev1) |
| 実行環境 | macOS 26.6.2、Python 3.9.6(サポート終了版。サポート中の版では未確認)、SQLite 3.51.0(メモリ上)。2026-09-18 実行 |
| 本人確認や保存先は本物か代用か | 本人確認は操作者IDを引数で渡す代用。保存先はメモリ上の新規SQLite(本番の保存先ではない) |
| 接続の設定 | 明示的な確定・取消を使う設定(isolation_level が None でない)。外部キー検査は接続ごとに有効化し実値1を確認 |
2. 要件・テスト対応表
| テストID | 要件/受入条件 | 種類 | 前提データ | 操作 | 期待結果 | 保存内容で照合するもの | 修正前(v1) | 修正後(v2) |
|---|
| T1 | REQ-003, 005/AC-001 | 正常 | REQ-A01 提出済み、承認者=鈴木 | 鈴木が承認 | 承認済み | 履歴の最後の1行=(承認、鈴木、固定時刻、備考なし)。既存履歴は不変 | 成功 | 成功 |
| T2 | REQ-003/AC-002 | 権限なし(割当外) | 同上 | 高橋(割当外)が承認 | 拒否 | 依頼・履歴の全行が操作前と同一 | 失敗(承認されてしまう) | 成功 |
| T3 | REQ-003/AC-003 | 自己承認 | REQ-A03 依頼者=承認者=鈴木(異常データ) | 鈴木が承認 | 拒否 | 全行同一 | 失敗(承認されてしまう) | 成功 |
| T4 | REQ-003/AC-004 | 状態外 | REQ-A02 下書き、承認者=鈴木 | 鈴木が承認 | 拒否 | 全行同一 | 失敗(承認済みになる) | 成功 |
| T5 | REQ-006/AC-008 | 重複 | REQ-A01 提出済み | 鈴木が2回承認 | 2回目は拒否 | 1回目後と2回目後で全行同一。承認履歴1件 | 失敗(履歴が2件) | 成功 |
| T6 | REQ-007/AC-010 | 途中失敗 | REQ-A01 提出済み | 状態更新直後に保存失敗を模擬 | 失敗 | 全行が操作前と同一(状態も履歴も戻る) | 失敗(承認済みなのに履歴なし) | 成功 |
| T7 | REQ-004/AC-006 | 入力不足 | REQ-A01 提出済み | 鈴木が理由なしで差戻し | 拒否 | 全行同一 | 失敗(差し戻される) | 成功 |
| T8 | REQ-004, 005 | 正常 | 同上 | 鈴木が理由ありで差戻し | 差戻し | 履歴の最後の1行=(差戻し、鈴木、固定時刻、理由)。既存履歴は不変 | 成功 | 成功 |
| T9 | REQ-003 | 役割 | REQ-A05 承認者でない運用管理者を割当(異常データ) | 運用管理者が承認 | 拒否 | 全行同一 | 失敗(承認されてしまう) | 成功 |
| T10 | (保存先の関係) | 関係の保護 | 存在しない依頼ID | 履歴を直接追加 | 保存先が拒否 | 外部キー検査の実値が1 | 成功(保存先の設定のため) | 成功 |
| T11 | REQ-003, 006 | 保存先の状態条件 | REQ-A02 下書き。処理側の確認を素通り | 鈴木が承認 | 失敗 | 全行同一(UPDATEの状態条件と更新件数で止まる) | スキップ(該当関数なし) | 成功 |
| T12 | REQ-007 | 接続設定 | 自動確定モードの接続 | 鈴木が承認 | 変更前に拒否 | 全行同一 | 失敗(処理が進む) | 成功 |
件数:v1 は原版8件中6件失敗+追加4件中2件失敗・1件スキップ。v2 は12件すべて成功。
3. 発見した不備と修正記録
| 番号 | 発見したテスト | 不備の内容 | 原因(コードのどこ) | 修正内容 | 修正後に通ったテスト |
|---|
| D-1 | T2, T3 | 誰が承認しようとしているかを見ていない | approve の冒頭で state しか読んでいない | 承認者の割当と依頼者との一致を確認し、違えば拒否 | T2, T3 |
| D-2 | T4, T5 | 対象の状態を見ていない | UPDATE に状態の条件がない | 提出済みのときだけ承認。UPDATE にも状態条件を付け、更新件数が1でなければ取り消す | T4, T5, T11 |
| D-3 | T6 | 状態変更と履歴追加を別々に確定している | 2回の commit の間で失敗すると片方だけ残る | 2つの変更を1つのトランザクションにまとめる(with conn:) | T6 |
| D-4 | T7 | 差戻し理由の有無を見ていない | send_back に検査がない | 理由が空なら拒否 | T7 |
| D-5(rev1) | T9 | 操作者の役割を見ていない。割当だけで判断 | users の role を読んでいない | 役割が承認者でなければ拒否。役割と割当を別条件に | T9 |
| D-6(rev1) | T12 | 取消を保証できない接続設定でも処理が進む | with conn: の動作が接続設定に依存 | 自動確定モード・未確定処理ありの接続は変更前に拒否 | T12 |
| D-7(rev1、保存先) | T10 | 宣言した関係が守られていない(外部キー検査が既定で無効) | common.py の接続で PRAGMA を設定していない | 接続作成時に PRAGMA foreign_keys = ON、実値1を確認 | T10 |
4. AIへの修正指示(送った文章の例)
記事B 第6.2節の指示文と同じ(役割・接続設定の項目を含む)。
4b. テストの検出力(実行確認済み)
故意に誤らせたコピーを一時フォルダに作り(mutation_check.py)、強化したテストが検知するかを確かめた。誤らせたコードは正本に混ぜず、終了時に削除。
| 故意の誤変更 | 初版テスト(GPT環境の観測) | 改訂版テストが検知したテスト | 判定 |
|---|
| UPDATEの状態条件と更新件数の検査を削除 | 見逃し | T11 | 検知 |
| 割当外を拒否する直前に既存履歴を削除 | 見逃し | T2 | 検知 |
| 理由なし差戻しを拒否する直前に履歴を追加 | 見逃し | T7 | 検知 |
| 差戻し成功時の操作者を別人・時刻を空に | 見逃し | T8 | 検知 |
5. この検証で確かめていないこと
| 範囲 | 確かめていない理由 | いつ・どこで確かめるか |
|---|
| 2人の承認者が同時に操作したとき | 単一プロセス・逐次実行のみ。T11は保存先条件の動作確認であって同時操作の再現ではない | 09-03 の同時操作テストで、実際の保存先を使って確認 |
| 本物の本人確認(ログイン) | 操作者IDを引数で渡す代用。役割確認はIDの役割を見るだけ | 05-03 / 08-03 で認証機能を実装した後 |
| 複数の役割を持つ人 | 1人1役割の最小モデル | 05-03 |
| 画面からの操作 | 処理関数を直接呼んでいる | 画面実装後の 09-02 通し検証 |
| 本番の保存先での動作 | メモリ上のSQLite | 環境を分けた検証環境で |
| 対応しない接続設定での取消 | 処理前に拒否する方式にしたため、その設定での取消は未確認 | 必要なら別途 |
| 差戻しの重複 | テストを用意していない | 追加テストを検討 |
| サポート中のPythonでの実行 | この環境には3.9.6しかない | 環境を用意してから |
6. 判定