diff --git a/docs/adr/0024-pdf-resume-import.md b/docs/adr/0024-pdf-resume-import.md
new file mode 100644
index 00000000..aa381bcf
--- /dev/null
+++ b/docs/adr/0024-pdf-resume-import.md
@@ -0,0 +1,104 @@
+# ADR-0024: 手持ち PDF 経歴書のフォーム流し込み(AI 抽出の再導入)
+
+## ステータス
+
+Accepted
+
+## 関連 ADR
+
+- 継承: [ADR-0010](0010-devforge-agent.md)(DevForge Agent の不変条件: LLM は `services/agent/` のみ・DB 非更新・エラー契約・構造化出力・リトライ 1 回)、[ADR-0023](0023-remove-billing-multiprovider.md)(LLM は Claude Haiku 固定 / ローカル Ollama)
+- 手本: [ADR-0018](0018-github-resume-draft-generation.md)(構造 = ルールベース / 自然文 = LLM・構造化出力・DB 非更新でフォーム前段まで)。同期方式は `POST /agent/chat`(ADR-0010)に倣う
+- 歴史的経緯(**再発防止のため必ず参照**): [ADR-0004](0004-llm-provider-abstraction.md) で「職務経歴書 PDF の AI 抽出」を導入 → [ADR-0008](0008-remove-llm-to-rule-based-design.md) で撤去した。本 ADR はこの機能を**再導入**するが、旧設計の敗因(下記)を ADR-0010 の不変条件で構造的に塞ぐ
+- 前提: [#524](https://github.com/yusuke0610/devforge/issues/524)(Resume payload → フォーム state 注入機構)。本機能の抽出結果はこの共有部品に渡す
+
+## コンテキスト
+
+転職者はほぼ全員、手持ちの経歴書 PDF を持っている。それでも DevForge は**空フォームを前に手入力を始める瞬間が最大の離脱ポイント**になっている(コールドスタート問題)。手持ち PDF をアップロード → LLM で構造化抽出 → フォームに流し込むことで、ユーザは「ゼロから入力」ではなく「既存内容を確認・微修正」から始められる。
+
+この機能自体は過去に存在した(ADR-0004 で導入)。**旧設計の敗因は、抽出関数 `generate()` が失敗時に空文字を返し、エラーが UI に届かなかったこと**(ユーザは「何も起きない」体験に直面した)。ADR-0008 でルールベース設計へ寄せた際に撤去された。
+
+再導入にあたっては、以下の環境が旧時代と異なる:
+
+- **ADR-0010 の Agent 基盤が確立済み**: 構造化出力(tool use スキーマ)・明示的なエラー契約(`AGENT_LLM_ERROR` / `AGENT_PARSE_ERROR` の 502)・リトライ 1 回・DB 非更新という不変条件がある。空文字握りつぶしは契約違反として構造的に禁止できる。
+- **ADR-0018 の「構造 = ルールベース / 自然文 = LLM・DB 非更新でフォーム前段まで」の実績**がある。PDF 抽出も同じ流儀に乗せられる。
+- **ADR-0023 で LLM が Haiku 固定**になり、プロバイダ選択の複雑さが無い。
+
+## 決定内容
+
+**手持ち PDF 経歴書を Claude Haiku で構造化抽出し、Resume 互換 payload を返す同期エンドポイントを `services/agent/` 配下に追加する。** DB は更新せず、抽出結果はフォーム注入機構(#524)経由でユーザが確認・保存する(ADR-0010 の DB 非更新原則)。
+
+### v1 スコープ: テキスト埋め込み PDF のみ
+
+- **対応**: テキストが埋め込まれた PDF(ワープロ / 変換出力の経歴書。大多数)。
+- **非対応**: スキャン PDF(画像)。OCR / vision が必要でコスト・失敗モードが別物のため v1 では扱わない。**抽出テキストが空 or 極端に少ない場合はスキャン PDF と判定し、日本語メッセージで明示的にエラーを返す**(「テキストを含む PDF のみ対応。スキャン画像は手入力をお願いします」等)。無言で失敗させない。
+
+### PDF テキスト抽出: pypdf
+
+- ライブラリは **pypdf**(純 Python / MIT / ネイティブ依存なし)を採用し、`backend/pyproject.toml` に `==` 完全固定で追加する(P7 / ADR-0021 の uv2nix build)。
+- pypdf は純 Python のため `flake.nix` のネイティブ依存(devshell / backendRuntime)変更が不要。WeasyPrint(生成専用)の libvips 系ネイティブ依存とは別系統で、サプライチェーン面も軽い。
+- テキスト抽出の前処理(改ページ結合・空白正規化・スキャン判定)は**決定論ロジック**として実装し、TDD 対象とする(`.claude/rules/common/tdd.md`)。
+
+### 同期方式(`POST /agent/chat` 相当)
+
+- PDF テキスト抽出(ms オーダー)+ Haiku 1 コールの構造化抽出で完結し、`/chat`(ADR-0010)と同等の負荷で 60s 内に収まる。**非同期タスク基盤(ADR-0020)は過剰**なため採らない。
+- エンドポイント: `POST /api/agent/resume-import/pdf`(multipart アップロード)。レスポンスは **Resume 互換 payload のみ**(DB 非更新)。
+- 構造化出力は ADR-0018 の流儀を踏襲: 機械制約(フィールド構造・文字数上限)はスキーマ(`services/agent/resume_import/output_schema.py`)に、品質制約(捏造禁止・目安字数・抽出方針)はプロンプト(`app/prompts/agent_resume_import.md`)に置く(P4)。文字数上限は `output_schema.SCOPE_FIELDS`(= `schemas/resume.py` と drift テスト済み)を正本として揃える。
+
+### エラー契約(旧設計の空文字握りつぶしの再発防止)
+
+抽出・パースの失敗を**明示的な日本語 HTTP エラー**で返す。ADR-0010 の契約を継承する。
+
+| 事象 | HTTP | ErrorCode |
+|---|---|---|
+| PDF 以外 / 破損 / サイズ超過 | 422 | `VALIDATION_ERROR` |
+| テキスト非埋め込み(スキャン PDF 判定) | 422 | `VALIDATION_ERROR`(専用メッセージ) |
+| LLM 呼び出し失敗 | 502 | `AGENT_LLM_ERROR` |
+| 抽出結果のパース / スキーマ違反(リトライ後も失敗) | 502 | `AGENT_PARSE_ERROR` |
+| レート制限超過 | 429 | — |
+
+**空の payload を「成功」として返すことを禁止する**(旧敗因の構造的封じ込め)。抽出できなければ上表のいずれかで倒す。
+
+### レート制限(#521 / ADR-0023)
+
+`resume-import/pdf` は LLM を呼ぶ高コスト経路のため、ユーザ単位の日次上限(`enforce_daily_limit`)の対象に含める。既存の `/chat`・`/resume-draft` と同じ蓋を掛ける。
+
+### ファイルアップロードのバリデーション(`security.md`)
+
+- MIME だけでなく PDF の magic bytes(`%PDF-`)で検証する。
+- ファイルサイズ上限をエンドポイントで強制し OOM を防ぐ(上限は妥当な既定値。必要なら env 化を #527 の stage で判断)。
+- 保存はしない(抽出してレスポンスを返すのみ・一時ファイルも即破棄)。パストラバーサルの余地を作らない。
+
+## 代替案
+
+- **非同期タスク化(ADR-0020 パターン)**: 抽出 + Haiku 1 コールは同期で 60s 内に収まり、タスク基盤・ポーリング・状態遷移の追加は保守コストに見合わない。却下(P1)。
+- **pdfplumber / PyMuPDF**: pdfplumber は表・レイアウト抽出に強いが依存が重く、経歴書の素テキスト抽出には pypdf で十分。PyMuPDF は高速だが AGPL ライセンス + ネイティブ(MuPDF)依存で、個人開発 SaaS のライセンス・nix build 負荷の観点から却下。
+- **スキャン PDF を v1 で OCR 対応**: OCR / vision はコスト・失敗モード・レイテンシが別物。まず大多数のテキスト埋め込み PDF で価値を出し、スキャン対応は将来判断とする(P6)。
+- **抽出結果を直接 DB へ保存**: ADR-0010 の DB 非更新原則に反する。ユーザ確認を挟まない自動保存は捏造・誤抽出をそのまま確定させる。却下(P5)。
+
+## トレードオフ・既知のリスク
+
+- **スキャン PDF は非対応**(画像経歴書のユーザは手入力へ誘導)。テキスト埋め込みかどうかはユーザには自明でないため、判定時の日本語メッセージで「なぜ使えないか・次に何をすべきか」を明示する。
+- **抽出品質は PDF の構造に依存する**(多段組・特殊フォント・図表混在で精度が落ちる)。だからこそ DB 非更新でユーザ確認を挟む設計にし、誤抽出を保存前に直せるようにする。
+- **PDF に含まれる PII(氏名・経歴)を LLM に送る**。ただし ADR-0023 で残した Anthropic は Vertex AI(ADC) 経由(学習除外・アジア圏データ所在 / ADR-0015 の判断を継承)であり、既存の `/chat`・`/resume-draft` と同じ信頼境界に収まる(P2)。新たな境界を越えるものではない。
+- **Haiku の API コストが 1 インポートあたり発生する**(運営持ち / ADR-0023)。レート制限(#521)で abuse を抑える。
+
+## 将来の移行条件
+
+- **スキャン PDF 対応**: OCR / vision モデルを導入する場合は本 ADR を更新し、コスト(vision は Haiku より高い)・失敗モード・レート制限見直しを再評価する。
+- **抽出精度が用途に不足する場合**: プロンプト(品質基準・few-shot)で対処する。ADR-0023 でモデル昇格パスは撤去済みのため、上位モデル前提の改善は新規 ADR 起票が前提。
+- 本機能自体が使われない・維持コストが価値を上回ると判断した場合は、ADR-0008 の流儀で撤去する(P6。ADR-0004→0008 の前例どおり可逆に畳める)。
+
+## 設計原則との関係
+
+- **P1(コスト最適化)**: 同期・pypdf(純 Python)・タスク基盤なしで最小構成。非同期・重量ライブラリを避ける。
+- **P2(PII を信頼境界の外に出さない)**: 抽出の LLM は既存の Anthropic Vertex(ADC) 経路(学習除外・アジア圏所在 / ADR-0015 継承)に収め、新たな境界を作らない。抽出結果は DB に保存せずフォーム前段で留める。
+- **P4(責務を層で分離する)**: 機械制約 = スキーマ / 品質制約 = プロンプト、決定論の前処理 = ルールベース / 自然文抽出 = LLM を混ぜない。
+- **P5(LLM は対話型に限定)**: 抽出結果は自動確定せず、ユーザが確認して保存する(DB 非更新)。
+- **P6(可逆性)**: ADR-0004→0008 で一度撤去した機能の再導入。撤退条件を明記し可逆に畳める。
+- **P7(依存は固定)**: pypdf を `==` 完全固定で追加し `uv lock` を再生成する。
+
+## 関連リンク
+
+- [#517 機能整理・体験改善ロードマップ](https://github.com/yusuke0610/devforge/issues/517)(親 issue)
+- #526(本 ADR)/#527(backend 抽出エンドポイント)/#528(web アップロード UI)/#524(フォーム注入機構・前提)
+- [ADR-0010](0010-devforge-agent.md) / [ADR-0018](0018-github-resume-draft-generation.md)(手本)/[ADR-0004](0004-llm-provider-abstraction.md) / [ADR-0008](0008-remove-llm-to-rule-based-design.md)(AI 抽出の導入と撤去の歴史)
diff --git a/docs/adr/README.md b/docs/adr/README.md
index 1bfcd951..1e89b631 100644
--- a/docs/adr/README.md
+++ b/docs/adr/README.md
@@ -25,6 +25,7 @@
| [ADR-0021](./0021-nix-managed-python-env.md) | backend Python 環境の Nix フルマネージド化(.venv 廃止) | 開発プロセス / 品質 | 依存 SSoT を pyproject + uv.lock に一本化し、devshell / CI / 本番イメージの 3 経路を uv2nix(flake)で統一 |
| [ADR-0022](./0022-remove-blog-integration.md) | ブログ連携機能の撤去 | プロダクト / 機能整理 | 経歴書へ還流せずスコアが逆効果になり得るブログ連携(テーブル 3 つ・router / service / web 一式)を全量撤去 |
| [ADR-0023](./0023-remove-billing-multiprovider.md) | プリペイド課金・マルチプロバイダの撤去と Haiku 無料一本化 | LLM / Agent | 課金の壁を撤去し Haiku 無料一本化 + ユーザ単位レート制限へ縮退。Anthropic は Vertex(ADC) 維持、Gemini/OpenAI/Stripe を撤去 |
+| [ADR-0024](./0024-pdf-resume-import.md) | 手持ち PDF 経歴書のフォーム流し込み(AI 抽出の再導入) | LLM / Agent | 空フォーム離脱の解消。テキスト埋め込み PDF を pypdf 抽出 + Haiku 構造化で Resume 互換 payload に。同期・DB 非更新でフォーム注入(#524)へ渡す。ADR-0004→0008 で撤去した AI 抽出を ADR-0010 の不変条件で再導入 |
## 全 ADR 一覧
@@ -56,6 +57,7 @@
| [ADR-0021](./0021-nix-managed-python-env.md) | backend Python 環境の Nix フルマネージド化(.venv 廃止) | Accepted | 開発プロセス / 品質 | 関連: 0017(uv 非管理前提を更新)、0014(依存固定・Renovate manager)、0007(Nix devshell 規約) | P7・P3・P6 |
| [ADR-0022](./0022-remove-blog-integration.md) | ブログ連携機能の撤去 | Accepted | プロダクト / 機能整理 | 手本: 0008(撤去の流儀)。関連: 0010(Agent コンテキストの入力縮小)、0016 | P6・P1 |
| [ADR-0023](./0023-remove-billing-multiprovider.md) | プリペイド課金・マルチプロバイダの撤去と Haiku 無料一本化 | Accepted | LLM / Agent | Supersedes: 0012・0013・0015。関連: 0010(Agent 不変条件を継承)、0018・0020(課金配線を剥がす)、0005 | P1・P6・P2 |
+| [ADR-0024](./0024-pdf-resume-import.md) | 手持ち PDF 経歴書のフォーム流し込み(AI 抽出の再導入) | Accepted | LLM / Agent | 継承: 0010(不変条件)、0023(Haiku 固定)。手本: 0018。歴史: 0004→0008(AI 抽出の導入と撤去)。前提: #524 | P1・P2・P5・P6 |
## テーマ別の決定系統
@@ -77,9 +79,12 @@ graph LR
A0010 -.-> A0018["0018
経歴書ドラフト生成"]
A0016 -.-> A0018
A0018 -.-> A0020["0020
ドラフト生成の非同期化"]
+ A0004 -.->|"再導入(0010 の不変条件で)"| A0024["0024
PDF 経歴書 AI 抽出"]
+ A0010 -.-> A0024
+ A0023 -.-> A0024
```
-このプロダクトで最も判断の往復が大きい系統。「LLM 抽象の先行実装(0004)→ 利用見込み薄と判断して全撤去(0008)→ 対話型として価値が明確になった時点で、0008 自身が規定した手続きに従い再導入(0010)→ 課金・マルチプロバイダ・データガバナンスへ段階拡張(0012/0013/0015)」という流れで、**撤退条件を先に書いておく運用が実際に機能した実例**になっている。0016 は 0010 の「機械検証可能な制約はコード、不能な制約はプロンプト」という責務分離を「機械=幅 / 人間=深さ」の 3 層モデルへ一般化した。0018 は 0010 の不変条件と 0016 の決定論データを前提に、経歴書ドラフト生成へ「構造=機械 / 自然文=LLM」の分離を適用した。
+このプロダクトで最も判断の往復が大きい系統。「LLM 抽象の先行実装(0004)→ 利用見込み薄と判断して全撤去(0008)→ 対話型として価値が明確になった時点で、0008 自身が規定した手続きに従い再導入(0010)→ 課金・マルチプロバイダ・データガバナンスへ段階拡張(0012/0013/0015)」という流れで、**撤退条件を先に書いておく運用が実際に機能した実例**になっている。0016 は 0010 の「機械検証可能な制約はコード、不能な制約はプロンプト」という責務分離を「機械=幅 / 人間=深さ」の 3 層モデルへ一般化した。0018 は 0010 の不変条件と 0016 の決定論データを前提に、経歴書ドラフト生成へ「構造=機械 / 自然文=LLM」の分離を適用した。0024 は 0004 で導入し 0008 で撤去した「PDF 経歴書の AI 抽出」を、0010 の不変条件(DB 非更新・明示的エラー契約)と 0023 の Haiku 固定の上で再導入するもので、**空文字握りつぶしという旧敗因を契約で構造的に塞ぐ**再導入の実例になっている。
### 基盤(データ / インフラ / 認証)