# 要件・テスト対応表と修正記録（記入例：承認処理の最小実験、改訂版 rev1）

記事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. 判定

- [x] 修正前に不備が再現した（v1：原版6件・追加2件失敗、evidence/rev1-2026-09-18/sample-b/run_log.md）
- [x] 修正後に対応テストが通った（12件成功）
- [x] テストの検出力を確認した（故意の誤変更4種を検知）
- [x] 通ったテストの範囲を超える主張をしていない（第5節に未確認範囲を明記）
- 判定者：Claude Code（制作者自身による自己確認。GPTによる別環境のAIレビューを受けたが、人間の独立監査・利用者テストではない）　日付：2026-09-18
