Repository navigation
Description
親: #2168(Neural Development Factory を Web UI で操作できるサービスにする)。方針: マイルストーン「25 Neural Development Factory」のスプリント MVV の Value 2(画面先行)・Value 4(AI からも人と同じく使える)。
具体例
利用者が、自分の手元の Claude Code から「Factory で #2172 のスプリントを始めて、承認待ちになったら教えて」と頼む。今の Factory には MCP(Model Context Protocol)の受け口が無く、API は画面の都合で 1 件ずつ受け渡す形が混ざっている。この課題の後は、エージェントが利用者の委任で MCP からスプリントを始め、一覧を読み、承認の依頼を読める。ただし承認の確定は人だけが行う。だれの委任で、どのエージェントが、いつ何をしたかは、追記だけの記録に残る。
依頼(原文)
| AI からも人と同じく使える | 画面で行えるすべての操作を API と MCP からも行える。画面も同じ API を通る。委任を明示する認証・人と同じ認可・追記だけの操作の記録を持つ。承認ゲートとレッドラインの承認は人だけが行う |
| 画面先行 | UX の土台(画面の地図・部品・端末・オフラインの見せ方・国際化)→ 機能の画面をダミーデータで作り切る → API の中身をつなぐ、の順で作る。API の入出力は画面の 1 枚に合わせず機能から起こし、常に配列で受け渡す |
(書き手: 利用者、日付: 2026-11-02。#2168 の「方針(利用者の決定)」の表の 2 行。表は起票者が書き起こしたもので、利用者の決定として承認された行である)
画面で行えるすべての操作を API と MCP からも行えるようにする。画面も同じ API を通して動かし、画面にしか無い操作も、API や MCP にしか無い抜け道も作らない。ただし、承認ゲートの承認と、共通原則の C1〜C8・プロジェクト MVV の P に当たる操作の承認は人だけが行う。API と MCP からは承認の依頼と材料を読めるが、承認を確定できない(AI のエージェントの委任でも同じ)。API と MCP を使う者は、だれの委任で、どのエージェント・クライアントが動くかを確かめ、認可は人の操作と同じく掛ける。読み取りを含むすべての操作を、だれが・いつ・どの経路で・何を行ったかの追記だけの記録に残す。秘密と個人情報の値は記録に書かない。
(書き手: 利用者の承認を受けたスプリント MVV の Value 4、日付: 2026-11-02。文面は起票者が利用者の方針から起こし、利用者がスプリント MVV として承認した)
課題の題と、この後の「何をするか」の表・受け入れ条件の案(起票時の本文)は起票者が書いた。原文に無い条件は「起票者の推定」に分けた。
起票者の推定
題・本文のうち、利用者の指示の原文に無く起票者が推して足した条件。承認ゲート 1 で利用者が確かめるまで、利用者の決定として扱わない。
| # | 条件 | 推した出所 | この要求での扱い |
|---|---|---|---|
| S1 | 配列の受け渡しで、一部だけ失敗したときの返し方・冪等性・配列の上限を決める | 起票時の本文の「入出力の形」の行 | 受け入れ条件 6〜9、前提 3 |
| S2 | 委任の権限は短い期限で、範囲を絞り、取り消せる | 起票時の本文の「委任の認証」の行 | 受け入れ条件 11〜14、前提 4 |
| S3 | 認可は要素ごとに掛ける | 起票時の本文の「認可」の行 | 受け入れ条件 15 |
| S4 | 操作の記録の項目は、操作した人・委任を受けたエージェントかクライアント・日時(UTC)・呼び出し元の種類(画面・API・MCP)・操作・対象の ID | 起票時の本文の「操作の記録」の行。原文は「だれが・いつ・どの経路で・何を」 | 受け入れ条件 19 |
| S5 | 画面の操作と契約の操作と MCP のツールの対応を、検査で確かめる | 起票時の受け入れ条件の案 1 | 受け入れ条件 1〜3 |
| S6 | C1(秘密に触れる)・C2(認証・認可を変える)に当たる Factory の操作(モデルの認証情報の保存と削除、席の追加・変更・削除、チームの作成)は、委任の資格情報からは確定させず、人が画面で行う | 起票者の推定(この要求で足した)。原文の「C1〜C8 に当たる操作の承認は人だけが行う」を、Factory には操作ごとの承認の仕組みが無いため「委任では確定させない」と読んだ | 受け入れ条件 17、前提 5 |
| S7 | ランナー向けの経路(実行ジョブの経路・進捗の受け口)と GitHub の Webhook は、配列の規則と MCP の対象から外す | 起票者の推定(この要求で足した)。画面で行える操作ではなく、GitHub の Webhook の形は Factory が決められないため | 前提 2、含まない |
目的
- 人が任せた AI のエージェントや連携するシステムが、画面と同じ操作を、画面と同じ認可と記録のもとで行える状態にする
- API の入出力を画面の 1 枚から切り離し、機能(エンティティと操作)単位の配列の形へそろえる。画面・API・MCP が同じユースケースを通る
- 承認ゲートの承認と、人の承認が要る操作の確定を、委任の経路から行えないことを仕組みで保証する
- だれの委任で、どのエージェントが、いつ何をしたかを後から確かめられる記録を残す
前提
- 前提 1: 「画面で行える操作」は、画面の API クライアント(
factory/web/src/api.tsのApi)が呼ぶ操作の全体と、承認と通知(NDF Factory: 承認ゲートの通知(Slack を含む)と Web からの承認 #2173)が足す Web からの承認の操作を指す。2026-11-04 の時点でApiは 31 の操作を持つ(request(の呼び出し 31 件) - 前提 2: 配列の規則と MCP のツールの対象は、利用者(人か、人の委任を受けたエージェント)が呼ぶ操作である。ランナー向けの経路(
/run-jobs/*・/ingest/events・/ingest/api/events)と GitHub の Webhook(/ingest/github)は対象に含めない(S7) - 前提 3: 1 回の要求で受け渡す配列の要素は 100 個までとする。値は設計で実測を見て変えてよいが、上限を超えた要求は処理せずに 400 と上限値を返す、という振る舞いは変えない
- 前提 4: 委任の資格情報の期限は 1 時間以内とする。範囲は「読み取りだけ」と「読み書き」の少なくとも 2 つを選べる。値と範囲の分け方は設計で決める
- 前提 5: GitHub App の導入とリポジトリへの認可は、人がブラウザで GitHub の画面を操作する流れである。MCP からは導入と認可の URL を返すところまでを行い、GitHub の画面の操作は人が行う
- 前提 6: 委任の資格情報の発行と取り消しは、人が画面で行う。委任の資格情報で委任の資格情報を発行できない
- 前提 7: 既存の契約(
factory/contracts/openapi/の 5 ファイル)の経路を配列の形へ変える。画面と API は同じリポジトリで同時に変わり、外部の利用者はまだいないため、旧い形との互換の経路は持たない - 前提 8: 操作の記録を置く表の定義は、インフラ(private リポジトリ)が作る。このリポジトリは保存の契約(interface)と、メモリの実装・本物の実装を持つ
対象範囲
含む:
- 契約(
factory/contracts/openapi/)の利用者向けの操作を、機能(エンティティと操作)単位の配列の入出力へ起こし直すこと - 画面の API クライアントと、ダミーの API クライアントを新しい契約の形へ合わせること
- MCP のサーバー(API と同じユースケースを呼ぶ)と、契約の操作と MCP のツールの対応表
- 委任の資格情報の発行・検証・取り消しと、それを発行・取り消す画面
- 人だけが確定できる操作の印と、その印のある操作を委任の資格情報から断る共通の処理
- 操作の記録(追記だけ)の保存の契約・実装と、すべての利用者向けの操作からの書き込み
- 画面の操作・契約・MCP の対応と、単一のレコードの受け渡しが無いことを確かめる検査
含まない:
- ランナー向けの経路と GitHub の Webhook の形(前提 2)
- Web からの承認の操作そのもの(NDF Factory: 承認ゲートの通知(Slack を含む)と Web からの承認 #2173 が作る)。この課題は、その操作に人だけが確定できる印が付き、委任の資格情報から断られる仕組みを用意する
- 操作の記録を読む画面と、記録の検索の機能
- 操作の記録の保存期間と、国ごとの法令(GDPR など)に応じた削除の手続き(未決 2)
- 外部の利用者向けの公開の手続き(MCP のサーバーの一覧への掲載など)
- インフラの定義(表・Lambda・API Gateway)
ドメインイベント
| # | イベント | 引き金 | 失敗したとき | 順序の前提 |
|---|---|---|---|---|
| E1 | 人が委任の資格情報を発行した | 人が画面で、委任するクライアントの名前・範囲・期限を選んで発行する | 範囲か期限が許す値の外なら 400 で、発行しない | 人がログインしている |
| E2 | エージェントが委任の資格情報で API か MCP を呼んだ | エージェントが操作を送る | 資格情報が無効・期限切れ・取り消し済みなら 401 で、操作を行わない | E1 |
| E3 | 委任の資格情報の範囲と、操作の要る範囲を照らした | E2 | 範囲の外なら 403 で、操作を行わない | E2 |
| E4 | 人と同じ認可を要素ごとに掛けた | E3 | 認可の無い要素は、その要素だけを 403 相当の結果にする | E3 |
| E5 | 人だけが確定できる操作を断った | E3 で、操作に人だけが確定できる印がある | — (断ること自体が結果) | E3 |
| E6 | 配列の要素ごとに操作を行い、要素ごとの結果を返した | E4 | 一部の要素だけが失敗したら、成功した要素はそのまま残し、失敗した要素に理由を付けて返す | E4 |
| E7 | 同じ冪等の鍵の作成を 2 回受け、2 回目は 1 回目の結果を返した | E6 で、作成の要素に既に使われた冪等の鍵がある | — | E6 の 1 回目 |
| E8 | 操作の記録を 1 件追記した | E2〜E6 のすべての結果(成功・一部失敗・401・403・400) | 追記に失敗したら操作を失敗として返す(前提として未決 1) | E2 |
| E9 | 人が委任の資格情報を取り消した | 人が画面で取り消す | 既に取り消し済みなら何も変えずに成功を返す | E1 |
| E10 | 取り消した委任の資格情報での要求を断った | E9 の後の E2 | — | E9 |
E8 の「追記に失敗したとき操作も失敗にするか」は、記録の欠けを許すかと可用性の取り合いである。未決 1 に置いた。
用語
| 用語 | 意味 |
|---|---|
| 委任の資格情報 | 人が画面で発行し、エージェントかクライアントに渡す、期限と範囲つきの資格情報。だれの委任か(利用者)と、どのクライアントか(人が付けた名前と識別子)を持つ。人が取り消せる |
| 人だけが確定できる操作 | 承認ゲートの承認・判断の依頼への答えと、共通原則の C1〜C8・プロジェクト MVV の P に当たる Factory の操作。契約に印を持ち、委任の資格情報からは断る |
| 操作の記録 | 利用者向けの操作 1 回ごとに 1 件追記する記録。書き換えと削除の経路を持たない |
| 呼び出し元の種類 | 操作の記録に残す、操作がどこから来たかの区分。画面・API・MCP の 3 つ |
| 機能から起こした契約 | 経路と入出力を、画面の 1 枚でなくエンティティと操作から決めた契約。取得・作成・更新・削除とも配列で受け渡す |
受け入れ条件
対応と形:
- 1. 画面の API クライアントが呼ぶ操作がすべて契約(
factory/contracts/openapi/)のoperationIdに対応することを、検査(npm run checkの一部)が確かめる。対応しない操作が 1 つでもあると検査が落ちる - 2. 契約の利用者向けの操作がすべて MCP のツールに対応し、MCP のツールがすべて契約の操作に対応することを、検査が確かめる。片方にしか無い操作かツールが 1 つでもあると検査が落ちる
- 3. MCP のツールは、API の経路と同じユースケースの関数を呼ぶ。MCP のツールから、契約に無い保存の操作を呼べないことをテストで確かめる
- 4. 契約の利用者向けの操作で、要求の本文か応答の本文が配列でない操作が無いことを、検査が確かめる(1 件の取得・作成・更新・削除も要素 1 個の配列で受け渡す)
- 5. 経路の変数で単一のレコードを指す取得(
/sprint-runs/{sprintRunId}の形)が、利用者向けの操作の契約に無いことを、検査が確かめる
配列の受け渡し:
- 6. 101 個の要素を送ると、どの要素も処理されずに 400 が返り、応答に上限の値 100 が入る
- 7. 3 個の要素のうち 1 個だけに認可が無いとき、応答は入力と同じ順に 3 個の結果を返し、認可の無い 1 個だけに理由(
forbidden)が付き、残り 2 個は処理される - 8. 0 個の要素を送ると、何も処理されずに 400 が返る
- 9. 作成の要素に同じ冪等の鍵を付けて 2 回送ると、レコードは 1 件だけでき、2 回目の応答は 1 回目と同じ識別子を返す
委任の認証:
- 10. 人のログインの token で呼んだ操作と、同じ人が発行した委任の資格情報で呼んだ同じ操作は、同じ認可の判定になる(人に許された操作は委任でも許され、人に断られる操作は委任でも断られる)
- 11. 期限を過ぎた委任の資格情報で呼ぶと 401 になり、操作は行われない
- 12. 取り消した委任の資格情報で、取り消しの後に呼んだ最初の要求が 401 になる
- 13. 「読み取りだけ」の範囲の委任の資格情報で作成・更新・削除の操作を呼ぶと 403 になり、操作は行われない
- 14. 委任の資格情報で委任の資格情報の発行を呼ぶと 403 になる(前提 6)
- 15. 認可は要素ごとに掛かる。他人のアカウントの要素を混ぜた配列で、他人の要素だけが断られ、応答に他人のデータが含まれない
人だけが確定できる操作:
- 16. 契約で、人だけが確定できる操作に印が付いている。ループの判断待ちへの答え(
answerLoopPending)には印がある - 17. 印のある操作を委任の資格情報で呼ぶと、範囲が「読み書き」でも 403 になり、答えも状態も保存されない。印のある操作をすべて委任の資格情報で呼ぶテストがある(S6 の操作を含む)
- 18. 委任の資格情報で、承認の依頼とその材料(スプリントの詳細・承認待ちの一覧)は読める
操作の記録:
- 19. 利用者向けの操作 1 回ごとに、操作の記録が 1 件増える。記録は、操作した利用者の ID・委任の資格情報の識別子(人の直の操作では空)・日時(UTC)・呼び出し元の種類(画面・API・MCP)・
operationId・対象の ID の配列・結果(成功・一部失敗・断った理由)を持つ - 20. 読み取りの操作と、401・403・400 で断った操作も記録に残る
- 21. 操作の記録の保存の契約に、書き換えと削除の関数が無い。テストが契約の関数の一覧を確かめる
- 22. モデルの認証情報(API キー・ロールの ARN)・ログインの token・委任の資格情報の値・GitHub の token を含む要求を送っても、記録にそれらの値が入らないことをテストで確かめる
- 23. 記録に、メールアドレス・氏名・チームの名前・課題の題と本文が入らない
退行しないこと:
- 24. 契約の形を変えた後も、画面の既存の画面テスト(
factory/webの Vitest と Playwright)が通る - 25. ランナー向けの経路(
/run-jobs/*・/ingest/*)の入出力が変わらない(前提 2) - 26. 委任の資格情報を使わない人の操作で、今と同じく 401(token の検証の失敗)と 403(アカウントの解決の失敗)が返る
前提の確認:factory/api/src/auth/verify.test.tsとfactory/api/src/handlers/api.test.tsが今の 401・403 を確かめている(実装の前にnpm run checkで通ることを確かめる)
非機能の条件
| 大項目 | 条件 |
|---|---|
| 性能・拡張性 | 配列の要素は 1 回の要求で 100 個まで。超えたら 400 と上限値を返す(前提 3)。画面は今と同じ回数以下の要求で同じ画面を描ける(今は詳細を要素の数だけ別々に取っている。factory/web/src/api.ts の sprintRunDetails・stepDetails・backlogs) |
| 運用・保守性 | 1 つの操作を、操作の記録の 1 件と、その操作の要求の識別子でたどれる。秘密と個人情報の値は記録に書かない(受け入れ条件 22・23) |
| 移行性 | 旧い形の経路との並走は持たない(前提 7)。画面と API は同じ Pull Request の系列で同時に切り替える |
| セキュリティ | 委任の資格情報は期限 1 時間以内で、取り消しの後の最初の要求から断る。委任の資格情報の値は保存の時点でハッシュにし、平文で持たない。人だけが確定できる操作は委任から断る |
| システム環境 | MCP のサーバーは factory/api/ と同じ Node 24 の上で動き、新しい実行基盤を足さない。足す場合は理由と代わりの案を設計に書く(スプリント Value 6) |
影響
| 対象 | 影響 |
|---|---|
| 公開インタフェース | 変わる。factory/contracts/openapi/ の利用者向けの経路の入出力が配列の形になる。互換なし(前提 7。Factory はまだ外部の利用者に公開していない) |
| データ | 操作の記録の表と、委任の資格情報の表が増える(定義はインフラが作る)。既存の表の形は変わらない |
| 既存の振る舞い | 画面の API クライアントとダミーの API クライアントが新しい形を呼ぶ。利用者から見た画面の振る舞いは変わらない |
検証手段
| 項目 | 手段 |
|---|---|
| 起動 | cd factory && npm run dev:dummy -w web(ダミーの API クライアントで画面を起動する。手順は docs/specifications/ndf-factory-screen-map.md の「ダミーで起動する」) |
| テスト | cd factory && npm run check(契約の検査・各 workspace の型検査と Vitest)と npm run e2e -w web(Playwright) |
| 静的解析・型検査 | npm run check に含まれる tsc --noEmit と OpenAPI の lint(Spectral) |
| 手動確認 | リリース後に、人が手元の Claude Code に Factory の MCP のサーバーを登録し、委任の資格情報でスプリントの一覧を読めることと、承認の依頼に答えようとすると断られることを見る |
前提とする取り決め
| 項目 | 参照先 / 決めたこと |
|---|---|
| プロジェクト構造 | 変更は factory/ の中に置く。plugins/ と .claude-plugin/marketplace.json は factory/ を参照しない(python3 scripts/check-service-boundary.py)。インフラの定義と秘密は private リポジトリに置く(AGENTS.md の「マーケットプレイスの構造」) |
| コーディング規約 | factory/ の TypeScript の規約と npm run check(docs/specifications/ndf-factory-accounts-and-plans.md の「パッケージの管理」)。契約の正は OpenAPI で、型は生成する(docs/specifications/ndf-factory-contracts-and-progress.md) |
| テスト戦略 | 契約と対応の検査は factory/contracts/tests/、委任・認可・記録の振る舞いは factory/api/ の Hono の app.request() を使うテスト、画面は既存の Vitest と Playwright |
境界
| 区分 | 内容 |
|---|---|
| 常に行う | npm run check の実行、契約からの型の生成、変更する経路のテストの追加 |
| 確認してから行う | 依存パッケージの追加(MCP の SDK など)、契約の経路の名前の変更、記録の項目の追加。いずれも承認ゲート 1・2 で人が見る |
| 行わない | ランナー向けの経路の形の変更、インフラの定義の追加、plugins/ から factory/ への参照、操作の記録への秘密と個人情報の値の書き込み |
未決
| 項目 | 誰が決めるか | 期限 |
|---|---|---|
| 1. 操作の記録の追記に失敗したとき、操作も失敗にするか(記録の欠けを許さない側)、操作を通して後から補うか(可用性の側) | 設計で案を出し、承認ゲート 1 で利用者が決める | 設計 PR のマージ |
| 2. 操作の記録の保存期間と、個人の削除の求め(GDPR など)への応じ方。記録が持つ利用者の ID を、削除の求めのときにどう扱うか | 利用者 | 外部の利用者へ公開する前 |
3. 読み取りを含むすべての操作を記録する費用。画面の再読み込み(factory/web/src/poll.ts)の回数を含めた月の件数と保存の費用の見積り |
設計で実測から見積り、承認ゲート 1 で利用者が見る | 設計 PR のマージ |
| 4. 規模(Size 13)が 1 回の承認で読み切れる量に収まるか。収まらないなら、契約の配列化・委任の認証と人だけが確定できる操作・操作の記録・MCP のサーバーの 4 つへ分けるか | 設計で分け方の案を出し、承認ゲート 1 で利用者が決める | 設計 PR のマージ |
| 5. MCP の委任の認証を、MCP の認可の仕様(OAuth 2.1)に沿わせるか、Factory が発行する資格情報を直に渡す形にするか | 設計 | 設計 PR のマージ |
関連
- 前提にする契約:
docs/specifications/ndf-factory-accounts-and-plans.md(認証)・docs/specifications/ndf-factory-contracts-and-progress.md(契約) - NDF Factory: UX の土台(画面の地図・部品・端末・オフラインの見せ方・国際化・ダミーデータの API クライアント)を機能の画面より先に作る #2382(UX の土台)のダミーの API クライアントは、この契約の形へ合わせる
- NDF Factory: 承認ゲートの通知(Slack を含む)と Web からの承認 #2173(承認ゲートの通知と Web からの承認)が足す承認の操作は、人だけが確定できる操作の印を持つ
進行
モード: — / 進め方: auto
- 要求と受け入れ条件 — 2026-11-04 15:29
- 作業場所の用意 — 2026-11-04 22:15
- 設計 — 2026-11-04 15:34
- 素材の収集と出典の確定
- ドキュメント再構成 — 2026-11-04 15:57
- ドキュメントレビュー
- 計画 — 2026-11-04 22:15
- 実装 — 2026-11-04 22:15
- 構造改善 — 2026-11-05 00:25
- 実装レビュー — 2026-11-05 00:50
- 完了判定 — 2026-11-04 22:47
- Pull Request — 2026-11-04 23:06
- 確定仕様化 — 2026-11-05 03:28
- 後片付け — 2026-11-05 03:53
- 配布 — 2026-11-05 01:34
- 体裁レビュー
- リリース後テスト — 2026-11-05 03:48
- 振り返り — 2026-11-05 03:48
- 棚卸し — 2026-11-05 03:54
人の判断待ち(開発ループ lfactory3)
- 判定: unknown(承認ゲート 1)
- 理由: 判定を読めない
- 根拠の項目: —
- 設計 Pull Request: NDF Factory: 画面で行える操作を、委任を受けたエージェントが API と MCP から同じ認可と記録のもとで行える(#2384) #2498
- 答え: approved
- 答え方:
python3 /persistent/ai/.claude/plugins/cache/ai-plugins/ndf/10.27.16/scripts/sprint-state.py loop answer lfactory3 2384 --approved|--rejected|--revise --note <指摘ファイル>
振り返り: #2532 (comment)
Activity
Merge pull request #2498 from devbasex/design/issue-2384
利用者向けの操作の形を契約の定義の確定仕様へ移し、全体の契約を行数の上限に収める(#2384)
確定仕様のループの認可を、要素ごとに照らす結果の形へ合わせる(#2384)
Merge pull request #2512 from devbasex/feat/issue-2384-lfactory3-4
fix(factory): 冪等の再送のアカウント照合・競合時の再確認・要素ごとの 503・画面の鍵の持ち越し
takemi-ohama commentedon Nov 5, 2026
スプリント(スプリント lfactory3-4の後片付け)を通りました