(1)AI内部監査支援 実装済みコンポーネント一覧と場所
Phase1: 匿名化(マスキング)エンジン
監査で使用する固有名詞等を匿名化してAIに送るシステム
- app/Services/InternalAudit/MaskingRuleEngine.php — 固有名詞検出エンジン本体。Python版audit_case_extract/masking_rules.py(rules.json v1.3)のPHP移植。検出のみ(置換はしない)
- config/ia_masking_rules.json — ルール定義(35ルール、block 13 / warn 22)
- tests/Unit/InternalAudit/MaskingRuleEngineTest.php/tests/Fixtures/ia_masking_test_vectors.json(50件、Python版と両方でPASS必須)
Phase2: データ基盤
- migration 6本: 2026_08_08_100001〜100006(ia_reference_cases / ia_sessions / ia_dictionary_terms / ia_allowed_terms / ia_principles / ia_ai_logs)
- モデル: IaReferenceCase(トレイトなし・全社共通の読み取り専用マスタ) / IaSession・IaDictionaryTerm・IaAllowedTerm・IaAiLog(BelongsToTenantDirect) / IaPrinciple(BelongsToTenantNullable、company_id NULL=共通・値ありはテナント)
- app/Services/InternalAudit/BigramVectorizer.php — 文字バイグラム+TF-IDFコサイン類似度の共通処理
- app/Services/InternalAudit/CaseSearchService.php — 類似事例検索(ia_reference_cases+テナント確定指摘の2種、テナント指摘を優先)
- artisanコマンド: ia:import-reference-cases {csvPath} / ia:import-principles {mdPath} {–force}
- config/audit.php に finding_rank_slots / reference_rank_slots / slot_groups / slot_expression_strength を追記
Phase3: AIサービス統合
- app/Services/InternalAudit/AiGatewayService.php — 全AI呼び出しの唯一の経路。送信ゲート(MaskingRuleEngine)→AnthropicClient→ia_ai_logs記録→JSON解析失敗時1回だけ自動リトライ
- ClarifyService.php(確認質問) / FactDraftService.php(事実文ドラフト) / CandidateService.php(条項候補Top-3+2分類推定+文書化根拠AI判定+手入力整合検証) / GenerateService.php(指摘文生成) / PrincipleProvider.php(解釈原則の取得結合)
- app/Exceptions/MaskingGateBlockedException.php / AiJsonParseException.php
- config/anthropic.php に internal_audit 用途を追記 / config/ia_support.php(用途別max_tokens、confusion_pairs)
- app/Services/InternalAudit/IsoClauseCatalog.php — 条項マスタの実在番号一覧(TTL1時間キャッシュ)。Phase4.3で条項ハルシネーション対策として追加
- app/Services/InternalAudit/TenantDictionaryProvider.php — block級テナント辞書の合成(手動登録ia_dictionary_terms+既存マスタ自動導出)。TTL10分、IaDictionaryTermの更新は即時キャッシュ無効化
Phase4〜4.3: 画面組み込み
- app/Http/Controllers/IaSupportController.php — 9アクション(storeSession/check/clarify/factDraft/candidates/checkClauseFit/recordClauseFitDecision/generate/adopt/storeAllowedTerm)。ルートはroutes/web.phpのia_support.*(9本)
- resources/views/audits/findings/_ia_support_modal.blade.php + resources/js/audits/ia-support.js — Alpine CSPコンポーネント(iaSupportModal)。STAGE 3-C方式(JSON設定タグ経由で設定値を受け渡し)
- resources/views/audits/findings/edit.blade.php — 詳細編集モーダル(findingsEditor)に「✨ AI支援」ボタン。別AlpineスコープのiaSupportModalとはwindow.dispatchEventのカスタムイベント(ia-support:open-request / ia-support:applied)で疎結合連携
- AuditFinding.php(ia_session_idをfillableに追加) / AuditFindingController.php(upsert時にia_session_idを素通し)
- tests/Feature/IaSupportControllerTest.php(12件)
(4) 未対応の既知課題リスト
- IsoClauseCatalogキャッシュの無効化がCSV取込に連動していない。IsoClauseControllerの管理画面CSV全置換後、最大1時間は古い条項番号一覧のままになりうる(候補生成・手入力マスタ実在チェックの両方に影響)。Cache::forget(IsoClauseCatalog::cacheKey($code))をCSV取込処理に追加すべきだが未着手。
- モーダルを途中で閉じた場合、ia_sessions.status=0のまま残る(プロトと同じ既知の割り切り。クリーンアップ/バッチ処理は未実装)。
- AnthropicClientへのtemperature任意パラメータは未追加(Phase3完了報告の「将来の小改善候補」)。JSON解析失敗時の1回リトライで実運用上は担保しているが、応答安定性が問題化した場合は呼び出し元4箇所への影響を含めて検討要。
- ランクマスタの完全テナント可変化(ia_rank_master)は未着手。現状スロット対応はconfig/audit.phpのみで完結させており(Phase2完了報告に明記)、テナントごとのランク名称カスタマイズはPhase5相当として先送り。
- resolveAdoptedRank等のメトリクス(candidate_adopted_rank/group_selected等)は記録のみで分析・活用先が未実装。ia_sessionsに溜まっているだけで、これらを使った改善ループ(候補精度の可視化等)は今後の課題。
- Phase4.2/4.3は指示書のみでDropbox側の完了報告mdが作成されていない(本メモ作成時点で確認)。次に大きな変更を入れる際は、まずコード側コメント(IaSupportController/CandidateServiceのdocblock)を一次情報として参照し、必要なら完了報告を追補すること。
(2) 設計上の重要な規約
- AIはaudit_findingsに一切書き込まない。サーバ書き込みは既存の一括upsert API(AuditFindingController::update)のみ。IaSupportControllerはia_sessionsへの経過記録のみ行う。反映(adopt)後もクライアント側でfindingsEditorのフォームへセットするだけで、ユーザーが「決定・保存」を押した時点で初めて保存される。
- 送信ゲートの不変条件: AiGatewayService::send()に渡す$messagesは、実際にAnthropicClient::messages()へ渡すオブジェクトと完全に同一でなければならない。ゲート検査対象(extractUserText())と実送信内容が別経路で構築されることは厳禁(迂回防止)。新しいフィールド(部署名・条項等)を追加する場合は必ず各サービスのbuildUserPrompt()内で$messagesの文字列に組み込むこと。回帰はAiGatewayServiceTestで確認。
- doc_basisの(e)完全一致規約: docBasis === ‘(e)’の場合のみ意見系(改善の機会)調を適用する。それ以外の非空文字列(複数選択で(e)+他根拠を含む場合も含む)はすべて「根拠あり」として通常の指摘調になる。IaSupportController::resolveDocBasis()が唯一の解決箇所(改ざん耐性のためクライアントからはトグルの状態のみ受け取り、詳細文言はサーバ側保存済みのdoc_basis_judgmentから都度組み立てる)。
- 条項はマスタ実在のみ(IsoClauseCatalog::validClauseNumbers())。AI候補・手入力とも、実在しない条項番号はCandidateService::filterValidCandidates()で除外する(2026-08-08の条項ハルシネーション事故対応)。マスタが空(未整備)の場合は安全側でフィルタしない。除外時の代替候補への繰り上げはしない(見せる候補が減るだけ、TAM指定の方針)。
- ユーザーには事実のみを尋ね、判定はAIが提示する(CLAUDE.md原則の実装例)。文書化根拠(doc_basis_judgment)はAIが質疑応答から判定して宣言文で提示し、ユーザーは上書きトグルで検証・反転のみ行う(「根拠がありますか」とは質問しない)。手入力条項の整合検証も同様で、mismatch時は強制ブロックせず「選び直す/このまま生成する」の選択肢を提示するのみ(条項の最終権威は監査員)。
- warn級は自動伏字化、block級は修正必須(Phase4.3)。次ステップへ進む操作の時点で未処置warnヒットを○○(カテゴリ)形式へ自動置換し、以後の全処理(AI送信含む)にその置換後テキストを使う。warn_passed_countの意味は「無処置通過数」ではなく「自動伏字化数」(列コメント参照)。
- モデル自身の内部状態でウェイトUXを実装(ai_modal.blade.phpは使わない)。同一モーダル内で複数回AI呼び出しを行う多段ウィザードはai_modal.blade.php(単発処理→リダイレクト専用)と構造的に不適合なため、iaSupportModal自身のloading/timedOut/elapsedSecondsで待機UXを実装している(CLAUDE.md原則からの意図的逸脱、完了報告に理由記載済み)。
(3) 触ってはいけないもの/前提を誤解しやすいもの
- database/seeders/IsoClauseSeeder.php は化石。初期セットアップのフォールバックに過ぎず、第2階層まで・要約文言なしの不完全データ。正式マスタはIsoClauseController.phpの管理画面CSV取込(指定ISOシステムの条項を全置換)であり、本番・開発とも既にCSV取込済みの充実データが入っている。環境再構築時にこのSeederだけを実行すると、既存マスタより貧弱なデータで上書きしてしまう。CSV原本はD:\Dropbox\03システムアシスト\00-Bulid-Assist\内部監査\のISO9001-2015_要求事項要約.csv等。
- AuditFindingのclient_key対応バックエンドは意図的に残置。Phase4.3でopenCorrectiveReport()撤去に伴い現在フロントからの送信元は無いが、「未保存行から確定IDを引きたい」将来用途のためのバックエンド仕組みとして削除しない(AuditFindingController.phpのコメント参照)。
- config/audit.phpのreference_rank_slotsのキーはia_reference_cases.rank_labelの実データ値そのもの(改善指摘A/改善指摘B/懸念領域/観察事項/改善の機会/充実点/参考)。既存finding_ranks(iso_app本体の語彙)とは別語彙であり、変換・正規化は一切していない。キー名を「綺麗に」リネームすると初期コーパスとの対応が壊れる。
- FactDraftServiceは解釈原則(PrincipleProvider)を付加しない。Clarify/Candidate/Generateの3サービスとは非対称(app.py精読で判明した既存プロトの仕様を忠実踏襲。「揃えたほうが綺麗」に見えても直さないこと)。
- IsoClauseCatalogはTTL1時間キャッシュだが、CSV取込側にキャッシュ無効化処理が無い(現状把握。詳細は(4)参照)。
- similar_text()によるedit_ratioはバイト単位の近似値であり、Python版(difflib.SequenceMatcher、文字単位)との厳密一致は保証しない。単調性(修正が多いほど値が大きくなる)のみ担保。厳密な一致を要求する変更をしないこと。
- AnthropicClient.php本体・既存4呼び出し元は無改修のまま。internal_audit用途はconfig追記のみで対応しており、system/temperatureパラメータをAPIに渡さない既存インターフェースを崩していない(IA側は役割定義+原則をuser roleメッセージ先頭に折り込む方式)。

