Skipped / Follow-up 解消 + 追加指摘対応 PR Report#263
Conversation
📝 WalkthroughWalkthroughThis PR consolidates multiple independent refactoring and quality improvements: infrastructure rules documentation clarifying symlink-based file unification; backend cleanup of unused schema exports and centralization of PDF table styling; frontend API endpoint path constants; systematic React type import standardization; and expanded test coverage for authentication loading state precedence and concurrent refresh failure scenarios. ChangesMaintenance and Refactoring
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Summary
4 つの直前 PR レポートの Skipped と Follow-ups から、Rule of Three 未達 / 「現状維持」明記済み / 別 ADR 必須の項目を除いて 9 件を解消した。BE:
TaskStatusResponseの互換 re-export を削除、test_blog_collector.pyの httpx モック 5 重複を 3 ヘルパに集約、PDF generator の TableStyle 9 行 clone を_table_style()で集約。FE: guards にauthLoading=true分岐 2 件、api/client.tsに並行 401 + リフレッシュ失敗テスト 1 件を追加。XR:/auth/me//auth/github/login-url//auth/logoutをpaths.tsに統合、docs/api.mdから欠落していたAPP_BOOTSTRAPPEDを追記。INFRA: symlink + jscpd ignore の前提を duplication.md に、monitoring 新規 alert の運用ルールを opentofu.md に追記。作業中の追加指摘でReact.Dispatch<React.SetStateAction<...>>の名前空間参照を 8 ファイルでimport type { Dispatch, SetStateAction } from "react"の明示 import に統一。507 BE / 122 FE テスト pass、jscpd 66 → 46 clones(2.24% → 1.46%、-0.78pt)。Applied Changes
A. コード変更(6 件)
A-1. BE:
schemas/career_analysis.pyのTaskStatusResponsere-export 削除backend/app/schemas/career_analysis.pyfrom .shared import TaskStatusResponse # noqa: F401routers/career_analysis.py) は既にfrom ..schemas.shared import TaskStatusResponseに切り替え済みで、互換 re-export は誰も使っていなかったA-2. BE:
test_blog_collector.py内 httpx モック 5 重複の集約backend/tests/test_blog_collector.py_mock_async_client_returning_json(api_json)—raise_for_status()+json()を返す_mock_async_client_with_status(status_code)—status_codeのみのレスポンス_mock_async_client_raising(exc)—get()で例外送出fetch_note_articles(2),fetch_qiita_articles(1),fetch_zenn_articles_timeout(1),verify_user_exists(5 箇所)pytest tests/test_blog_collector.py tests/test_blog_collector_extended.py30 passedA-3. BE:
intelligence_generator.py(PDF) の TableStyle 9 行 clone 解消backend/app/services/pdf/generators/intelligence_generator.py_table_style(header_range, valign) -> TableStylebuild_intelligence_pdf({...})smoke test でb'%PDF-1.4'ヘッダ出力を確認intelligence_generator.py内 9 行 clone」A-4. FE:
guards.test.tsxにauthLoading=true分岐テスト追加frontend/src/router/guards.test.tsxPrivateRoute:user=testUser, authLoading=trueでローディング優先PublicRoute:user=testUser, authLoading=trueでリダイレクトせずローディング表示A-5. FE:
client.test.tsに並行 401 + リフレッシュ失敗テスト追加frontend/src/api/client.test.ts_refreshPromiseの共有によりrefreshCallCount === 1、2 件ともAUTH_REQUIREDで rejectedclient.tsの並行 401 リフレッシュ flow」(成功ケースは既存、失敗ケースを追加)A-6. XR:
/auth/me//auth/github/login-url//auth/logoutをpaths.tsに追加frontend/src/api/paths.ts—PATHS.authにme/githubLoginUrl/logoutを追加frontend/src/api/auth.ts— 3 箇所の fetch 直叩きを${API_BASE_URL}${PATHS.auth.XXX}に置換requestラッパーではなくfetchを直接使うため XR_apply 時にスキップされていた。fetch 直叩きでも paths.ts からパスは引けるので統合npm run buildpass/auth/me等の paths.ts 追加」B. ドキュメント追記(3 件)
B-1. INFRA: symlink + jscpd ignore の前提を duplication.md に追記
.claude/rules/common/duplication.mdの「検知の運用」セクション直下infra/environments/{dev,stg,prod}/{variables,moved,outputs}.tfは../shared/<file>.tfへの symlink で物理統合済み。jscpd は同一ファイルを 3 回スキャンすると 100% 重複として誤検出するため.jscpd.jsonのignoreで 9 件(3 環境 × 3 ファイル)を明示除外している。HCL 重複率は「真の重複ゼロ」ではなく「symlink 除外後の重複ゼロ」を意味する。新規 symlink を増やす場合は同様に追記B-2. INFRA: monitoring 新規 alert の運用ルールを opentofu.md に追記
.claude/rules/infra/opentofu.mdの「重複・DRY」セクション直下notification_channels.tf/uptime.tf/auth_failures.tf/rate_limits.tf/task_failures.tf) に追加するか、新しい責務であればmonitoring/<新規責務>.tfを新設する。1 ファイルに集約すると「監視増→ファイル肥大→責務不明瞭」が再発するためB-3. XR:
docs/api.mdとenv_keys.pyの現状一致確認docs/api.md「運用・ロギング」セクションAPP_BOOTSTRAPPED—env_keys.pyに定義あり、main.py:48で参照、しかしdocs/api.mdから欠落していた1指定で起動時 bootstrap(DB / 鍵検証)をスキップ。マイグレーションを別途流す環境で使用」APP_BOOTSTRAPPEDのみ欠落。逆方向 (docs/api.mdにあってenv_keys.pyに無い) はOLLAMA_BASE_URL/TASK_MAX_ATTEMPTSの 2 件で、XR_pr で「docker-compose 専用 / 必要になった時に追加」と判断済みdocs/api.mdの env 一覧とenv_keys.pyのエントリ一致確認」追加指摘対応(作業中の差し込み 3 件)
Ad-1.
React.Dispatch<React.SetStateAction<...>>→Dispatch<SetStateAction<...>>統一frontend/src/components/forms/sections/CareerQualificationsSection.tsx:171 箇所のみfrontend/src/components/forms/sections/CareerQualificationsSection.tsx:17frontend/src/components/forms/sections/CareerExperienceSection.tsx:16frontend/src/components/blog/BlogPlatformList.tsx:33frontend/src/hooks/useDocumentForm.ts:55frontend/src/hooks/career/useCareerExperienceMutators.ts:23frontend/src/hooks/analysis/useAsyncAnalysisPage.ts:55,59,63import type { Dispatch, SetStateAction } from "react";を追加(既存のimport { useMemo } from "react"がある場合は別行で type-only import を追加)grep -rn "React.Dispatch\|React.SetStateAction" frontend/src→ 0 件、build pass、lint pass、vitest 122 passedReact名前空間がレガシー扱いになっても影響を受けない、tree-shaking が効きやすい、import が型のみで明示されるAd-2.
useDocumentForm.test.tsの setup ヘルパで cacheKey ハードコード解消frontend/src/hooks/useDocumentForm.test.ts:60key: "career"→key: overrides.cacheKey ?? "career"overrides.cacheKeyを hook に渡すが、presetCache 用のsetCacheは"career"ハードコードで dispatch していた。将来別のcacheKeyを渡すテストを書いた際に「キャッシュは "career" に置かれるが hook は別キーで読む」silent bug を防ぐAd-3.(参考)当初指摘を受けたが見送ったもの
なし。両指摘とも「現行コードに対して妥当」と判定し適用。
Test Changes
Added (3 件)
frontend/src/router/guards.test.tsx:PrivateRoute (user+authLoading=true)/PublicRoute (authLoading=true)の 2 件frontend/src/api/client.test.ts: 「並行 401 + リフレッシュ失敗で両方失敗 + refresh 1 回共有」の 1 件Modified
backend/tests/test_blog_collector.py: 5 箇所の httpx モック生成を 3 ヘルパに置き換え。テスト数・assert は不変(全 18 件 pass)frontend/src/hooks/useDocumentForm.test.ts: setup の cacheKey 導出を override 経由に変更。既存 5 テストは不変Removed
なし。
Duplication Resolved
test_blog_collector.py内 httpx モック 5 ペア_mock_async_client_*3 ヘルパintelligence_generator.pyTableStyle 9 行 clone_table_style()ヘルパ残した偶発的重複 (Allowed Duplication)
test_blog_collector.py↔test_blog_collector_extended.pyの_runヘルパ重複(4 行): minTokens 未満で jscpd 対象外。両ファイル統合は extended の責務分担議論が必要なため別 PRSkipped
採用しなかった指摘と理由(C カテゴリ):
Validation
make lint-backendmake test-backendmake lint-frontendmake test-frontendmake build-frontendmake dupe-checknpm run test:e2e).claude/rules/frontend/test.mdの E2E トリガー条件に該当しないmake infra-validate.tf変更なし(ドキュメント追記のみ)dupe-check の改善内訳
Follow-ups
test_blog_collector_extended.pyとの統合: basic と extended の責務分担を明確化する別 PR(parametrize 集約 or ファイル責務の本質的分離)docs/adr/に 1 件起票して BE↔FE DTO 二重定義の方針を確定するtfファイル側を自動生成する案。要 PoCvars.GCP_PROJECT_ID_*等を GitHub に登録すれば.github/workflows/ci.ymlの||fallback から切り替えられるReact.Dispatchの lint ルール化: 今回統一したが、将来再導入を防ぐなら eslint でno-restricted-syntaxでReact.Dispatchを禁止すると堅いSummary by CodeRabbit
Documentation
APP_BOOTSTRAPPEDenvironment variable for skipping startup bootstrap validation.Refactor
Tests