---
Status: SSOT
Scope: Facts→Planner→(DomainPlan→CorePlan) の「非重複」設計（JoinIR/Plan/Frag）
Related:
- docs/development/current/main/design/planfrag-ssot-registry.md
- docs/development/current/main/design/planfrag-freeze-taxonomy.md
- docs/development/current/main/design/joinir-plan-frag-ssot.md
- docs/development/current/main/design/join-explicit-cfg-construction.md
---

# CorePlan Skeleton/Feature Model (SSOT)

目的: “pattern 列挙の重なり” を増やさずに、Facts→Planner→CorePlan を **一意・合成可能**な形に収束させる。

結論:
- **CorePlan は構造SSOT**（emit/merge は CorePlan/Frag 以外を再解析しない）
- **DomainPlan は意図（recipe）**（長期的に縮む。SSOTは CorePlan 側に寄せる）
- “Pattern” は入口の分岐名ではなく、**(Skeleton, FeatureSet)** の合成へ落とす

## 1. Skeleton（骨格）= まず一意に決める

Skeleton は “構造カテゴリ” のみ。ここが一意に決まらない場合は `Freeze` の対象。

推奨の最小集合:
- `LoopSkeleton`（自然ループ: header/latch/exit が確定できる）
- `If2Skeleton`（2分岐 + join）
- `BranchNSkeleton`（match/switch 相当: N分岐 + join）
- `StraightLine`（plan 対象外 → `Ok(None)`）

## 2. Features（直交特徴）= 骨格の上に足す

Features は “別パターン” を増やさずに足す（重なりの根治）。

例（代表）:
- `ExitMap`（Return/Break/Continue の出口集合。Pattern2/4/5 を “別pattern” にしない）
- `ValueJoin`（join 値が必要 = post-phi 表現）
- `ContinueEdges`（continue が複数箇所から飛ぶ等。latch 一意に拘らない表現）
- `Cleanup`（return/break/continue で走る cleanup。将来 `Unwind` も同語彙へ）
- `CondShape` / `StepShape`（normalize 済みの “形”）
- `AlgorithmIntent`（scan/split/predicate 等のアルゴリズム意図: DomainPlan に残して良い）

## 3. Freeze（Fail-Fast）にすべき “要注意パターン”

“通らない” または “通るが設計が壊れやすい” を SSOT として明示する。

### A. Unstructured CFG（Irreducible / multi-entry loop）

症状:
- Skeleton が一意に決まらない（複数入口ループ / irreducible）

扱い:
- `Freeze(unstructured)`（strict/dev は即Fail）
- 既定挙動を変えない場合は `Ok(None)` に落とすのも可だが、strict/dev では **タグ付きで理由を観測**する

### B. Unwind / 例外 / finally（“別系統の出口エッジ”）

症状:
- Return/Break/Continue 以外の出口（unwind）で cleanup が必要になる

扱い:
- 設計として `ExitKind::Unwind` を想定し、`ExitMap + Cleanup` で吸収できることを前提にする
- 未実装の段階では `Freeze(unsupported:unwind)`（“対象っぽいのにNone” にしない）

### C. Coroutine / async generator（yield）

症状:
- 関数内で制御が閉じない（skeleton だけでは表現できない）

扱い:
- `Freeze(unsupported:coroutine)`（将来は別 Skeleton/別パイプライン）

### D. 多分岐（match）を If2 で潰そうとする

症状:
- planner が肥大化し、normalize が崩れる（pattern 爆発の起点）

扱い:
- `BranchNSkeleton` を設計語彙として追加し、normalize で分岐順序を安定化する

### E. “plan が JoinIR 専用パターンを飲み込む” 事故

実例:
- nested loop（phase1883）が plan 側の Pattern1 に誤マッチして JoinIR の `Pattern6NestedLoopMinimal` が選ばれない

扱い:
- “より一般的な pattern” は **上位形（nested loop 等）を `Ok(None)` へ倒す**（pattern 側の責務）
- 入口での by-name 分岐ではなく、Facts/Extractor の **構造条件**で遮断する

## 4. SSOT 運用ルール（設計側の約束）

- Planner は “骨格推論→特徴推論” を意識して実装し、complete pattern 追加を最小化する
- Emit は CorePlan 以外を見ない（再解析禁止）
- `Ok(None)` / `Freeze` の境界は `docs/.../planfrag-freeze-taxonomy.md` を SSOT として従う

## 5. Next (docs-first)

次に SSOT として固める候補（レバレッジ順）:
1. post-phi（join 入力の最終表現）不変条件（局所 verify）
2. effect 分類（pure/control/rc/obs）と “許される変形” の法典

