ユーザーの判断が必要なとき
Bridge は実行前にモデルで質問を繰り返すことはありません。確認するのは形式と必須内容であり、依頼の意味が十分に明確かどうかまでは判断しません。writer の作業内容も reviewer の判定基準も作業指示が根拠になるため、要件、制約、未決事項をそこに書きます。ユーザーの対応や承認が必要になるのは、次の 3 つの場面です。
カードの表示前:必要な内容を補う
start は作業指示をフォームとして読み取ります。必要な内容がなければ、カードの前で停止して問題と行番号を表示します。
requested_workまたはrun_planが空で、作業内容がない。- 完了条件のリストがない、またはリスト項目でない行がある。
一、や(1)は Markdown のリスト記号ではありません。 open_questionsに質問が残っている。各行を未回答として扱うため、回答を作業指示へ書き、質問を削除するかnoneだけにしてください。
必須ブロックのマーカーを削除していた場合は、既存の文章を変えず、マーカーと見出しを末尾に補います。内容を記入し、表示されたコマンドを実行し直してください。この処理でトークンは使いません。
決まっていないことは open_questions に残してください。回答するまで start が止まるため、writer の推測で進むのを避けられます。
カードの確認時:実行内容を承認する
カードには、固定した作業指示の原文、コントラクトの SHA-256、範囲、予算、役割を表示します。承認の対象はその内容です。後から編集した内容を使うには、再び start が必要です。エージェントはカード全文を提示して回答を待つだけで、代わりに承認してはいけません。
実行中:判断が必要になって停止する
writer は実行途中に回答を待ち続けることはありません。判断が必要、未完了で停止、または reviewer がユーザーの判断・範囲外の変更・公開操作を理由に停止を求めた場合、run を終了します。結果のタイトルは Your decision needed となり、Why に質問や writer の説明、reviewer の停止理由を記載します。Next step の案内に従って作業指示に回答を書き、start を実行し直してください。自動修正の回数を使い切った場合は Needs fixing になります。
記入した内容がどう使われるか
各ブロックはそのままコントラクトへ転記し、完了条件のリストを 1 項目ずつ条件にします。writer の各ラウンド後に Bridge がテストし、reviewer が条件ごとに確認します。結果は proven、failed、unknown です。コードやテストから確かめられない条件は、見た目がよくても unknown のままです。
完了条件は、コード、テスト、アプリの動作から reviewer が確認できる内容にしてください。
同じ変更を 3 通りで依頼する
以下は同じ変更の依頼で、どれも形式チェックを通ります。違うのは writer に委ねる判断の量と、reviewer が確認できる範囲です。
短く依頼する
# 同期時刻の表示
<!-- bridge:requested_work -->
ダッシュボードのどこかに最終同期時刻を表示する。
<!-- bridge:acceptance -->
- 同期時刻が見える。場所、文言、形式は writer に任せることになり、reviewer が確認できるのも時刻が表示されることだけです。試作には使えますが、公開する成果に具体的な期待があれば、条件を補う必要があります。
利用場面から伝える
# データの最終同期日時を表示する
<!-- bridge:context -->
ダッシュボードの数値が最新かどうか、サポートへの問い合わせが続いている。
<!-- bridge:requested_work -->
ダッシュボード上部に、最後に同期が成功した日時をユーザーのタイムゾーンで表示する。
<!-- bridge:acceptance -->
- 読み込み後、画面上部に「最終同期」と日時を表示する。
- 一度も同期していない場合は、空欄ではなく「まだ同期されていません」と表示する。
- ブラウザーのタイムゾーンを使う。ファイル名やコードは不要で、変更する場所は writer が探します。各条件をコードやテストで確認でき、一度も同期していない場合も含めて、期待する成果が明確になります。
変更するコードを指定する
# DashboardHeader:lastSyncedAt を表示する
<!-- bridge:requested_work -->
`DashboardHeader.vue` で `GET /api/sync/status` の `lastSyncedAt` を読み、
`src/utils/time.ts` の `formatLocalTime()` で表示する。
<!-- bridge:scope_notes.include -->
- src/components/DashboardHeader.vue
- src/utils/time.ts
<!-- bridge:acceptance -->
- `lastSyncedAt` があれば「最終同期」に続けて `formatLocalTime()` の出力を表示する。
- `lastSyncedAt` が `null` なら「まだ同期されていません」と表示する。
- `npm test` が通る。
<!-- bridge:open_questions -->
noneファイルと関数を指定すると writer の出発点が明確になり、範囲のメモで変更先も伝えられます。コードを把握している場合に向いています。ユーザーに何が見えてほしいかだけが決まっていれば、ひとつ前の書き方で十分です。
どの書き方でも押さえておきたいこと
- 1 件の作業指示はひとつの変更に絞ります。無関係な変更は分け、それぞれの成果を確認できるようにします。
- 空データ、欠損、エラー、2 回目の操作など、重要な境界条件を書きます。記述がなければ、その場面の明確な判定基準もありません。
- 変えてはいけない動作は
scope_notes.must_keep、既知の背景はcontextに書きます。どちらもコントラクトに転記され、writer が読みます。 - チームの慣例、過去の決定、完了済みの実例は
referencesに文書パスを記載します。これもコントラクトに転記します。
使えるブロックは最初の作業指示にまとめています。