Repository navigation
スプリント lfactory3-4 - #2518
スプリント lfactory3-4#2518
Conversation
利用者向けの 34 の操作を、取得と削除は鍵の query の繰り返し、作成・更新・操作は本文の配列にした。 各操作に操作の扱い(x-ndf-access)・要素の鍵(x-ndf-keys)・作った識別子(x-ndf-id)を持たせ、 委任の 3 操作(delegations.yaml)を足した。契約から操作の表(src/generated/operations.ts)を生成し、 形・扱い・記録へ写す鍵を検査で確かめる。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
操作の登録の層(routes/operation.ts)が、経路の登録・要素の数と重複の検査・経路のアカウントの解決・ 要素ごとの実行を、すべての利用者向けの操作に同じく掛ける。スプリントの実行・開発ループ・チームの作成に 作成の冪等の鍵を足し、鍵の行を作るものと同じトランザクションで書く。画面の API クライアントは要求を 操作の表から組み、詳細・工程の中身・バックログ・ループの詳細を要素の数によらず 1 回の要求で読む。 ソースの検査に、要求の経路を文字列で直に組む書き方を落とす規則を足した。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
委任の資格情報(ndfd_<ID>_<秘密>)を人が画面で発行し、秘密は SHA-256 だけを保存する。 要求のたびに表を強い整合で読み、期限切れと取り消し済みは 401 にする。操作の登録の層が、 扱い human の操作を範囲によらず 403 human_only、読み取りだけの範囲の書き込みを 403 scope_insufficient で断る。委任の画面(/delegations)を足し、画面の地図に行を足した。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
認証より外の中間処理が、成功・一部の失敗・400・401・403・404 のどれでも記録を 1 件追記する。 記録は許可した鍵の値と固定の列だけで組み、要求の本文を写さない。呼び出し元の種類は資格情報の種類と MCP の内部の印だけで決める。追記に失敗したら記録の全体を構造化ログへ出し、503 audit_unavailable を返す。 保存の実装は追記の関数だけを持ち、表が無い間は構造化ログへ出す。ログの行に要求の識別子を足した。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
POST /mcp で MCP の要求を状態を持たずに受け(@modelcontextprotocol/server 2.4 の Web 標準の受け口)、 操作の表から作ったツールの呼び出しを、委任の資格情報を付けたまま同じアプリへ内部の要求として送る。 認証・範囲の照合・要素の検査・認可・記録は API と同じ処理を通り、記録の呼び出し元の種類は mcp になる。 受け口は委任の資格情報だけを受け、画面と違うオリジンは 403、GET と DELETE は 405 にする。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ndf-factory-service-boundary.md が 516 行で上限 500 行を超え、doc-line-limit-check と pytest が落ちていた。 節は factory/contracts の操作の表を正とする契約の形のため、契約の定義と型の確定仕様へ移し、参照 6 件の行き先を合わせた。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2384 を実装する(スプリント lfactory3-4)
予定の 3 行(承認・請求と使用量・手元のマシン)の載る機能の末尾に、作る課題の番号と題を括弧で添える。冒頭の手順に、作る課題がその行を「あり」へ変えるときの扱いを足す。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2431 を実装する(スプリント lfactory3-4)
….ts#recordOf 委任の資格情報の頭 ndfd_ を delegations/model.ts の CREDENTIAL_PREFIX に寄せる。 auth/resolve.ts の DELEGATION_PREFIX をそこから組み、判定を isDelegationAuthorization として公開し、 認証の分岐(E2)と操作の記録の via の判定(I16)が同じ関数を使う。 delegations/service.ts の値の正規表現も CREDENTIAL_PREFIX から組む。振る舞いは変えない。 Item-Id: I-001 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s#positiveInt factory.ts と sprint-views.ts が実行時に互いを読む循環を外す。入力検証の positiveInt を 共通の経路層 routes/operation.ts へ移し、両方がそこから直接読む。factory.ts からの再公開は残さず、 sprint-views.ts の FactoryDeps は type import のままにする。影響範囲は routes の 3 ファイルだけで、振る舞いは変えない。 Item-Id: I-002 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…yRunsTable.createRun createRun の拒否の判定を refuseCreate に、全条件が通った後の書き込みを commitCreate に抽出した。 拒否条件の順序と「どれかが当たれば何も書かない」境界をメソッドの切れ目で示す。振る舞いは変えていない。 Item-Id: I-003 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
改修計画 — devbasex/ai-plugins #2518
改善項目I-001 —
|
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| magic_value | centralize_configuration | major | high | claude | 採用 | 1 |
なぜ: 委任の資格情報の頭 ndfd_ が delegations/model.ts の CREDENTIAL_PREFIX、delegations/service.ts の VALUE の正規表現、auth/resolve.ts の DELEGATION_PREFIX('Bearer ndfd_')、audit/middleware.ts の recordOf の直書き 'Bearer ndfd_' の 4 か所に別々に書かれている。via の判定(I16)と認証の分岐(E2)が同じ知識を別の文字列で持ち、片方だけ変えると記録の via と認証の経路が食い違う
手順: 1. auth/resolve.ts の DELEGATION_PREFIX を Bearer ${CREDENTIAL_PREFIX} から組み、isDelegationAuthorization(header: string | undefined): boolean を export する
2. verifyCaller の startsWith をその関数へ置き換える
3. audit/middleware.ts の recordOf の直書きを isDelegationAuthorization(c.req.header('Authorization')) に置き換える
4. delegations/service.ts の VALUE を CREDENTIAL_PREFIX から new RegExp で組む
5. テストを流す(audit.test.ts の via の検査と delegations.test.ts が通ること)
I-002 — factory/api/src/routes/factory.ts#positiveInt
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| circular_dependency | fix_dependency_direction | major | high | codex | 採用 | 1 |
なぜ: factory.ts は registerSprintViews と sprintRunList を sprint-views.ts から読み、sprint-views.ts は positiveInt を factory.ts から実行時に読み戻す。単なる入力検証の再利用により、経路を組み立てる側と個別の経路が相互依存している。FactoryDeps の型だけの参照とは区別できる循環である。
手順: 1. positiveInt の参照を検索し、既定メッセージと文字列の数字の扱いを固定する
2. 対象内の共通の経路層 routes/operation.ts へ positiveInt を移す
3. factory.ts と sprint-views.ts を移動先の直接 import に変え、factory.ts からの再公開は残さない。FactoryDeps は type import のままにする
4. factory.test.ts と sprint-views.test.ts で正常な ID・不正な ID・バックログの経路を確認する
I-003 — factory/api/src/runs/memory-table.ts#MemoryRunsTable.createRun
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| long_method | extract_method | major | medium | codex / kiro | 採用 | 1 |
なぜ: createRun に枠・古い版・配布中・課題とマイルストーンの持ち分・ループの版・冪等の鍵の判定と、複数の Map への書き込みが同居する。拒否条件の優先順位と、全条件が通るまで何も書かない境界を読み分けにくい。
手順: 1. guards の拒否判定(slots / legacy / release_running / issue_in_use / issue_in_loop / loop_changed / duplicate を返す部分)を private refuseCreate(run, expected, guards): CreateRunResult | null として抽出する
2. 書き込み部(枠・レガシー・課題持ち分・applyLoop・idempotency・runs/jobs の set)を private commitCreate(run, job, expected, guards) として抽出する
3. createRun は refuseCreate の結果があれば返し、無ければ commitCreate を呼ぶ形にする
4. 各手ごとに control.test.ts と factory.test.ts を実行する
指標の測定
- 状態: written / 言語とツールの対応: 既定(.ndf/code-metrics.json は無い) / 所要: 4.2 秒(使えた時間 90 秒 / 上限 90 秒)
- 指標のファイル: /tmp/ndf-worktrees/devbasex--ai-plugins/rf2518/work/.cross_refactoring/code-metrics-rf2518.md
| 言語 | ツール | 版 | ランナー | ファイル | 秒 | 結果 |
|---|---|---|---|---|---|---|
| python | ruff-complexipy | ruff 0.16.9 / complexipy 8.0.1 | uvx | 3 | 0.1 | 測った |
| shell | — | — | — | 10 | — | unsupported_language |
| typescript | lizard | lizard 1.24.0 | uvx | 61 | 0.5 | 測った |
| 重複: python | symilar | pylint 4.0.9 | uvx | 3 | 0.8 | 測った(0 箇所) |
| 重複: shell, typescript | jscpd | jscpd 4.3.0 | npx | 71 | 2.7 | 測った(3 箇所) |
時間の上限
| 値 | 中身 |
|---|---|
| 提案の枠の終わり(監視の上限 = 残り + 余裕) | 2026-11-05T00:32:37+00:00 |
| 改修計画の枠の終わり(同上) | 2026-11-05T00:35:37+00:00 |
| テストの追加の終わり = 実装の終わり − Σ(採っていて未検証の項目の実装の見積り) | 2026-11-05T00:36:07+00:00 |
| 実装の終わり = 最終ゲートの修正の打ち切り − バッファ − Σ(採っていて未検証の項目の検証の見積り) | 2026-11-05T00:37:04+00:00 |
| 直しの試行の打ち切り | 2026-11-05T00:39:09+00:00 |
| 想定最大時間の終わり H(子プロセスはすべてここまでに止まる) | 2026-11-05T00:55:48+00:00 |
| 確かめの開始の締め切り = H − 確かめの見込み(最終ゲート修正と打ち切りの後の取り消しもここまで) | 2026-11-05T00:40:26+00:00 |
| 確かめの見込み(秒。最終ゲートの確かめ 1 回。バッファの最終ゲートの全体テスト) | 922 |
| 最終ゲート修正 1 回の見込み(秒。バッファの final_fix。起動は今 + この値が確かめの開始の締め切り以前のときだけ) | 77 |
| 指標の測定の上限(秒。提案の枠の中から割く) | 90 |
| 着手前のテスト 1 回の上限(秒) | 4644 |
| 範囲テスト 1 回の上限(秒) | 149 |
| 手元の全体テスト 1 回の上限(秒) | 4644 |
| CI の待ちの上限(秒) | 2766 |
| 余裕(秒。手順の上限と CLI の上限に足す) | 90 |
入力: 予算 30 分 / 全体テストの所要 w 1548.0(ci-steps) / 着手前の実測 x 49.4 / CI の壁時計 c 922.0 / 着手前のテストの所要の見込み s 1548.0(whole) / 戦略 local-scoped-ci-whole
無音の打ち切りは手順の監視の上限と同じ値である。項目ごとの期限は持たない(実装を止めるのは実装の終わりだけ)。
見送った提案
| 対象 | 兆候 | 理由 | 根拠(MVV) | 補足 |
|---|---|---|---|---|
factory/web/scripts/check-source.ts#checkSource.visit |
long_method | duplicate | Value 2 / Value 7 | C-013 と同じ変更 |
factory/api/src/runs/control.ts#RunControl.finalize |
long_method | no_target | Value 2 / Value 3 / Value 8 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/accounts/store.ts#DynamoAccountStore.createTeam |
duplication | no_target | Value 1 / Value 7 / Value 8 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/runs/loops.ts#loopStateAfter |
conditional_chain | no_target | Value 3 / Value 8 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/audit/dynamo-log.ts#DynamoAuditLog |
duplication | no_target | Value 1 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/accounts/memory-store.ts#MemoryAccountStore.createTeam |
duplication | budget | Value 7 / Value 8 | 見積り 3.2 分が残りに入らない |
factory/api/src/auth/resolve.ts#verifyCaller |
duplication | budget | Value 7 / Value 8 / C2 | 見積り 3.2 分が残りに入らない |
factory/api/src/runs/memory-table.ts#MemoryRunsTable.idempotencyFree |
duplication | budget | Value 7 | 見積り 3.2 分が残りに入らない |
factory/web/scripts/check-source.ts#checkSource.visit |
conditional_chain | budget | Value 2 / Value 8 | 見積り 2.8 分が残りに入らない |
factory/api/src/delegations/service.ts#DelegationService.issue |
long_method | budget | Value 2 / Value 8 / Value 7 | 見積り 1.8 分が残りに入らない |
factory/api/src/runs/control.ts#RunControl.startSprintRun |
long_method | budget | Value 2 / Value 8 / Value 7 | 見積り 1.8 分が残りに入らない |
factory/api/src/runs/control.ts#RunControl.admit |
long_method | budget | Value 2 / Value 8 | 見積り 1.8 分が残りに入らない |
factory/web/scripts/check-source.ts#visit |
long_method | budget | Value 2 / Value 5 / Value 7 | 見積り 2.8 分が残りに入らない |
factory/api/src/audit/middleware.ts#recordOf |
long_method | budget | Value 2 / Value 8 | 見積り 1.8 分が残りに入らない |
factory/api/src/runs/control.ts#RunControl.admit |
duplication | budget | Value 7 / Value 8 | 見積り 1.8 分が残りに入らない |
factory/api/src/idempotency.ts#IdempotencyRef |
duplication | budget | Value 7 | 見積り 1.8 分が残りに入らない |
factory/api/src/routes/accounts.ts#registerAccounts |
duplication | budget | Value 7 | 見積り 1.8 分が残りに入らない |
factory/api/src/runs/loops.ts#LoopControl.startLoop |
long_method | budget | Value 2 / Value 8 | 見積り 1.8 分が残りに入らない |
factory/web/src/pages/DelegationsPage.tsx#DelegationsPage |
divergent_change | budget | Value 2 | 見積り 1.8 分が残りに入らない |
factory/web/src/pages/DelegationsPage.tsx#DelegationsPage |
duplication | budget | Value 7 | 見積り 1.8 分が残りに入らない |
factory/api/src/mcp/server.ts#callTool |
duplication | budget | Value 7 | 見積り 1.9 分が残りに入らない |
factory/api/src/routes/operation.ts#contextOf |
scattered_config | budget | Value 7 / Value 8 | 見積り 1.9 分が残りに入らない |
factory/api/src/routes/factory.test.ts#FakeSecrets |
duplication | budget | Value 7 / Value 5 | 見積り 2.0 分が残りに入らない |
factory/api/src/routes/factory.test.ts#beforeEach |
duplication | budget | Value 7 | 見積り 2.0 分が残りに入らない |
factory/api/src/testing/app.ts#createTestApi |
duplication | budget | Value 7 | 見積り 2.0 分が残りに入らない |
factory/web/src/pages/DelegationsPage.tsx#DelegationsPage |
conditional_chain | budget | Value 8 | 見積り 2.8 分が残りに入らない |
factory/contracts/scripts/operations.ts#readOperations |
long_method | budget | Value 2 / Value 5 | 見積り 2.8 分が残りに入らない |
factory/api/src/accounts/service.ts#AccountService.hist |
long_parameter_list | budget | Value 5 / Value 3 / Value 8 | 見積り 1.4 分が残りに入らない |
factory/api/src/runs/memory-table.ts#MemoryRunsTable |
large_class | budget | Value 3 / Value 7 | 見積り 1.5 分が残りに入らない |
factory/api/src/audit/audit.test.ts#personal |
duplication | budget | Value 7 | 見積り 2.0 分が残りに入らない |
factory/api/src/audit/middleware.ts#recordOperations |
hidden_dependency | budget | Value 3 / Value 1 / Value 4 | 見積り 2.5 分が残りに入らない |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | codex | REQUEST_CHANGES
再送・並列処理・アカウント境界に関する 4 件の修正を求めます。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | kiro | APPROVE
委任の資格情報・操作の記録・MCP の受け口・操作の表の生成を、既存の認証と解決の経路へ一貫して載せている。秘密は SHA-256 で保存し timingSafeEqual で照合、委任の値は発行時に 1 度だけ返し画面でも閉じると消す、記録の target_ids は許可した鍵(client_name と秘密を除く)だけに絞る、MCP は内部要求として同じ guard/記録を通す、と秘密・認可・記録の扱いはいずれも設計どおりで、利用者の経路を壊す・秘密や認可を漏らす・起動や呼び出しを不当に増やす・設計の実装が食い違う、のいずれにも当たる指摘は見つからなかった。critical/major の修正アクションは無い。
- startSprintRun と startLoop の再送で、鍵が指す実行・ループが要求のアカウントに属さなければ forbidden にする - 同じ鍵の先行の要求が途中で作り終えたときは、枠・持ち分・名前の断りより先にその結果を返す - 要素の中の ApiError でない例外もその要素の 503 にし、ほかの要素の成功の結果を残す(#2384 の決定 3) - 画面の作成は、結果が分からない失敗(503・通信の失敗)の後の同じ中身の送り直しで同じ冪等の鍵を使う Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🔧 /ndf:fix サマリ | round 1 | commit b31183d対応件数: critical=0 / major=4 / minor=0(合計 4 件) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | claude | REQUEST_CHANGES
round 1 の 4 件の修正は意図どおりに入っている。残る修正は 1 件で、作成の鍵を持ち越す修正(b31183dcf)が委任の発行で、値を返せない再送を画面が黙って受け取る点である。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | kiro | APPROVE
round 2。委任の資格情報・操作の記録・MCP の受け口・操作の表の生成と、画面・API・MCP の経路を一貫して確認した。round 1 の 4 件(loops.ts の replayLoop のアカウント境界、control.ts の replayRun のアカウント境界、elements.ts の Promise.all の例外の扱い、web api.ts の再送時の冪等の鍵)はいずれも b31183d で設計どおりに直っている。秘密は SHA-256 で保存し timingSafeEqual で照合、委任の値は発行時に 1 度だけ返し画面でも閉じると消す、target_ids は AUDIT_KEYS で絞り client_name と秘密を含めない、認可(human/scope)は本文の解析より前に掛かり、アカウント境界は resolveAccount で担保されている。冪等の鍵の行はメモリと DynamoDB の両実装で一致し、操作の表の生成と生成物も契約と整合する。画面は i18n の鍵がすべて定義済みで、アカウント画面からの導線と router への登録もそろっている。critical/major の修正アクションは見つからなかった。
結果が分からない失敗の後の再送は同じ冪等の鍵で前の発行を credential: null で返す。 画面が黙って受けると使えない有効な資格情報が残るため、取り消して発行し直すよう知らせる。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🔧 /ndf:fix サマリ | round 2 | commit 644ce77対応件数: critical=0 / major=1 / minor=0(合計 1 件) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | claude | APPROVE
round 2 の 1 件(委任の送り直しで値が返らないときの知らせ、644ce77f7)は意図どおりに入っている。credential が null のときに取り消しと発行し直しを知らせ、一覧の同じ資格情報の行を差し替え、成功で鍵を捨てる。round 1 の 4 件の修正(アカウントの照合・競合時の再確認・要素ごとの 503・画面の鍵の持ち越し)も含めて、新しい critical/major の修正アクションは見つからなかった。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | codex | APPROVE
追加の修正指摘はありません(判断の根拠: Value 1・Value 3、共通原則 C1・C2・C3)。
🔧 /ndf:fix サマリ | commit (なし)対応件数: critical=0 / major=0 / minor=0(合計 0 件) |
スプリント lfactory3-4 の課題を develop へ取り込む。
利用者向けの変化
移行の手順
課題と設計
コミット
変更の統計
テスト(supervise.py の run のステップ)
集めた実装の PR
閉じる課題
Closes #2384
Closes #2431
手動確認
gh issue view <番号> --json state,titleを打ち、OPENとその画面を作る題であることを確かめる。リリース後テストで、developの画面の地図を読んで受け入れ条件 1・3 を確かめるモード: standard / 通した工程: 実装 → Pull Request
🤖 Generated with Claude Code