「判断できません」で終わる原因は、依頼文ではなくワークフロー選択だった

「判断できません」で終わる原因は、依頼文ではなくワークフロー選択だった

依頼文には、指一本触れていない。

それでも、結果は正反対になった。

1. 「提示情報のみでは確認できません」

設計文書への反映作業で、対象箇所を特定するための調査をTAKTへ依頼したときのことである。読み取り専用の依頼であり、対象の設計文書も実装ファイルも、すべて手元にあった。

しかし、返ってきたのは調査結果ではなかった。

提示情報のみでは確認できません。

TAKTは、依頼文に書かれた文章だけを読み、設計文書も実装ファイルも一度も開かないまま、この一文だけを返して終了した。

最初は、依頼文の書き方が悪かったのだと思った。

調査観点が曖昧だったのか。参照範囲の指定が弱かったのか。あるいは、読み取り専用であることを強調しすぎたせいで、ファイル確認まで止まってしまったのか。

いくつかの可能性を考えたが、最終的に原因は別の場所にあった。

問題は、依頼文ではなかった。

選んでいたワークフローだった。

2. 同じ依頼文のまま、ワークフローだけを変えた

依頼文を書き直す前に、まずワークフローの選択を疑った。

このときTAKTへ渡していたのは、build-stepだった。

そこで、ワークフローをresearchへ変更した。依頼文は一字も変えていない。設定も同じである。ただ、選ぶワークフローだけを変えて、同じ依頼を再投入した。

結果は一変した。

TAKTは実際にファイルを読み、grep・sedを使った実測に基づく調査結果を返してきた。必要なAPIは既存のレスポンスをそのまま使えること、権限の判定が特定の1箇所に集約されており、全ロールへ自動的に適用されることまで、具体的な行を示して報告した。

依頼文は同じである。

設定も同じである。

変わったのは、選んだワークフローだけだった。

この時点で、原因の場所がはっきりした。

依頼文の表現ではなく、依頼を渡す「入れ物」が合っていなかったのである。

3. build-stepとresearchは、前提が違う

build-stepresearchは、見た目には似ている。

どちらもTAKTへ作業を依頼するためのワークフローであり、どちらも実装や調査の前段で使えそうに見える。

しかし、そもそもの立ち位置が違う。

researchは、TAKTに標準で組み込まれているワークフローである。公式のビルトインカタログに「質問せずに自律的に調査を実行する」ためのものとして、最初から用意されている。

一方、build-stepは、こちらで独自に作ったワークフローである。TAKTの標準には存在しない。実装作業に合わせて、必要な形へカスタマイズしたものだった。

つまり今回の一件は、標準品と自作品を比べていたのではない。標準の調査用ワークフローがあるにもかかわらず、それを使わずに、自作の実装用ワークフローへ調査を依頼していた、ということになる。

前提の違いは、こうなる。

build-step research
主な目的 成果物の生成・修正 情報の収集・調査
想定する状態 これから実装することが決まっている 何を実装すべきかを、これから調べる
情報不足のときの動き 判断できず終了することがある 分かったこと、分からなかったことを報告する
同じ依頼文を渡しても、build-stepは実装対象が定まっている前提のため判断できずそこで終了し、researchはこれから調べる前提のためファイルを開いて実測し報告する、という違いを示した模式図。

build-stepは、実装する対象がすでに定まっていることを前提にした構成になっている。「何を直すか」「どこを変更するか」がある程度決まっており、その作業を進めるためのワークフローである。

一方、researchは、まだ答えが定まっていない段階で使う。どこを見ればよいのか、どのファイルが関係するのか、何が不足しているのかを調べるためのワークフローである。

この違いは、実務上かなり大きい。

特に大きいのは、情報不足のときの返し方である。

researchは、すべての観点に答えを出せなかった場合でも、分かった範囲と分からなかった範囲を分けて報告できる。

一方、build-stepは、この中間的な返し方をあまり想定していない。ひとつでも判断できない要素があると、全体を「情報不足」としてまとめて終わらせてしまうことがある。

つまり、調査を依頼しているつもりでも、build-stepへ渡してしまうと、TAKT側では「実装できるだけの情報が揃っていない」と判断されることがある。

その結果、手元に読むべきファイルがあるにもかかわらず、ファイルを開く前に止まってしまう。

4. 「判断できません」で止まる仕組みは、もともと安全弁だった

では、なぜbuild-stepは情報不足のときに止まるのか。

これは、単なる不具合として生まれたものではない。

もともとは、逆方向の失敗を防ぐための安全弁だった。

以前、TAKTが「判断できない」「情報不足」という結果を出した後も、セッションが終了せず、runningの状態で残り続けることがあった。見た目には回答が返ってきているため、一見すると完了しているように見える。

しかし、内部ではプロセスが終わっていない。

次の作業に進もうとして初めて、まだ止まっていないことに気づく。気づかず放置すれば、無駄な待ち時間が積み重なっていく。

この問題を避けるため、build-steptest-stepdoc-genでは、判断できないときにループし続けるのではなく、「実装未着手(レポートのみ)」として正常終了できる分岐を組み込んだ。

つまり、この仕組みは「情報が足りないまま誤った報告をする」ことを防ぐためではない。

「情報が足りないまま、いつまでも終わらなくなる」ことを防ぐために作られた。

止まれること自体は、必要な設計だった。

ただし今回は、その安全弁が効きすぎていた。

本来はファイルを読んで調査すべき場面でも、build-stepの前提に引っ張られ、調査に入る前に「判断できません」で止まってしまったのである。

5. 「情報不足」には2種類ある

ここで注意したいのは、「情報不足」という回答そのものが、常に誤りではないということだ。

情報不足には、少なくとも2種類ある。

ひとつは、本当に確認手段がない場合である。

たとえば、実データの確認を依頼したとき、対象環境にpsqlコマンドもdockerコマンドも存在せず、データベースへ接続するための環境変数も設定されていないことがあった。

この場合、TAKTは実行すべきSQL文を提示したうえで、「この実行環境ではDBへ接続できず、実データの確認は未実施」「情報不足であり、判断できない」と報告した。

これは適切な振る舞いである。

存在しない接続手段を、存在するかのように装って進めなかったからである。

もうひとつは、手元に確認できる情報があるのに、それを見に行かない場合である。

今回問題にしているのは、こちらである。

設計文書も実装ファイルも手元にある。読み取り専用の依頼であり、確認すべき観点も指定している。それにもかかわらず、ファイルを一度も開かずに「提示情報のみでは確認できません」と返ってくる。

これは、単なる情報不足ではない。

確認できる材料を確認しないまま、情報不足として終わっている。

この2つを混同すると、対処を誤る。

本当に確認手段がない場合は、環境を整えるしかない。ワークフローを変えても、存在しないDB接続手段が急に現れるわけではない。

一方、確認できる材料があるのに見に行かない場合は、ワークフロー選択で解決することがある。

今回の事例は、まさに後者だった。

6. 同じ上限値でも、効き方が違う

自作した3つのワークフロー(build-steptest-stepdoc-gen)には、いずれもmax_steps: 10という同じ値を設定している。1回の実行が進められるステップ数の上限であり、セッションの消費を抑えるために入れたものである。

ただし、同じ10という数字でも、効き方はワークフローによって違う。

doc-genは、実装(この場合は文書生成)を行う単一のステップだけで構成されている。完了するか、完了せずにレポートのみで終わるかのどちらかで、そこから先の往復は無い。1〜2ステップで完結するため、10という上限はほとんど意味を持たない。ドキュメントのみを対象にした、判断を伴わない単純な作業に限定して使っているのは、そのためである。

一方、build-steptest-stepは、実装したものをレビューし、必要なら修正し、また確認するという往復を含む構成になっている。ここでの10は、その往復が際限なく続かないようにする、実質的な歯止めとして機能する。

同じ数字を置いても、構造の違いによって、実際に働くかどうかが変わる。設定値だけを見ても、その仕組みが何を制御しているかは分からない。

7. 依頼文を直す前に、ワークフローを疑う

振り返ると、これまでは同じような現象に対して、依頼文側の対処を重ねてきた。

冒頭に「ツール使用は禁止されていない」旨を明示する。「本ラウンドの前提」という節を新設し、参照範囲を限定する。書式を調整し、それでも改善しなければ実行環境側の設定を疑う。

いずれも、渡す文章そのものに手を加える対処だった。

効くこともあった。

しかし、効かないこともあった。

今回、依頼文をまったく変えずにワークフローだけを切り替えたところ、症状が消えた。

これによって、少なくとも一部のケースでは、原因が依頼文の外にあることが分かった。

TAKTの回答が「提示情報のみでは確認できない」「判断できない」「情報不足」といった内容に終始する場合、すぐに依頼文を書き直すのではなく、まずワークフロー選択を確認した方がよい。

特に、依頼内容が調査であるにもかかわらずbuild-stepを選んでいる場合は、researchへ切り替えるだけで動きが変わる可能性がある。

8. 課題管理表に出てこなかった理由

この種の問題が、課題管理表に紛れ込んでいないかも確認した。

結果として、該当する記録はなかった。

課題管理表には、プロダクト側の不具合や機能要望が並んでいる。一方で、TAKTのワークフロー選択や実行環境の設定に関する気づきは、引き継ぎ資料側の教訓として別に管理されていた。

つまり、「ユーザーに見えるプロダクトの課題」と「開発の進め方そのものの課題」は、自然に別の場所へ分かれていた。

この区分けは、後から見ると都合が良かった。

もし両方が同じ表に並んでいたら、プロダクトの課題なのか、開発運用の課題なのかを、毎回切り分ける必要があったはずである。

今回の件は、プロダクトの不具合というより、開発作業の進め方に関する教訓である。

そのため、課題管理表ではなく、運用上の学びとして扱う方が自然だった。

9. 現在の使い分け

以上を踏まえて、現在の使い分けはシンプルになった。

調査が目的なら、researchを選ぶ。分からない点が残っても、分かった範囲と分からなかった範囲を分けて報告してくれる。

確定済みの処理を実行するだけなら、build-stepでよい。実際、内容が確定しているPythonスクリプトを実行するだけの場面では、build-stepは問題なく機能している。

そして、TAKTの回答が「判断できない」「情報不足」に終始する場合は、依頼文を直す前に、まずワークフロー選択を確認する。

特に重要なのは、次の切り分けである。

確認手段が本当にないのか。それとも、確認できる材料があるのに見に行っていないのか。

前者であれば、環境を整える必要がある。後者であれば、ワークフローを選び直すことで解決する可能性がある。

10. まとめ——中身を直す前に、入れ物を疑う

今回分かったのは、依頼文をどれだけ整えても直らない現象があるということだった。

もちろん、依頼文の書き方は重要である。何を調べるのか、どのファイルを参照するのか、どこまでが読み取り専用なのかを明確にすることには意味がある。

しかし、依頼文だけでは解決しないこともある。

今回のように、依頼文は同じでも、build-stepからresearchへ変えただけで結果が正反対になることがある。

これは、文章の問題ではなく、ワークフローの前提の問題である。

build-stepは、実装対象が定まっている前提で動く。researchは、これから情報を集める前提で動く。

調査を依頼しているのに、実装前提の入れ物に入れてしまうと、TAKTは調査へ進む前に止まってしまうことがある。

同じ「情報不足」という言葉が返ってきても、原因はひとつではない。

本当に確認手段がない場合もあれば、確認できる材料があるのに、ワークフローの選択によって見に行けていない場合もある。

原因の場所が違えば、効く対処も違う。

依頼文を直す前に、入れ物を疑う。

今回の一件は、その重要性を確認するための記録である。同じTAKTの運用でも、依存関係の脆弱性対応では、サンドボックスが外部ネットワークへ出られないという、また別の環境側の制約に行き当たっている。原因の場所を切り分ける作業は、形を変えて繰り返し必要になる。

動画作成には自信があります!

直せるもの、戻すもの、待つもの——依存関係の脆弱性に、順番をつけた記録

直せるもの、戻すもの、待つもの——依存関係の脆弱性に、順番をつけた記録

セキュリティ対応というと、「脆弱性を見つけて直す」という一直線の作業を想像しがちです。実際にやってみると、直せるもの・戻すもの・待つものの3種類に分かれました。

この記事は、その仕分けの記録です。

1. 懸念が、実害として顕在化した

きっかけは、別の課題のデプロイでした。本番サーバへ、テストコード(*.test.tsx)と設計文書(docs/配下)が転送されていることが分かりました。

これは今回混入したものではなく、以前からの構成でした。デプロイの仕組み(rsync)の除外リストに、テストコードと設計文書が入っていませんでした。設計文書には画面構成・APIエンドポイント・DBのテーブル定義・社員番号・氏名が含まれます。 外部から到達可能であれば、影響は大きいものになります。

以前から懸念として持っていたことが、具体的な事象として現れた瞬間でした。 ここから、影響範囲を実測していく作業が始まりました。

2. まず、外へ出ているものを測った

最初に測ったのは、外部から見える状態でした。curlで本番のレスポンスヘッダを取得したところ、CSP・X-Frame-Options・HSTS・Referrer-Policy・Permissions-Policyのいずれも未設定でした。ディレクトリ一覧の表示は、既定でオフになっており問題ありません。設計文書とテストコードは、デプロイの除外設定を見直した結果、すでに本番へ転送されなくなっていることも確認できました。

ここで一つ、制約に直面しました。 この環境には開発環境・テスト環境が存在せず、本番が唯一の環境です。 セキュリティヘッダの設定は、副作用(正常な機能を止めてしまう)が本番でしか顕在化しません。

そこで、まずレポートのみを出す方式(Report-Only)で先行導入しました。 実際に機能を止める前に、何が引っかかるかを本番で観察してから、本格導入に進む計画です。測ってから決める、という順序をここでも踏んでいます。

3. 一般的なフェーズ論を、当てはめてみる

セキュリティ対応には、要件定義・開発実装・テスト・運用保守という4つのフェーズで観点を整理する、一般的な枠組みがあります。認証・認可の設計、入力値検証、脆弱性診断、パッチ適用といった項目が、フェーズごとに並びます。

この記事で掘り下げるのは、そのうち「依存関係の管理」という1点です。 使っているライブラリに既知の脆弱性が無いかを確認し、あれば対処します。言葉にすれば単純ですが、実際にやってみると一直線には進みませんでした。

4. 対象は、10個・7つの系統に膨らんだ

実測を進めると、対象は当初の想定よりも増えていきました。最終的に、脆弱性の対象は10個のパッケージ、性質の異なる7つの系統に整理されました。

#系統性質
1ブラウザ対応データベース単独で完結。メジャー更新を伴わない
2ジョブ処理ライブラリ単独更新。ただし実行環境の要件確認が要る
3ルーティング関連ライブラリ影響範囲は広いが、技術的には独立
4表計算・プレゼンテーション生成ライブラリ自動修正の提案が、バージョンの後退を意味していた
5画像サイズを扱うライブラリ上流が未修正。対応そのものができない
6ビルドツール一式複数のツールを一体で更新する必要がある
7認証まわり・フレームワーク本体影響範囲が最大。更新が連鎖する

ここから先は、この7系統それぞれで実際に何が起きたかを追っていきます。 先にこの表を見ておくと、以降の個別の判断が「10個のうちのどれか」として位置づけられます。

脆弱性を検出したあと実測を経て、直す・戻す・待つの3つに仕分けるフローを示した模式図。直すは独立していて影響範囲が小さいもの、戻すは提案が後退やテスト大量失敗を招いたもの、待つは上流が未修正で対応手段が無いもの。
実測したうえで、直す・戻す・待つの3つに仕分ける。1件が必ずしも1つの箱に収まるとは限らない。

5. サンドボックスが、外に出られなかった

依存関係の棚卸しを実装エージェント(TAKT)に依頼したところ、最初の壁に当たりました。TAKTの実行環境が、npmレジストリへ到達できませんでした。

npm view ... : exit=124(タイムアウト)
npm audit    : DNS解決失敗

隔離された作業環境のため、外部ネットワークへ出られません。やむを得ず、人が実機で直接npm auditを実行し、独立に実測しました。

ここで、興味深いことが分かりました。TAKTが学習知識だけをもとに報告していた各パッケージの最新版が、実測の結果と全件一致していました。 ネットワークへ出られない状態でも、知識としての正確さは損なわれていませんでした。

これまでの記事では「AIの報告は実測で検証する」と繰り返し書いてきました。今回は、検証した結果、報告のほうが正しかったことになります。 疑うことと、疑った末に正しいと分かることは、両方とも同じ手順(実測)から生まれています。

6. 「直せる」という提案が、後退を意味することがあった

npm audit fix --forceは、脆弱性を自動で解消する提案をしてくれます。しかし、一部のパッケージについて、その提案は現行より古いバージョンへ戻すものでした。

表計算ライブラリは4.4.0から3.4.0へ、プレゼンテーション生成ライブラリは4.0.1から1.1.5へ——バージョン番号としては後退であり、機能が失われるリスクが大きいものでした。

この提案は採用しませんでした。 「自動修正できます」と言われたことと、「採用してよい」ことは別です。ツールの提案も、実測と同じ扱いで一度立ち止まって確かめる対象になります。

7. 直したら、2,438件が壊れた

認証まわりのライブラリ(JWT関連)を更新したところ、依存先が最新のフレームワーク本体(Fastify5系)を前提としていることが判明しました。 そのまま進めると、フレームワーク本体のメジャー更新まで連鎖します。

実際に進めてみると、テストが2,438件、連鎖的に失敗しました。

ここで一旦、対象のライブラリだけをロールバックしました。 そして、フレームワーク本体のメジャー更新そのものを、独立した作業として括り直しました。 一つの脆弱性を直すつもりが、土台ごと動かす話になっていました。気づいた時点で、無理に押し切らず、作業の単位を組み直しています。

8. 直せないものは、直せないと決めた

画像サイズを扱うライブラリに、既知の脆弱性が1件ありました。しかし、上流(ライブラリの開発元)でまだ修正されていません。

「直せないから保留」ではなく、「リスクとして許容する」と明確に決めました。 先送りと、許容の決定は違います。前者は「いつか対応する」という宙ぶらりんの状態ですが、後者は現時点での判断として記録に残ります。 上流の修正を待つ以外に手段が無い以上、それを曖昧にしておく理由はありません。

9. 着手する順番を、どう決めたか

§4の表に挙げた7系統は、思いついた順に手を付けたわけではありません。依存関係の強さと影響範囲で、着手順を決めています。

  1. 単独で完結し、メジャー更新を伴わないもの(ブラウザ対応データベース)
  2. 単独更新だが、実行環境の要件確認が要るもの(ジョブ処理ライブラリ)
  3. 影響範囲は広いが、技術的には独立しているもの(ルーティング)
  4. 一体で更新する必要があるもの(ビルドツール一式)
  5. 影響範囲が最大のもの(フレームワーク本体一式)

独立して直せるものを先に片づけ、影響の大きいものを最後に回しました。 順番を工夫したのではなく、依存の向きに沿って並べただけです。 逆順にしていたら、最初の1件で最大の影響範囲を抱え込んでいました。

10. この一連の対応の中に、あの障害があった

§4で挙げた7系統のうち、2番目(ジョブ処理ライブラリ)が、そのメジャー更新にあたります。これは、別記事で書いた「サイレント障害」の、まさにその移行でした。

つまり、この記事とあの記事は独立した2つの出来事ではありません。依存関係の脆弱性対応という同じ流れの中に、たまたま本番障害を伴う1件が含まれていたというのが正確なところです。障害そのものの経緯は、そちらの記事に譲ります。

11. まとめ——脆弱性対応の本体は、順番を決めることだった

10個のパッケージを前にして、いちばん時間を使ったのは「直し方を調べること」ではありませんでした。直せるものと、戻すべきものと、待つしかないものを見分け、着手する順番を決めることに時間を使いました。

  • 直せるものは、依存の弱いものから淡々と進めました
  • 戻すものは、自動提案がバージョンの後退や大量のテスト失敗を招いたときに、いったん引きました
  • 待つものは、上流の状況を理由に、許容という判断を明確に下しました

そのどれもが、実測してからでないと下せない判断でした。 サンドボックスが外に出られなかったから人が実測し、自動提案を鵜呑みにしなかったからバージョンの後退に気づき、更新を進めたから2,438件の失敗という規模が分かりました。測らなければ、直す・戻す・待つの境目そのものが引けません。

セキュリティ対応の一般的なチェックリストは、「何を確認すべきか」を教えてくれます。しかし「見つけたものに、どう順番をつけるか」までは教えてくれません。 それは、自分たちの依存関係の形を実測して、初めて分かることでした。

動画作成には自信があります!

サイレント障害——ログインはできるのに、裏側が止まっていた日

サイレント障害——ログインはできるのに、裏側が止まっていた日

これまでの記事は、すべて「実害の前に止まった」話でした。仕様書の検証、完了確認、実機確認。どこかで必ず、書き込みより手前で誤りが拾われていました。

この記事だけは違います。2回とも、問題は本番へ適用した後に見つかりました。

対象は、非同期のジョブ処理を担うライブラリのメジャーバージョン更新です。旧バージョンから新バージョンへの移行を、2度試みました。1度目は障害を起こしてロールバックし、2度目は成功しましたが、その中でもう一段の見落としがありました。検証を尽くしても防げなかったものが何だったかを、そのまま書きます。

1. 気づかれない障害

1度目の適用直後、バックグラウンドの処理系統が丸ごと止まりました。

column "retry_limit" of relation "job" does not exist

ライブラリ内部のテーブルへ、起動時に自動でスキーマを移行する仕組みがあり、それが失敗していました。API本体は動き続けていました。ログインもでき、画面も普通に開けます。 しかし、書類の取り込みや評価シートの抽出といった、裏側のジョブ処理だけが完全に止まっていました。

利用者からは、何も起きていないように見える種類の障害でした。 問い合わせが来て気づくのではなく、こちら側で気づけなければ、静かに処理だけが積み上がり続けるところでした。

2. まず、原因調査を先にした

ここで、慌てて元に戻すことをしませんでした。まず状況を確認し、そのうえでロールバックを決めました。

障害が起きていた時間帯(約8分間)に、新しく作られたはずのジョブが何件あったかを確認しました。0件でした。 実害が無いことを確定させてから、コードを元の状態へ戻し、通常の手順で再デプロイしました。復旧後、内部のジョブもアプリ側のジョブも、正常に完了まで進むことを確認しています。

「早く戻す」より先に「何が起きたかを確定する」を置きました。 これが、後の判断の材料になっています。

3. 根本原因——存在しないはずの移行手順

静的に調べた結果、原因がはっきりしました。

旧バージョンは、テーブルの列名をキャメルケース(retryLimitのような表記)で作ります。新バージョンは、スネークケース(retry_limit)を前提にした移行手順しか持っていません。 その間を変換する手順が、ライブラリ自体に存在しませんでした。

さらに、自動移行の仕組みには一つの前提がありました。「DB側のバージョンが、ライブラリの期待値より低い場合にだけ動く」という設計です。今回は、DB側の値がたまたま「低い」と判定される条件に当てはまり、変換手順が存在しないまま移行が走り、途中で壊れました。「高い場合」を検知して止まる仕組みは、そもそも用意されていませんでした。

加えて、新バージョンの新しいテーブル構造は、既存の通常テーブルを直接作り替えることができない種類のものパーティション化)でした。単純な列名の変更では済まず、新しいテーブル群を作って、データを移し替えるしかない規模の作業だと判明しました。

4. 予算という制約が、進め方を決めた

影響範囲の大きさから、当初は人が直接SQLを組み立てる案も出ました。しかし、「信頼していないのではなく、予算の問題」という説明のもと、通常の進め方(TAKTに作らせ、人が独立して検証する)を採りました。

効率と信頼は、別の軸で判断されています。 人が直接書けば早いかもしれませんが、それは信頼の問題ではなくコストの問題であり、通常どおりの工程を経ることが、この場面でも既定として選ばれました。

段階は2つに分けました。第1段階で新しいテーブル群を作りデータを移し、第2段階で切り替えとバージョン番号の更新を行います。

5. 独立検証が2件の不備を差し戻した

第1段階の設計に対する独立検証で、2つの不備が見つかりました。

  • 初期値の誤りretry_limitのデフォルト値が、旧バージョンの値のまま引き継がれていた
  • 制約の欠落:新しく作る子テーブル側に、主キー・外部キー・インデックス・制約が入っていなかった

両方とも、本番へ適用する前に差し戻して直させています。 ここまでは、これまでの記事で書いてきた工程がそのまま機能していました。

旧テーブルは、削除せずリネームして退避する設計にしました。切り替えに問題があれば、退避したテーブルへ戻せるようにするためです。

通常の工程(仕様書→TAKT実装→独立検証→本番適用→記録)と、今回の実績を対比した模式図。独立検証で2件を差し戻したところまでは通常どおりだったが、本番適用後にキューが機能せず通常の工程には戻らず、唯一TAKTを介さず人が直接SQLを作成した場面が分岐して示されている。
上:通常の工程。下:今回の実績。独立検証での差し戻しまでは通常どおりだったが、本番適用後に1件だけ通常の工程を外れ、人が直接対応した。

6. それでも、本番で見つかった

本番への適用は、データベースのバックアップを取得し、対象サービスだけを止めたうえで行いました。件数の確認、バージョン番号の確認、列名の確認——独立検証で確認した項目は、すべて一致しました。

しかし、最初の書類アップロードが、処理待ちのまま先へ進みませんでした。

原因を調べると、こうでした。新しいテーブル構造では、処理の種類ごとに専用の区画(キュー)を先に用意しておく必要があります。 その区画をどの種類ぶん作るかを、移行の瞬間にDBへ残っていた実データから決めていました。

ところが、移行を実行したちょうどそのとき、書類の抽出処理とCVの抽出処理という2種類については、たまたま処理待ちのジョブが1件も残っていませんでした。 残っていなければ、その種類の区画自体が作られません。存在しないのだから、そこへ来たジョブは行き場を失います。

「今、DBに何が残っているか」ではなく、「アプリケーションのコードが、そもそも何種類の処理を持っているか」を数えるべきでした。 実データを正として使ったことが、たまたまその瞬間の偶然に左右される結果を生みました。

7. このときだけ、工程を外れた

ここが、この記事でいちばん書いておきたい場面です。

本番が稼働している最中の不具合だったため、修正のSQLは、TAKTを介さず人が直接書きました。 理由は明確で、依頼して結果を待ち、検証して適用するという通常の往復にかかる時間を、避ける必要があったからです。

連載でずっと書いてきたのは、仕様書を書き、実装させ、独立に検証してから適用する、という順序でした。 この場面だけは、その順序を意図的に外しています。

外れることを許容できたのは、対応の中身が単純だったからでもあります。足りない区画を2つ追加するだけの、限定された操作であり、既存のデータへ触れる範囲ではありません。通常の工程を外れてよいのは、影響範囲が狭く確認しやすい場合に限られます。 今回はその条件に当てはまっていました。

追加のあと、処理待ちのまま止まっていた2件を再実行し、両方とも正常に完了することを確認しました。進行できないまま孤立していた1件は、失敗として記録し、そこで終わらせています。

8. 消さずに、退避した

最後に、退避しておいた旧テーブルをどうするかという判断が残りました。

すぐに消す案と、しばらく様子を見てから判断する案の2つを検討し、様子見を選びました。 理由は、この移行が2度とも本番で問題を起こしており、通常の稼働下での実績が、まだ移行当日の1日分しかなかったためです。

この判断は、課題として記録する場所には残しませんでした。 課題管理表は「対応すべきこと」を管理する場所であり、「しばらく様子を見る」という状態そのものは、対応すべき課題ではありません。 別の場所(引き継ぎの申し送り事項)で管理することにしました。

どこに何を書くかも、判断の一部です。

9. まとめ——網羅では防げないものがある

2回の障害には、共通する構造があります。どちらも、「存在するはずの手順が、実は存在しなかった」ことが原因でした。 1度目は列名を変換する手順そのものが無く、2度目は区画を用意する根拠が、移行のその瞬間だけの偶然に依存していました。

これは、書き込み前の検証を増やせば防げた種類のものではありません。 独立検証は機能していました。デフォルト値の誤りも、制約の欠落も、本番へ適用する前に見つけて直しています。それでも、本番の実データだけが知っている条件までは、検証の対象にできませんでした。

だから、備え方も変わります。 事前にすべてを見通そうとするのではなく、戻れる余地を残しておくこと——旧テーブルを消さずに退避したこと、限定的な範囲でだけ通常の工程を外れる判断を認めたこと、様子見という状態をそのまま記録に残したこと。すべて、防げなかった前提で組まれています。

網羅できないものがある、という前提に立つと、設計は変わります。それが、この記事で書いておきたかったことです。

1件の修正が別の場所に影響するという構造そのものは、課題管理を扱った別記事でも書いています。あちらは画面の見た目の話でしたが、根っこにある考え方は同じです。

動画作成には自信があります!

「原因が判明しました」は、まだ言ってはいけない

「原因が判明しました」は、まだ言ってはいけない|IT保守の障害報告で信頼を失わない言葉の使い分け

ECサイトの保守を受託していると、こんな連絡が飛び込んできます。

「注文が完了できないと購入者から問い合わせが来ています。至急確認をお願いします」

調査を進めると、30分ほどで一つの手がかりが見つかります。

「クーポン適用の処理でエラーが出ています。該当箇所を特定しました」

対応に追われている報告者は、これを「原因が判明した」として運用会社に伝えたくなります。前に進んだ実感があり、ようやく報告できる材料が揃ったからです。

しかし、運用会社が「原因判明」という言葉を聞いた瞬間、次の判断が始まります。

  • では、いつ復旧するのか。開催中のセールは継続してよいのか
  • 決済だけ通って注文が作られていない購入者がいるのではないか
  • 他の決済パターンでも起きるのか。それとも今回だけか

ここで答えられないと、報告と実態の乖離が露呈します。そして次の報告で「実は原因はまだ調査中でした」と訂正することになれば、障害そのものよりも報告の信頼性が問題になります。

保守サービスにおいて、技術的な復旧と同じくらい難しいのが、今どこまで分かっているのかを正確に伝えることです。その鍵は、日常的に混同されている「理由」「原因」「根本原因」という3つの言葉の切り分けにあります。

前提:日本語の「原因」と「理由」は同じではない

まず一般的な日本語として、この2つの言葉には明確な違いがあります。境目は「人の意志(判断・感情)が関わっているかどうか」です。

用語性質指すもの
原因客観的な事実人の意志とは無関係に物事を引き起こしたきっかけ、メカニズム
理由主観的な根拠人の意志・判断・動機が含まれる説明

具体例

遅刻したとき

  • 「遅刻した原因は、電車の信号トラブルです」
    → 客観的な事実。本人の力ではどうにもならないメカニズム。
  • 「遅刻した理由は、アラームをかけ忘れて二度寝したからです」
    → 本人の行動や判断が関わっている。

交通事故

  • 「事故の原因は、路面凍結です」
    → 物理現象。
  • 「事故の理由は、運転手がスマホに気を取られていたからです」
    → 人間の心理と行動。

使い分けのチェックポイント

  • 自然現象・物理現象には「原因」しか使えません
    • ⭕ 台風が発生した原因
    • ❌ 台風が発生した理由(台風に意志はないため)
  • 行動の目的や動機には「理由」を使います
    • ⭕ 会社を辞めた理由を教えてください
    • ❌ 会社を辞めた原因を教えてください(体調不良など物理的な引き金しか指さなくなる)

ここが重要です。報告の場で「原因」と口にした瞬間、聞き手は「技術的なメカニズムが解明された」と受け取ります。処理を特定しただけの段階でこの言葉を使うと、意図せず過大な報告になってしまいます。

障害報告は3つの層に切り分ける

冒頭のECサイト障害を題材に、3層で整理します。この事例は説明のために構成した架空のものです。本記事は以降、このケースで統一して説明します。

答えるべき問い今回のケース英語表現
① 事象・トリガー(理由)何をしたら、何が起きたかクーポンとポイントを併用した注文で、注文確定処理がエラーになる。決済は成立しているのに注文レコードが作成されないSymptom / Trigger
② 原因(メカニズム)なぜその処理で壊れたのか割引適用後の支払金額が0円になる場合、決済APIへ渡す金額のバリデーションが例外を発生させる実装になっていたDirect cause
③ 根本原因(ルートコーズ)なぜその不具合が作り込まれ、本番まで見逃されたのか仕様書にクーポンとポイント併用で0円になるケースの記載がなく、テスト観点にも存在しなかった。加えて保守引継ぎ時に仕様の網羅性を確認する工程がなかったRoot cause
障害報告の3層構造。事象・トリガー(報告できる)、原因=メカニズム(直せる)、根本原因(再発を防げる)の3層と、それぞれの問い・具体例を示した図
障害報告の3層構造。「原因が判明しました」と言えるのは②の再現確認を終えてからで、再発防止策は③にしか打てない。

この3層は、障害対応の実務書でも共通して扱われる考え方です。Googleが公開しているSRE Book「Postmortem Culture: Learning from Failure」でも、個人の責任ではなく仕組みの問題として原因を掘る姿勢が、事後分析の前提として置かれています。

「クーポン処理で発生」はどの層か

冒頭の「クーポン適用の処理でエラーが出ています」という状態は、①の層でしかありません

引き金となる操作と、壊れた場所は分かった。しかしその処理の内部で何が起きたのか(②)は未解明であり、なぜその不具合が本番環境まで到達したのか(③)にはまだ手が届いていません。

この段階で使うべき言葉は「事象の特定」であり、「原因判明」ではありません。

②と③の役割の違い

  • ②が分かると、直せます。 修正すべきコードが確定します。
  • ③が分かると、再発を防げます。 同種の不具合が他の決済パターンにも潜んでいないか、次の改修で同じことを繰り返さないか、という話がここで初めてできます。

運用会社が本当に知りたいのは③です。②だけで報告を終えると、「今回は直った。で、次のセールは大丈夫なのか」という不安が残り続けます。

保守サービス特有の4つのリスク

リスク1:報告がそのまま外部へ転記される

EC運用会社は、受け取った報告を購入者向けの告知文やCSの応答マニュアルに転用します。つまり保守ベンダーの一言は、その先の一般ユーザーにまで伝播します。

「原因は判明しております」と書いた報告書が、そのまま購入者向けのお知らせになり、後日訂正することになる。この二次被害は保守契約の信頼に直結します。報告書は転記される前提で書く必要があります。

リスク2:客先が金銭的な判断を迫られる

ECの障害は機会損失が即座に金額になります。運用会社はこちらの報告を材料に、セールを止めるか、購入者に返金と謝罪を告知するか、広告出稿を停止するかを判断します。

「今どこまで分かっているか」が曖昧なままでは、この判断ができません。不確定であっても、判断材料になる形で伝えることが求められます。

リスク3:暫定対応が恒久対応と誤解される

「対応しました」という一言は、暫定回避なのか恒久修正なのかを区別しません。運用会社は恒久対応と理解して次のセールを予定どおり開催し、同じ障害を踏むことがあります。

リスク4:責任論に転化しやすい

保守は「作った人と直す人が違う」領域です。原因が前ベンダーの設計や、決済代行サービス側の仕様変更にあることも珍しくありません。

ここで「原因」と「理由」が混ざったまま議論すると、メカニズムの話をしていたはずが「どちらの責任か」という話にすり替わります。原因究明の場が責任追及になると、以降の情報が双方から上がってこなくなります。

なお、報告先や報告様式が契約で定められている場合や、セキュリティインシデントに該当する可能性がある場合は、社内手順に加えて外部への届出も検討が必要です。IPAが公開する情報セキュリティ白書や、JPCERT/CCのインシデント報告の手引きが、報告範囲を判断する際の参考になります。

速報と報告書は、別の文書として扱う

障害対応中のやり取りは、実際には2種類あります。この2つを混ぜることが、誤った断定が残ってしまう最大の経路です。

速報報告書
手段電話、チャット、口頭書面(PDF、メール本文)
タイミング検知から30分以内、以降は随時収束後、および最終報告
目的相手に判断を始めてもらう記録として残す
確度低くてよい(ただし確度の明示が必須)裏付けのある記述のみ
寿命その日のうちに役目を終える数年残る

速報の役割は「安心させること」ではない

速報の目的は、相手が動き出すために必要な最小限を渡すことです。原因が分からなくても速報は出せます。むしろ分からない段階でこそ速報の価値があると考えるべきです。

【速報 10:32】
クーポンとポイント併用の注文でエラーが発生しています。通常注文は正常です。
現在37件が影響、うち31件は決済成立・注文未作成の状態です。
原因は未特定。11:00までに暫定対応の可否をご連絡します。

3〜5行で十分です。ここに「原因は◯◯と思われます」を足したくなりますが、その一言が後に残ります。

速報の文面を、そのまま報告書に貼らない

チャットで書いた文章は、そのまま報告書に転記されがちです。しかし速報は緊迫した状況で、限られた情報のもとに書かれています。書き手の主観や、その場を収めたい気持ちが混ざっています。

報告書は必ず書き直す。 これを運用ルールにします。速報にあった推測表現を報告書で確定表現に格上げする際は、再現確認を経ていることを条件にします。

残る文書だからこその重み

報告書は、障害当日の温度感が消えたあとも残ります。

  • 数か月後の契約更新の席で読み返される
  • 監査やセキュリティ評価の資料として提出される
  • 次期ベンダー選定の際に、比較材料として参照される
  • 社内で類似障害が起きたとき、前例として引用される

当日の「一刻も早く安心させたい」という気持ちで書いた一文が、半年後に「あのとき原因判明と言っていたのに、また同じことが起きた」という指摘に変わります。

信頼は、書面に残った一文で失われます。速報は流れますが、報告書は残る。この非対称を意識するだけで、言葉の選び方は変わります。

誤解を与えない報告テンプレート

「今どこまで分かっていて、次に何を調べるのか」を明確に分けるのが鉄則です。以下は速報ではなく、書面としての報告のテンプレートです。

第一報:事象の特定

【現状】
本日 10:15 頃より、クーポンとポイントを併用したご注文において、注文確定処理がエラーとなる事象が発生しております。事象が発生している処理(クーポン適用ロジック)を特定いたしました。

【業務影響】
・発生時間帯:10:15〜(継続中)
・該当注文:37件(うち決済が成立し注文レコードが未作成のもの 31件)
・金額換算:約48万円
・影響範囲:クーポンとポイントの併用注文のみ。通常注文、クーポン単独、ポイント単独では発生を確認しておりません

【判明していること】(確定)
・上記の条件を契機に事象が発生すること
・決済処理自体は完了しており、二重課金は発生していないこと

【未判明のこと】
・クーポン適用ロジックの内部で何が起きているのか(原因)

【次のアクション】
・11:00 を目途に、併用注文を一時停止する暫定対応の可否を判断します
・並行して該当処理のログを解析し、発生メカニズムを調査いたします

【次回報告】
本日 12:00 までに、進捗をご報告いたします。

ポイント:ここで「原因判明」という言葉は使いません。代わりに「業務影響」「判明していること」「未判明のこと」「次のアクション」「次回報告のタイミング」を必ず入れます。この5点が揃っていれば、原因が未特定でも報告として成立し、運用会社は判断を進められます。

特に業務影響は件数と金額まで書くことが重要です。技術情報だけを渡されても、運用会社はセールを止めるかどうかを決められません。

第二報:原因の特定

【原因】(確定)
調査の結果、割引適用後の支払金額が0円となる場合に、決済APIへ渡す金額のバリデーションが例外を発生させる実装であることを確認いたしました。検証環境にて同条件(クーポン500円+ポイント全額充当により支払額0円)を再現し、本番と同一の事象が発生することを確認しております。

【暫定対応】
11:40 に該当条件の注文を一時的に受け付けない設定を適用し、新規発生を停止いたしました。決済が成立し注文が未作成の31件については、注文データを手動で登録済みです。購入者への影響はございません。

【恒久対応】
プログラム修正を◯月◯日にリリース予定です。それまでの間、併用注文の受付停止を継続いたします。

【継続調査】
本不備が作り込まれた経緯(根本原因)および他の決済パターンへの影響については、引き続き調査のうえ最終報告いたします。

ポイント:「原因」と言い切るには、再現性の確認が前提です。ログ上の推測だけで原因と断定せず、再現できた事実をセットで示します。また、暫定対応と恒久対応をここで明確に分離し、暫定対応が続く間の制約(併用注文が使えないこと)も併せて伝えます。

最終報告:根本原因と再発防止策

【根本原因】
本不備は、割引適用後の支払金額が0円となるケースが仕様として定義されておらず、結合テストの観点にも含まれていなかったことによるものです。また、弊社が保守を引き継いだ際、仕様書の網羅性を確認する工程を設けていなかったため、この欠落を検知できませんでした。

【再発防止策】
・金額計算を伴う処理について、0円・上限値・マイナス値の3観点をテストケースの必須項目として追加(◯月◯日より適用)
・保守引継ぎ時の仕様書レビュー手順を整備し、金額・在庫・権限に関する境界条件の定義有無を確認する工程を新設(◯月◯日まで)
・境界値テストを自動テストに組み込み、リリースごとに実行(◯月◯日まで)

【横展開調査の結果】
金額が0円になり得る処理を全12箇所調査し、同種のリスクを3箇所(ギフト券全額利用、送料無料クーポン、返品時の差額精算)で確認いたしました。◯月◯日のリリースにあわせて修正いたします。

ポイント:横展開調査の結果を必ず入れます。「他は大丈夫なのか」という運用会社の最大の関心に、先回りして答えるためです。

事業停止リスクを、煽らずに伝える

ECの障害は、放置すれば売上が減り続けます。この事実を報告に含めるべきか迷う場面があります。書けば急かすことになり、書かなければ判断材料を渡していないことになる。

答えは「含めるべき」です。ただし書き方に条件があります。

「判断材料の提示」と「判断の代行」を分ける

保守ベンダーが「セールを止めるべきです」と言うのは越権です。事業判断は運用会社の領域であり、こちらは在庫状況も広告契約も販促の意図も知りません。

一方で、影響の見通しを出さないのは不作為です。運用会社は数字がなければ決められません。

分岐点は、選択肢を複数示すかどうかです。一つのリスクだけを書けば圧力になり、選択肢を並べれば材料になります。

避けたい書き方

このままでは売上への影響が拡大します。至急ご判断ください。

事実として正しくても、これは相手を追い詰めるだけです。「至急」「拡大」という言葉が、判断の質を下げます。

推奨する書き方

【影響の見通し】
現在のペースで推移した場合、1時間あたり約12件・約16万円の影響が継続する見込みです。

【選択肢と影響】
① 現状維持(調査を継続)
 影響は継続します。恒久対応まで最短で3時間を見込んでいます。
② 併用注文のみ停止(弊社作業15分)
 新規発生は停止します。クーポン施策の訴求と齟齬が生じるため、告知が必要になる可能性があります。
③ セール全体を一時停止(弊社作業なし・貴社側のご判断)
 確実に影響を止められますが、通常注文分の機会損失が発生します。

【弊社の推奨】
②を推奨いたします。影響を限定でき、通常注文への波及もないためです。ただし販促上の判断は貴社にてお願いいたします。ご指示から15分で着手可能です。

推奨は述べます。技術的な観点からの推奨は、保守ベンダーの職責です。しかし推奨と決定を明確に分け、決定権が相手にあることを言葉にする。これが煽らずに材料を渡す形です。

数字は「継続すると」で書く

「1時間あたり約16万円」は、恐怖を煽る数字ではなく、単位あたりの事実です。「このままでは数百万円の損失に」という書き方は、推計の幅が大きく、相手を焦らせる効果しか持ちません。

単位あたりで書けば、相手が自分の時間軸を掛け算して判断できます。計算は相手に委ねるのが、寄り添った書き方です。

訂正を「訂正」にしない ― 確度ラベルと差分の明示

複数回にわたって内容が変わると、相手は混乱します。「結局どれが正しいのか」「この報告も後で覆るのか」と、報告そのものへの信頼が落ちていきます。

しかし調査が進めば内容が変わるのは当然です。問題は変わることではなく、変わり得ることを事前に示していないことにあります。確度を書かずに断定すれば、更新は全て「訂正」になってしまいます。

記述ごとに確度ラベルを付ける

ラベル意味使用条件
【仮説】ログや状況からの推測裏付け未実施。覆る可能性あり
【検証中】再現試験を実施している段階結論は未確定
【確定】再現確認済み、または実測値以降覆らない

これがあれば、内容が変わっても「仮説が外れ、確度が上がった」という説明になります。訂正ではなく前進です。

確度ラベルの遷移図。仮説から検証中、確定へと進む3段階と、ラベルの有無で「訂正」と「前進」に分かれることを示した図
確度ラベルがあれば、内容の更新は「訂正」ではなく「確度が上がった」という前進として伝わる。

【仮説】現時点では、金額計算の境界値処理に問題があると推測しています。裏付けは未実施です。
【検証中】検証環境で0円条件の再現試験を実施中です。12:00 に結果をご報告します。
【確定】決済が成立し注文が未作成の件数は31件です(決済ログとの突合済み)。

版番号と「前回からの変更点」を常設する

報告書には毎回、版番号と変更点を書きます。

障害報告書 第3版(2026年◯月◯日 15:00 時点)

【前回(第2版)からの変更点】
・原因を【検証中】から【確定】に更新(再現試験完了のため)
・影響件数を37件から39件に修正(11:30〜11:40の2件を追加計上したため)
・恒久対応日を◯月◯日に確定

件数の修正のような、こちらに不都合な変更こそ明記します。黙って数字を差し替えることが、最も信頼を失います。 相手が前回の報告を保管していれば、必ず気づきます。

覆る可能性を、先に伝えておく

第一報の段階で一文を添えます。

現時点の内容には調査中の項目が含まれており、進展に応じて更新いたします。更新の際は変更点を明示してご報告します。

これを最初に宣言しておけば、以降の更新は約束の履行になります。何も言わずに更新すれば訂正ですが、宣言してから更新すれば運用です。

そのまま使える言い換え表

避けたい表現推奨する表現
原因が判明しました(事象特定の段階で)事象が発生する処理を特定しました。現在、その内部のメカニズムを調査中です
対応済みです暫定対応により新規発生を停止しています。恒久対応は◯月◯日を予定しています
復旧しました新規注文の受付を再開しました。障害中に発生した31件のデータ復旧は別途◯時完了予定です
影響は軽微です影響は併用注文37件、金額換算で約48万円です。通常注文には影響しておりません
このままでは損失が拡大します現在のペースで1時間あたり約16万円の影響が継続します。選択肢を3案ご提示します
至急ご判断くださいご指示から15分で着手可能です。ご判断のタイミングをお知らせください
想定外の事象でした本条件を仕様として定義できておりませんでした
単純なミスです0円ケースを検証する仕組みがテスト工程に組み込まれていませんでした
おそらく◯◯だと思われます【仮説】現時点の推測は◯◯です。12:00までにログにより裏付けを行います
現在調査中です現在、決済API連携部分の観点で調査しております。12:00に中間報告いたします
全力で対応いたします本日は◯名体制で対応し、19:00まで1時間ごとに状況をご報告します
二度と起こさないよう注意します0円・上限値・マイナス値をテスト必須観点に追加し、リリース判定の条件とします

右側に共通しているのは、主観を排し、数値・期限・検証方法を添えている点です。「注意します」「徹底します」「全力で」は意志の表明であって対策ではありません。

責任範囲に触れるときの言葉選び

保守では、原因が自社の実装ではなく、客先の運用や外部サービスにあることがあります。ここでの一言が関係を左右します。

避けたい書き方

決済代行会社側の仕様変更が原因です。弊社に責はございません。

事実として正しくても、運用会社にとっては「では誰が直すのか」が分からず、突き放された印象だけが残ります。責任の話と復旧の話が混ざっている点も問題です。

推奨する書き方

【原因】(確定)
決済代行サービスにおいて、◯月◯日にバリデーション仕様が変更され、金額0円のリクエストが拒否されるようになったことを確認いたしました。

【弊社側の課題】
当該変更は事前告知されておりましたが、弊社の保守運用において外部サービスの変更通知を確認する手順が定まっておらず、影響評価を実施できておりませんでした。

【対応】
決済代行会社へ確認済みで、仕様変更は取り消されない方針とのことです。弊社側で0円時の処理を回避する改修を行います。

構成の型は次のとおりです。

  1. まず客観的事実としての原因を書く(ここに評価や感情を入れない)
  2. その上で自社側に改善余地がある点を明示する
  3. 誰が何をするのかを書く

外部起因であっても、影響評価や通知確認の仕組みという形で、自社側にできることはほぼ必ず存在します。それを先に出せるかどうかが、保守ベンダーとしての信頼を決めます。

なぜ「原因判明」と言ってしまうのか

ここまで「早すぎる断定を避けよう」と書いてきました。しかしそれだけでは、この記事自身が次章で批判する「意識を高めましょう」で終わってしまいます。なぜ人はそう言ってしまうのかを、本記事の3層構造で分解します。

内容
事象事象を特定した段階で「原因が判明しました」と言ってしまう
原因相手を安心させたい、頼りにされたいという主観が、確実性を前借りさせる
根本原因誠意を示す手段が「断定」しか用意されていない。報告のフォーマットに、寄り添いの置き場所がない

断定は、悪意から生まれません。むしろ善意から生まれます。不安そうな相手を前にして「まだ分かりません」と言い続けるのは、心理的にかなりの負荷がかかります。何か確かなことを渡したい。その気持ちが、確度の低い情報を確定表現に押し上げます。

だとすれば対策は「気をつける」ではありません。寄り添いを表現する手段を、断定以外に用意しておくことです。

① 次回報告の時刻を、自分から刻む

相手に催促させないことが、最大の寄り添いです。「進展があり次第ご報告します」は、相手を待たせる文です。「12:00にご報告します」は、相手が12:00まで他の仕事をできる文です。

② 相手の判断デッドラインから逆算する

「11:00までに暫定対応の可否を判断します」という時刻には、根拠を添えます。

セール継続のご判断が12:00に必要と伺っておりますので、その1時間前に材料をお出しします。

相手の都合を起点に自分の予定を組んでいることが伝われば、それは言葉以上の誠意になります。

③ 進展がないときこそ報告する

沈黙が最も不安を生みます。

【12:00 定時報告】
検証環境での再現試験を継続中です。現時点で新たな判明事項はありません。
次回13:00に報告いたします。影響件数に変動はありません。

「変わっていません」という報告には情報がないように見えますが、相手にとっては「悪化していない」という重要な情報です。

④ 相手が外部に説明するための文面案を先回りして添える

これが最も効きます。

【参考】購入者様向け告知の文案(そのまま、または修正のうえご利用ください)

「◯月◯日 10:15〜11:40 の間、クーポンとポイントを併用したご注文において、注文が完了できない事象が発生しておりました。
決済が完了したにもかかわらず注文履歴が表示されないお客様につきましては、弊社にて注文の登録を完了しております。二重のご請求は発生しておりません。
ご迷惑をおかけしましたことを深くお詫び申し上げます。」

運用会社は障害対応中、購入者対応とCS向け説明という別の仕事を抱えています。その一部を肩代わりすることは、「全力で対応します」と100回書くより強い寄り添いです。

そして重要なのは、これらの手段がどれも確度を偽らずに実行できることです。原因が分からなくても、時刻は刻めます。告知文案も書けます。誠意を示すために断定する必要は、そもそもありません。

根本原因を掘るときの2つの落とし穴

落とし穴1:人に着地させてしまう

「なぜ」を繰り返すと、しばしば「担当者のテスト漏れ」という結論に着きます。これは根本原因ではありません。人は交代し、繁忙期には余裕がなくなります。同じ状況になれば同じ結果が再現されるため、対策になっていないのです。

着地させるべきは仕組みです。「テスト漏れ」で止まらず、「0円ケースを検証する観点が、テスト設計の標準に存在しなかった」まで進めます。

落とし穴2:抽象度を上げすぎる

逆に掘りすぎて「品質意識の不足」「保守体制の脆弱さ」まで抽象化すると、今度は具体的な打ち手が作れません。

止める位置の目安は、明日から実行でき、実行されたかどうかを客先が検証できるレベルです。「テスト必須観点に3項目を追加する」「引継ぎ時のレビュー手順を新設する」は検証できます。「意識を高める」は検証できません。

掘り方の枠組みそのものを整えたい場合は、公的機関の資料が参考になります。インシデント対応の標準的な進め方はNIST SP 800-61(IPAによる解説)が、実際の障害事例と再発防止の観点はIPAのシステム障害事例に関する資料がまとまっています。

報告前セルフチェックリスト

内容の正確さ

  • 「原因」と書いた箇所は、再現確認まで完了しているか
  • 事象(何が起きたか)と原因(なぜ起きたか)を分けて書いているか
  • 記述ごとに【仮説】【検証中】【確定】の確度が分かるか
  • 分かっていないことを、分かっていないと明記しているか

判断材料としての十分さ

  • 業務影響を件数・金額・時間帯で書いているか
  • 影響しない範囲(正常に使える機能)も明記しているか
  • 選択肢を複数示し、決定権が相手にあることを明示しているか
  • 暫定対応と恒久対応を区別し、暫定期間中の制約を伝えているか

文書としての管理

  • 版番号と「前回からの変更点」を記載しているか
  • 自社に不都合な数値の修正も明記しているか
  • 速報の文面をそのまま貼り付けていないか
  • この文章がそのまま購入者向け告知に転記されても問題ないか
  • 半年後に読み返されても、過大な断定が残っていないか

姿勢の示し方

  • 次のアクションと、次回報告のタイミングを書いているか
  • 「全力で」「至急」といった情緒表現を、行動と時刻に置き換えているか
  • 同種の事象が他に潜んでいないか(横展開調査)に触れているか
  • 外部起因の場合、自社側の改善点をあわせて示しているか
  • 対策が「意識」「注意」「徹底」で終わっていないか

まとめ

障害報告における言葉選びは、細かい言い回しの問題ではなく、客先の意思決定に必要な情報を正確に渡せているかどうかの問題です。

  • 「クーポン処理で発生している」は、事象の特定であって原因判明ではない
  • 「原因」と言い切るには、再現による裏付けが要る
  • 「根本原因」は、なぜその不具合が本番まで到達したのかというプロセスの問題
  • 未確定でも、業務影響・確度・次の手・次回報告時刻が揃っていれば報告は成立する
  • 事業影響は単位あたりの数字と複数の選択肢で示し、決定は相手に委ねる
  • 確度ラベルと変更点の明示があれば、内容の更新は訂正ではなく前進になる
  • 速報は流れるが、報告書は数年残る
  • そして、寄り添いを示す手段は断定以外にいくらでもある

早すぎる断定は、たいてい誠意から生まれます。だからこそ厄介です。「気をつける」では防げません。

防ぐ方法は、誠意の出口を別に用意しておくことです。時刻を刻む。選択肢を並べる。相手の次の仕事を先回りする。これらは確度を偽らずに実行でき、しかも断定より深く相手に届きます。

急ぎたい場面ほど、使う言葉を一段慎重に選ぶ。それが結果として、保守契約という長い関係を守ることにつながります。

動画作成には自信があります!

5週間前の正しい修正が、今日の不具合になる——4つの課題がつながっていた話

5週間前の正しい修正が、今日の不具合になる——4つの課題がつながっていた話

これまで、AIエージェントと開発を進める工程について書いてきました。仕様書の書き方、報告の検証、完了確認、バックアップ。今回は、1件の課題を起票から設計文書の反映まで、最後まで追いかけた記録です。

そして、この1件で分かったことがあります。5週間前に入れた正しい修正が、今日の不具合の原因になっていました。

1. 「見出し」の一語が通じない

発端は、画面キャプチャ3枚でした。社員情報一覧・評価一覧・職位一覧の3画面について、赤い矢印で一箇所を指し示したうえで、こういう指摘をいただきました。

一覧の項目名が、下へスクロールすると本文と一緒に流れて隠れてしまう。スマートフォンやタブレットから見るときに特に困る。

要求は明確です。列の名前が並んだ行を、スクロールしても上に留めてほしい。

ところが、着手する前にひとつ確認が要りました。「見出し」という語が、指しているものが一致していなかったのです。

対話AI(ひかり)は「見出し」を一覧内の列名が並んだ行の意味で使っていました。しかし画面には、そう呼びうるものが他にもあります。画面の一番上にある「職位一覧」というタイトルも、日本語としては見出しです。実際、「見出しというのは画面タイトルを指すのでは」という確認が入りました。

画像で場所を指し示していても、言葉の側で取り違えが起きかけます。 赤い矢印がどの行を指しているかは見れば分かります。だが、それを何と呼ぶかは、見ただけでは決まりません。

着手前に確認して一致させました。この一往復がなければ、画面タイトルを固定する実装が出来上がっていた可能性があります。

2. 画像が対象範囲を決めた

もう一度、画像が判断を決めた場面があります。対象範囲の確定です。

3画面のうち職位一覧には、表示形式が2種類あります。ひとつは行と列のマトリクス形式、もうひとつは段組みのカード形式です。カード形式には、そもそも列名の行が存在しません。 固定すべきものが無いのだから、対象になり得ません。

これを画面キャプチャで確認していただき、対象を「3画面、うち職位一覧はマトリクス形式のみ」と確定しました。

文章で「表形式の表示のみを対象とする」と書くこともできました。 しかし、その画面に表示形式の切り替えがあること自体を知らなければ、その文は書けません。画像を見て初めて、書くべき条件が分かりました。

3. 実装は、先例に倣った

方針は単純でした。同じ仕組みが、すでに別の画面で使われています。

評価シートのテンプレート指定を行う画面で、行と列を固定する書き方がすでに実装されていました。新しい書き方を発明せず、その先例に合わせます。 対象の3画面それぞれの列名行に、同じ指定を追加します。

職位一覧のマトリクス形式だけは、少し違います。上の行と、左の列の両方を固定する必要があります。

見出し行と職位列の固定を示した模式図。左が修正前でスクロールにより見出しが流れて消える状態、右が修正後で見出し行と職位列が固定された状態。
左:スクロールすると見出し行も職位列も流れて消える。右:両方が固定され、セルだけが動く。左上のセルだけは上下左右とも固定する必要がある。

図のとおり、左上のセルは行の固定と列の固定を両方受けます。この1セルだけ、指定が他と異なります。

4. 保守フェーズと、依頼の単位

ここで、進め方について触れておきます。8月15日以降、この開発は保守フェーズに入り、実装エージェント(TAKT)の実装主体をCodexへ切り替えています。

工程は一つも書き換えていません。 調査→仕様書→実装→独立検証→テスト→デプロイという流れは、これまで書いてきたそのままです。変わったのは、1回の依頼に載せられる作業量です。

選定で重視したのは、処理能力ではなくセッションの消費でした。毎回すべてを読み直すのではなく差分で管理される点に着目し、加えて、より高性能なモデルではなく、汎用的なモデルを積極的に選びました。

その結果、以前は「仕様書と実装」「テスト」といった単位に分けて投入していたものが、まとめて1回で通るようになりました。今回の設計文書への反映も、4文書への追記が1回の依頼で完了しています。 処理そのものには10分以上かかりますが、人が手を動かすのは1回です。

これは、以前に書いた「工程数は、AIの作業回数ではなく、指示を出す人が実際に実行した回数で数える」という指標での改善にあたります。 4回分の投入が1回になったということは、確認と貼り付けの往復も4分の1になったということです。

ただし、何でも1回に載るわけではありません。4文書の全文を読み込んで自己矛盾を洗い出すような依頼は、今もトークンの上限に触れるため、観点ごとに分割しています。 今回1回で通ったのは、仕様書の段階で反映箇所が特定済みだったからです。読む範囲が定まっていれば1回で通り、全文走査を伴うなら分割が要ります。

プロバイダを切り替えたときに何が変わり、何が変わらなかったかについては、別記事(番外編)に書いています。

なお、Claude CodeとCodexの使い分けについては、「立ち上げは前者、精密な修正は後者」といった整理が一般に語られています。ただし本稿は、その優劣を検証したものではありません。 ここに書いたのは、保守フェーズという段階で、セッションの消費を抑える目的で選んだという、運用上の判断だけです。

5. 全工程を通過したのに、そうは見えなかった

実装は、これまで書いてきた工程どおりに進みました。

  • 独立検証:仕様書どおりの差分(列名行への指定の追加のみ)であることを確認
  • 対象範囲のテスト:失敗0件
  • 全体テスト:失敗0件
  • デプロイ:成功

そして実機で確認したところ、見出し行は流れて消えました。

再びキャプチャ3枚をいただきました。スクロールした状態で、見出し行が画面から消えています。「固定されていません」という一文より、この3枚のほうが速く、正確でした。

すべての検証を通過した実装が、意図した見え方になりませんでした。 テストが検証できるのは「書いたとおりに指定が入っているか」であって、「画面上でそう見えるか」ではありません。両者は別のことです。

6. 原因は、5週間前の自分たちの修正だった

再調査を依頼して、原因が確定しました。

固定の指定を入れた要素の親に、横スクロールを許す指定overflow-x: auto)が入っていました。CSSの仕様上、横方向にこの指定をすると、縦方向も実効的に同じ扱いになります。 その結果、固定の基準がページ全体ではなく、その親要素そのものへ移っていました。

親要素には高さの制限が無く、内部でスクロールが起きません。基準が動かないのだから、固定しても何も起きません。 指定は正しく入っていて、効果だけが消えていました。

そして、この overflow-x: auto は、5週間前に自分たちで入れたものでした。

7. 4つの課題を、時系列で並べる

さかのぼると、同じ領域を4度通っています。

課題時期何をしたか
A7月前半全画面共通のレイアウトを整備。左メニューと上部ヘッダーを固定し、本文だけがスクロールする構造を作った。このとき、画面タイトルは固定ヘッダーに含めず、スクロール領域に残す方針を決めている
B7月20日画面右上の操作がスクロールバーと重なる問題を是正。Aで作った構造を、設計文書に明記した
C7月21日「見出しのスクロール時の挙動が他画面と揃っているか確認する」課題。調査の結果、共通の仕組みに乗っており対応不要と判断して閉じた
D7月22日表が画面幅を超えると右端が見切れる問題を是正。テーブルを横スクロール可能な要素で包む構造を、共通の型として設計文書に新設した
今回8月31日見出し行を固定。Dで入れた構造が原因で、機能しなかった

Aは、この記事の冒頭にもつながっています。 画面タイトルを固定ヘッダーに含めないという方針は、このとき明示的に決めたものです。つまり画面上には「固定されている上部の領域」と「固定されていない画面タイトル」が同居しています。 「見出し」という語がどちらを指すか一致しなかったのは、言葉の曖昧さというより、画面の構造がそうなっているからです。

Dの対応は、当時として正しいものです。 右端が見切れて操作できないという実害があり、それを解消しました。既存の画面と同じ構造に揃え、同じ原因を持つ画面を横断的に洗い出し、対象外とする画面の理由まで記録し、設計文書にも反映しています。やるべきことは、すべてやっています。

それでも5週間後、別の要求と衝突しました。

Cについても触れておきます。見出しの挙動を確認する課題は、実際に7月に存在しました。 ただしそれは「他画面と揃っているか」を問うもので、列名行を固定してほしいという要求ではありません。調査の結果、共通の仕組みに乗っており差分は無かったのです。当時の観点では、対応不要は妥当な判断です。

4件とも、それぞれの時点では正しいものです。 しかし積み重なると、後から入る要求を妨げる構造ができあがっていました。

8. 是正と、許容の判断

是正の方針は2案ありました。

  • 案1:親要素の縦方向の指定を打ち消す → CSSの仕様上、解消できないことを確認済み
  • 案2:一覧を囲む要素に高さの上限を設け、その中で独立してスクロールさせる

案2を採りました。 高さの基準値は、固定ヘッダーや余白を考慮して実装エージェントが実測し、3画面共通の値として決定しました。この値を人が決めていたら、画面ごとに違う数字を指定していたかもしれません。

そして実機確認で、1画面だけ二重スクロールが発生しました。 ページ全体のスクロールと、一覧内のスクロールが同時に存在する状態です。

これは事前に「起こさないこと」という条件を付けていませんでした。起きるかどうか、起きたときにどの程度気になるかは、実際に見なければ判断できないと考えたためです。

実際に見たうえで、許容範囲と判断しました。 見出し行が固定される利点のほうが大きい、という判断です。

9. コミットせずに、本番へ反映されていた

もう一件、この課題で起きたことを書いておきます。

是正の実装が終わり、独立検証もテストも通り、デプロイして実機確認も合格しました。課題管理表にも完了として記録しました。その時点で、変更はまだ一度もコミットされていませんでした。

発覚したきっかけは、「pushは実施しましたっけ?」という一言でした。確認すると、3ファイルの差分が作業ツリーに残ったままでした。

原因は、デプロイの仕組みにあります。 この環境のデプロイはファイルの直接転送であり、gitを経由しなくても本番へ反映できてしまいます。 そのため、「テストが通った」「本番で動いた」という事実は、コミットされたことを何も保証しません。

独立検証とテストが完了した直後に、必ずコミットを挟む。 これを工程として明示しました。「デプロイの後で git status を見たら空でなかった」という事後の発覚に頼りません。

10. 過去の記述を、打ち消さずに残す

最後に、設計文書への反映で下した判断を書きます。

調査の結果、Aの課題で書いた「本文が唯一のスクロール要素である」という記述が、4つの設計文書すべてに存在し、今回の3画面に限って例外が生じることが分かりました。 記述と実装が食い違います。

打ち消し線を引いて訂正することもできました。 しかし、そうしませんでした。

採ったのは、既存の記述はそのまま残し、その隣に追記するという方針です。 理由は明確で、Aの時点では、その記述は正しかったからです。誤りではなく、後から例外ができました。打ち消し線は「間違っていた」という意味になり、当時の判断まで否定してしまいます。

反映後、削除された行は版数と更新日の4行のみで、本文からは1文字も消えていないことを確認しました。追記だけです。

11. まとめ——正しい修正は、正しいまま原因になる

この1件で確認できたことを、3つ書きます。

第一に、正しい修正が不具合の原因になります。 5週間前の対応に、手抜きも見落としもありません。それでも、後から入る要求と衝突しました。参照関係のある領域では、1件を直すと隣が動きます。 これは避けられるものではなく、起きたときに追跡できるようにしておくしかありません。4件をさかのぼって原因を特定できたのは、それぞれの課題に対応の内容と理由が記録されていたからです。

第二に、検証を全部通過しても、意図した見え方になるとは限りません。 独立検証も、対象範囲のテストも、全体テストも通りました。それでも実機で見るまで、分かりませんでした。 テストが保証するのは「書いたとおりに動くこと」であり、「意図したとおりに見えること」ではありません。最終防衛線は、人が実物を見ることです。

第三に、画像が言葉より速いことがあります。 要求の指定、対象範囲の確定、不具合の報告——この課題では3か所とも、判断を決めたのは文章ではなくキャプチャでした。 ただし、それでも冒頭のように語の取り違えは起きます。画像は場所を指せますが、名前は決められません。 両方が要ります。

そして、設計文書の記述を打ち消さずに残したことは、この記事の第一の結論への向き合い方そのものです。 過去の判断を「間違いだった」と塗り潰せば、記録は整うかもしれません。しかし、なぜその構造になっているかを、次に読む人が追えなくなります。

正しかったものが、正しいまま合わなくなる。それを訂正ではなく履歴として残せるかどうかが、5週間後の自分を助けます。

動画作成には自信があります!

手付かずは0件、やりかけが24件——課題が「終わらない」ときに何が起きているか

手付かずは0件、やりかけが24件——課題が「終わらない」ときに何が起きているか

前回の記事は、「433件のうち306件をやらなかった」というところで終わりました。

では、その残りは今どうなっているのか。実際に開いて集計してみたところ、想定と違っていました。

結論を先に書きます。手を付けていないレベル1・2の課題は、0件でした。止まっているのは、すべて着手済みのものです。

1. 対象のシステムについて

先に、この記事で必要になる範囲だけ説明しておきます。

対象は、社員の評価を運用するタレントマネジメントシステムです。評価は半期ごとに区切られ、半期には版があります(設定を確定して運用を始めた後も、必要があれば作り直せます)。利用者には役割による権限があり、加えてシステム全体の既定値(どの半期を初期表示するか等)を持つ設定があります。

この3つ——半期の版・権限・システム設定——が、互いを参照しています。 後半で、この構造が効いてきます。

2. 未完了は164件。ただし内訳が重要である

課題管理表を状態別に集計すると、未完了は164件でした。

状態件数
未着手87
未整理39
一部完了28
実機確認待ち9
本番反映待ち1
合計164

この表だけを見ると、「87件が手付かずで残っている」ように読めます。 しかし、レベルを重ねて見ると、まったく違う絵になります。

3. 手付かずのレベル1・2は、0件だった

未着手87件と未整理39件を、レベル別に分解した結果がこれです。

状態レベル1レベル2レベル3レベル473・74空欄
未着手(87)003830190
未整理(39)0053301

レベル1・2は、1件も含まれていません。 手を付けていない126件は、すべてやらないと決めたもの(レベル3・4・73・74)でした。

前回の記事で「レベル1と2だけをやると決めた」と書きましたが、その方針が実データで守られていることは、集計して初めて確認できました。 方針を掲げることと、方針どおりに進んでいることは別です。確認して初めて、後者が言えます。

4. 止まっているのは、着手済みのものだけ

では、レベル1・2の未完了はどこにあるのか。24件あります。そのすべてが「一部完了」または「実機確認待ち」でした。

状態レベル1レベル2
一部完了51520
実機確認待ち044
合計51924

手付かずが0件で、やりかけが24件。 前回の記事が「やらないと決める」話だったとすれば、この記事は「終わらせきる」話になります。

5. 「一部完了」とは何を指すか

変換スクリプトは、完了欄または実機確認欄に全角の「/」が含まれていると、状態を「一部完了」と判定します。画面ごと・機能ごとに状態が分かれている、という記録です。

なお、半角の / は区切りとみなしません。N/A やコミットのパスに現れるため、これを区切りと解釈すると誤判定が大量に出ます。全角と半角を区別することが、この判定を成り立たせています。

「一部完了」が意味するのは、こういう状態です。

3画面のうち2画面は本番へ反映済み。残る1画面は、関連する別の課題の対応を待っている。

中途半端に見えますが、そうではありません。 どこまで終わっていて、どこが残っているかを1行に書き残した結果です。「完了」でも「未着手」でもない状態を、そのまま記録できる欄になっています。

6. なぜ一部完了が生まれるのか

止まっている24件を実際に開くと、特定の領域に集中していることが分かります。冒頭で挙げた3つです。

  • 半期の版の作り直しに関わるもの——版を作り直すと、前の版で使っていた設定が引き継がれるかどうかが問題になります。引き継ぐべきものと、引き継ぐべきでないものがあります
  • 役割の追加に関わるもの——新しい役割を1つ足すと、その役割で何が見えて何が操作できるかを、既存のすべての画面について決め直すことになります
  • システム設定の既定値に関わるもの——「初期表示する半期」のような既定値は、参照先が削除されたときにどうなるかを、削除する側の機能で守る必要があります

共通しているのは、1件を直すと隣が動くことです。 半期の版を直せばシステム設定に響き、役割を足せば各画面の権限判定に響きます。互いを参照している3つの領域では、1件の課題が単独では閉じません。

だから、こうなります。着手して、大半は直り、参照先の課題が片づくまで最後の1画面が残る。 これが「一部完了」の正体です。

やりかけが残っているのは、手を抜いたからではありません。参照関係のある領域では、単独で終わらせられない課題が構造的に生まれます。

7. 前回の「未整理39件」に、答えが出ていた

前回の記事で、こう書きました。

「未整理」は元表で「完了・本番反映」「実機確認」の両列が空欄だったものである。着手前か記入漏れかは元表からは判別できない。

レベルを重ねて見たら、判別できました。 39件のうち33件がレベル4(検討対象外)、5件がレベル3(保留)で、レベル欄が空なのは1件だけでした。

記入漏れではなく、対象外と判断したから完了欄を埋めていないもので占められていました。「未整理」という状態名が実態と合っておらず、正確には「対象外として、記入する必要がなかったもの」です。

1つの列だけを見て判断すると、こういう誤読が起きます。 状態列だけでは「未整理39件」ですが、レベル列を重ねれば「対象外33件+保留5件+本当に未整理1件」になります。前回の記事で「判別できない」と書いたのは、状態列しか見ていなかったからにすぎません。

8. 欄を2つに分けていること

最後に、この記事で書いておきたい設計の話があります。完了・本番反映の欄と、実機確認の欄を、2つに分けていることです。

これは「デプロイした」と「実際に動いた」を区別するための仕掛けです。1つの欄にまとめていたら、実機確認待ちの9件は「完了」に見えていました。

前回の記事で書いた127件という数字も、この分離があって初めて成り立っています。あの数字は verify contains 済 AND level < 4 という条件で数えたものであり、実機確認の欄が独立していなければ、この条件自体が書けませんでした。

欄を分けるということは、「終わっていない状態」に名前を与えるということです。 名前がなければ記録できず、記録できなければ集計もできません。「一部完了」「実機確認待ち」「本番反映待ち」といった状態が数えられるのは、それを書き分けられる欄が先にあったからです。

9. まとめ——分類で終わるのは、半分だけ

前回と今回で、はっきりしたことがあります。

やらないと決めるのは、分類でできます。 レベルを付けて、1・2以外を対象から外す。実際、手付かずのレベル1・2は0件になりました。分類は機能しています。

しかし、やりかけを終わらせるのは、分類ではできません。 24件が止まっているのは、優先度の付け方の問題ではなく、参照関係のある領域では課題が単独で閉じないという構造の問題です。レベルを付け直しても、この24件は動きません。

課題管理の道具にできるのは、「終わっていないこと」を、終わっていない形のまま正確に持ち続けることまでです。そこから先を動かすのは、道具ではありません。

動画作成には自信があります!

433件の課題を、レベルで切り捨てる——2か月で127件を実機確認済みにするまで

433件の課題を、レベルで切り捨てる——2か月で127件を実機確認済みにするまで

課題管理の記事はたいてい、「漏れなく管理する方法」を書きます。この記事は逆です。433件のうち、何をやらないと決めたかを書きます。

結論を先に書きます。2か月で127件を実機確認済みにできたのは、433件を全部やらなかったからです。

1. 433件という現実

一通りの開発を終えたタレントマネジメントシステムの課題管理表は、Markdown の表1本で管理しています。現状はこうなっています。

項目実測
総課題数433件(最大 P-439・欠番6件)
ファイルサイズ1.19MB
1件の「その他」欄の最長5,187字

この規模になると、表として開いても、もう読めません。 横に8列あり、1行の中に数千字が入っていることもあります。エディタで開けば1行が画面外まで伸び、スクロールしても目的の行にたどり着きません。

「大量にあり過ぎる」——そう相談したところから、この記事の話が始まります。

2. レベルは優先度ではなく、「やらないこと」を決める軸

課題には6段階のレベルを付けています。ただしこれは優先度の順位ではありません。

レベル意味
1緊急対応
2まとめて後日対応
3一旦、保留
4検討対象外(ただし、メモは残す)
73TAKT 一旦、保留
74TAKT 検討対象外(ただし、メモは残す)

注目していただきたいのは、3と4を分けていることです。 どちらも「今はやらない」ですが、3はいずれ見直す、4は見直さないという違いがあります。そして4には「ただし、メモは残す」と付いています。やらないと決めたものも、消しません。

73・74は、実装エージェント(TAKT)に起因する課題を切り分けるための番号です。ツール側の事情で生じたものを、プロダクトの課題と同じ列に並べません。

この6段階は、着手する順番を決めるためのものではありません。「レベル1と2だけをやる」と決めるためのものです。 3以下は、分類された時点で当面の対象から外れます。

3. 道具を提案させた

433件を目の前にして相談したのは、「どう優先順位を付けるか」ではなく「どう見るか」でした。

提案として返ってきたのが、Obsidian の Bases 機能を使う方法でした。1課題=1ノートに変換し、表の各列を frontmatter のプロパティとして持たせます。 そうすると、Obsidian の側でフィルタ・グループ化・並べ替えが画面操作でできるようになります。

変換すると、1件はこういう形になります。

---
no: "P-186"
no_num: 186              # 並べ替え用の数値
title: "..."
level: 2
state: "実機確認待ち"     # 導出した総合状態
deploy: "反映済み"        # 「完了・本番反映」列を正規化
verify: "未"             # 「実機確認」列を正規化
deploy_raw: "..."        # 元の記述をそのまま保持
verify_raw: "..."
level_raw: "..."
related:
  - "[[P-184]]"
---

表の1行だった課題が、リンクを持ったノートになります。 related を Obsidian の内部リンク形式にしてあるため、関連課題へ直接飛べて、バックリンクで逆方向もたどれます。433件の中で「この課題は他のどれと関係しているか」が、初めて目で追えるようになりました。

4. 変換は一方通行にする

ここで一つ、運用として決めたことがあります。元のMDが正であり、Obsidian 側は閲覧専用とします。

元MDが更新されたら、変換スクリプトを実行して issues/ を作り直します。

python regenerate.py "元MDのパス" --dry-run   # 何が変わるか確認(書き込まない)
python regenerate.py "元MDのパス"             # 実行

Obsidian 上でノートを直接編集しても、次回の再生成で失われます。 これは README に明記してあります。

双方向に同期させたくなるところを、あえて片方向に固定しました。 理由は単純で、正が2つあると、どちらが正しいか分からなくなるからです。閲覧のための表現は、いくら作り直しても構いません。作り直せない一次情報を、1箇所に固定しておくほうが大事です。

同じ理由で、スクリプトには停止条件を組み込んであります。

  • 表の列構成が想定と違えば、変換せずに中断する
  • 列数の合わない行があれば、中断してその課題番号を表示する
  • 課題番号が重複していれば、中断する
  • 上書きの直前に、既存の issues/ をバックアップへ退避する

「変換できるところまで変換して、あとは目視で」という作りにはしていません。想定と違う入力が来たら、何も書かずに止まります。 この設計は、AIエージェントに作業させるときの完了確認とまったく同じ考え方です。

5. 正規化しても、原文は捨てない

変換では、「完了・本番反映」欄や「実機確認」欄の表記ゆれを正規化しています。たとえば実機確認欄なら、こう判定します。

  • 「対応済み」「実機確認済み」「確認済み」を含む、または「済」で始まる →
  • 「対応不要」「文書のみ」「調査のため」、または全角ダッシュで始まる → 不要
  • 「未」で始まる →

ただし、正規化した値だけを持つのではなく、原文も deploy_raw verify_raw level_raw に必ず残しています。

理由は、正規化のルール自体が、あとから間違っていたと分かることがあるからです。「済」と判定した中身が、実際には「未済」だったら——という懸念は、判定の順序で回避していますが、それも設計時点での想定にすぎません。原文が残っていれば、ルールを直して再生成すれば済みます。原文を捨てていたら、元の表まで戻ることになります。

判断に迷ったら raw を見る。 これが運用の基本になっています。

6. 数字は、フィルタ条件とセットでしか意味を持たない

ここから、この記事を書く過程で実際に起きたことを書きます。

この記事を書き始めたとき、「解決済みは127件」という数字を持っていました。 Obsidian の画面に「127 件の結果」と表示されていたからです。

ところが、記事に書くために手元で集計し直すと、127という数字がどこにも出てきませんでした。

集計条件件数
state が「完了」241
「完了」+「完了(確認不要)」269
「完了」かつレベル1・2108
「完了」かつレベル1・2・3116

どれも127ではありません。 そこで、Obsidian のビューに設定されたフィルタ条件を確認しました。答えはこうでした。

verify contains 済  AND  level < 4

この条件で数え直すと、ちょうど127件になりました。内訳はレベル2が94件、レベル1が24件、レベル3が9件、レベル4が2件(level < 4 の判定でレベル欄が空の129件が除外される)です。

つまり127件は「完了した課題の数」ではなく、「実機確認まで済んでいて、かつ検討対象外ではない課題の数」でした。 意味がまったく違います。

「解決済み127件」と書いていたら、それは誤りでした。 そして誤りだと気づけたのは、記事に書くために数え直したからにすぎません。

数字は、それ単体では意味を持ちません。何を数え、何を除外したかとセットでなければ、別の場面へ持ち出した瞬間に意味が変わります。 集計の話をする記事が、自分の集計で一度躓いた——これは書いていて居心地が悪いのですが、記録として残す価値のある種類の躓きだと考えています。

7. レベル欄が空のまま残っている151件

もう一つ、実測して分かったことがあります。433件のうち151件は、レベル欄が空です。

レベル件数
1(緊急対応)27
2(まとめて後日対応)114
3(一旦、保留)52
4(検討対象外)69
73(TAKT 保留)6
74(TAKT 対象外)14
(空欄)151

151件は、全体の3分の1を超えます。ただし、うち129件は実機確認まで済んでいます。 未処理のまま放置されているのではなく、レベルを付けないまま処理されたという形です。

変換スクリプトは、これを level: null として保持します。空欄を「未分類」という別のレベルへ機械的に振り替えることはしていません。 空欄は空欄のまま持ちます。

分類しきれていないものを、分類しきれていないまま保持する。 これは怠慢ではなく、意図した設計です。無理に埋めれば、埋めた値がいつのまにか根拠として使われます。空欄であれば、「まだ決めていない」ことが一目で分かります。

8. まとめ——片づいたのは、全部やらなかったから

2か月で127件を実機確認済みにできました。しかしこれは、433件のうち306件をやらなかった結果でもあります。

内訳を見れば、その構造がはっきりします。レベル3・4・73・74に分類した141件は、分類された時点で当面の対象から外れています。 レベル欄が空の151件は、そもそも分類の対象にもなっていません。残ったレベル1・2の141件に集中しました。

課題管理の道具を入れることの効果は、課題を漏れなく追えるようになることではありません。 433件を1枚の表で眺めても「多い」としか分かりませんが、レベルと状態で切ってみれば、「本当に手を付けるべきなのは141件だ」という判断ができるようになります。

道具が与えてくれるのは、やることを増やす能力ではなく、やらないと決める根拠です。

動画作成には自信があります!

【番外編】エージェントを乗り換えて、何が変わり、何が変わらなかったか

エージェントを乗り換えて、何が変わり、何が変わらなかったか

第8回の最後に、こう書きました。

より賢いモデルが出れば不要になる工夫は、この中に一つも無い。

連載を書き終えたあと、実装エージェント側のプロバイダを切り替えました。 TAKT の runtime.yaml で、provider.profiles の既定を Claude から Codex(gpt-5.6-luna)へ変更し、対話AI側は Claude Code のまま残しました。

その後6日間・11セッションを回した結果を、この番外編で書きます。 期せずして、連載の主張を著者自身が検証する形になりました。

0. 先に断っておくこと

これは「Claude Code と Codex のどちらが優れているか」という記事ではありません。

比較には対照実験が要ります。しかし切り替えの前後では、扱っている課題も、文書の規模も、開発のフェーズも違います。同じ作業を両方でやって比べたわけではないので、優劣は書けません。 連載で「実測してから書く」と繰り返しておきながら、ここで印象論を書くわけにはいきません。

書けるのは「切り替えたときに、何が影響を受け、何が影響を受けなかったか」だけです。 それでも、そこには一つはっきりした結果が出ました。

1. 変わらなかったもの——工程のすべて

結論から書くと、第1回から第8回までに書いた工程は、一つも書き換えていません。

R0調査 → 仕様書 → build-step → 独立検証 → コミット
→ デプロイ → 実機確認 → 課題管理表の更新

この流れも、三層構造(人・対話AI・実装エージェント)も、仕様書を条件で書くことも、完了確認で止めることも、そのまま通用しました。

それどころか、連載で書いた原則が必要になる場面が、切り替え後も同じ頻度で発生しています。

連載で書いたこと切り替え後に起きたこと
第3回:報告値をそのまま転記しない「フェンス行数364で不変」という報告に対し、実測は前後とも356だった
第3回:報告の状態表示を信じないステータスが「実装未着手」でも、実測すると正しく反映されていた(複数回)
第8回:発見は広く、是正は狭く対象を2課題に限定した依頼で、指示していない別課題の食い違いまで4文書すべてで自主的に是正された
第5回:既存の失敗と自分の変更を切り分ける変更を退避した状態でも同じ5スイート29件が失敗することを確認し、無関係と実証した

プロバイダが変わっても、報告値と実測値は食い違います。ステータス表示は実態とずれます。指示範囲を超えた自主是正は起きます。 これらは特定のモデルの癖ではなく、「エージェントに作業させて報告を受け取る」という構図そのものに付随する性質であると考えるほうが、実測に合っています。

2. 変わったもの①——トークン上限という物理的な壁

一方で、切り替えによって新しく必要になった工夫が2つあります。1つ目は、依頼の分割です。

まず、対象の規模を示しておきます。実装ファイルのみ(テストを除く)で161ファイル・54,678行・2.21MBです。内訳の主なものは次のとおり。

領域ファイル数行数
frontend/src/pages1912,035
backend/src/routes2211,735
backend/src/services256,161
frontend/src/components163,731
backend/src/lib242,214
(ほか)5518,802
合計16154,678

画面1本あたり、エンドポイント1本あたりのファイルが厚いのです。 frontend/src/pages は1ファイル平均633行、backend/src/routes は同533行です。第1回で書いた設計文書4本(約84万字)と合わせると、「関連しそうなものをまとめて読ませる」という依頼の出し方が、そもそも成立しない規模になっています。

その前提で、設計文書4本を横断して自己矛盾を洗い出すラウンドを依頼したところ、2回連続で異常終了しました。

Request too large for gpt-5.6-luna ... tokens per min (TPM): Limit 200000

詳細設計書1本だけで6,700行を超えるため、全文読み込みを前提とした依頼が分あたりのトークン上限に抵触していました。

対処は、依頼を「1回1観点」まで絞ることでした。 全文を読ませるのをやめ、確認したい観点ごとに該当する章・節番号を明示し、部分的に読ませる形へ分割しました。これで解消しました。

この経験から得た一般則は、意外と単純です。4文書を横断する走査ラウンドは、最初から観点ごとに分割して依頼するほうが、手戻りが少ない。「まとめて1回で」を優先すると、かえってやり直しの回数が増えます。そして「やり直しの回数」は、第7回で書いたとおり、人の実行回数として跳ね返ります。

3. 変わったもの②——プロンプトの問題に見えて、設定の問題だった

2つ目のほうが、教訓としては大きいものです。

切り替え後、依頼文に禁止の文言を一切含めていないにもかかわらず、エージェントが「ツール使用が禁止されている」という趣旨の報告だけを返し、調査も実装も一切せずに終了するという事象が、複数回発生しました。

当初の対処は、運用での回避でした。依頼文の冒頭に、次の一文を足します。

本タスクではファイルの読み取り・調査・編集にツールを使用してください。ツール使用は禁止されていません。

これで実際に解消しました。 解消したのだから、原因は依頼文にあると考えたくなります。

しかし、原因は依頼文ではありませんでした。 後日、TAKT のワークフロー設定4ファイルを見直したところ、runtime.yamlprovider.profiles.*.options.allowed_tools——エージェントに許可するツール(ReadGlobGrepEditWriteBash)を列挙する箇所——に不足があった可能性が浮上しました。

許可リストに BashEdit が無ければ、エージェントの側からは「一部の操作を禁止されている」ように見えます。 依頼文に何の制約も書かれていなくても、です。設定を見直したあとのセッションでは、この事象は再発していません。

この一件から、運用の目安を一つ加えました。

依頼文の書式を2回調整して改善しなければ、3回目を試す前に、ワークフロー・ランタイム設定の側を点検する。

「プロンプトを工夫すれば直る」ように見える不具合が、実は実行環境の設定に由来していることがあります。 そして回避策が効いてしまうと、根本原因は見つからないまま残り続けます。回避策が効いたことは、原因が特定できたことを意味しません。

4. 導入時の前提条件

実務的な注意点を一つ。TAKT から Codex を使うには、ChatGPT の契約とは別に、エージェント向けの契約が必要になります。

runtime.yamlprovider.profiles はプロファイル単位で構成されており、既定プロファイルを Codex に、別プロファイルを Claude に割り当てて併存させることもできます。切り替えは設定ファイル1本の変更で済みますが、その手前に契約の確認が要ります。 試す前に把握しておくと、段取りが変わります。

5. 現在の構成

保守フェーズに入った現在は、次の組み合わせに落ち着きつつあります。

使用しているもの
対話AI(仕様書・検証条件の設計)Claude Code
実装エージェント(実装・テスト・走査)Codex(TAKT経由)

この2つを分けていること自体は、連載第1回で書いた三層構造そのままです。 変わったのは、三層目に入るものが差し替わっただけで、層の設計は動いていません。

6. まとめ——工程は、乗り換えのコストを下げる

6日間・11セッションを回して、はっきりしたことがあります。

工程を「ツールの使い方」として組んでいたら、乗り換えのたびに組み直しになっていました。 そうならなかったのは、連載で書いた原則がどれも「報告を実測で検証する」「範囲を超えたら止める」「壊れる前に確かめる」という、エージェントの実装に依存しない形をしていたからです。

切り替えで新しく必要になったのは、トークン上限への対処と、ランタイム設定の点検という2点だけでした。どちらも工程の話ではなく、環境の話です。

第8回で「より賢いモデルが出れば不要になる工夫は一つも無い」と書きました。今のところ、この主張は取り下げなくてよさそうです。 ただしこれは6日間・11セッションの結果にすぎません。さらに回した先で覆るなら、そのときはまた実測を添えて書きます。


参考リンク

動画作成には自信があります!

AIが人の一覧を超えるとき

AIが人の一覧を超えるとき

第2回で、仕様書を「行番号の一覧」ではなく「条件」で書くようにした話を書きました。その狙いは、人が見落とした該当を、実装を全文走査するエージェントの側で拾わせることでした。

最終回は、それが実際に起きた場面を書きます。TAKTが、人の作った一覧にも仕様書にも無かった乖離を、自ら見つけた実例が3つあります。

1. 誰も挙げていなかった一覧

設計文書への反映作業で、走査が2件の該当を検出しました。

  • ある章の設定キー一覧に、新設した2つのキーが載っていなかった
  • 別の節の記述が、処理の起動時刻を固定値かつ特定のタイムゾーン固定として述べていた(実際には設定変更が可能になっていた)

この2件が示すことは、単に「見落としがあった」ということではありません。調査ラウンドの報告も、その報告を読んで書いたひかりの仕様書も、どちらもこの章を一度も挙げていませんでした。

つまり、人(ひかり)が2段階の工程を経て作った一覧に、この2件は最初から入っていなかったのです。 条件による走査でなければ、そのまま取りこぼしていました。

2. 仕様書に書いていないことを、TAKTが直した

もう一つは、性質が異なります。

あるテストの是正作業で、期待値が旧い仕様のまま残っていた箇所を直す指示を出しました。仕様書には「改めた箇所にコメントを残す」としか書いていませんでした。

ところがTAKTは、そのファイルの冒頭にあるコメントが、旧い仕様を断定的に説明していることを自ら見つけ、あわせて是正しました。

期待値だけを直していれば、そのコードの冒頭に、誤った前提を説明するコメントが残り続けるところでした。 テストは通りますが、次にそのファイルを開いた人は、冒頭のコメントを読んで誤解します。最も見つかりにくい種類の負債です。

3. 判断を仰いだ場面

三つ目は、TAKTが「直さなかった」例です。

同じ作業で、TAKTはある群のテストについて「これは仕様判断を要する」と報告し、そこで止まりました。実装を直すべきか、テストの期待値を直すべきかが、コードだけからは判定できないという理由でした。

この報告は正しいものでした。 課題管理表を確認すると、その論点についての方針が、過去の課題の記録として残っていました。コードには書かれておらず、資料の側にしか存在しない情報でした。

ここで重要なのは、TAKTが「判定できない」と正しく述べたことです。もし推測で片方を選んでいたら、確定済みの方針と食い違う実装になっていた可能性があります。

4. 3つの例から見える線引き

この3つは、それぞれ違うことを示しています。

場面TAKTの振る舞いなぜ正しかったか
一覧に無い該当を発見条件に該当するものとして報告仕様書が「条件」で書かれていたため、一覧の外まで探せた
コメントの旧仕様を是正仕様書に無いことを、自ら是正是正の目的(旧仕様の記述を残さない)に照らして一貫していた
仕様判断が必要と報告判断せず、止まって報告コードの外にある情報が必要であり、推測すれば誤りえた

2番目だけが「仕様書に無いことをした」例です。 これを許容してよかったのか——連載を通して「指示にないことは独自に判断させない」と書いてきた立場からすると、矛盾するように見えるかもしれません。

しかし、2番目は「是正の対象を広げた」のではなく、「同じ是正を、同じ理由が当てはまる箇所に適用した」ものです。 旧い仕様の記述を残さないという目的は、期待値にもコメントにも等しく当てはまります。目的の範囲内での適用は、範囲の逸脱ではありません。

一方、3番目で止まったのは、目的そのものが定まっていなかったためです。「実装が正しいのか、テストが正しいのか」は、是正の目的の定義に関わる問いであり、コードからは決められません。

この線引きは、実は第7回で書いた人間側の作法とまったく同じ形をしています。 任された範囲では決める。任されていない範囲では止まって報告する。同じ原則が、人にも、対話AIにも、実装エージェントにも適用されています。

5. 走査を「書き込みの後」に置く

ただし、この自律性には条件があります。走査は、書き込みの前ではなく後に置きます。

これは経験から定まった順序です。先に走査させると、TAKTがその結果を踏まえて、編集範囲を自ら広げる余地が生まれます。 走査で見つかった該当を、そのまま「ついでに」直してしまえる状態になります。

そこで、書き込みを終えてから走査させ、該当が見つかっても「是正せず報告する」という形にしています。冒頭で挙げた2件も、この形で報告され、次のラウンドとして人が判断してから是正しました。

自律的に発見させることと、自律的に是正させることは、分けて設計できます。 発見の範囲は広く取り、是正の範囲は狭く保つ。この2つを混ぜないことが、走査を安心して任せられる条件になっています。

6. 連載のまとめ——8回で書いてきたこと

全8回を通して書いてきたことを、最後に整理します。

  1. 三層構造——人が決め、対話AIが仕様と検証条件を設計し、実装エージェントが実装する
  2. 仕様書は条件で書く——一覧は書いた人が見つけた範囲でしかない
  3. 報告ではなく検証手段を疑う——誤っているのは、たいてい確認コマンドの側である
  4. 完了確認は「止まる条件」まで書く——数値を報告させるだけでは足りない
  5. バックアップは作業の外側に置く——gitの挙動を把握しないまま復元に使わない
  6. 誤りは消せない、拾う——1セッションで7件、すべて書き込み前に検知された
  7. 工程は人の実行回数で数える——最適化すべきはAIの手間ではない
  8. 発見は広く、是正は狭く(本稿)

この8つに共通するのは、どれもAIの性能の話ではないということです。 より賢いモデルが出れば不要になる工夫は、この中に一つもありません。むしろ、エージェントが賢くなるほど、「どこまでを任せ、どこで止めるか」の線引きは重要になります。

第1回に書いたとおり、この連載は成功談ではありません。書いてきたのは、誤りの記録と、その誤りが実害になる前に止まった仕組みの話です。 誤りが7件あったセッションを「うまくいった日」と呼べるのは、7件すべてがどこかで止まったからにすぎません。

AIと開発するとは、AIに開発させることではありません。 誤りうる主体を複数並べ、それぞれが違う種類の誤りを拾えるように工程を組み、そのうえで人が決める——そういう作業のことです。

この連載が、同じ問題に取り組んでいる方の参考になれば幸いです。 8回にわたりお読みいただき、ありがとうございました。


参考リンク

動画作成には自信があります!

人間側の作法——指示は字面でなく実体で/工程は「人の実行回数」で数える

人間側の作法——指示は字面でなく実体で/工程は「人の実行回数」で数える

これまでの6回は、AIの側の設計を書いてきました。仕様書の書き方、報告の検証、完了確認、バックアップ、そして誤りの実例。第7回は視点を変えます。対話AI(ひかり)の側にも、繰り返し是正されてきた作法があります。 その一部を書きます。

結論を先に書きます。この開発でいちばん高くつくのは、AIの誤りではなく、人の実行回数です。

1. 指示は字面ではなく実体で受け取る

ある指示に対し、指示文中の語をそのまま検索キーワードとして扱い、見つからないと「実行できません」と述べたことがありました。見つからなかった時点で書式を変えて検索をやり直し、それでも見つからず、また書式を変える——これを4回繰り返しました。

このとき指摘を受けた一言があります。

字面が無い=指示が特定できない、と結論づけたことが誤りです。

指示の実体は、別の言い回しで文書の中に存在していました。 探し方を変えて何度も検索を繰り返すことは、一見粘り強く見えますが、実際には指示を出した人の確認の手間を増やしているだけです。 以降、こうしています。

  • 見つからないと分かった時点で、探索をやめる
  • 語を変えて検索を繰り返さない
  • 「どういう状態を指しているか」を、その場で尋ねる

字面と実体がずれる場面は、大きな開発ほど増えます。同じ対象を指す呼び方が、文書ごとに、時期ごとに変わっていくためです。探すことに時間を使うより、尋ねることに時間を使うほうが、双方にとって早いのです。

2. 質問は冒頭に、1回に1件

長い報告や考察の末尾に質問を置くと、その質問がどこにあるか自体を、相手が探さなければなりません。

質問までの、回答、コメントが長くなるほど、事故が発生します。

これ以降、次の3つを徹底しています。

  1. 質問は、応答の冒頭に置く
  2. 1回の応答で、質問は1件に絞る。 複数の質問を並べると、いただいた返答がどの質問への答えなのかが判定できなくなる
  3. 選択肢は、相手にしか決められないことに限って並べる。 選べる形で並べること自体が、論点を不必要に増やす

3. 貼り付けだけを受け取ったときは、止まっていることを明示する

調査結果や実行結果の貼り付けは、それ自体では質問への回答になりません。 貼り付けを受け取っただけで作業を先へ進め、実は先に出していた質問への回答をまだ受け取っていなかった、という事故が実際に起きました。

以降、「これは質問への回答ではないため、止まっています」と明示することにしています。黙って待つのではなく、止まっていることそのものを言葉にします。指示を出す側も、時に取り違えることがあります。双方の食い違いを防ぐのは、沈黙ではなく明示です。

4. 止まることを目的化しない

作法を是正した直後、今度は逆方向に振れたことがありました。何でも案を並べて判断を仰ぐようになり、任せられた範囲まで止まって確認を求めるようになりました。

では、このまま何も対応しない意思と捉えます。

止まるべきは、指示の範囲を超えるときです。「決めるのが不安なとき」ではありません。 任された範囲では決めます。判断を仰ぐのは、相手にしか決められないこと(設計判断・仕様の解釈・運用の方針)に限ります。

第1〜6回で書いてきた「TAKTは仕様書に無い乖離を独自に是正しない」という設計は、実はこの原則の裏返しでもあります。任された範囲は進め、任されていない範囲は止まって報告する。 この線引きは、AIエージェントにも、対話AI自身にも、同じ形で適用しています。

5. 気づいた不整合を、その場で課題として立てない

作業中に、本題とは別の小さな不整合に気づくことがあります。それをその場で課題として提起しないことにしています。

1点でもほころびがあると、課題にするため、未整理が増え、そもそも忘れてしまう。

引き継ぎ資料に記録するだけに留め、整理する時機は、指示を出す側が決めます。 気づいたことを逐一提起するのは、一見誠実に見えますが、受け取る側の検討事項を無制限に増やす行為でもあります。

同じ理由で、新しい運用・新しい分類・新しい欄を、こちらから提案しないようにもしています。既存の枠の中で解く方法を、まず探します。運用を増やす提案は、課題を新規に作るのと同じだけの負担を、後々まで残します。

6. 定着している運用を、確認せずに変えない

ある更新作業で、「相手が内容を編集する」という前提で手順を組み立てたことがありました。実際には、その更新は一貫してこちら側の担当であり、相手はスクリプトを実行するだけという運用が、最初から定着していました。

今まで一度も私が更新したこともありません。

定着している運用は、書き換える前に必ず確認します。 良かれと思って前提を変えることは、相手の作業のやり方そのものを覆すことがあります。

7. 調査は、原則としてTAKTに依頼する

視点を変えて、もう一つ。「範囲が絞れているように見える調査」を、手元のコマンドで済ませてしまうことがありました。「TAKTの報告はどのみち実測で検証するのだから、最初から自分で実測したほうが早い」という判断でした。

これは誤りでした。 減っていたのは、対話AI側の工程数にすぎません。指示を出す側のコマンド実行の回数は、むしろ増えていました。1件の調査に4往復かかり、うち2回は対話AI側の誤りによる作り直しでした。

8. 工程数は「人の実行回数」で数える

ここが、この回でいちばん大事な点です。工程数を、対話AIやAIエージェントの作業回数ではなく、指示を出す人が実際にコマンドを実行した回数で数えます。

この観点に立つと、評価が逆転することがあります。「対話AIが自分で調べれば1工程減る」という判断は、対話AIの工程を1つ減らす代わりに、人の実行回数を増やしていました。 逆に、TAKTへ調査を依頼すれば、対話AIの工程は1つ増えますが、人が実行するコマンドは減ります。

以降、次の形にしています。

種別担当
コードの調査(実装・依存関係・テスト・呼び出し関係・規模)TAKT(実装エージェント)
本番のデータの実測(データベース・実ファイルなど)人が実行
手元に持ち込めた成果物の解析(添付ファイルなど)対話AI

手元のコマンドで代替してよいのは、1〜2本のコマンドで判定が終わる場合に限ります。 それを超える調査は、範囲が絞れているように見えても、TAKTへ依頼します。

依頼する範囲は、意図的に広く取ります。 往復を減らすため、後続の判断に必要になりそうな事項(依存の有無・規模・既存のテストの所在など)まで、最初の1回の依頼にまとめて含めます。細かく分けて何度も依頼するほうが、結果として人の確認の回数を増やします。

9. まとめ——最適化すべきは、AIの手間ではない

この回で書いた作法は、どれもAIの性能とは無関係です。指示の受け取り方、質問の出し方、止まる基準、報告の作法、そして工程の数え方——これらはすべて、指示を出す人の負担をどう小さくするかという一点に集約されます。

第6回で「AIは誤る前提で工程を組む」と書きました。この回で書いたのは、その裏側にある原則です。AIの側の工程をどれだけ効率化しても、人の確認の回数が増えていれば、開発全体としては遅くなっています。 最適化すべきは、AIの手間ではなく、人が実際に手を動かす回数のほうです。


次回(第8回・最終回):AIが人の一覧を超えるとき。TAKTが、人の作った一覧や仕様書には無かった乖離を自ら発見した実例と、そこまで任せてよい範囲について書きます。

動画作成には自信があります!

PAGE TOP