Repository navigation
スプリント lfactory3-6 - #2534
スプリント lfactory3-6#2534
Conversation
…er の配線だけにする(#2199 の R20・R02) - requireEnv の 5 つの写しを src/env.ts へ寄せる - createApiApp・jsonLogger・webOriginFromEnv を app.ts、depsFromEnv を auth/deps.ts、 progressStoreFromEnv を progress/deps.ts へ移し、index.ts・runs/deps.ts・handlers/ どうしが handlers/ を読まない形にする - テストは createApiApp の import 元だけを替える(期待値は変えない) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…9・R10・R11・R17・R18・R19) - AccountStore・AccountPatch・ConditionFailedError と新しい AccountUpdate を accounts/port.ts へ移す - updateAccount の 5 つの位置引数を AccountUpdate 1 つにする - DynamoAccountStore.transact が履歴を受け取り、items → 履歴 → after の順に並べる - AccountPatch の列を PATCH_COLUMNS の表で回す(プレースホルダは :plan・:mode のまま) - 鍵の頭を USER_PREFIX・ACCOUNT_PREFIX と userPk・accountPk にまとめる - AccountService の 4 つの再試行を retryOnConflict、3 つの条件の失敗の読み替えを writeOr にし、hist を消す - store.test.ts は import 元と updateAccount の呼び出しの形だけを替える(期待値は変えない) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…13・R03・R12) - validateSeatType を accounts/service.ts に置き、teams.ts と accounts.ts の 3 つの経路が使う(文言は同じ) - 「チームなら席を読んで詳細の本文を作る」を views.ts の accountDetailBody にし、3 つの経路が使う - github-oidc/app.ts の /token と /userinfo が githubUser を使う(判定の条件は同じ) - auth/verify.ts の IdP の判定を idpFromUsername に出す(判定の順序は同じ) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- RequireLogin(context.tsx)で App.tsx のログインの後の枠を包み、12 画面の hasToken と /login への転送を消す - usePolled の enabled の引数を消す(呼ぶ画面はすべて token の有無を渡していただけ) - 「呼んで、失敗なら画面の文を出す」を useAttempt(context.tsx)にし、判定表の対象の try/catch を置き換える - 席の種類の <option> を SeatTypeOptions(parts.tsx)にし、TeamPage と NewTeamPage が使う Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…の R16) 11 のテストに写っていた読み込みの 4 行を関数スコープの fixture check_module にする。 テストの関数の数と、確かめる入力・期待値の組は変えない(46 passed のまま)。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2199 を実装する(スプリント lfactory3-6)
…positoryNames どこからも呼ばれていない repositoryNames と、それだけが使っていた Repository の 型の読み込みを消す。一覧は SprintRunRow.repo を表示しており振る舞いは変わらない。 Item-Id: I-002 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tService.seatHistory createTeam・addSeat・changeSeat・removeSeat で手で組んでいた席の履歴の行を seatHistory に寄せる。null の側は before / after を null にし、行の中身は変わらない。 Item-Id: I-003 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Service 席の操作(requireTeamOwner・addSeat・changeSeat・removeSeat)を SeatService (accounts/seat-service.ts)へ切り出し、AccountService は委譲だけにした。 席の履歴の行を作る seatHistory は createTeam と共有するため同じファイルの関数にし、 retryOnConflict・writeOr は両方が使うため accounts/conflict.ts へ移した。 AccountService の公開メソッドは変えていないので、呼び出し元は書き換えていない。 Item-Id: I-004 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
改修計画 — devbasex/ai-plugins #2534
改善項目I-001 —
|
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | extract_test_helper | major | high | claude / codex | 取り消し | 0 |
なぜ: FactoryDeps の組み立て(RepositoryService・CredentialService・LoopControl・memoryProgressReader など 9 項目)が testing/app.ts:93-101・routes/factory.test.ts:82-90・routes/sprint-views.test.ts:100-110 の 3 か所に写されている(jscpd が 9 行を検出)。連番の newId(00000000-0000-4000-8000-…)も同じ 3 か所、FakeSecrets は testing/app.ts と factory.test.ts に 2 つあり、後者は fail を足しただけ。FactoryDeps に項目が増えるたびに 3 か所を直すことになる
手順: 1. testing/app.ts に sequentialIds(): () => string を足し、3 か所の newId を置き換える
2. testing/app.ts に testFactoryDeps(h, { secrets, github?, proofKey?, candidateModel? }): FactoryDeps を足し、createTestApi の組み立てをこれへ置き換える
3. testing/app.ts の FakeSecrets に fail = false を足して create/put/delete で投げるようにし、factory.test.ts の写しを消して import する
4. factory.test.ts と sprint-views.test.ts の beforeEach の組み立てを testFactoryDeps へ置き換える(sprint-views は github に呼び出しを数える Proxy、proofKey に new Uint8Array(32)、secrets に noSecrets を渡す)
5. factory.test.ts・sprint-views.test.ts・api.test.ts を実行する
取り消した理由: テストの期待する振る舞いが変わっています(factory/api/src/routes/factory.test.ts, factory/api/src/routes/sprint-views.test.ts)。構造改善では期待出力を変えません。振る舞いの変更は別の変更に分けてください
I-002 — factory/web/src/pages/SprintsPage.tsx#repositoryNames
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| dead_code | remove_dead_code | minor | medium | codex | 採用 | 1 |
なぜ: リポジトリ全体で repositoryNames を検索すると定義だけが見つかる。一覧は既に SprintRunRow.repo を表示し、名前がない場合は repository_id の文へフォールバックしているため、一覧とは別に名前を取得するこの関数と Repository 型の import は使われていない。web は private のブラウザアプリで、この関数を配布用の公開 API として使う入口もない。
手順: 1. 参照検索を再確認し、repositoryNames の定義とその説明コメントを削除する。
2. Repository の型 import だけを削除し、SprintRunRow と SprintsPage の表示処理は維持する。
3. 既存の pages/sprints.test.tsx と TypeScript の型検査を実行し、一覧のリポジトリ表示・状態のタブ・読み直しが変わらないことを確認する。呼び出しを新設して関数を生かす変更は行わない。
I-003 — factory/api/src/accounts/service.ts#AccountService
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | extract_method | minor | medium | claude | 採用 | 1 |
なぜ: 席の履歴の行(accountId・type・at・actor・before/after の { user_id, seat_type })が createTeam・addSeat・changeSeat・removeSeat の 4 か所で手で組まれている。account.created には accountCreated があるのに、席の履歴だけ共通化されていない
手順: 1. accountCreated の隣に private seatHistory(type: 'seat.added' | 'seat.changed' | 'seat.removed', accountId, at, actor, userId, before: SeatType | null, after: SeatType | null): HistoryRecord を足す(null の側は before/after を null にする)
2. createTeam と addSeat の seat.added を seatHistory へ置き換える
3. changeSeat と removeSeat の history の組み立てを置き換える
4. handlers/api.test.ts(履歴の type と中身を見るテスト)を実行する
I-004 — factory/api/src/accounts/service.ts#AccountService
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| divergent_change | extract_class | major | low | kiro | 採用 | 1 |
なぜ: AccountService(340 行・36 関数)が、利用者と文脈の解決(ensureUser/resolveFor/context/listAccounts)・席の管理(addSeat/changeSeat/removeSeat/requireTeamOwner)・料金プランと実行形態(setPlan/setExecutionMode)の 3 つの関心を 1 クラスに持ち、別々の理由で変わる
手順: 1. 席の操作(requireTeamOwner/addSeat/changeSeat/removeSeat)を SeatService として切り出し、store と retryOnConflict を共有して注入
2. AccountService は席の操作をその型へ委譲する
3. 呼び出し元(routes/teams.ts・testing/app.ts)の参照を新しい型へ合わせる
4. store.test.ts / api.test.ts / factory.test.ts を実行して公開の振る舞いが不変であることを確認
指標の測定
- 状態: written / 言語とツールの対応: 既定(.ndf/code-metrics.json は無い) / 所要: 3.8 秒(使えた時間 90 秒 / 上限 90 秒)
- 指標のファイル: /tmp/ndf-worktrees/devbasex--ai-plugins/rf2534/work/.cross_refactoring/code-metrics-rf2534.md
| 言語 | ツール | 版 | ランナー | ファイル | 秒 | 結果 |
|---|---|---|---|---|---|---|
| python | ruff-complexipy | ruff 0.16.9 / complexipy 8.0.1 | uvx | 4 | 0.4 | 測った |
| shell | — | — | — | 10 | — | unsupported_language |
| typescript | lizard | lizard 1.24.0 | uvx | 40 | 0.4 | 測った |
| 重複: python | symilar | pylint 4.0.9 | uvx | 4 | 0.7 | 測った(0 箇所) |
| 重複: shell, typescript | jscpd | jscpd 4.3.0 | npx | 50 | 2.3 | 測った(6 箇所) |
時間の上限
| 値 | 中身 |
|---|---|
| 提案の枠の終わり(監視の上限 = 残り + 余裕) | 2026-11-05T02:48:19+00:00 |
| 改修計画の枠の終わり(同上) | 2026-11-05T02:51:19+00:00 |
| テストの追加の終わり = 実装の終わり − Σ(採っていて未検証の項目の実装の見積り) | 2026-11-05T02:52:26+00:00 |
| 実装の終わり = 最終ゲートの修正の打ち切り − バッファ − Σ(採っていて未検証の項目の検証の見積り) | 2026-11-05T02:53:04+00:00 |
| 直しの試行の打ち切り | 2026-11-05T02:55:00+00:00 |
| 想定最大時間の終わり H(子プロセスはすべてここまでに止まる) | 2026-11-05T03:11:39+00:00 |
| 確かめの開始の締め切り = H − 確かめの見込み(最終ゲート修正と打ち切りの後の取り消しもここまで) | 2026-11-05T02:56:17+00:00 |
| 確かめの見込み(秒。最終ゲートの確かめ 1 回。バッファの最終ゲートの全体テスト) | 922 |
| 最終ゲート修正 1 回の見込み(秒。バッファの final_fix。起動は今 + この値が確かめの開始の締め切り以前のときだけ) | 77 |
| 指標の測定の上限(秒。提案の枠の中から割く) | 90 |
| 着手前のテスト 1 回の上限(秒) | 4644 |
| 範囲テスト 1 回の上限(秒) | 122 |
| 手元の全体テスト 1 回の上限(秒) | 4644 |
| CI の待ちの上限(秒) | 2766 |
| 余裕(秒。手順の上限と CLI の上限に足す) | 90 |
入力: 予算 30 分 / 全体テストの所要 w 1548.0(ci-steps) / 着手前の実測 x 40.6 / CI の壁時計 c 922.0 / 着手前のテストの所要の見込み s 1548.0(whole) / 戦略 local-scoped-ci-whole
無音の打ち切りは手順の監視の上限と同じ値である。項目ごとの期限は持たない(実装を止めるのは実装の終わりだけ)。
見送った提案
| 対象 | 兆候 | 理由 | 根拠(MVV) | 補足 |
|---|---|---|---|---|
factory/web/src/pages/DelegationsPage.tsx#DelegationsPage |
long_method | no_target | Value 3 / C1 / Value 2 / Value 1 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/LoopsPage.tsx#LoopsPage.start |
conditional_chain | no_target | Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/LoopsPage.tsx#LoopsPage.start |
long_method | no_target | Value 3 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/github-oidc/app.ts#createGithubOidcApp |
divergent_change | no_target | C2 / Value 3 / Value 7 / Value 5 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/github-oidc/app.ts#createGithubOidcApp |
duplication | no_target | C2 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/SprintsPage.tsx#SprintsPage |
duplication | no_target | Value 7 / Value 5 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/handlers/ingest.ts#webhookSecretFromEnv |
duplication | no_target | C1 / Value 3 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/runs/deps.ts#factoryDepsFromEnv |
scattered_config | no_target | Value 3 / C1 / Value 7 / Value 6 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/LoopDetailPage.tsx#LoopDetailPage.act |
duplication | no_target | Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/LoopsPage.tsx#LoopsPage |
duplication | no_target | Value 3 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/ModelCredentialPage.tsx#save |
long_method | no_target | Value 3 / C1 / Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/NewSprintPage.tsx#NewSprintPage.start |
conditional_chain | no_target | Value 7 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/SprintDetailPage.tsx#StepPanel |
long_method | no_target | Value 3 / Value 2 / Value 1 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/web/src/pages/TeamPage.tsx#TeamPage.act |
duplication | no_target | Value 7 / Value 5 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
factory/api/src/accounts/service.ts#validateSeatType |
divergent_change | budget | Value 7 | 見積り 1.8 分が残りに入らない |
factory/api/src/routes/factory.test.ts#FakeSecrets |
duplication | budget | Value 7 / Value 5 | 見積り 1.8 分が残りに入らない |
scripts/tests/test_check_markdown_links.py#run |
duplication | budget | Value 7 | 見積り 1.8 分が残りに入らない |
scripts/tests/test_check_markdown_links.py#test_heading_anchors_collision_with_explicit_numbered_heading |
inconsistent_naming | budget | Value 8 / Value 7 | 見積り 1.8 分が残りに入らない |
factory/api/src/accounts/store.ts#DynamoAccountStore.createTeam |
magic_value | budget | Value 1 / C3 / Value 7 | 見積り 2.7 分が残りに入らない |
factory/api/src/app.ts#createApiApp |
long_parameter_list | budget | Value 7 | 見積り 4.6 分が残りに入らない |
factory/api/src/accounts/service.ts#resolveFor |
long_method | budget | Value 3 / C2 / Value 7 | 見積り 1.6 分が残りに入らない |
factory/api/src/accounts/service.ts#AccountService.listAccounts |
one_by_one_iteration | budget | Value 4 / C2 / Value 7 | 見積り 1.8 分が残りに入らない |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | codex | APPROVE
指定基準に該当する修正指摘はありません。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | kiro | APPROVE
43 ファイルを確認。アカウントの競合・再試行の切り出し(conflict.ts / SeatService)、app.ts と deps.ts の分離、web のログイン判定の RequireLogin への集約、useAttempt への例外処理の集約、dead code 削除、テストの fixture 化のいずれも、挙動を保つ構造改善であることを到達経路で確認した。setPlan/createTeam/ensureUser の条件失敗と非条件失敗の分岐、idempotency の勝者解決、認証経路の被覆、CORS、requireEnv、usePolled の呼び出し更新を追い、critical / major の基準に当たる食い違いは見つからなかった。指摘なし。
🔧 /ndf:fix サマリ | commit (なし)対応件数: critical=0 / major=0 / minor=0(合計 0 件) |
スプリント lfactory3-6 の課題を develop へ取り込む。
利用者向けの変化
移行の手順
課題と設計
コミット
変更の統計
テスト(supervise.py の run のステップ)
集めた実装の PR
閉じる課題
Closes #2199
モード: standard / 通した工程: 実装 → Pull Request
🤖 Generated with Claude Code