起案者向けサイト /intake の UI 仕様。 審査側 chat UI (/chat) とは別の SPA として独立。基盤は ADR-0164

実装:


1. 役割と位置づけ

起案者が「ADR の起案を土俵に乗せる」までを完結させるサイトです。 壁打ち AI と対話して起案文を仕上げ、triage 判定 + 静的 lint を pass したら KV に commit します。

審査側 Pipeline (/chat) とは UI も bundle も分離しています。 verdict プレビュー・補強策プレビュー・3 モデルレビュー結果・PR 作成ボタンはすべて intake.html に含めません。

ADR-0164 が課す境界:

  • 起案者の責任 = 「土俵に乗ったかの確定」までで一発完了する体験
  • 審査者の責任 = 価値ある起案かを別画面 /chat で裁く
  • 壁打ち AI は審査結果を絶対に予測しない

2. UI 構成

intake.html は左ペイン (起案フォーム) + 右ペイン (壁打ちチャット) の 2 ペイン構成です。

2.1 起案フォーム

  • author 欄: 起動時に /intake/me で JWT 由来 email を自動取得。詳細は ADR-0096
  • title 欄: 起案タイトル。30 字以内・動詞 + 目的語形。style-guide §3.7 準拠
  • context 欄: 起案本文 (markdown)。canonical 10 節構造で書く
  • options 欄: 検討した代替案。任意・空文字可
  • commit ボタン: triage + 静的 lint を走らせて KV へ保存

2.2 壁打ちチャットパネル

  • env INTAKE_CHAT_ENABLED=true のとき右ペインを表示
  • model 切替: claude-sonnet / claude-opus / gemini-pro / gemini-flash の 4 択
  • max_tokens 切替: 1024 / 4096 / 16384 の 3 択
  • 既定: claude-opus + 16384 token
  • 履歴は直近 20 ターンに cap。user/assistant 合計 40 messages
  • temperature = 0.4。壁打ちのため triage の 0.2 より柔らかく設定

2.3 Rewrite モード

起案者が「ここまでの議論を踏まえて修正版の起案本文を Markdown 全文で出力してください」または「rewrite モード」と書くと発火します。

  • 出力は context 欄にそのまま貼り付けられる ADR 本文 markdown 全文
  • 説明や前置きは出力しない
  • ADR draft template を system prompt 末尾に inject。SSoTdocs/_meta/templates/adr-draft.template.md
  • canonical 10 節 (§1 Executive Summary 〜 §10 過去 ADR との関係) を厳格に守る

2.4 Section Rewrite モード

「セクション rewrite モード」+ ## セクション名 を書くと発火します。

  • 対象セクション 1 つだけを出力。他節は出力しない
  • 該当節の構造規約に従う。例: Executive Summary なら 5 行 bullet
  • 複数候補が同等に見える場合は出力せず「対象セクションを 1 つに絞ってください」と返す

3. SSE chunked transfer 経路

Rewrite モード時は出力が長くなり、典型 4-8k token に達します。 Cloudflare Workers の wall-clock 30 秒制限を超えて 524 origin timeout を踏むため、Rewrite / Section Rewrite モード時のみ SSE 経路に分岐します。 通常応答の 3-7 文の壁打ちは既存 JSON 1 ショット経路を維持します。

3.1 経路分岐の条件

3.2 SSE event の構造

eventdata用途
chunk{ delta: string }LLM の partial 出力を逐次追加
done{ usage, model, max_tokens, llm_ms, total_chars }最終 usage と統計を返す
error{ error: string, status?: number }upstream 失敗・read エラー

3.3 client 側の適用

  • intake.html は ReadableStream で chunk を受け、context 欄に逐次 append
  • Section Rewrite 時は対象節だけを差し替え。実装は intake_pure.ts::rebuildContextWithSection
  • done 受信で UI のスピナーを止める

4. 起案者フロー

  1. ブラウザで /intake を開く。env INTAKE_SITE_ENABLED=true 必須・未設定なら 410 Gone
  2. /intake/me で author を自動取得 → 起案フォームに反映
  3. context 欄に起案本文を書きながら、右ペインで壁打ち AI と対話
  4. 必要に応じて Rewrite / Section Rewrite で context を更新
  5. 「commit」を押す
  6. /intake/commit が triage と静的 lint を atomic に走らせる
  7. 両方 pass で DRAFTS_KV.put を実行し、draft_id + 「審査へ進む」CTA を返す
  8. 起案者は /chat?draft=<draft_id> で審査キューへ載せる動線へ進む

reject 時はどちらかが fail で KV に保存せず即座に画面で返します。 LLM 由来 reject (problem_space_pregate) は intake では走らせないため、起案者は「土俵に乗った」気で離脱しても審査側で再 reject される可能性があります。 通知設計は ADR-0166 で別決定。


5. UI と worker の API 契約

5.1 routes 一覧

methodpath用途副作用
GET/intakeintake.html を返すなし
GET/intake/meJWT 由来 author を返すなし
GET/intake/chat壁打ち AI の値域 + flag を返すなし
POST/intake/chat壁打ち AI を 1 ターン回すconsole.log のみ
POST/intake/triagetriage プレビュー (KV 書込なし)なし
POST/intake/committriage + 静的 lint pass で KV put + telemetryKV put + D1 insert
GET/intake/draftsKV draft 一覧 (audit status 付き)なし
GET/intake/drafts/:id単一 draft 取得なし
PUT/intake/drafts/:id途中保存 (triage skip)KV put
DELETE/intake/drafts/:iddraft 削除KV delete

5.2 state 共有

intake と chat は同じ DRAFTS_KV を共有します。 intake で commit された draft は metadata に committed: true が立ち、/intake/drafts の起案者一覧では状態ラベルが「審査」または「差戻」に変わります。 chat 側は逆に committed: true のみを表示することで責任境界を draft 一覧の表示でも物理表現しています。

draft の状態ラベルは intake_pure.ts::classifyDraftStatus で導出:

  • intake = 起案中。commit 未実行
  • audit = 審査中。commit 済かつ最新 verdict が CONFLICT/SUPERSEDE 以外
  • rejected = 差戻。commit 済かつ最新 verdict が CONFLICT/SUPERSEDE

5.3 author 解決

ADR-0096 に従い intake_app.ts::resolveAuthor で次の優先順位:

  1. JWT 由来 email (via='user' のとき)
  2. body.author (service token または identity 不在のとき)

Cf-Access-Authenticated-User-Email ヘッダは spoof 可能なため不使用です。

5.4 id 自動採番

body.id 空欄なら server が draft-YYYYMMDD-{4-hex} 形式で自動採番します。 JST 日付 + crypto.getRandomValues 由来の 4-hex で、1 日 100 件想定なら衝突確率 ≈ 1/655、3 回連続衝突は ≈ 3.6e-9 で実質起きません。 明示指定経路は CI や scripts/draft_push.sh の後方互換のため温存しています。


6. 撤退条件と無効化

env INTAKE_SITE_ENABLED=false で即時無効化できます。 無効化中は /intake/* 全 route が 410 Gone を返し、起案者は /chat へ誘導される設計です。

ADR-0164 §撤退条件 の主要閾値:

  • wall-time 30s 超過率 > 0.5% (4 週連続) → triage 非同期化案へ移行
  • LLM 由来 reject > 50% (4 週連続) → 静的 lint 拡張
  • /intake 起案完了率の 20% 以上低下 (4 週) → UX 修正
  • KV 100 件上限到達 → 通知設計 ADR の緊急受理 + cleanup batch
  • chat 過剰介入による起案者の能動性低下 (chat 利用 session の commit 試行回数比率 < 0.9 倍) → INTAKE_CHAT_ENABLED を OFF へ戻す

観測列の詳細は state.md を参照してください。


7. 関連 ADR

  • ADR-0164 — intake サイト分離と静的 lint 先行
  • ADR-0157 — C 萎縮対策の先行決定
  • ADR-0142 — 起案前ゲートの LLM 部分
  • ADR-0091 — 静的 lint 3 ルール定義
  • ADR-0096 — author 解決の優先順位
  • ADR-0094 — triage_reject_kind 区分
  • ADR-0166 — 審査側 LLM reject の通知設計
  • ADR-0037 — KV draft staging lifecycle

8. 参照