@ -0,0 +1,92 @@
---
Status: SSOT
Scope: JoinIR → PlanFrag → CorePlan への移行道筋(仕様不変で完了と言える条件)
Related:
- docs/development/current/main/10-Now.md
- docs/development/current/main/30-Backlog.md
- docs/development/current/main/design/coreplan-skeleton-feature-model.md
- docs/development/current/main/design/post-phi-final-form-ssot.md
- docs/development/current/main/design/effect-classification-ssot.md
- docs/development/current/main/design/exitkind-cleanup-effect-contract-ssot.md
- docs/development/current/main/phases/phase-29ae/README.md
---
# CorePlan Migration Roadmap (SSOT)
目的: “JoinIR を CorePlan で組み立てる” 状態へ、仕様不変( release既定) で段階的に収束するための道筋を 1 枚に固定する。
## 0. 前提(守ること)
- 既定挙動不変( release の意味論/エラー文字列/恒常ログを変えない)
- silent fallback 禁止( strict/dev では Freeze/Fail-Fast で検出可能にする)
- by-name ハードコード禁止( 構造条件・SSOT境界で解く)
- JoinIR integration gate( SSOT) を常に緑維持:
- `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
## 1. “CorePlan で組み立てる” の定義
ここでの完了は「pattern列挙が消えた」ではなく、以下が成立していること。
- 構造SSOTは `CorePlan` ( emit/merge は CorePlan/Frag 以外を再解析しない)
- `Facts → Planner → (DomainPlan) → CorePlan → lowerer/emit → merge` が主経路
- `DomainPlan` は意図/recipe として残ってもよいが、最終の verify/emit 契約は CorePlan 側で固定されている
## 2. すでに固めた SSOT( 再発防止の土台)
- Skeleton/Feature: `docs/development/current/main/design/coreplan-skeleton-feature-model.md`
- post-phi final form: `docs/development/current/main/design/post-phi-final-form-ssot.md`
- effect classification: `docs/development/current/main/design/effect-classification-ssot.md`
- cleanup contract: `docs/development/current/main/design/exitkind-cleanup-effect-contract-ssot.md`
## 3. 移行タスクの流れ(安全順)
### Step A: CorePlan 語彙の “穴” を埋める( lowerer/verifier)
狙い:
- `CorePlan` の構造ノードが単独でも lower/verify できる(未対応分岐を減らす)
典型:
- `CorePlan::If` / `CorePlan::Exit` の lowerer 対応
- verifier の不変条件を “局所検証” で完結させる
### Step B: Facts を Skeleton+Feature の SSOTへ寄せる
狙い:
- Pattern1/2/4/5 のような “complete pattern” の増殖を止める
- `LoopSkeleton + ExitMap + ValueJoin + ...` の合成で表現できる状態に寄せる
やらない:
- Facts から emit/merge を助けるための再解析を前提にした “不足した Facts” を作る
### Step C: Planner を「骨格の一意化→特徴付与→Freeze」へ
狙い:
- CandidateSet は骨格の一意化に集中( 0/1/2+ → None/Some/Freeze)
- feature は “別パターン” ではなく合成の材料として付与
### Step D: Normalizer を “合成だけ” にする
狙い:
- `(Skeleton, FeatureSet, DomainIntent)` → `CorePlan` の純変換に収束
- join 入力( post-phi) と effect/cleanup 契約を壊さない
### Step E: 入口から legacy fallback を段階的に 0 へ
狙い:
- `single_planner` の legacy extractor fallback を削減し、planner-first を主にする
- JoinIR 側 wrapper/router を薄くし、PlanFrag 側 SSOT に寄せる
注意:
- “落ちる” を `Ok(None)` で隠さない(対象っぽいのに一意化できない場合は Freeze)
## 4. 完了( Done) の判定( 設計上)
最低限の Done:
- JoinIR 回帰 SSOT が緑: `phase29ae_regression_pack_vm.sh`
- 回帰対象(現状の gate: pattern2/6/7 + phase1883 + phase263) が “CorePlan 合成” 経路で通る
強い Done( 段階2) :
- Facts が complete pattern を増やさず Skeleton+Feature に寄っている
- DomainPlan は scan/split/predicate 等の “意図” 以外は CorePlan 合成へ吸収されている
- Freeze taxonomy が運用でぶれず、strict/dev の診断が安定タグで追える