Intake サイト UI 仕様
起案者向けサイト
/intakeの UI 仕様。 審査側 chat UI (/chat) とは別の SPA として独立。基盤は ADR-0164。
実装:
- Hono sub-app:
drp/src/intake/intake_app.ts - 純粋 helper:
drp/src/intake/intake_pure.ts - Rewrite 経路:
drp/src/intake/intake_chat_fallback.ts - ADR テンプレ inject:
drp/src/intake/adr_template_inline.ts - 公開 SPA:
drp/public/intake.html
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。SSoT は
docs/_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 経路分岐の条件
intake_pure.ts::isRewriteRequest(text)またはisSectionRewriteRequest(text)が true- どちらかが true の OR で SSE 経路を発火
3.2 SSE event の構造
| event | data | 用途 |
|---|---|---|
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. 起案者フロー
- ブラウザで
/intakeを開く。envINTAKE_SITE_ENABLED=true必須・未設定なら 410 Gone /intake/meで author を自動取得 → 起案フォームに反映- context 欄に起案本文を書きながら、右ペインで壁打ち AI と対話
- 必要に応じて Rewrite / Section Rewrite で context を更新
- 「commit」を押す
/intake/commitが triage と静的 lint を atomic に走らせる- 両方 pass で
DRAFTS_KV.putを実行し、draft_id+ 「審査へ進む」CTA を返す - 起案者は
/chat?draft=<draft_id>で審査キューへ載せる動線へ進む
reject 時はどちらかが fail で KV に保存せず即座に画面で返します。
LLM 由来 reject (problem_space_pregate) は intake では走らせないため、起案者は「土俵に乗った」気で離脱しても審査側で再 reject される可能性があります。
通知設計は ADR-0166 で別決定。
5. UI と worker の API 契約
5.1 routes 一覧
| method | path | 用途 | 副作用 |
|---|---|---|---|
| GET | /intake | intake.html を返す | なし |
| GET | /intake/me | JWT 由来 author を返す | なし |
| GET | /intake/chat | 壁打ち AI の値域 + flag を返す | なし |
| POST | /intake/chat | 壁打ち AI を 1 ターン回す | console.log のみ |
| POST | /intake/triage | triage プレビュー (KV 書込なし) | なし |
| POST | /intake/commit | triage + 静的 lint pass で KV put + telemetry | KV put + D1 insert |
| GET | /intake/drafts | KV draft 一覧 (audit status 付き) | なし |
| GET | /intake/drafts/:id | 単一 draft 取得 | なし |
| PUT | /intake/drafts/:id | 途中保存 (triage skip) | KV put |
| DELETE | /intake/drafts/:id | draft 削除 | 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 で次の優先順位:
- JWT 由来 email (via='user' のとき)
- 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. 参照
- 上位カテゴリ: intake_chat README
- プロンプト設計: prompt.md
- 観測 telemetry: state.md
- 審査側ノード仕様:
../nodes/