Skip to content

Latest commit

 

History

History
652 lines (505 loc) · 69.9 KB

OPERATIONS.md

File metadata and controls

652 lines (505 loc) · 69.9 KB

運用手順

正常運用時のVOICEVOX Task Trackerは毎日03:00、07:00、11:00、15:00、19:00、23:00 UTCに起動します。 日本時間では00:00、04:00、08:00、12:00、16:00、20:00にPagesとDiscordを更新します。 GitHub Actionsのscheduleには遅延があるため、厳密な投稿時刻は保証しません。

日々の確認

.github/workflows/daily.ymlの最新runで、実行対象のjobが依存順に成功したことを確認します。

  1. quality
  2. collect-analyze
  3. persist-state
  4. build-pages
  5. deploy-pages
  6. notify-discord
  7. publish-notification-history 通知候補があるときのみ
  8. notify-operations 失敗時のみ
  9. report-workflow

通常の公開経路はnotify-discordまでの6 jobです。通知候補があるrunでは、その後にpublish-notification-historyが動きます。 notify-operationsは収集、Pages関連、Discord通知のいずれかのjobが失敗したときだけ実行されます。 report-workflowは先行jobの成否にかかわらず実行され、全job結果と収集metricをActions artifactへ保存します。

Pagesではトップの項目一覧に未完了の追跡項目が表示され、既定が要対応度の降順であることを確認します。 状態で「すべて」を選ぶと、完了済みの追跡項目も表示されます。 現在対応の責任主体と実行可能性の絞り込みが、担当者一覧と個人ページの項目数に一致することを確認します。同じ相手に複数の原因があっても同じ項目は1件と数えます。項目全体の状態とblockerは現在対応と併記し、停滞時間の集計は「項目の最長停滞時間」として確認します。 表が表示される幅では列見出しから並び替えられ、カードが表示される幅では並び順の選択UIが現れることも確認します。 共通ヘッダーには「最新更新」と相対時刻、共通フッターにはrun IDだけが表示されます。 通知履歴ではDiscordへ送信済みの項目通知が新しい順に表示され、履歴がなければ空状態になることを確認します。 送信した通知は、同じrunのpublish-notification-historyがPages公開に成功した後に表示されます。 個人通知の履歴は送信時の相手と行動であり、現在対応が変わっても書き換わらないことを確認します。 tracker-stateではstate/run-reports/YYYY-MM-DD.jsonを確認します。 ローカル実行のreportはartifacts/run-reports/へ出力されます。 Actionsでは収集reportとworkflow全体のreportを、run IDと試行番号を含む別々のartifactへ保存します。

run reportの主な確認項目は次のとおりです。

field 意味
status successは完全成功、fallbackはCodex縮退を含む完全run、failureは不完全run
complete stateと公開処理へ進める完全性を満たしたか
failedStage failureが起きた処理段階
diagnostics secretや信頼できない本文を含まない診断
metrics.repositoryCount 公開allowlistに入ったrepository数
metrics.itemCount 追跡項目数
metrics.changedItemCount 前回から更新された追跡項目数
metrics.activeEdgeCount 有効な関係edge数
metrics.aiCallCount preflightを含むCodexの論理call数。retryとsemantic補正の追加世代は含めない
metrics.aiProcessAttemptCount preflight、汎用AI、個人原因AI、retry、semantic補正のCodex exec実試行数
metrics.aiCacheHitCount AI cacheを再利用した件数
metrics.aiRetainedResultCount AI分析対象へ入れず前回のAI結果を保持した件数
metrics.estimatedInputTokens 選択した分析候補とpreflightの入力token見積り。追加試行の増分は含めない
metrics.githubApiRemaining 最後に観測したGitHub API残量
metrics.staleRepositoryCount 前回値を利用したrepository数
metrics.notificationCount Discord送信結果を通知管理記録へ記録した通知数。holdとacknowledge-currentでは0
metrics.scheduleDelayMilliseconds 予定起動時刻からCLI開始までの遅延
metrics.durationMilliseconds CLI開始からrun完了までの所要時間

個人原因はmetrics.personalReminderCauseCountで件数を確認します。personalReminderAiCallCountは複数原因をまとめた実行batch数で、preflightを含みません。personalReminderAiCacheHitCountとpersonalReminderAssessmentReuseCountは原因ごとのcache利用数と採用値再利用数です。全体のaiCallCountとestimatedInputTokensには、汎用AI、個人原因のAI、preflightを合わせて計上します。 aiProcessAttemptCountは論理call数と別に、processRunnerへ渡したcodex execを1回ずつ数えます。呼び出し後の起動失敗、timeout、結果不明も含み、呼び出し前の失敗とcodex --versionは含みません。成功、縮退、段階失敗のreportに記録します。 personalReminderUnknownCountは正常に完了した未確定判定です。personalReminderFailedCount、personalReminderDeferredCount、personalReminderNotEvaluatedCountは現在有効な採用値がない原因を数えます。正常なunknownだけではrunをfallbackにせず、失敗・延期で有効な判定を使えない場合を縮退として確認します。

Codex出力のschema検証とsemantic検証に失敗した場合、diagnosticsへ違反件数がvalidationIssueCountとして残ります。 違反した検証ルールは先頭5件までvalidationIssue0PathとvalidationIssue0Codeの形式で残り、添字は0から始まります。 違反のmessageは入力値を含みうるため残しません。

AI有効runで汎用AIの分析処理が結果を返した場合、diagnosticsにcodex_semantic_generationsから始まる集計行が1行残ります。

field 意味
generationCount 初回を含む汎用AIの生成世代数
correctionStartedCount 第2世代の補正を開始した候補数
correctionSucceededCount 補正出力がcanonical検証まで通った候補数
correctionExhaustedCount 補正を開始し、総世代数の上限までsemantic違反が残った候補数
processAttemptCount 汎用AIのtransport retryを含むprocess試行数

これらの件数は個人催促AIと認証preflightを含みません。ここでのprocessAttemptCountは汎用AIだけの集計で、run全体のmetrics.aiProcessAttemptCountとは範囲が異なります。集計行にはitem ID、違反のpathやcode、本文を含めません。 補正上限に達した項目を縮退させて完了した通常runにも集計行が残ります。 致命的なalias変換失敗やforcedモードの失敗でanalyzeCodexが戻らない場合は、この行が残らないため、行がないことから補正0件とは判断できません。

汎用AIのsemantic補正はai.execution.maxSemanticGenerationsで制限します。必須の整数設定で範囲は1から3、初回を含みます。1は補正無効で、現行値3では2回まで補正できます。 各世代にはai.execution.maxAttemptsまでのtransport retryがあり、候補1件あたりのprocess試行数は最大で両設定値の積になります。実試行のrun残枠がなければretryと補正は行わず、候補を延期します。 補正の追加世代はmetrics.aiCallCountに加算せず、補正envelopeの増分も論理入力予算とmetrics.estimatedInputTokensへ含めません。実際の入力文字数は暗号化した詳細診断のstandardInputCharactersで確認します。

Codex認証preflight

汎用AIと個人原因のAIは、Codex exec実試行回数、入力文字数、見積費用のrun上限を共有します。後段の原因評価は、関係を含む前段の分析が消費した予算を引いて計画します。認証preflightも両段で共有し、run中に1回だけ実行します。 入力文字数と見積費用は候補選択時の概算です。retryやsemantic補正の追加入力と出力tokenを含む実課金の上限ではありません。

auth-jsonで実行候補が1件以上あるrunだけ、候補processより先に固定した短文を空の一時directoryで実行します。候補データと通常のsystem promptは渡さず、preflightの完了後に候補workerをai.execution.maxConcurrentCallsの設定値まで並列実行します。 api-key、候補なし、cache hitだけのrun、全候補が予算延期されたrunでは実行しません。preflightに失敗した場合は候補を開始せず、実行段階に応じてcodex_analysisまたはpersonal_reminder_analysisを失敗させます。 preflightを始める前に、preflightと最優先候補の初回試行に2枠を確保します。2枠を確保できなければ候補を延期します。preflightの完了後に残りの候補の初回試行枠を優先順で予約し、retryとsemantic補正には未予約枠だけを使います。 preflightはrun全体の入力文字数と見積費用へ1論理callとして計上し、項目ごとの入力文字数上限には含めません。ai.budget.maxCodexExecAttemptsPerRunの現行値は50で、preflightを実行するrunでは初回試行を最大49候補へ配れます。preflightと候補の実試行は、複数attemptになった分も同じ50枠から消費します。成功runのaiCallCountとestimatedInputTokensにもpreflightを含めます。 これは必要時のtoken更新機会を先に設ける緩和策であり、refreshを強制しません。preflight後に各並列processが更新条件へ入れば認証競合は残ります。

tracker-stateは自動更新専用です。 人間がsnapshot、履歴、AI cache、通知管理記録を直接編集すると履歴と通知抑制の整合を壊すため、修正はGitHub上の正本かconfig.ymlで行います。

forkでPRのコードを動かし、試行環境ごとにstateを分ける

PRのコードで実推論とstate更新を確認するときは、Hiroshiba/voicevox_task_trackerのActionsからsandbox task trackingを起動します。 同じPRでも試行環境を複数作り、それぞれのstateで実行できます。 Codex認証の更新を共有するため、sandbox、手動dry-run、同じrepositoryの日次収集jobは一つずつ実行します。 このworkflowはforkのデフォルトブランチであるmainから起動した場合だけ動きます。 最初にsandbox用のworkflowと実行コードをforkのmainへ反映し、Actionsを有効にします。 実行対象の作業ブランチにも、この機能の実装を含めます。 デプロイ手順に従い、GitHub Appの設定と、repository secretsのCODEX_AUTH_JSON、CODEX_AUTH_SYNC_TOKENを登録します。 Codex認証ファイルは実行中だけrunnerの一時ディレクトリへ配置し、変更があれば同じrepository secretへ書き戻します。 同期用tokenは書き戻しstepだけへ渡します。 Discord用secretはsandbox workflowに渡しません。

通常モードで新しい環境を作る例です。

gh workflow run sandbox.yml --repo Hiroshiba/voicevox_task_tracker --ref main \
  -f operation=create -f source_ref=feature/example -f analysis_mode=normal

createではenv-<workflow run ID>-<run attempt>形式の環境IDを自動生成し、VOICEVOX本番repositoryの公開tracker-stateの最新コミットから、forkにsandbox-state/<環境ID>ブランチを作成します。 複製元のコミットをseedと呼びます。 state/sandbox-environment.jsonへ環境ID、対象ブランチ、複製元のSHAを保存し、実推論より先にpushします。 このmanifestは環境の存続中に更新しません。 作業ブランチは実行開始時のコミットSHAへ固定し、run contextのartifactへコードとstateのSHA、run ID、attempt、分析モードを記録します。 Pagesはdeployせず、生成したサイトとrun contextをActions artifactへ保存します。 通知処理はholdで完了記録だけを保存するため、Discordへ送信しません。

一つの項目を指定して実推論する場合は、NODE_IDを対象のGitHub node IDへ置き換え、AI判定要素をカンマ区切りで指定します。

gh workflow run sandbox.yml --repo Hiroshiba/voicevox_task_tracker --ref main \
  -f operation=create -f source_ref=feature/example -f analysis_mode=forced \
  -f forced_node_id=NODE_ID -f forced_elements=status,waitingOn

利用できる要素はstatus、waitingOn、nextAction、relations、progress、importance、deadline、notification、selfCommitmentです。 forcedモードではnode IDを一つだけ指定し、要素の重複や空要素は受け付けません。 生成不要と判定された要素や、指定外の判定を維持するための情報が不足する指定は拒否します。 指定要素はcacheを再利用せず、すべての指定要素で実推論に成功しなければ実行を失敗にします。 normalモードでは本番と同じ選別とcache再利用を行うため、実推論が0件でも成功します。

relation判定とsemantic補正を確認するときは、上記のforced実行で対象nodeを指定し、forced_elements=relationsとします。 生成された関係の向きと根拠が妥当であり、検証を通ってstateへ保存されたことを確認します。 実AIの応答は非決定的なので、補正世代が発生すること自体は必須にしません。 補正が発生した場合は、run reportのcodex_semantic_generationsと詳細診断の世代別attemptを照合します。第2世代に進んだ候補は開始数へ1件、検証を通った候補は成功数へ1件を計上し、生成世代数とprocess試行数が設定上限内であることを確認します。

保存したstateから実行を続ける場合は、manifestに記録された作業ブランチを指定します。 作業ブランチを更新した後のcontinueでは更新後のSHAを固定しますが、別ブランチを指定すると停止します。 解析に失敗した環境も同じ方法で再開できます。

gh workflow run sandbox.yml --repo Hiroshiba/voicevox_task_tracker --ref main \
  -f operation=continue -f environment_id=env-123456789-1 \
  -f source_ref=feature/example -f analysis_mode=normal

環境をseedからやり直す場合はresetを使います。 resetは元の環境を読み取り、新しい環境IDとstateブランチを作ります。 reset_source=seedは元環境のmanifestにあるseedへ戻し、reset_source=latestはVOICEVOX本番repositoryの最新tracker-stateから開始します。

gh workflow run sandbox.yml --repo Hiroshiba/voicevox_task_tracker --ref main \
  -f operation=reset -f environment_id=env-123456789-1 \
  -f source_ref=feature/example -f reset_source=latest -f analysis_mode=normal

不要になった環境は環境IDを指定して廃棄します。 削除時にリモートのheadが取得時の値から変わっていた場合は、競合として停止します。

gh workflow run sandbox.yml --repo Hiroshiba/voicevox_task_tracker --ref main \
  -f operation=dispose -f environment_id=env-123456789-1

state更新の排他単位はforkリポジトリと書き込み先の環境です。 createとresetは新しく作る環境、continueとdisposeは指定した環境への操作を一つずつ実行します。 resetは元環境のmanifestを取得してから、選択した複製元のSHAを固定して新環境を作ります。 manifestの取得前に元環境が削除された場合は失敗します。 cancel-in-progress: falseでも、同じstate更新の排他groupの待機中runは後から来たrunに置き換わります。 同じ環境で順番に実行したい場合は、前の実行が完了してから次を起動します。

異なる環境のsandbox job、手動dry-run、同じrepositoryの日次workflowのcollect-analyzeは、認証を共有する排他groupで一つずつ実行します。 このgroupはqueue: maxで最大100件の待機jobを保持します。 実行順は保証されません。 repository secretはworkflow runの受付時に読み込まれるため、待機中に別runが認証を更新しても、受付済みrunは古い認証を使います。 異なる環境でも、同じ認証を使う前のrunが完了してから次を起動します。日次workflowとdry-runの手動実行も同様です。 この排他は同じrepositoryの日次収集job、sandbox、手動dry-runに限り、別のrepositoryやローカルで同じ認証を使う処理には及びません。

初回は異なる二つの作業ブランチでcreateを起動し、環境ID、stateブランチ、run contextのartifactが分かれていることを確認します。 その後、それぞれの環境でcontinueを実行し、前回保存したstateが読み込まれることと、Pagesのartifactを確認します。

gh run list --repo Hiroshiba/voicevox_task_tracker --workflow sandbox.yml --limit 2
gh run view RUN_ID --repo Hiroshiba/voicevox_task_tracker

性能profile

OPS-004は通常のCIから分離したend-to-end性能profileで確認します。 日次runの処理時間、API予算、AI論理call数、Pages summaryのサイズに影響する変更で、GitHub Actionsの「性能profile」を対象のリモートブランチから手動実行します。 通常のPull Requestでは自動実行されません。

gh workflow run performance.yml --repo Hiroshiba/voicevox_task_tracker --ref feature/example

repositoryとbranchは検証対象に置き換えます。 完了後はrunのActions artifact end-to-end-performance-profileを取得し、中のperformance-profile.jsonを確認します。 ローカルでpnpm perf:profileは実行しません。

外部サービスへ接続せず、本番のdailyトランザクションへ5,000項目、10,000 edge、変更300件を流します。 変更項目は3件ずつ100組に分け、関係先を組内で共有します。 GitHub APIは15,000 unitのモックrate limitから、一覧のpaginationと項目ごとの詳細取得で消費したunitを差し引きます。 Codex processは起動せず、変更300件から汎用AIの論理callを300件、個人催促AIのbatchを300件実行し、モック出力を予算選別、schema検証、reducerへ通します。 profile専用のCodex実試行上限を600件、総入力文字数の上限を2,000万字に設定します。 日次reportのaiCallCountが合計600件、内訳がそれぞれ300件であることを確認します。 ここで測るのは外部接続をモックしたdaily経路の処理時間です。Codex processは起動しないため、実Codex processを600回起動した場合の性能は保証しません。 state永続化はメモリ上で行い、Pages初期summaryは実際に生成してgzipサイズを測ります。

workflow内の検証コマンドはNodeのheap上限を4 GiBに設定します。 30分、GitHub API 70%、summary gzip 1 MiBのいずれかを超えると終了codeが1になります。汎用AIが300件、個人催促AIが300 batch、aiCallCountの合計が600件と一致しない場合も失敗します。 測定結果はartifacts/performance-profile.jsonへ保存されます。

stageごとの実行

日次workflowはjobの権限と副作用を一致させるため、次のstageを別processで実行します。 以下のコマンド例は各stageの仕様を示します。実データを使う一連の処理は目的に応じたActionsで実行し、ローカルでは変更箇所に絞った確認に使います。 各stageはartifacts/workflow/validated-run.jsonをschema検証、semantic検証、公開安全性検証へ通してから利用します。 前stageのartifactが存在しない場合や検証に失敗した場合は明示的なエラーで停止します。

収集と判定はGitHub Appの認証情報を使います。 現行のconfig.ymlはai.authentication: auth-jsonを指定します。 Actionsのcollect-analyze jobは配置stepだけへCODEX_AUTH_JSONを渡し、非空なら一時的なauth.jsonを配置します。収集stepへはCODEX_HOMEと同期用tokenの有無だけを渡します。 CODEX_AUTH_SYNC_TOKENの値は書き戻しstepだけへGH_TOKENとして渡します。 jobは認証ファイルを配置した場合に限り、一時ファイルを削除する前に更新されたauth.jsonをCODEX_AUTH_JSONへ同期します。 ai.enabled: trueで実行候補がある場合は、lockfileで固定したcodexに加え、auth-jsonならCODEX_HOME直下のauth.json、api-keyならOPENAI_API_KEYが必要です。 検証後のsnapshot、通知候補、通知管理記録、run report生成用の収集指標、AI cacheを公開可能なartifactへ保存します。

pnpm build
pnpm tracker:run collect-analyze --mode none

backfillでは--mode linkedか--mode all-openを指定し、対象を絞る場合は--repository VOICEVOX/voicevoxを繰り返します。

state永続化は収集artifactを受け取り、tracker-stateへ一つのcommitとして保存します。 GitHub App、Codex、Discordのsecretは読みません。

pnpm tracker:run persist-state

Pages buildは保存済みstateと同じ収集artifactから公開DTOを生成します。 外部secretは読みません。

pnpm tracker:run build-pages --output web/public/data
pnpm build:web

notify-discordが成功して通知候補がある場合は、publish-notification-historyが通知後の最新stateを取得し、送信済み通知を含むPagesを再生成してdeployします。候補がない場合、hold、acknowledge-currentではこのjobを実行しません。

GitHub Pagesへのdeployが成功した後だけ、deploy結果のURLを渡してDiscord stageを実行します。 Discordへの送信には、通常通知用のDISCORD_WEBHOOK_URLと障害通知用のDISCORD_OPERATIONS_WEBHOOK_URLを使います。 通常digestはHTTP送信の前に、送信開始済みの記録を保存してoriginのtracker-stateへpushします。送信結果が不明なまま停止しても、同じ通知を自動再送しないための記録です。 メッセージを1通送信するたびに、送信済みの通知管理記録と通知履歴を同じcommitへ保存し、originのtracker-stateへpushします。pushが成功してから次のメッセージを送信します。途中で失敗しても、保存済みの送信結果は残ります。同じrunを再実行するときは、送信済みまたは確認済みの通知理由を除いて送信します。

GitHub Actionsではcheckoutが設定したGit認証を使います。ローカルでnotify-discordまたはdailyを実行する場合も、originのtracker-stateへpushできる認証が必要です。追跡開始時刻とrun完了の記録は、すべてのメッセージを処理した後に確定します。

pnpm tracker:run notify-discord --pages-url https://voicevox.github.io/voicevox_task_tracker/

本番の収集、state保存、Pages公開、Discord通知を実行する場合は、日次workflowの手順に従い、本番repositoryのデフォルトブランチから「日次タスク追跡」をbackfill: noneで手動実行します。 通常は定期実行に任せ、運用上必要なときだけ手動で起動します。 開発中のコードで収集・判定を確認する場合は手動dry-run、試行用stateの保存とPages生成まで確認する場合はsandboxを使います。

誤判定の直し方

tracker専用のcommand comment、override UI、専用labelはありません。 次回runで機械的に解釈できるように、GitHub上の事実を明確にします。 GitHubのassigneeは確定情報として保持します。未アサインIssueの実質担当は表示上の推定であり、trackerはGitHubへassignを書き戻しません。

個人への催促が疑わしい場合は、現在対応の責任主体、行動、根拠と実行可能性を先に確認します。項目全体の依存待ちと、並行して進められる対応は両立します。 unknownは判断に必要な情報の不足や競合を表し、AIの実行失敗とは区別します。正常に評価したunknownは同じ入力で再利用するため、再実行を繰り返すだけでは変わりません。failedとdeferredは必要性が残れば次回runで再試行します。有効な採用値が現在入力と一致する場合は、直近の実行失敗だけでその判定を消しません。 正式な依頼や担当決定などの規則による義務は、AIから義務なしに変更しません。通知を止めるために無関係なassigneeやstatusを変更せず、依頼の解決・撤回・引継ぎ、実際に待っている工程を正本へ反映します。

AI表示を三つの軸で読み分ける

AIの実行状態、判定要素が決定論的に不要だったか、表示値が現在入力で検証済みかは別の情報です。

公開DTO 読み方
runStatus その項目で今回行ったAI分析の処理結果です。failedは失敗、deferredは予算上限による未実行を表します
omission 9個のAI判定要素のうち、確定規則だけで決まるためAI推定を不要とした範囲です。partialは一部、allは全部を表します
aiAnalysis.unverifiedValues 項目の最終表示値のうち、現在入力でAI依存が検証済みと証明できない値です
currentResponses[].unverifiedValues 一つの現在対応について、責任主体、行動、実行可能性、待機先、根拠のどの値が現在入力で未検証かを示します
currentResponses[].subjectMembershipUnverified その対応の責任主体を現在の対応者として数えるかが未検証であることを示します。同じ項目で同じ主体を示す別の対応が一つでも検証済みなら、その主体の項目への所属は確定します
currentResponsesUnverified 現在対応の件数や構成が現在入力で未検証で、表示内容が増減する可能性があることを示します
currentResponseSubjectChanges 人物集計へ追加または削除され得るuserとteamを示します。boundedでは対象をaddableSubjectsとremovableSubjectsへ列挙し、特定できない場合はunboundedにします。roleだけの増減は人物集計を変えないため、責任主体が検証済みならboundedの空配列になります

not_requiredはAI判定が不要だったことを表し、失敗や延期ではありません。確定規則だけで決まった値には警告マークが付きません。 failedまたはdeferredの項目と、未検証の表示値や現在対応を持つ項目には一覧行の警告マークが付きます。詳細では、未検証の値のそばにある警告マークから説明を確認できます。一覧のai=unverifiedはこれらの項目をまとめて絞り込みます。ai=partialは一部要素がAI不要、ai=allは全要素がAI不要の項目を絞り込みます。

現在の対応に表示される「今回はAI判定を実行していません」は、今回の意味評価を実行しなかったdeferredを表します。原因にはAI予算の上限だけでなく、上流relationの未確定、入力の不完全、入力件数や文字数の上限があります。GitHub上の方針判断を延期した意味でも、AIが判断したうえで結論を先送りした意味でもありません。

期限日はCodexが本文やコメントから抽出し、期限の切迫度は期限日と現在日から決定論的に計算します。この場合、切迫度の計算にAIを使わなくても、期限日が現在入力で未検証なら切迫度も同じAI producerに依存するため警告マークが付きます。

抽象的なmaintainer、reviewer、merge_deciderの責務は、config.ymlでrepositoryごとに設定したメンテナ全員へ展開されます。 担当者を変える場合はmaintainers.defaultsかmaintainers.repositoriesのGitHubユーザー名一覧を更新します。 GitHubのteam review requestと本文やコメントの@organization/teamはteamへの待ちとして残ります。 trackerはteam memberを取得しないため、team宛て項目ではコメントした人がteam memberかどうかを判定しません。 個人のコメントを待ち先の活動として停滞計算へ反映させる場合はuserを名指しします。 PRのレビュー担当選定待ちとレビュー待ちでは、teamへの依頼でも人間のレビューを進展として扱います。

コメント

最新コメントで、次に誰が何をするかを一文で明示します。 Issue全体を担当する場合は、その旨を明記し、追跡中でGitHubがclosing referenceとして認識した直接関連PRや継続成果物と結び付けます。本文に書いただけの推定relation、部分対応、助言、検証、review、条件付きの意向、撤回、延期の記載は実質担当の根拠になりません。 複数人を候補にする場合も、Issue全体を共同で進めていることを明記します。部分PRの組み合わせだけから共同担当を推定しません。 trackerは一般的な活動状態を実質担当へ読み替えず、部分担当や部分実装を別の担当としてモデル化しません。 方針判断待ちへ直す場合は、maintainer roleへ必要な判断を明記します。 返答待ちへ直す場合は、回答を求めるuserかteamを名指しします。 質問の内容と未回答であることも明記します。 依存関係なら対象IssueかPRのURLに加え、どの行動を止めているか、並行できる行動があるか、単なる関連情報かを明記します。部分実装や代替案を、Issue全体の完了や同じ対応の重複と取り違えないよう範囲も示します。

古いmention、謝辞、単なるリンクだけでは責務移動やblockerを確定しません。 Issue author、Pull Request author、最新commenterであることだけでも担当は確定しません。親Issueや横断Issueの作業者を現在のIssueの担当へ移しません。 依頼が解決した場合は、回答か決定を新しいコメントとして残すと未回答扱いを解消しやすくなります。

assignee

Issueを正式な作業待ちへ直す場合は、実際に作業するuserをassigneeへ設定します。 assigneeが空でもtrackerがIssue全体の実質担当を表示する場合があります。その表示は推定であり、正式なGitHub assigneeの代わりにはなりません。 担当が決まっていない場合や、実質担当の根拠が不足する場合はassigneeを設定しません。 誤って推定された場合は、部分対応、reviewのみ、撤回、延期、引継ぎであることを最新コメントへ明記します。正式assigneeの設定や新しい全体担当の根拠は次回runで再判定されます。 正式assigneeを解除すると、解除前の根拠は実質担当の推定に再利用されません。同じ人や別の人を実質担当にする場合は、解除後にIssue全体を進める新しい根拠を残します。

ラベル

config.ymlのlabels.rulesへ登録した既存labelだけがtrackerの意味を持ちます。 repository globとlabel名の正規表現を一致させ、必要な効果を設定します。

effect 用途
priorityWeight 重要度を通じて要対応度を上げ、通知候補の順位も上げる
severityLift 通知判断に使う停滞レベルを最大1段階引き上げる
requiresMaintainerDecision 方針判断待ちとし、maintainer roleへ責務を置く
suppressNotifications graphには残したまま通常通知を抑える
countsAsProgress そのlabel変更を意味のある進捗として扱う

trackerはlabelを追加も変更もしません。 label規則を変えた場合はdry-runで通知候補の差分を確認します。

review request

PRをレビュー待ちへ直す場合は、Current reviewersへレビューを依頼するuserかteamを追加します。 不要になったreview requestはGitHub上で解除します。 現在のreview requestは自然言語より強い決定論的根拠です。

人間のCHANGES_REQUESTEDが最新head以後にある場合は修正待ちを優先し、authorの修正を待ちます。 authorが修正をpushした後はレビュー待ちとしてreviewer側を再評価します。 必要ならreview requestも現在の担当へ合わせます。 未解決のreview threadも修正待ちの根拠になります。 authorが最後に返信したthreadは修正待ちの根拠から外し、reviewerの再確認を待つレビュー待ちとして扱います。 botのreviewとcommentだけではbotへ責務を移しません。 review、助言、検証だけを行った人をIssue全体の実質担当者へ移しません。

これらで待ち先が決まった後も、その相手本人がさらに発言していれば発言の内容から判定し直します。 変更要求を受けたauthorが修正せずに質問すれば返答待ちとなり、reviewerの返答を待ちます。 authorが了解を返しただけなら修正待ちを維持し、authorの修正を待ちます。 待ち先を確実に伝えたい場合は、質問や依頼を明示した文にするか、review requestで示してください。

native dependency

本当に作業を止めるIssue同士はGitHubのblocked byとblockingで接続します。 親子関係はsub-issueを使います。 native relationはauthoritativeであり、本文のplain linkやCodex推定より優先されます。 子Issueや直接関連PRの作業者を、親Issueや横断Issueの実質担当者へ拡張しません。 Pull RequestがIssueを閉じる関係は、GitHubがclosing referenceとして認識する形で書きます。 GitHubが認識したclosing referenceはauthoritativeなimplements関係になります。 GitHubが認識しない書き方は本文のclosing keywordとしてしか読めず、Codexの推定に頼る関係になります。

blockerが完了したら対象Issueをcloseし、誤ったnative relationはGitHub上で解除します。 単なる関連項目はnative dependencyにせず、本文かコメントで関連だけであることを明記します。 個人原因の評価はnative blockの事実を変更しません。reviewや計画などが並行可能なら、依存関係を残したまま現在対応へ表示します。単なるrelated_toを理由に催促は抑止しません。

重要度

重要度は項目そのものの重要さを表し、停滞レベルとは別に確認します。 個別の項目の重要度がずれている場合は、まず詳細ページの内訳でどの要因が効いているかを確かめます。 決定論的な要因は、優先度ラベル、native dependency、downstream impactをGitHub上の事実へ合わせると変わります。 Codex由来の重要度要因は、重要な機能である根拠と放置した場合の将来問題が本文かコメントから読み取れるかで決まります。期限の切迫度は重要度へ影響しません。 本文へ重要だと書くだけでは根拠になりません。 全体の加点やlevelを調整する場合はconfig.ymlのimportanceを変更し、dry-runでscore、level、内訳を確認します。

要対応度

要対応度は重要度、期限の切迫度、停滞の鮮度から計算します。 個別の項目の要対応度がずれている場合は、重要度score、期限日、期限の切迫度、stallSince、現在のwait class、そのwait classのwatch閾値を順に確認します。 terminal項目とブロック解消待ちの項目が0点になるのは意図した動作です。 importanceCapacity = 100 - deadlinePoints.overdueとして、recencyScore = round(importanceScore × recencyCoefficient × importanceCapacity / 100)、score = recencyScore + deadlinePoints[currentLevel]で計算します。

停滞による下がり方を全体で調整する場合はconfig.ymlのattention.recencyFloorを変更します。 要対応度、重要度、期限の切迫度、停滞時間は、項目一覧と担当者ごとのページで選べる四つの並び替えキーです。 既定は要対応度の降順です。 停滞レベルはWeb UIで参照しないため、Webの表示順を直す目的でseverityLiftを変更しません。

設定変更後はdry-runを実行し、要対応度のscore、level、表示対象、並び順、依存グラフのnode選定を確認します。

修正を反映したい場合は日次runを待つか、日次workflowをbackfill: noneで手動実行します。

backfill

本番で追跡項目を追加するbackfillは、本番repositoryのデフォルトブランチからGitHub Actionsの日次タスク追跡を手動実行して指定します。 この操作は本番のstateとPagesを更新し、notification_actionの指定に従って通知を処理します。

backfill 対象
none 通常の日次追跡だけを行う
linked 追跡済み項目とrelationで接続する未追跡open項目を追加する
all-open 対象repositoryの全open IssueとPull Requestを追加する

repository_filterはVOICEVOX/voicevox,VOICEVOX/voicevox_engineのようなfull nameのカンマ区切りです。 空ならVOICEVOX全体が対象です。 backfill: noneではrepository filterを指定できません。

1 runで追加する件数はtracking.backfill.maxItemsPerRunまでです。 上限を超える場合は同じmodeとfilterで手動runを繰り返します。 linkedは追跡済み項目の直接の隣接項目を追加し、繰り返すと新しく追加した項目の隣接へ範囲を広げます。

特定の古いIssueかPRだけを追加する場合は、URLかnode IDをtracking.includeへ追加します。 一度追跡対象へ入った項目は作成日時に関係なく同じ状態、停滞、通知規則で扱います。 大規模なall-openはCodex予算と通知候補を急増させるため、Discordを無効にしてrepository単位で確認してから範囲を広げます。

通知量の調整

送信結果が不明な通知を確認する

通信例外、HTTP 5xx、応答不正が発生すると、Discordに届いたかどうかを判定できません。プロセスが送信中に停止した場合も、通知管理記録には送信開始済みのdelivery_startedが残ります。この記録は時間が経っても解除しません。同じrunの再実行は確認を求めるエラーで停止し、次の通常runは保留中の通知を除いて処理します。

Discordの投稿と実行ログを確認し、対象メッセージを確認済みにするか、次回の送信候補へ戻します。運用障害通知のincident ID、または再実行時のエラーに表示されるdeliveryIdで対象を指定します。ログが残っていない場合は、tracker-stateのstate/notification-ledger.jsonからstatusがdelivery_startedの記録を確認します。

  1. 日次workflowが実行中でないことを確認し、ローカルのtracker-stateをoriginの最新状態へ取得します。

  2. Discordで通知を確認できた場合、または送信を不要と判断した場合は、次のコマンドで確認済みにします。IDには対象のdeliveryIdを指定します。

    pnpm tracker:run resolve-discord-delivery --delivery-id ID --resolution acknowledge
  3. Discordへ届いていないことを確認できた場合は、--resolution retryを指定して実行します。その後、新しい日次runを開始します。

このコマンドは通知管理記録を保存してpushします。ローカルでのビルドと、originのtracker-stateへpushできる認証が必要です。retryは通知を直接送信せず、次の集計時にまだ有効な候補だけを選別対象に戻します。acknowledgeは確認済みにし、送信済みの履歴は作りません。受信の有無を確認せずにretryを選ぶと重複送信する可能性があります。

通知候補を保持して送信を保留する

AI判定の更新内容を確認してから通知したい場合は、手動実行のnotification_actionをholdにします。 通知候補は通知管理記録のpendingNotificationsへ保存し、送信予約、確認済み、送信済みの記録は追加しません。 すでに送信済み・確認済み・送信開始済みの記録は維持します。

  1. repository variableのVOICEVOX_TASK_TRACKER_SCHEDULE_PAUSEDを文字列trueにし、定期実行を停止します。
  2. 実行中と待機中の日次runを確認します。変数の変更だけでは開始済みのrunは止まらないため、state更新と通知処理の完了を待ちます。
  3. default branchの「日次タスク追跡」を、backfill: none、repository_filterは空、notification_action: holdで手動実行します。
  4. persist-state、notify-discord、report-workflowの成功を確認します。notify-discordは送信せずにrunの完了処理を行うため、jobを省略しません。
  5. Pagesとrun reportで判定結果を確認し、通知管理記録で保留候補を確認します。分析の失敗・延期が残る場合は、各runの完了を待ってholdで再実行します。
  6. 通常送信に戻すときは、手動実行でsendを指定します。保留候補は現在の条件で再検証され、まだ有効な候補だけが通常の件数上限に従って送信されます。
  7. 古いrunが残っていないことを確認し、停止用変数を削除するかfalseにして定期実行を再開します。

停止用変数は手動実行を止めません。 定期実行のイベントは発生しますが、開始jobと、障害通知・run報告を含む後続jobを省略します。 hold自体は指定したrunだけに適用されるため、確認中は停止用変数を維持してください。 手動実行中に障害が発生した場合の運用障害通知は通常どおり動きます。

個人原因の候補は、同じ通知keyなら検出時刻を保って再検証します。入力が変わって採用値が使えない場合や、waiting・unknownへ変わった場合は送信を保留します。失敗・延期やrepositoryの収集失敗だけでは責務を終了させません。 進捗や待機解消で停滞起点が変わった場合は、現在の閾値で候補を選び直します。新しいkeyになると検出時刻も更新し、閾値未満なら古い候補を失効させます。責務が終了した場合、not_required・duplicateになった場合、相手・行動・責務期間が交代した場合も旧候補を取り除きます。

stateの保存形式を移行する

保存形式を変更するPRは、実stateのコピーで移行と保存後の再読み込みを検証し、CIが通ったことを確認してから切り替えます。

  1. 停止用変数をtrueにし、Actionsで日次workflow全体を無効にします。切替前のコードによる新たなstate更新を防ぐため、マージ前に行います。
  2. 実行中・待機中のrunと手動のstate操作を確認し、更新と送信の完了を待ちます。受信結果が不明なdelivery_startedは消さず、既存の送信結果確認手順で扱います。
  3. 稼働中のコードとtracker-stateのコミットIDを復旧用に記録します。そのstateに対してverify-stateを再実行し、成功後にPRをマージします。
  4. マージしたコードのCI成功を確認して日次workflowを有効に戻します。停止用変数は維持し、初回をholdで手動実行します。
  5. GitHubへ反映されたstateで、snapshotが現行形式になり、追跡開始時刻・追跡対象・履歴・通知管理記録を引き継いでいることを確認します。snapshot 18から19への移行では、AI依存の単一のreasonを1要素のreasons配列へ変換します。値・producer・AI要素の適用元・採用済み評価・根拠・時計と、汎用AI・個人原因の現行cacheは保持します。
  6. 必要なAI再推論の結果と通知候補を確認してから、前節の手順で通常送信と定期実行を再開します。

snapshot 14の読み込み時は個人原因を空配列として移行し、列挙計画personalReminderCausePlanningをopen項目ではpending、原因がないterminal項目ではexcludedにします。旧AIの文章から個人義務や時刻を補填しません。初回は現在の収集結果から原因を組み立て、open項目の列挙が完了すれば0件でもcompletedと観測時刻を保存します。stale項目は前回値を維持します。 計画versionの変更や、必要性が残る未評価・失敗・延期で有効な採用値がない場合は、次回runで再取得・再評価します。terminalになった原因も終了を確認します。AI無効中は個人原因の再試行だけを理由に毎回取得しません。正常なunknownや有効な採用値がある失敗は、この再試行と縮退件数の対象に含めません。 snapshot、追加cache、通知管理記録の更新は同じcommitで保存します。保存済みのsentとacknowledgedは維持し、現在の原因との一致を証明できる通知keyはそのまま再利用します。既存のoverdue候補を個人原因へ対応付けられない場合、system通知として送信してはいけません。 ローカルのcommit作成とGitHubへの反映は別なので、pushが成立しなければ移行完了として扱いません。 反映前に失敗した場合は、日次停止を維持し、最新のremote headを取得して再試行します。 反映後にAI分析が失敗・延期した場合は、新形式のstateで再試行します。保存形式の移行をやり直す必要はありません。

移行後は、原則として新形式のまま修正します。 旧stateへ単純に戻すと、移行後の通知済み・確認済み記録を失うためです。 コードとstateを復旧用の保存点へ戻せるのは、以後の外部送信やstate更新を確認し、失われる記録がないか整合を取れた場合だけです。 履歴と保証対象の復旧用保存点に旧形式が残る間は、その形式を読み込む移行処理を削除しません。

現在の通知候補を一括で確認済みにする

通知条件を調整した直後など、現在の候補をDiscordへ送らず、通知済みと同様に扱いたい場合は、日次workflowの手動実行で通知処理をacknowledge-currentにします。

  1. default branchのActionsから「日次タスク追跡」のworkflowを開きます。
  2. backfillをnone、repository_filterを空、notification_actionをacknowledge-currentにして実行します。
  3. collect-analyze、persist-state、build-pages、deploy-pages、notify-discord、report-workflowが成功することを確認します。publish-notification-historyは候補がないため実行されません。

acknowledge-currentは現在の通知条件を満たす候補を、reasonごとに最大件数の制限なく、確認済みとして通知管理記録へ保存します。同じnotification keyは送信済みと同様に通知対象から除外します。すでに送信済みの同じkeyは送信日時とDiscord message IDを維持します。通常のDiscord digestは送信せず、notification_sent履歴も作りません。snapshotとPagesの生成は通常runと同じで、通知管理記録の更新は同じatomic transactionへ含まれます。運用障害が発生した場合のnotify-operationsは別系統で動作します。

成功確認では、tracker-stateの通知管理記録に未送信だった対象候補のstatus: acknowledgedが保存され、通知履歴に送信済み項目が追加されていないことを確認します。すでに送信済みだった同じkeyはstatus: sentのままです。state branchや通知管理記録を直接編集して確認済み状態を解除してはいけません。

sentとacknowledgedの同じnotification keyは期限なく通知対象から除外します。 個人通知は同じkeyの記録を照合します。意味入力や表示文だけの変化ではkeyを変えませんが、進捗や待機解消で起点が変われば現在の閾値で選び直します。 systemの時間系通知と待ち先不明の通知は、同じ待ち期間・通知理由・停滞レベルの送信済みまたは確認済み記録も照合します。進捗で停滞起点が変わっても、同じ待ち期間の同じ通知は再送しません。 待つ行動や相手の変更、同じレビュワーへの新しいレビュー依頼、停滞レベルの上昇は新たな通知候補になります。依存解消や循環検出などは、それぞれの変化に応じた選別を行います。 確認済みにする操作は、実行時点で通知条件を満たす候補だけを対象にします。まだ基準時間に達していない項目の将来の通知は抑制しません。

分析が延期された項目から、後日のrunで新たな通知候補が生じることがあります。 判定結果の確認中に候補を失わず保留する場合はholdを使います。 acknowledge-currentは本来送るべき通知も確認済みにするため、一時的な送信停止には使いません。

通常のsendは、maxItemsPerDigestを含む既存の通知選別を行います。 件数上限で送れなかった候補は、検出日時と通知理由を通知管理記録のpendingNotificationsへ保存します。次回以降の集計では、保存した理由が現在も有効な候補を通知対象に戻し、その時点の停滞レベルと優先順位で選別します。新しい候補が増え続ける場合、優先順位の低い候補は引き続き送信を待ちます。

持ち越した責務移動の通知は、移動先の待ち相手が変わったら破棄します。たとえばAからBへの移動を通知する前にCへ移った場合、Bへの移動は通知しません。BからCへの移動は、その変化自体が通知条件を満たす場合に新しい候補になります。依存解消の候補は再び依存待ちになったら破棄し、停滞の候補は進捗や状態が変わったら見直します。収集に失敗したリポジトリの候補は送信せずに保持し、次に収集できたときに有効性を確認します。送信済みまたは確認済みになった候補は持ち越し対象から除きます。

依存循環の通知候補は、グラフで新しく検出した循環から作ります。同じ循環が続いている間は同じ通知として扱い、一度解消してから再発した場合は新しい通知にします。

停滞レベルはDiscord通知の判断にだけ使います。 通知選別は停滞レベルの変化、長期停滞、責務移動、重要な依存解消、dependency cycleを優先します。 直近に意味のある進捗がある項目、botだけの活動、recent draft、低信頼のAI判定、labelで抑制した項目は通常通知から外します。 botが作成した項目のtitleがnotifications.automationNoiseTitlesのいずれかと大文字小文字を区別せず一致した場合、graphへ残したまま通常通知から外します。 RenovateのdependencyDashboardTitleを変更した場合は同じtitleをこの一覧へ追加します。

特定の状態だけ通知時刻を調整する場合は、対応するstaleness.thresholdsHoursのキーを変更します。 各キーのwatchは要対応度の半減期にも使うため、変更するとWebの要対応度と並び順も変わります。 urgentとcriticalは通知判断だけに使います。

状態 キー
内容確認待ち assessment
担当決め待ち、待ち先不明 owner
方針判断待ち decision
レビュー待ち review
CHANGES_REQUESTED後の修正待ち revision
作業待ち、作業中、CI失敗やconflictによる修正待ち work
返答待ち reply
マージ待ち merge
自動処理待ち automation

ブロック解消待ちには直接の閾値がありません。 blockerの停滞レベルとdownstream impactが通知順位を決めます。 ブロック中にも実行可能な独立した個人対応は、その行動の閾値で判定します。原因のobligationSinceは責務発生、actionableSinceは実行可能性の起点で、実際の通知時刻は有効な進捗を反映したstallSinceから計算します。 イベント時刻が取得できない原因は、最初に責務や実行可能性を確認できたsnapshotの観測時刻をfirst_observationとして保持します。AI評価のたびに起点が更新されていないことを確認してください。

通知が多すぎる場合は次の順で調整します。

  1. 個人通知では原因の相手、行動、実行可能性、停滞起点を確認し、その根拠となる依頼・進捗・依存をGitHub上で明確にします。system通知では項目全体のstatus、waitingOn、理由固有の変化を確認します。 実質担当の誤判定は、Issue全体を担当する宣言、追跡中でGitHubが認識したclosing reference、継続成果物を明記するか、部分対応、reviewのみ、撤回、延期、引継ぎであることを最新コメントへ明記して直します。
  2. automation dashboardのtitleをnotifications.automationNoiseTitlesへ追加するか、対象labelへlabels.rules.effects.suppressNotificationsを割り当てます。
  3. 通知を減らす状態に対応するstaleness.thresholdsHoursを増やします。
  4. 全状態で直近の進捗を長く猶予する場合はrecentProgressGraceHoursを増やします。
  5. maxItemsPerDigestを減らします。
  6. 汎用AIの低信頼な推定が原因ならai.confidence.mediumを上げ、実モデルを呼び出すdry-runでAI判定と通知候補の差分を確認します。個人原因では、まず義務と実行可能性の根拠がそろっているかを確認します。

通知が少なすぎる場合は逆方向に調整します。

  1. maintainer設定、userかteamの指定、review request、native dependency、label規則が実態に合うか確認します。個人通知では現在対応がwaiting・unknownになっていないか、入力変更後の意味評価や前段の関係評価が延期されていないかも確認します。
  2. 通知を増やす状態に対応するstaleness.thresholdsHoursを減らします。
  3. 全状態で直近の進捗を短く猶予する場合はrecentProgressGraceHoursを減らします。
  4. maxItemsPerDigestを増やします。
  5. 重要labelへpriorityWeightかseverityLift: 1を設定します。
  6. AI予算不足ならai.budgetを増やし、dry-runのmetrics.aiCallCount、metrics.estimatedInputTokens、deferred項目と個人原因、通知候補を確認します。前段の関係評価だけで予算を使い切っていないかも確認します。

閾値、confidence、label規則、AI予算を変更する場合は、dry-runを実行して通知候補の差分を確認します。 model、reasoning effort、promptを変更する場合は、metrics.aiCallCountが1以上になるdry-runでAI判定と通知候補の差分を確認します。 ai.execution.maxConcurrentCallsを上げるとrun時間は縮みますが、Codexのrate limitに当たる頻度が増えて再試行が発生しやすくなります。 上げた後はcodex_analysis stageの失敗数と再試行数を確認します。 mentionは通知量の調整に使わず、運用上必要なuserだけをallowlistへ追加します。

障害時の確認

失敗したActions jobをworkflow全体のreportにあるjobsと照合し、収集失敗ではCLI reportのfailedStageも確認します。

詳細なエラーを確認する

run reportのdiagnosticsは公開可能な要約です。 スタックトレースやCodex processの出力が必要な場合は、失敗したjobに対応するdaily-diagnostics-<run ID>-<試行番号>-<job名>artifactを取得します。 artifactには暗号化済みの.bundleファイルだけが入り、保持期間は7日です。

依存関係を導入してCLIをビルドした後、登録時と同じ鍵ファイルで復号します。 出力先に既存ファイルがある場合は上書きしません。

pnpm install --frozen-lockfile
pnpm build
node dist/cli/tracker-run.js diagnostics decrypt \
  --key-file path/to/diagnostics-key.b64 \
  --input path/to/voicevox-task-tracker-diagnostics-collect-analyze.bundle \
  --output path/to/diagnostics.jsonl

復号したJSONLには、例外のstack、cause、AggregateErrorの各error、Codexの試行番号、終了状態、標準出力、標準エラー出力、最終応答が記録されます。 汎用AIはsemanticGenerationが生成世代、attemptがその世代内のtransport試行番号です。standardInputCharactersは補正envelopeを含む入力文字数であり、論理入力予算へ含まれない増分も確認できます。 認証preflightはcodex.authentication_preflight.attempt.startedとcodex.authentication_preflight.attempt.completedで開始と終了を確認できます。標準出力、標準エラー出力、stackも暗号化診断にだけ記録し、公開run reportへraw出力を載せません。preflight失敗runでは通常metricsは完成しません。 内容は公開用に無害化していないため、調査はローカルで行い、そのまま公開IssueやPull Requestへ貼り付けないでください。 CLIが起動する前に失敗した場合や暗号化処理自体が失敗した場合は、対応するartifactが作られないことがあります。

stageまたはjob 確認内容
quality Actionsの失敗stepと診断を確認し、必要なら対象箇所だけをローカルで再現する
configuration maintainerのGitHubユーザー名一覧、repository名、未知field、日時、正規表現、secret名を確認する
authentication GH_APP_ID、PEM形式、Organizationへのinstallation、必要なread権限だけがあることを確認する
repository_inventory Appのrepository access、public、archive、disabledの状態を確認する
incremental_collection GitHub API残量、429と503、対象repositoryの一時障害を確認する
codex_analysis codex executable、model ID、reasoning effort、予算、timeout、同時実行数、ai.authenticationを確認し、auth-jsonではCODEX_HOME直下のauth.json、api-keyではOPENAI_API_KEYを確認する
state_persistence Actionsのcontents: write、tracker-stateのruleset、同時runがないことを確認する
build-pages Pages DTO、web.basePath、Web build、公開guardの診断を確認する
deploy-pages Pages Source、github-pages environment、pages: writeとid-token: writeを確認する
publish-notification-history 通知後のstate取得、通知履歴を含むPages DTO、再deployの診断を確認する
discordまたはnotify-discord enabled設定、Webhook secret、channel、Webhook失効、429と503を確認する

incremental_collectionがerrorType=CliRelationExpansionLimitErrorで失敗した場合は、同じ診断行のrelationExpansionLimit、relationExpansionFetchedCount、relationExpansionUnfetchedCountを確認します。 件数が想定より多いときは、GitHub上の誤ったnative relationや参照を直します。 妥当な件数なら、GitHub API残量とoperations.githubApiBudgetRatioを確認したうえでtracking.relationExpansion.maxItemsPerRunを引き上げ、backfill: noneで再実行します。 この失敗ではstate、Pages、通常のDiscord通知を更新しません。

収集の診断に「端点を取得できなかった関係候補を除外しました」が出る場合は、archive済みrepositoryやOrganization外の参照先など、公開境界の外にある関係先が残っています。 run自体は成功し、除外した関係候補は依存グラフへ載りません。

Actions上でCodexの認証エラーが起きた場合は、まず過去のcollect-analyzeでCodex認証の書き戻しstepが失敗していないか確認します。 書き戻しが失敗していたときは、CODEX_AUTH_SYNC_TOKENの登録、tokenの有効期限、Organizationの承認、対象repositoryとSecretsのRead and write権限を確認して直し、backfill: noneで再実行します。 保存済みのCodex認証をrefreshできず、再実行でも回復しない場合だけローカルのCodexへログインし直します。 デプロイ手順のコマンドで、新しいauth.jsonをCODEX_AUTH_JSONの初期値として登録します。

fallbackはAI分析に失敗または延期した項目を決定論的判定と利用可能な前回結果へ縮退した完全runです。個人原因も、有効な採用値がない失敗・延期が残る場合に含まれます。 汎用AIの対象は項目一覧を未検証値・分析失敗・未実行で絞り込み、各行の警告マークと詳細の局所的な警告マークで特定します。この絞り込みには未検証の表示値や現在対応に加え、runStatusがfailedまたはdeferredの項目も含まれます。run reportのcodex_fallbackとcodex_deferred、およびvalidationIssue0Codeから原因を追います。 semantic補正の上限に達した場合、codex_fallbackには最後の世代のsemantic違反が残ります。unknown_native_relationのような入力の不整合、schema検証失敗、process失敗、alias変換失敗、canonical検証失敗はsemantic補正の対象外なので、補正上限を増やしても解消しません。alias変換失敗は項目ごとの縮退にせず、run全体を停止します。 個人原因は現在対応のunknownとrun reportの専用件数を確認し、正常な未確定判定か実行失敗・延期かを区別します。未確定の原因には個人催促を送らず、項目全体の判定とsystem通知はそれぞれの規則で確認します。 metrics.aiCacheHitCountが0でもmetrics.aiRetainedResultCountが1以上なら、未変更項目のAI結果はAI分析対象へ入れず保持されています。 failedまたはdeferredの対象項目は次回runで詳細取得とAI分析へ再び含まれるため、原因を直せば手動再実行なしで解消します。それ以外の未検証値は、詳細の警告説明と保存済みの適用元を照合します。 failureがstate_persistenceより前ならstateは更新されません。 pagesかdiscordで失敗した場合はstate commit後の可能性があるため、snapshotのrun IDとPagesの生成時刻を比較し、両者が同じrunか確認します。 初回Pages deployに失敗した場合は最後に成功したPagesを基準にし、Discordを送信しません。通知後のpublish-notification-historyに失敗した場合も最後に成功したPagesを基準にし、通知自体は重複送信しません。 state commit後のPages失敗は想定内であり、stateを巻き戻しません。

公開guardが失敗した場合は安全設定を無効化しません。 どの入力にallowlist外repository、private sentinel、secretらしい値、長すぎる全文、安全でないURLが入ったかを、secretをlogへ出さずに調べます。 原因を除いた後にbackfill: noneで手動再実行します。

同じrunを再実行してもworkflow concurrencyと通知管理記録が競合と通常通知の重複を抑えます。 GitHubとCodexの429と503は設定した回数だけretryし、それでも失敗する場合は外部サービスの回復後に再実行します。Discordが自動retryするのは429だけです。通信例外、5xx、応答不正の場合は、送信結果が不明な通知の確認手順に従います。