diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md
index 178986e0..05998f20 100644
--- a/docs/development/current/main/10-Now.md
+++ b/docs/development/current/main/10-Now.md
@@ -3,7 +3,7 @@
## Current Focus
- Phase: `docs/development/current/main/phases/phase-29ao/README.md`
-- Next: TBD (P47 done; see `docs/development/current/main/phases/phase-29ao/README.md`)
+- Next: TBD (P48 done; see `docs/development/current/main/phases/phase-29ao/README.md`)
## Gate (SSOT)
diff --git a/docs/development/current/main/30-Backlog.md b/docs/development/current/main/30-Backlog.md
index c5b39a8b..7cd5c086 100644
--- a/docs/development/current/main/30-Backlog.md
+++ b/docs/development/current/main/30-Backlog.md
@@ -5,7 +5,7 @@ Scope: 「次にやる候補」を短く列挙するメモ。入口は `docs/dev
## Active
-- CorePlan migration: `docs/development/current/main/phases/phase-29ao/README.md`(Next: TBD, P47 done)
+- CorePlan migration: `docs/development/current/main/phases/phase-29ao/README.md`(Next: TBD, P48 done)
## Near-Term Candidates
diff --git a/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md b/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md
index c0f2598c..8fd57ee8 100644
--- a/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md
+++ b/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md
@@ -34,7 +34,7 @@ Related:
## 1.1 Current (active)
- Active phase: `docs/development/current/main/phases/phase-29ao/README.md`
-- Next step: TBD (P47 done)
+- Next step: TBD (P48 done)
## 2. すでに固めた SSOT(再発防止の土台)
diff --git a/docs/development/current/main/phases/phase-29ao/README.md b/docs/development/current/main/phases/phase-29ao/README.md
index 19ee8bb9..49e0ea14 100644
--- a/docs/development/current/main/phases/phase-29ao/README.md
+++ b/docs/development/current/main/phases/phase-29ao/README.md
@@ -261,6 +261,11 @@ Gate(SSOT):
- 指示書: `docs/development/current/main/phases/phase-29ao/P47-CORELOOPCOMPOSER-V1-SPLITSCAN-VALUEJOIN-INSTRUCTIONS.md`
- ねらい: Pattern7 value-join を v1 で受理し、block_params/EdgeArgs 経由の PHI 一本化を維持(仕様不変)
+## P48: CoreLoopComposer v1 — Pattern2 (Break) value-join minimal composition ✅
+
+- 指示書: `docs/development/current/main/phases/phase-29ao/P48-CORELOOPCOMPOSER-V1-PATTERN2-BREAK-VALUEJOIN-INSTRUCTIONS.md`
+- ねらい: Pattern2 after-join を v1 で受理し、block_params/EdgeArgs 経由の PHI 一本化を維持(仕様不変)
+
## Next(planned)
- Next: TBD
diff --git a/src/mir/builder/control_flow/plan/composer/coreloop_gates.rs b/src/mir/builder/control_flow/plan/composer/coreloop_gates.rs
index 726d958b..fe9c69dd 100644
--- a/src/mir/builder/control_flow/plan/composer/coreloop_gates.rs
+++ b/src/mir/builder/control_flow/plan/composer/coreloop_gates.rs
@@ -7,6 +7,10 @@ pub(super) fn coreloop_base_gate(facts: &CanonicalLoopFacts) -> bool {
&& facts.cleanup_kinds_present.is_empty()
}
+pub(super) fn coreloop_value_join_gate(facts: &CanonicalLoopFacts) -> bool {
+ coreloop_base_gate(facts) && facts.value_join_needed
+}
+
pub(super) fn exit_kinds_allow_return_only(facts: &CanonicalLoopFacts) -> bool {
facts.exit_kinds_present.is_empty()
|| (facts.exit_kinds_present.len() == 1
@@ -16,3 +20,7 @@ pub(super) fn exit_kinds_allow_return_only(facts: &CanonicalLoopFacts) -> bool {
pub(super) fn exit_kinds_empty(facts: &CanonicalLoopFacts) -> bool {
facts.exit_kinds_present.is_empty()
}
+
+pub(super) fn pattern2_value_join_gate(facts: &CanonicalLoopFacts) -> bool {
+ coreloop_value_join_gate(facts) && exit_kinds_allow_return_only(facts)
+}
diff --git a/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs b/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs
index 154b1380..e7fee178 100644
--- a/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs
+++ b/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs
@@ -1,23 +1,32 @@
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
use crate::mir::builder::control_flow::plan::composer::coreloop_gates::{
- coreloop_base_gate, exit_kinds_allow_return_only,
+ coreloop_value_join_gate, exit_kinds_allow_return_only, pattern2_value_join_gate,
};
use crate::mir::builder::control_flow::plan::facts::scan_shapes::SplitScanShape;
use crate::mir::builder::control_flow::plan::normalize::CanonicalLoopFacts;
use crate::mir::builder::control_flow::plan::normalizer::PlanNormalizer;
-use crate::mir::builder::control_flow::plan::{CorePlan, SplitScanPlan};
+use crate::mir::builder::control_flow::plan::{
+ CorePlan, Pattern2BreakPlan, Pattern2PromotionHint, SplitScanPlan,
+};
use crate::mir::builder::MirBuilder;
-#[allow(dead_code)]
pub(in crate::mir::builder) fn try_compose_core_loop_v1(
builder: &mut MirBuilder,
facts: &CanonicalLoopFacts,
ctx: &LoopPatternContext,
) -> Result