---
name: pschool-course-builder
description: "pschool プロジェクト専用のコース・カリキュラム自動生成 skill (schema v2 = state machine DAG)。 Udemy / 技術学習プラットフォーム型の 1 コース = フラット chapters[] + sections[] view group 構成で、 各 chapter は lecture / mixed / exercise / quiz / review の 5 タイプ混在を許容 (handson は legacy、 新規生成禁止)。 mixed / exercise は書籍型 (コード片 → なぜそう書くか の往復) を強制し、 教材として「学んで作る」 を繰り返すフォーマットを担保。 各 chapter は `state_transitions[]` で前章 state から本章 state への遷移を明示し、 actions[] (create_file / edit_file / define_symbol / call_symbol / extend_enum / add_dependency / run_command) で受講者の操作を構造化、 asserts[] (file_exists / symbol_defined / symbol_called / shell_exit_0 / http_response / manual) で完了検証を多層化する。 wiring chain (define ↔ call) を schema 上で表現 + Step 5.7 dogfooding (`--mode full` で project 単位並列の実機実行) で全 action/assert を機械検証することで「コース通りに実装すれば動くアプリが完成する」 保証を 90%+ に引き上げる。 section 数 4-8 / chapter 数 3-10 per section の可変設計を topic 特性 (言語入門 / framework + product / infra / library) から判定。 Context7 MCP + WebFetch + GitHub Awesome List + Exa の 4 source RAG retrieval + 5-stage progression (導入 → 基礎 → 応用 → 実践 → まとめ + capstone) + Bloom's taxonomy + worked-example→faded→independent 練習設計 + spaced retrieval (末尾 chapter type=exercise) で技術学習ベストプラクティスを担保。 triple-research-dev の 5 stage パイプライン (4 体並列研究 → synthesizer → planner → generator → reviewer) を踏襲、 ハルシネーション対策として引用 URL 必須 / retrieval-only / chapter 並列 reviewer で 100% カバレッジ + spot-check / Opus fact-check pass の 4 防衛を実装。 Step 5.5 schema 検証 + Step 5.7 dogfooding (Phase 3a = `--mode full`) はいずれも `check_handson_chain_v2.py` の 1 行実行で完結。 トリガーは `/pschool-course-builder <topic>` slash command、 または自然言語で『<トピック> でコース作って』『<トピック> のカリキュラム生成』『マイクロコース作成』『ハンズオンコース作って』『Cloud Run + gRPC でコース』『新規コース』『教材生成』『カリキュラム構築』『course.yaml 生成』『state machine DAG コース』『pschool で<X>を学ぶコース』『chapter プラン作成』『capstone 設計』『Curriculum Generator 試作』『Awesome List からカリキュラム』『最新の<X>でコース』などの依頼。 必ずこの skill を使うこと: ユーザーが pschool 用コース生成に関する単一語句を出した時点でも、 明示的に「skill 使って」 と言われていなくても発動する。 pschool 固有 yaml schema v2 (state_transitions / actions[] / asserts[] / wiring chain) に厳密準拠し、 生成後は `pschool start <course_id>` でそのまま受講開始でき、 かつ `python check_handson_chain_v2.py --mode schema courses/<id>/` が CRITICAL 0 を返す状態で出力される。"
---

# pschool-course-builder

## Overview

pschool プロジェクトで「**最新情報に基づく信頼できる Udemy 型コース**」を自動生成する。triple-research-dev の 5 stage パイプラインを踏襲しつつ、教材生成特有の問題 (ハルシネーション / バージョンドリフト / カリキュラム品質のばらつき / 受講者が完走できない wiring chain 欠落) に対応した 4 source RAG + 4 防衛策 + schema v2 state machine DAG を持つ。

各フェーズの詳細は専用 micro-skill に委譲する:

| フェーズ | micro-skill | 入力 | 出力 |
|---|---|---|---|
| Step 1.5〜3 (研究) | `pschool-course-researcher` | topic + topic 特性 | claim ledger + URL マスター |
| Step 3.5 (正規化) | `pschool-course-canonicalizer` | claim ledger + URL マスター | course_canonical.yaml |
| Step 4/4.5 (設計) | `pschool-course-planner` | course_canonical.yaml | chapter 設計表 + section pack |
| Step 5 (生成) | `pschool-section-generator` | 設計表 + section pack | ch-NN-MM.yaml 群 |
| Step 6 (レビュー) | `pschool-course-reviewer` | chapter yaml 群 | 指摘リスト |
| Step 7 fix (修正) | `pschool-compile-fixer` | dogfooding feedback + 指摘 | 修正済み chapter yaml |

## コース構成 (Udemy 型統一構造、schema v2)

### ディレクトリ構造 (canonical)

```
courses/<course-id>/
├── course.yaml            # メタ + sections[] (view group) + states[] + initial_state
├── chapters/              # フラット配列、zero-padded
│   ├── ch-01-01.yaml
│   ├── ch-01-02.yaml
│   └── ...
└── capstone.yaml
```

### 全体構造 (5-stage progression)

```
1 Course
├─ Section 1: 導入 (3-5 chapter)
├─ Section 2: 基礎概念・構文 (4-8 chapter)
├─ Section 3-N: 応用機能・実装パターン (4-8 chapter × 複数 section)
├─ Section N+1: 実践プロジェクト・統合 (5-10 chapter)
├─ Section 末尾: まとめ・ベストプラクティス・次の一歩 (2-4 chapter)
└─ capstone (コース総合課題、推奨)
```

**section 数: 4-8、chapter 数: 3-10 per section、総 chapter 数: 25-60、総時間: 4-20 時間**。

### Chapter type 分類 (5 種)

| type | 主用途 | lecture_md | コードブロック | actions | asserts | est_min |
|---|---|---|---|---|---|---|
| **lecture** | 純粋概念 / 理論 | 2,500-4,500 字 | 任意 | **0** | 0-1 | 10-20 |
| **mixed** ★推奨 | 書籍型: コード片 ↔ 解説往復 | 2,500-3,500 字 | **3 以上必須** | 2-5 | 1-3 | 20-40 |
| **exercise** | コード演習 | 1,500-2,500 字 | **1 以上必須** | 0-3 | 1-3 | 15-30 |
| **quiz** | 確認テスト | 500-1,200 字 | 任意 | 0 | 0 | 8-15 |
| **review** | section / コース総括 | 1,500-3,000 字 | 任意 | 0 | 0-1 | 10-20 |

★ **handson は廃止**: 新規 chapter 生成では使用禁止。

詳細は `references/course-structure-design.md` 参照。

## Workflow

### Step 0: Tool schema 取得 + 進捗 TODO 初期化

1. ToolSearch で deferred tool のスキーマを取得 (`select:TaskCreate,TaskUpdate,WebFetch,WebSearch`)
2. TaskCreate で 15 step を pending 登録:
   - Step 1: 入力解析 + contract-first gate 判定 (api_ledger_gate: required | skip)
   - Step 1.5b: contract-first / spike gate (target course のみ: reference skeleton 実機ビルド → API-LEDGER → build-success.log)
   - Step 1.5: risk classifier (→ pschool-course-researcher)
   - Step 2: 4 体並列研究 (→ pschool-course-researcher)
   - Step 3: 研究まとめ役 (→ pschool-course-researcher)
   - Step 3.4: probe 代行実行 (orchestrator 自身が Bash で実行)
   - Step 3.5: canonicalizer (→ pschool-course-canonicalizer)
   - Step 4: 構成プランナー (→ pschool-course-planner)
   - Step 4.5: section lead generator (→ pschool-course-planner)
   - Step 5: 生成担当 (→ pschool-section-generator)
   - Step 5.5: 機械検証 schema mode
   - Step 5.7.0: deprecated syntax check
   - Step 5.7: dogfooding 実機検証 full mode
   - Step 5.7.5: LLM Simulator sentinel mode (sentinel chapter で受講シミュレーション → verdict inject → exit code 評価)
   - Step 6: レビュー担当 (→ pschool-course-reviewer)
   - Step 7: 生成↔レビューループ (→ pschool-compile-fixer)
   - Step 8: spot-check 案内 + 最終報告

3. **pipeline.yaml 検証** (任意): `python -m tools.pipeline_schema ~/.pschool/pipelines/<topic>.yaml` を実行。exit 0=OK / 1=schema 違反 / 2=FileNotFound。

4. **subagent 実行ログ記録 (★ 忘れやすい、cloud-run-pubsub-haskell 2026-05-29 で未実行)**: 各 subagent dispatch と **ペア**で必ず `log_subagent_execution(course_id, agent_name, model, effort, tools, start_time, end_time, exit_code)` を呼び、`~/.pschool/logs/<course_id>.jsonl` に記録する (dispatch だけして log を忘れるとトレース不能になり `_research/` + `_reference/` での代替に追加コストがかかる)。Step 1.5〜7 の各 Agent 起動直後に必ず実行。可能なら subagent_start/subagent_stop hook 化して取りこぼしを防ぐ (hook 配線は code 側タスク)。

### Step 1: 入力解析 (topic 確定 + topic 特性判定 + course_id 決定)

1. **topic 正規化**: 「Rust 所有権」→ `rust-ownership` のように kebab-case に
2. **topic 特性判定**: `language-intro` / `framework-product` / `infra-cloud` / `library-concept` のいずれか。曖昧なら AskUserQuestion
3. **course_id 決定**: 既存 `courses/<id>/` が存在する場合は **必ず user confirm**
4. **scope 確認**: 実環境を伴う chapter が含まれる予想では IaaS 環境前提を user に明示
5. **contract-first gate 判定**: 下記「Step 1.5b: contract-first / spike gate」の対象コース基準を照合し、`api_ledger_gate: required | skip` を確定して `course_canonical.yaml` に記録する

### Step 1.5b: contract-first / spike gate (★ MANDATORY for target courses)

**目的**: generator が実在しない外部 API signature を捏造 (hallucination) するのを構造的に防ぐ。  
**原則**: CLAUDE.md「コントラクト層 (API/型) を厳密に定義し、実装層は再生成可能に保つ」を course 生成に適用した版。  
**参照**: `references/api-ledger-template.md` (フォーマット仕様 + haskell-gogol-firebase worked example)

#### 対象コース判定基準 (いずれか 1 つを満たせば `api_ledger_gate: required`)

| 基準 | 具体例 |
|---|---|
| 自動生成クライアントを使う (proto/OpenAPI/Discovery から生成) | gogol, aws-sdk Haskell binding, openapi-generator 出力 |
| モデル training cutoff 以降のライブラリ、または公式 example が乏しいライブラリ | gogol 1.0.0.0 (2024 リリース)、jose 0.12 auth API |
| 複数ライブラリのバージョン制約が非自明な相互作用を持つ | jose + crypton + servant-auth-server (GHC 9.x 依存地獄) |
| 過去の dogfood / course run で signature レベルの build failure や hallucination が記録された | `fabricated-signature-detected` 違反が出た course の続編 |

**非対象コース** (`api_ledger_gate: skip` — gate を省略してよい):  
言語入門 / 標準 SDK のみ / 安定した wide-use ライブラリのみ (例: Rust 所有権入門、Flutter first app with SDK APIs)。  
判定は Step 1 topic 特性判定と合わせて orchestrator が行う。判定根拠を `course_canonical.yaml` に明記する (required の場合は `api_ledger_gate_reason:`、skip の場合は `api_ledger_gate_skip_reason:` フィールド。どちらも自由記述 1〜数行で、該当した判定基準行を引用する)。

#### gate が `required` の場合の手順

```
1. 外部 API surface を特定し "unknowns" リストを作る
     → ~/.pschool/spikes/<course-id>/unknowns.md

2. reference skeleton を書く (real source files + real build manifest)
     → ~/.pschool/spikes/<course-id>/<skeleton-dir>/
     ★ TDD コース (本編に test-first 章がある) では skeleton に **test-suite stanza + 代表 Spec ファイル**
       も含める (lib/exe だけにしない)。理由: test-suite の build-depends 漏れや Spec の import drift は
       skeleton gate で build しない限り dogfood 時 (高コスト・遅い) まで露呈せず fix loop を冗長化する
       (haskell-grpc-bff 2026-06-14: skeleton が library + 3 exe のみで test 層を欠き、test-suite
        build-depends と CatalogSpec import drift が dogfood まで検出されなかった)。

3. 実コンパイラ / build tool でビルドする (exit 0 必達)、出力を build.log に保存
     例 (Haskell): cd ~/.pschool/spikes/<course-id>/<skeleton-dir> && cabal build all && cabal test
     例 (Rust):    cd ~/.pschool/spikes/<course-id>/<skeleton-dir> && cargo build && cargo test
     → ~/.pschool/spikes/<course-id>/build.log
     ★ TDD コースでは test-suite が compile/実行できることまで gate に含める (build all だけにしない)。
       test の build 成功を build-success.log sentinel の前提条件にする。

4. 検証済み signature を API-LEDGER.md に転記する (build が通った code に現れた signature のみ)
     → ~/.pschool/spikes/<course-id>/API-LEDGER.md
       (フォーマット: references/api-ledger-template.md 参照)

5. 全て揃った最後に build-success.log sentinel を書く
     → ~/.pschool/spikes/<course-id>/build-success.log
       (内容は "BUILD OK YYYY-MM-DD HH:MM" 1 行でよい)
       ※ build-success.log は「build 成功 **かつ** API-LEDGER 転記完了」を示す最終 sentinel。
         ledger 転記より前に書くと未完成 ledger のまま generator が unblock されるため、必ず最後に書く。

★ GATE: ~/.pschool/spikes/<course-id>/build-success.log が存在しない限り
         Step 5 generator dispatch は BLOCKED。
         (この手順番号は references/api-ledger-template.md の Process 節と一致させてある。)
```

#### generator への signature 制約 (target course のみ)

Step 5 section-generator への入力に **SIGNATURE CONSTRAINT を必ず付与する**。
正文 (SSOT) は `references/api-ledger-template.md` の末尾「Generator constraint」ブロックを使い、
`<course-id>` を実 course-id に置換して貼る (ここで別文面を再定義しない — 二重管理を避けるため)。
要点: content_template 内の外部ライブラリ呼び出しは API-LEDGER の signature のみから引き、
argument order も ledger 通りに使い、ledger 外 signature と "known fabrications" は使わず、
不明な API は推測せず orchestrator にエスカレーションする。

#### skip 申告

`api_ledger_gate: skip` の場合は Step 1.5b をスキップし、Step 1.5〜3 研究フェーズへ進む。  
skip 理由を `course_canonical.yaml` の `api_ledger_gate_skip_reason:` フィールドに記録する。

### Step 1.5〜3: 研究フェーズ → pschool-course-researcher を起動

```
Agent tool dispatch: pschool-course-researcher skill
  入力: topic 正規化名 + topic 特性 + persona + lang ledger パス
  出力: claim ledger JSON array + 引用 URL マスター + hard_planner フラグ
  model: 役割別 (risk classifier=haiku / research=sonnet+haiku / synthesizer=sonnet)
```

詳細手順・4-source 並列起動規約・synthesizer 集約ロジックは `pschool-course-researcher` skill を参照。

### Step 3.4: probe 代行実行 (orchestrator が Bash で実行)

canonicalizer は `allowed-tools` に `Bash` を持たないため、orchestrator (course-builder、Bash 保有) が probe を代行実行して解決済み version table を canonicalizer に渡す。

**手順**:

1. **使用ライブラリの抽出**: researcher の claim ledger から「主役ライブラリ + 周辺パッケージ群」を特定する
2. **実機解決を 1 回実行し version table を取得**: 一時 dir で lockfile を作る実機解決を行い、パッケージマネージャが「一緒に解決した」バージョンを ground truth とする
   - **Flutter / Dart**: `flutter create` 不使用 (subdir 問題、`references/library/dart/riverpod.md` §dogfood 罠)。一時 dir に最小 `pubspec.yaml` を作成し `flutter pub add <全依存を 1 コマンドで列挙>` を実行 → `pubspec.lock` から version を抽出
   - **cargo / npm / pip / cabal**: 同様に `cargo add` → `Cargo.lock`、`npm install` → `package-lock.json`、`pip install` → freeze、`cabal build` → `cabal.project.freeze` で lockfile を作り解決済み version を確定
3. **probe 生ログは context に残さず version table のみ残す**: ログが長くなる場合はサマリ (library → resolved version の対応表) だけ保持する
4. **toolchain 不在時は probe skip + 文献値暫定採用 + Step 8 エスカレーション記録**: 実環境に toolchain が無い場合は probe をスキップし、研究フェーズの文献値を暫定採用する。ただし必ず Step 8 `## エスカレーション事項` に「probe skip (toolchain 不在): 文献値暫定採用」を記録する
5. **解決済み version table を Step 3.5 canonicalizer に渡す**: probe で得た `{library: resolved_version}` の対応表を Step 3.5 dispatch の入力に追加する

**継続更新 (library ledger との差分検出)**:

probe 結果と参照した library ledger (`references/library/<lang>/<library>.md`) の整合表に差分がある場合、以下を実行して ledger を更新する (実装済、#19):

```bash
python .claude/skills/pschool-course-builder/references/update_library_ledger.py \
  --ledger references/library/<lang>/<library>.md \
  --resolved '<json>' \
  --no-dry-run
```

例: `--resolved '{"riverpod": "2.6.1", "riverpod_annotation": "2.3.5"}'`

整合表に無い周辺パッケージが probe で解決された場合も ledger に追記する。

### Step 3.5: canonicalizer → pschool-course-canonicalizer を起動

```
Agent tool dispatch: pschool-course-canonicalizer skill
  入力: claim ledger + 引用 URL マスター
  出力: courses/<id>/course_canonical.yaml
  model: claude-opus-4-7 / effort=high
```

詳細手順は `pschool-course-canonicalizer` skill を参照。

### Step 4/4.5: 設計フェーズ → pschool-course-planner を起動

```
Agent tool dispatch: pschool-course-planner skill
  入力: courses/<id>/course_canonical.yaml + topic 特性 + hard_planner フラグ
  出力: chapter 設計表 (Markdown 表) + section pack (courses/<id>/sections/sec-<N>.pack.yaml、命名 SSOT は course.yaml sections[].id)
  model: hard_planner=opus / course_planner=sonnet / section_lead=sonnet
```

詳細手順・wiring chain 設計・section canonical 表・dogfood 戦略出力規約は `pschool-course-planner` skill を参照。

### Step 5: 生成フェーズ → pschool-section-generator を起動

**前準備 (main agent 責務)**:
1. `git status` 確認 + `mkdir -p courses/<id>/chapters/`
2. `course.yaml` (メタ + states[]) を main agent が直接 Write。**正確な構造は `references/yaml-schema-templates.md` の §course.yaml / §chapter yaml を必ず Read してから書く** (必須 field 列挙だけ見てフラット構造で書くと v2 loader が落ちる)。★ 構造の要点 (本コースで全部踏んだ):
   - **全メタを `course:` トップキーで包む** (`course:` の下に `id` / `topic` / `topic_characteristic` / `total_estimated_hours` / `schema_version: "2.0.0"` / `e2e_base_image`)。フラットに `id:` をトップに書くと loader が `course.schema_version is required (got: missing)` で **exit 2**
   - `sections[]` / `initial_state` / `states[]` は `course:` と同階層のトップレベル
   - `sections[]` の各 section は `chapter_ids: [ch-01-01, ch-01-02, ...]` 形式 (`chapter_range` ではない)
   - `initial_state` は `{id: state-initial}` オブジェクト、`states` は `[{id: ...}, {id: ...}]` リスト (文字列 list ではない)
   - **各 chapter yaml の `chapter:` 直下に `section_id: sec-<N>` が必須** (`course.yaml#sections[].id` への参照。欠くと loader が `'section_id' is required` で exit 2)。section-generator が入れ忘れることがあるので生成後に全章 grep 確認する
   - capstone の `success_criteria` は自由テキストではなく `[{id, description, measurement_asserts: []}]` のオブジェクトリスト (文字列を書くと loader が `string indices must be integers` で落ちる)

   必須 field 列挙: `id` / `topic` / `topic_characteristic` / `total_estimated_hours` / `schema_version: "2.0.0"` / `sections[]` / `initial_state` / `states[]`、加えて **`e2e_base_image`** (欠くと schema check が `e2e-base-image-missing` を **HIGH** 判定して exit 1。bias-free generator 2 体が独立に踏んだ。dual-language コースでも 1 つ設定する — `--mode full` は per-language image を使うので影響せず、`--mode e2e` 用)。★ planner の dogfood 戦略が「全 section 累積式・単一 top_dir」なら `course.yaml` に **`dogfood_mode: single-project` を必達設定** (欠くと Step 5.7 dogfood が per-project grouping で `<proj>/<proj>` 二重化 + file-less 章隔離 + 累積 build 不成立で全 FAIL。planner §6 / dogfooding-runner.md §single-project 参照)。逆に **per-chapter independent 競技形式 (章ごと `<ch>-java`/`<ch>-hs` 独立単一ファイル) では `dogfood_mode: single-project` を設定しない** (multi-project default のまま)

```
Agent tool 並列 dispatch: pschool-section-generator skill × (N chapter + 1 capstone)
  入力: 9 変数 (NN / MM / コースタイトル / course-id / chapterテーマ / type / lang / from_state / section_pack_path)
  出力: courses/<id>/chapters/ch-NN-MM.yaml (直接 Write)
  model: section_lead=sonnet (lecture_md・actions・asserts の主要部) / chapter_filler=haiku (metadata・citation 整形・軽微な補完)
```

**並列起動必須**: 1 メッセージ内に N+1 並列 dispatch。逐次起動禁止。

**section 別 batch dispatch** (総 chapter 数 20+ の場合): section 別に batch を分けて context 圧迫を防ぐ。

詳細手順・9 規約・書籍型フォーマット強制は `pschool-section-generator` skill を参照。

### Step 5.5: 機械検証 (`check_handson_chain_v2.py` 1 行実行)

```bash
python .claude/skills/pschool-course-builder/references/check_handson_chain_v2.py \
  --mode schema courses/<id>/ ; echo "EXIT=$?"
```

★ 他の gate (Step 5.6/5.7.0/5.7) と同じく `; echo "EXIT=$?"` を必ず付け、stdout の PASS/FAIL 文言ではなく **EXIT 値で判定する** (パイプを挟むと `$?` がパイプ末尾を拾い CRITICAL を EXIT=0 と誤報した事故あり)。

exit code:
- **0**: CRITICAL 0 + **HIGH 0** → Step 5.7 dogfooding へ
- **1**: CRITICAL/HIGH >= 1 → Step 7 ループ起動
- **2**: load error → Step 4 planner に遡って再設計

★ **exit 1 は CRITICAL だけでなく HIGH でも発火する** (`check_handson_chain_v2.py` 実装 = `exit_code = 1 if (critical_count > 0 or high_count > 0)`)。 CRITICAL を潰しても HIGH が残れば exit 1 のまま Step 5.7 に進めない。 algorithm-from-math-dp-foundations 2026-06-12 で book-format / lecture-code-not-in-content の HIGH 70 件が 5.5 ゲートを塞いだ (CRITICAL は 0 だった)。 **「完全 pass = CRITICAL 0 かつ HIGH 0」** と読むこと。

★ **Step 5.5 完全 pass (CRITICAL 0 + HIGH 0) まで Step 5.6 / Step 5.7 起動禁止** (シリアル境界絶対遵守)。

### Step 5.6: static-analysis gate (generator-time、`--mode static-gate`)

Step 5.5 pass 後・Step 5.7 dogfooding 前に実行する軽量静的解析 gate。
`content_template` を全適用した最終ファイルツリーに対し、言語別の format-check + 型/構文全列挙 check を実行し、ALL diagnostics を一度に violation 化する。
**build より前にエラーを全列挙**することで、fix loop 往復回数を削減する (Issue #348)。

```bash
PYTHONPATH=. python .claude/skills/pschool-course-builder/references/check_handson_chain_v2.py \
  --mode static-gate courses/<id>/ ; echo "EXIT=$?"
```

**対象プロジェクトの決め方**: `detect_projects(course)` と同じロジックで最上位 dir を検出し、language は `_detect_project_lang()` で推定する (add_dependency の package_manager / course.id プレフィックス)。

**言語別コマンド (SSOT: `pschool/dogfood/static_analysis.py`)**:

| lang | format-check | 型/構文全列挙 |
|---|---|---|
| rust | `cargo fmt --check` | `cargo check --message-format=json` |
| typescript | `npx prettier --check .` | `npx tsc --noEmit` |
| haskell | `cabal check` | `ghc -fno-code -Wall` |
| python | `ruff format --check .` | `ruff check --output-format=json .` |
| moonbit | `moon fmt --check` | `moon check` |

**skip 条件 (CRITICAL にしない)**:
- 言語が SSOT に未定義 → skip + `WARNING` 表示。無音 skip 禁止。
- ツールが PATH に不在 → そのチェックのみ skip + `WARNING`。CRITICAL にしない。
- gate を完全 skip したい場合: `PSCHOOL_SKIP_STATIC_GATE=1` 環境変数を設定する。この場合も必ず Step 8 `## エスカレーション事項` に「Step 5.6 静的ゲート手動 skip (PSCHOOL_SKIP_STATIC_GATE=1)」を記録する (無音の緑禁止)。

exit code:
- **0**: CRITICAL 0 + HIGH 0 → Step 5.7.0 / Step 5.7 dogfooding へ
- **1**: CRITICAL/HIGH >= 1 → Step 7 fix loop に統合 (Step 5.7 は継続実行)。 ★ exit 1 は HIGH でも発火する (Step 5.5 と同じ `critical>0 or high>0` 判定)
- **2**: load error

★ **ツール未インストールで ALL チェックが skip された場合は exit 0 (ツール不在は課題ではなく環境問題)**。Step 5.7 dogfooding が権威 gate として機能する。ただし ALL チェックが skip された (= 静的ゲート未実行) 場合は必ず Step 8 `## エスカレーション事項` に「Step 5.6 全 skip (toolchain 不在): 静的検証は dogfood に委譲」を記録する (Step 3.4 probe skip と同じ規約、無音の緑禁止)。
★ **SKILL 未対応言語のコースでは step ごと省略してよい** (skip + WARNING のみ)。

### Step 5.7.0: deprecated syntax 検出

```bash
python .claude/skills/pschool-course-builder/references/check_deprecated_syntax.py \
  courses/<id>/ <lang> --append-candidates ; echo "EXIT=$?"
```

lang ledger 未作成の言語では skip。CRITICAL 検出時 (EXIT=1) は Step 7 fix loop に統合。

★ **大量 FP 精査プロトコル (CRITICAL ≥ 20 件 または lang ledger に "FP 既知" 注記がある場合)**:
1. 出力の先頭・中央・末尾からそれぞれ 5-7 件をサンプリングし (偏り防止)、ヒット行が散文 (lecture_md) か実コード (content_template) かを確認する。サンプリング 20 件中 16 件以上が FP なら「FP 率 ≥ 80%」と判定する
2. **FP 率 ≥ 80% と判定できる場合**: Step 7 fix loop には送らず Step 5.7 dogfooding を権威 gate として継続。Escalation conditions に「Step 5.7.0 大量 FP (N 件) を精査後スキップ」を記録する
3. **FP 率 < 80% の場合**: 通常通り Step 7 fix loop に統合する
4. **判定できない場合 (散文/コード混在で判断不能)**: user 確認を求める

★ **Step 5.7.0 fail (EXIT=1) でも Step 5.7 dogfooding は継続する** (5.7.0 が gate になるのは FP 率 < 80% の Genuine CRITICAL 検出時のみ)。

### Step 5.7: dogfooding (実機実行検証、`check_handson_chain_v2.py --mode full`)

**出力は必ずファイルに保存してから集計する** (出力が数百行になり、exit code を正しく取るため):

```bash
PYTHONPATH=. python .claude/skills/pschool-course-builder/references/check_handson_chain_v2.py \
  --mode full courses/<id>/ > /tmp/dogfood-<id>.log 2>&1; echo "EXIT=$?"
# 集計はファイルから (tail で末尾を覗くのではなく grep -c で全件数える):
grep -c '\[CRITICAL\]' /tmp/dogfood-<id>.log   # CRITICAL 件数
grep -c '\[HIGH\]'     /tmp/dogfood-<id>.log   # HIGH 件数
grep -oE '\[(CRITICAL|HIGH)\] [a-z:_-]+' /tmp/dogfood-<id>.log | sort | uniq -c | sort -rn  # 種別集計
```

★★ **EXIT判定の罠 (絶対遵守・CRITICAL 見逃しの典型。本コースで実際に CRITICAL 16 を EXIT=0 と誤報して Step 6 まで進んだ事故あり)**: `... --mode full ... | tail -80 ; echo "EXIT=$?"` のように **パイプを挟むと `$?` はパイプ最後のコマンド (tail/grep、終了コードは常に 0) を拾い、python 本体が exit 1 でも `EXIT=0` と誤報する**。さらに `| tail -N` で末尾だけ見ると、CRITICAL/HIGH 行が末尾に並ぶ大量の MEDIUM に押し出されて視界から消え「violation 0」と誤認する。**回避**: 上記のように `> file 2>&1; echo "EXIT=$?"` でファイル保存 (パイプなしなので `$?` が python 本体の exit) してから `grep -c` で集計する。どうしてもパイプを挟むなら `; echo "EXIT=${PIPESTATUS[0]}"` を使う (素の `$?` は禁止)。この罠は `--mode schema` / `--mode static-gate` / `--mode full` / `--mode e2e` の全実行に共通する。

stdout 末尾の `EXIT=N` 行が**唯一の exit code source of truth**。`PASS` / `PARTIAL` / `FAIL` 表記から推測禁止。

★ **重い言語 / 初回ビルドが数十分かかる依存** (Haskell + 大型 library / 大量 crate / GHC・LLVM 系等) では `Bash` 10 分上限・timeout・キャッシュ未共有で頓挫しやすい。`references/dogfooding-runner.md §3.5` の運用指針 (probe で de-risk → 事前 dep build / global store 共有 → `run_in_background` + Monitor) に従う。「重いから skip」 は禁止 (CRITICAL/HIGH を隠す)。

exit code:
- **0**: 全 pass + CRITICAL 0 + HIGH 0 + SkipEntry < 50% → Step 6 reviewer へ
- **1**: CRITICAL/HIGH >= 1 → Step 7 fix loop
- **2**: 環境エラー → user escalation

★ **exit code と Violation count / SkipEntry の矛盾検出 (絶対遵守)**:

| 観測条件 | 判定 | 行動 |
|---|---|---|
| exit 0 ∧ CRITICAL/HIGH >= 1 | script bug 疑い、**Violation count 優先** | Step 7 fix loop |
| exit 0 ∧ SkipEntry / total_action >= 0.5 | 実機検証成立せず、**実質 exit 2** | user escalation |
| exit 1 ∧ ホスト環境問題 | env / course 由来を切り分け | env 由来は再実行 1 回、course 由来は Step 7 |

★ **「不動作リスト」 降格を許す条件 / 禁止する条件**:

| 区分 | 項目 | 扱い |
|---|---|---|
| ✅ 許容 | `manual` assert | 不動作リスト降格 + 手動検証手順併記 |
| ✅ 許容 | `dogfood_runner: skip` 明示指定 | 同上 |
| ✅ 許容 | 永久 SkipEntry pattern (cloud_run / emulator 未実装等) | 同上 + generator 側 runner 置換を第一手 |
| ✅ 許容 (条件付き) | `edit_file_diff_apply_skipped:unparseable` (prose) | generator 再起動で hint/unified 化を default 第一手 |
| ❌ 禁止 | **CRITICAL/HIGH Violation 全般** | Step 7 fix loop or user escalation 必須 |
| ❌ 禁止 | `unified diff context mismatch` (CRITICAL) | planner レベル再起動必須 |

★ **Step 5.7 完全 pass まで Step 6 reviewer dispatch 禁止** (シリアル境界絶対遵守)。

### Step 5.7b: e2e 実機検証 (user 手動 trigger 必須)

**main agent は自動連動で実行しない**。Step 8 最終報告で user に案内するのみ:

```bash
PYTHONPATH=. python .claude/skills/pschool-course-builder/references/check_handson_chain_v2.py \
  --mode e2e courses/<id>/ ; echo "EXIT=$?"
```

前提: `course.yaml` に `e2e_base_image: ubuntu:22.04` が定義済 + docker daemon 起動。

### Step 5.7c: LLM 受講シミュレーション (user 手動 trigger 必須)

**main agent は自動連動で実行しない**。Step 8 最終報告で user に案内するのみ:

```
/pschool-llm-simulate <course-id>
```

### Step 5.7.5: LLM Simulator sentinel mode (Step 5.7 pass 後に自動連動)

Step 5.5 + 5.7 + 5.7.0 全 pass 後、Step 6 reviewer に進む**前**に、sentinel chapter (各 section の最初の mixed chapter + 最後の exercise chapter + capstone、最大 15-17 chapter) で LLM Simulator を sequential dispatch して教育的明瞭性を early detect する。

sentinel mode skip 条件: 総 chapter 数 < 10 または `PSCHOOL_COURSE_BUILDER_SKIP_SENTINEL=1`。

実装: `pschool/pipeline/sentinel_simulator.py` (詳細は `references/hallucination-defense.md §B.3`)。

**★ 自動 pass 禁止 (fail-loud)**: `sentinel_simulator.py` は extraction + recording + exit-code 算出のみを担う最小実装で、 受講者 subagent の dispatch と per-chapter verdict の inject は orchestrator (= この skill 実行時の自分) の責務。 verdict を inject しないまま (CLI 単体実行を含む) だと `results=[]` となり、 **exit 0 ではなく exit 2 (NOT_RUN)** を返す。 exit 2 は「sentinel chapter が選定されたのに受講シミュレーションが 1 件も実行されていない = 教育的明瞭性は未検証」 を意味し、 **clarity pass として扱わず Step 8 `## エスカレーション事項` に記録する**。 明瞭性を実際に early detect するには、 選定 chapter ごとに `pschool-llm-simulate` の受講者 subagent を dispatch して verdict を sentinel_results.json に inject してから exit code を評価すること (skip 条件に該当する場合のみ `sentinel_chapters=[]` + exit 0 が正当)。

**実行手順 (CLI 単体実行＝exit 2 で済ませない)**: (1) `select_sentinel_chapters(course)` で対象 chapter を選定。 (2) 各 chapter につき `pschool-llm-simulate` の受講者 subagent (sonnet) を sequential dispatch、 入力 = `lecture_md` + assert_summary。 (3) 各 chapter の結果を `SentinelResult(chapter_id, status, violations, tokens_used, turns, llm_self_report)` として収集 (`status="pass"` = violations 0 + turn ≤ 20 + tokens ≤ 50K)。 (4) `build_report` → `write_report` で `.pschool/sentinel_results.json` に全件 inject してから `compute_exit_code` を読む。 **(2)-(4) を実施せず exit 2 をエスカレーション記録だけで通過させない** (skip 条件該当時のみ未実行が正当)。

### Step 6: レビュー担当 → pschool-course-reviewer を起動

Step 5.5 schema check + Step 5.7 dogfooding が**両方 pass 済み**の状態でのみ起動。

```
Agent tool 並列 dispatch: pschool-course-reviewer skill × (N section + 1 capstone)
  入力: 担当 section の全 chapter yaml + 引用 URL マスター + chapter type マップ
  出力: chapter 単位の指摘リスト (CRITICAL/HIGH/MEDIUM/LOW)
  第1段 model: claude-sonnet-4-6 / effort=medium (全件 100% カバレッジ)
  第2段 model: claude-opus-4-7 / effort=high (高シグナル章のみ)
  isolation: worktree (汚れた partial state を本体 repo に持ち込まない)
```

詳細手順・16 観点・二段構成・入力縮約規約・集約フローは `pschool-course-reviewer` skill を参照。

**expected reviewer count を事前計算して TaskList に記録** (停止現象防止)。全 reviewer 完了後、main agent が指摘リストを統合・重複排除・優先度ソートする。

統合後、全指摘を `courses/<id>/_review/findings.jsonl` に追記する (各行: `chapter_id` / `severity` / `observation_no` / `verbatim` / `resolved=false`)。reviewer 自身は Write 不可なので persistence は main agent の責務。理由: 指摘を chat のみに保持すると context compaction や fix-loop iter 跨ぎで **reviewer 固有の CRITICAL (dogfood が PASS する数値/論理誤り。例: dp-foundations EDPC-E v_i 制約・fib 境界、series #26 BFS-called-DFS) が消失する**。Step 7 の違反 inventory はこの jsonl も読み、fix 完了時に該当行を `resolved=true` に更新する。**`resolved=false` の CRITICAL/HIGH が残る状態で「動くコース」宣言・最終報告しない** (Step 7 で解消するか Step 8 `## エスカレーション事項` に明記)。

★ **findings.jsonl は append-only の検出ログ — raw な unresolved 件数を「現在の未解決数」と等値しない**: build workflow / sweep.py は検出を**追記**するが、fix 完了時の `resolved=true` 更新は orchestrator が明示的に行わない限り**自動では付かない**。過去 run で検出→既に fix 済みのエントリが `resolved` 未更新のまま大量に残りうる (atcoder-yellow-road P7 で `book-format` HIGH 80 件が fix 済みなのに resolved 未更新で残存し、誤って未解決と読みかけた)。**「コースが今クリーンか」の権威判定は findings.jsonl の生件数ではなく、ゲートの再実行で行う**: `check_handson_chain_v2.py --mode schema` (内部で `pschool.loader_v2.validator.validate_course` を呼ぶ) ＝ `scripts/validate_courses.py` (同じ `validate_course`、book-format/orphan lint を含む) を再実行し EXIT0 / C0 / H0 を確認する。findings.jsonl は fix-loop の inventory (何を検出したか) であって現状判定の SSOT ではない。 ゲート再実行が C0/H0 を返したら、findings.jsonl 上に残る `resolved=false` 行は過去 run の更新漏れと判断してよい。逆にゲートが H>0 を返す限り、それは既存文の「未解決 CRITICAL/HIGH」であり完了宣言してはならない。

停止条件:
| 条件 | 行動 |
|---|---|
| CRITICAL/HIGH 集計が 20 件超 | user 確認要請 |
| 同種 bug が 3 section 以上横断 + planner 再設計が妥当 | user 確認要請 (approach pivot go/no-go) |
| 上記以外 (CRITICAL/HIGH ≤ 20 件 + 単 section 内 fix で対応可) | 自動進行 (Step 7 起動) |

### Step 7: 生成↔レビューループ (max 3 + collapsed-loop + approach pivot)

reviewer 指摘 + dogfooding fail → pschool-compile-fixer を起動 → Step 5.7 再実行 → Step 6 再実行 → 終了条件 3 種 (指摘なし / collapsed-loop / iter=3) のいずれかで break。

**iter 開始時の全違反 inventorying (A-S7-1、必達)**:
1. Step 5.5 + Step 5.7 の違反を統合し全違反を抽出 (`grep -E "CRITICAL|HIGH"`)。Step 6 reviewer 完了後の iter では Step 6 指摘も統合する (3 source)
2. chapter 別 / 違反 kind 別 / root cause 別でグルーピング
3. 同種 bug の横展開 grep + 1 batch fix dispatch
4. fix dispatch グループ化: 同 kind + 同 root cause の違反は 1 batch

```
Agent tool dispatch: pschool-compile-fixer skill
  入力: 対象 chapter yaml + dogfooding feedback JSON (該当 chapter 分) + reviewer 指摘リスト
  出力: 修正済み chapter yaml (直接 Write) + 完了報告 1-3 行
  model: compile_fixer=sonnet / root_cause_fixer=opus
  isolation: worktree (汚れた partial state を本体 repo に持ち込まない)
```

**subagent vs main agent edit の選択**:
| 修正内容 | 担当 |
|---|---|
| 1 file 内 1-5 行修正 / typo / yaml field rename | main agent Edit |
| batch grep + 一括 sed | main agent Bash + Edit |
| 複数 file 跨ぎ (3+ files) / language syntax 生成 / 200+ 行修正 | subagent dispatch |

inner max 3 で HIGH 以上残存時は approach pivot (planner レベル再設計) を outer iter 上限 2 まで発動可能。

ループ内の再検証順序: compile-fixer 修正 → Step 5.5 再実行 → Step 5.7 再実行 → Step 6 再実行。

★ **single-project 累積コースでは compile-fixer は「中間状態」を検証する義務がある (CRITICAL、haskell-grpc-bff 2026-06-14 で収束が 6 iter に伸びた最大要因)**: forward-reference バグ (未作成 module の import / 後章で定義する型の参照 / manifest stanza が未作成ファイルを参照 / build-manifest の段階不整合) は **章を順に積み上げた中盤の cumulative 状態でのみ build が壊れ、最終章の全部入り状態では通る**。subagent fixer は楽をして「最終状態 (全 content_template 適用後) を 1 回ビルド」だけ検証しがちで、中間の forward-reference を見落とす (最終は通るので「直った」と誤報告 → 次 dogfood で中盤章が再 FAIL → loop が伸びる)。compile-fixer / verifier には **「各 build-assert 章までを累積 materialize して build/test する中間検証」を必須化**する (例: 章順に content_template を適用しつつ shell_exit_0 を持つ章で都度 build、最初の FAIL 章とエラーを可視化する verifier。haskell-grpc-bff では `~/.pschool/spikes/<course>/incr_verify.py` として実装)。dogfood `--mode full` 自体は per-chapter 検証するが、fixer の自己検証が最終のみだと取りこぼす。重い言語では中間検証を host warm store + 適切な timeout で回す。

### Step 8: spot-check 案内 + 最終報告

ユーザーへ対話メッセージで返答:

- `## 対応した内容` — course 概要 (topic 特性 / section 数 / chapter 数 / type 内訳 / 引用 URL 数 / 総時間)
- `## 変更ファイル一覧` — 絶対パス
- `## 機械検証結果 (Step 5.5 schema)` — exit code + CRITICAL/HIGH 件数
- `## dogfooding 結果 (Step 5.7 full)` — exit code + per-chapter pass/fail + CRITICAL/HIGH/MEDIUM/LOW 件数
- `## 不動作リスト` — manual assert + skip 指定 + 代替手段起動不可 action 一覧
- `## reviewer カバレッジ` — 第1段 Sonnet 全件 100%、第2段 Opus 高シグナル章
- `## spot-check 推奨` — 重要 5 件 (CRITICAL/HIGH 指摘章 + ランダム 2-3 件)
- `## エスカレーション事項`
- `## 次の一歩` — `pschool start <id>` + e2e 検証案内:

```markdown
## e2e 実機検証 + LLM 受講シミュレーション (Step 5.7b + 5.7c、user 手動 trigger 必須)

### 1) Step 5.7b: course 正確性検証 (30-60 分)
\`\`\`bash
PYTHONPATH=. python .claude/skills/pschool-course-builder/references/check_handson_chain_v2.py \
  --mode e2e courses/<id>/ ; echo "EXIT=$?"
\`\`\`

### 2) Step 5.7c: 教育的明瞭性検証 (1-3 時間、追加 API cost なし)
\`\`\`
/pschool-llm-simulate <course-id>
\`\`\`
```

- `## 実行ログ` — `~/.pschool/logs/<course_id>.jsonl` + `python -m tools.pipeline_runner <course-id>`

## task_mode 判定

- **content** (デフォルト): yaml 生成のみ
- **code** (Python loader test が必要な場合): TDD 強制フロー

mode 切替は Step 4 planner が判断。

## 4 source 並列研究の必須化

| source | 第 1 選択 | 第 2 選択 |
|---|---|---|
| Context7 | MCP 経由 | WebFetch で公式 docs 直接 |
| WebFetch | URL 取得 | Exa search 結果から URL 抜き出し |
| Awesome List | `gh search repos` | `gh search code` + README 直 fetch |
| Exa search | MCP 経由 | WebSearch (built-in) |

**3 source 以上が失敗した場合は skill 中断 + escalate**。

## ハルシネーション対策 (4 重防衛)

1. **引用元 URL 必須**: 各 chapter の `references[]` に最低 1 件 URL
2. **RAG retrieval ベース**: generator は synthesizer の「採用結論」+ 引用 URL マスターの範囲外の事実を生成しない
3. **version-sensitive 情報は 3-source triangulation 必達**: 公式 docs + 公式 GitHub repo + release notes。矛盾時の裁定: release notes > 公式 examples > 公式 docs
4. **spot-check workflow**: Step 8 で重要 5 件を user が手動 fact-check
5. **二段 reviewer fact-check pass**: 第1段 Sonnet 全件 100% カバレッジ + 第2段 Opus 高シグナル章精査

詳細は `references/hallucination-defense.md` 参照。

## Escalation conditions

以下が発生したら Step 8 `## エスカレーション事項` に記載:

1. 4 source 並列研究で 3 source 以上 failure
2. synthesizer の Minority findings / Conflicts に重要項目あり
3. reviewer fact-check pass で CRITICAL hallucination 検出
4. `check_handson_chain_v2.py` で CRITICAL/HIGH 違反が連続 2 ループ残存
5. Mermaid placeholder 数と diagrams 配列数の不一致
6. section 順序の 5-stage progression 逸脱
7. chapter type populate がレンジ外
8. ループ max 3 到達かつ未解決 CRITICAL/HIGH
9. 既存 `courses/<id>/` 上書き confirm を user が拒否
10. topic 特性判定が user の意図と乖離
11. section / chapter 数がレンジ外で正当化できない
12. handson chain coherence で wiring chain 不整合 CRITICAL 残存
13. capstone success_criteria の各項目が前章で 0 件紐付け
14. Step 5.7 dogfooding で CRITICAL/HIGH 違反が連続 2 ループ残存
15. Step 5.7 で環境エラー (exit 2)
16. 「不動作リスト」 が 10 件超

## Anti-patterns

### v2 schema 違反 (CRITICAL)

- ★ **chapter を section 単位ファイルにまとめる** (loader v2 は `chapters/ch-NN-MM.yaml` フラット構成のみ)
- ★ **`chapter:` の外に `state_transitions` / `lecture_md` を書く**
- ★ **action kind / assert kind に enum 外の値** (例: `kind: shell` / `kind: exec`)
- ★ **`define_symbol` 無しで `call_symbol` を書く**
- ★ **`extend_enum` で参照する enum を前章で `define_symbol kind=enum` していない**
- ★ **state graph に循環を作る**
- ★ **`call_symbol.defined_at` に存在しない chapter id を指定**
- ★ **同名 entity の章間揺れ**
- ★ **dependency first-mention 違反** (import あり / install action なし)
- ★ **capstone で初出する success_criteria 要件**
- ★ **wiring chain を形式的に閉じるために capstone から educational demo fn を call_symbol する**

### workflow 違反

- 4 source を逐次起動する (並列必須)
- 引用 URL を skip して lecture_md を埋める
- existing course.yaml を user confirm なしに上書きする
- chapter type の割当を generator に任せる
- ★ **section pack を `section-NN.pack.yaml` (0-padding) で二重作成 / symlink 量産する** (SSOT は `sec-<N>.pack.yaml` = course.yaml `sections[].id`、二重ファイルは stale mismatch を誘発)
- ★ **総時間 (est_min 合計) の圧縮を generator に委ねる** (generator は圧縮しない。planner が設計段階で目標 `total_estimated_hours` レンジに収める — Step 4 §9)
- ★ **公式 example の乏しい library (generated client / niche SDK) を、reference skeleton の実機ビルドで API を確定せずに generator に渡す** (signature からの API 捏造を招く — Step 1.5b / planner Step 4 §6.5)
- ★ **`api_ledger_gate: required` のコースで `~/.pschool/spikes/<id>/build-success.log` が存在しないまま Step 5 generator を起動する** (gate BLOCKED)
- ★ **API-LEDGER に無い外部ライブラリ identifier を content_template に書く** (`fabricated-signature-detected` HIGH violation を招く)
- ★ **api_ledger_gate の判定結果 (`required` / `skip`) と skip 理由を `course_canonical.yaml` に記録しない**
- 連続 `type: lecture` が 3 chapter 以上
- spot-check 案内を最終報告から省略する
- Step 5.5 と Step 5.7 / Step 6 を並列 dispatch する (5.5 → 5.7 → 6 の順は必ずシリアル)
- ★ **Step 5.7 dogfooding を skip して Step 6 reviewer に進む**
- ★ **dogfooding fail を reviewer 指摘と別 loop で処理する**
- ★ **「不動作リスト」 を最終報告から省略する**
- ★ **CRITICAL/HIGH Violation を「不動作リスト」 に丸めて Step 6 reviewer に進む**
- ★ **`exit code 0` を字面通り信じて Violation count / SkipEntry 比率を見ない**
- ★ **exit code を stdout の `PASS` / `PARTIAL` / `FAIL` 表記から推測する**
- ★ **Step 5.7 pass のみで「動くコース」と宣言し Step 5.7b の user 手動 trigger 案内を Step 8 から省略する**
- ★ **Step 5.7b を main agent が自動連動で実行する**
- ★ **Step 5.7b pass のみで「学べるコース」と宣言し Step 5.7c 案内を Step 8 から省略する**
- ★ **Step 5.7b 未 pass の状態で Step 5.7c を起動する**
- ★ **version-sensitive 情報を 1 source だけで主張する** (3-source triangulation 必達)
- ★ **release notes 取得不可で「生成 CLI の挙動を根拠に自己裁定」する**

## 生成後のメンテナンス (corpus 自己改善ループ)

このパイプラインの各ゲート (Step 5.5 schema / 5.6 static / 5.7 full) は **生成時にそのコース 1 本だけ**を検証する。
validator (`loader_v2/validator.py` の lint) を追加・厳格化すると、**それ以前に生成・commit 済みのコースは再検証されず黙って非準拠になる** (実証: 2026-06-20 の初回 corpus sweep で 14/25 コースが現行 schema ゲートで fail。詳細 `docs/self-improve/lessons/2026-06-20-validators-added-without-corpus-resweep.md`)。

この corpus drift を閉じるのが **`pschool-course-self-improve` skill** (設計: `docs/course-self-improvement-architecture.md`):

- **新しい validator/lint を追加したら** → `uv run pschool course-quality sweep` で全コースを再検証し、新たに fail したコースを Phase 3a で修復 PR にする。
- **同じ failure class が最新生成コースでも再発する** (generator-bug) と判明したら → Phase 3b でこの skill の prompt / micro-skill / lint を改修して再発を止める (fire-check + empirical-prompt-tuning で検証してから昇格)。
- 起動: `/pschool-course-self-improve` (引数なし=triage→bounded 1 アクション / `<course-id>`=単体修復 / `--systemic`=skill 改修 / `--detect-only`=検出のみ)。**1 invocation = 最大 1 PR、auto-merge 禁止、人間レビュー待ち。**

> この skill は course-builder の出力品質を監視し、悪化を検出したら course-builder 自身 (prompt/gate/lint) を durable に改修する**外側ループ**。course-builder (内側 = 1 コース生成) とは独立に user が手動起動する。

## Files

### 必須参照 (v2 schema 前提)

- **`docs/schema-v2.md`** (worktree 内) — schema v2 完全仕様書
- **`docs/adr/001-schema-v2-state-machine-dag.md`** — v2 移行決定の Context / Decision / Consequences
- `references/section-generator-template.md` — chapter generator subagent prompt テンプレ (single source of truth)
- `references/yaml-schema-templates.md` — course.yaml + chapter.yaml + capstone.yaml の schema テンプレート (v2)
- `references/schema-v2-action-templates.md` — action template 集
- `references/check_handson_chain_v2.py` — Step 5.5 + Step 5.7 機械検証 script
- `references/ast-grep-rules/{rust,typescript,dart,haskell}/` — `--mode static` 参照 ast-grep rules
- `references/dogfooding-runner.md` — Step 5.7 dogfooding 実装規約
- `references/information-sources.md` — 4 source 個別 prompt template + フォールバック手順
- `references/hallucination-defense.md` — 4 重防衛の詳細手順 + reviewer fact-check pass prompt
- `references/course-structure-design.md` — Udemy 型統一構造の詳細
- `references/lang/<lang>.md` — 言語別観測 ledger (構文 / deprecated / collection API)
- `references/stack/<stack>.md` — フレームワーク/スタック別観測 ledger (build lifecycle / config schema / plugin / IPC、例: `tauri.md`)。framework-product topic で対象スタックに該当ファイルがあれば lang ledger と併せて planner / section-generator が参照する。言語に跨る知見 (Rust backend + frontend + JSON config 等) は lang ledger でなく stack ledger に置く
- **`references/api-ledger-template.md`** — API-LEDGER の構造化フォーマット仕様 + haskell-gogol-firebase worked example + known fabrications 一覧。`api_ledger_gate: required` のコースで Step 1.5b gate 手順および Step 5 generator 制約として参照する。library ledger (`references/library/<lang>/`) との位置付け違いも記載

## 附録: モデル選定表

**SSOT**: `tools/model_selection_rules.py` の `MODEL_SELECTION` dict。

**Opus 使用役割は 4 つのみ**: `canonicalizer` / `hard_planner` / `root_cause_fixer` / `critical_reviewer`。

| 役割 (role) | model_id | effort_min | effort_max | 備考 |
|---|---|---|---|---|
| `query_planner` | `claude-haiku-4-5` | `none` | `low` | risk classifier (Step 1.5) |
| `official_docs_extractor` | `claude-sonnet-4-6` | `low` | `medium` | 研究体 ① ② ③ (Step 2) |
| `community_pitfalls_extractor` | `claude-haiku-4-5` | `low` | `low` | 研究体 ④ (Step 2) |
| `canonicalizer` | `claude-opus-4-7` | `high` | `xhigh` | Step 3.5 |
| `course_planner` | `claude-sonnet-4-6` | `medium` | `high` | Step 4 (通常時) |
| `hard_planner` | `claude-opus-4-7` | `high` | `high` | Step 4 (Haskell / MoonBit / niche) |
| `section_lead_generator` | `claude-sonnet-4-6` | `medium` | `medium` | Step 4.5 |
| `chapter_filler` | `claude-haiku-4-5` | `low` | `low` | Step 5 |
| `compile_fixer` | `claude-sonnet-4-6` | `medium` | `medium` | Step 7 fix loop |
| `root_cause_fixer` | `claude-opus-4-7` | `high` | `high` | Step 7 root cause 特定 |
| `pedagogy_reviewer` | `claude-sonnet-4-6` | `medium` | `medium` | Step 6a (全件) |
| `critical_reviewer` | `claude-opus-4-7` | `high` | `high` | Step 6b (高シグナル章) |
| `student_simulator` | `claude-sonnet-4-6` | `medium` | `medium` | Step 5.7.5 sentinel mode |
