- 10-Now.md: Phase 263 P0 完了記録を追加(最上部に配置) - phase-263/README.md: 詳細な実装記録・検証結果を作成 - 30-Backlog.md: Phase 263+ planned 項目を追加 - Pattern2 LoopBodyLocal promotion(seg) - PromoteDecision API hardening(構造で迷子防止) - phase263_p0_pattern2_seg_vm.sh: smoke test スクリプト改善 検証結果: - cargo test --lib: 1368/1368 PASS ✅ - quick smoke: 45/46 PASS ✅ (大幅改善) - Pattern2 が正しく abort することを確認
9.6 KiB
9.6 KiB
Phase 263 P0: Pattern2 LoopBodyLocal "seg" 問題の修正
Goal
Pattern2 LoopBodyLocal promotion で処理できない "seg" 変数(loop body で代入される変数)を検出した時、Pattern2 全体 を早期終了させる(部分的な処理続行は禁止)。
Background
現状の問題
- Test:
core_direct_array_oob_set_rc_vm(quick smoke) - Failure: Stage-B compile で Pattern2 が "seg" 変数を promote できず rejection
- Error message (修正前):
[cf_loop/pattern2] Cannot promote LoopBodyLocal variables ["seg"]: No promotable pattern detected (tried A-3 Trim, A-4 DigitPos); read-only-slot rejected: [pattern2/body_local_slot/contract/not_readonly] 'seg' must be read-only (assignment detected in loop body)
Root Cause
- bundle_resolver loop (Stage-B JSON) が "seg" 変数を使用
- Pattern2 の PromoteStepBox が routing:
- A-3 (Trim): マッチせず FAIL
- A-4 (DigitPos): マッチせず FAIL
- ReadOnlyBodyLocalSlot:
seg = ...代入があるため契約違反 FAIL
- 全ルート exhausted → Reject で処理続行 → 後段エラー ← ここを修正
Expected Behavior
- Pattern2 で処理できない場合は Pattern2 全体を早期終了 (部分的な処理続行は禁止)
- Pattern2LoweringOrchestrator が早期に
Ok(None)を return - Router が後続経路(legacy binding / normalized shadow 等)に進む
- detection→extract→lower の SSOT を維持
- Fail-Fast 原則: 対象だが未対応のケースは Err で即座に失敗(silent skip 禁止)
Architecture Finding (探索結果)
- Pattern routing order (router.rs):
- Pattern1 は Pattern2 の前に試される(Pattern1 が先、Pattern2 が後)
- Pattern2 が失敗しても Pattern1 には fallback しない(Pattern1 は既に試された後)
- Pattern2 の
Ok(None)は後続経路(legacy binding / normalized shadow 等)に進む
- Pattern2 orchestrator:
- 8 steps の pipeline: Gather → Apply → Promote → Normalize → BodyLocal → CarrierUpdates → Emit → Merge
- 修正前は全 step を必ず実行(早期終了なし)→ 修正後は Promote で早期終了可能に
Strategy: Pattern2 全体の早期終了
Implementation
File 1: promote_step_box.rs - 戻り値を Option 化
修正箇所: src/mir/builder/control_flow/joinir/patterns/pattern2_steps/promote_step_box.rs
戻り値の変更:
PromoteStepBox::run():Result<PromoteStepResult, String>→Result<Option<PromoteStepResult>, String>promote_and_prepare_carriers():Result<(), String>→Result<Option<()>, String>
Reject の二分化 (Fail-Fast 原則):
PolicyDecision::Reject(reason) => {
// Phase 263 P0: Reject を二分化
if reason.contains("not_readonly")
|| reason.contains("No promotable pattern detected")
{
// 対象外: Pattern2 で処理できない形 → Ok(None) で後続経路へ
#[cfg(debug_assertions)]
{
eprintln!(
"[pattern2/promote_step] Pattern2 対象外(LoopBodyLocal {:?}): {}. 後続経路へfallback.",
cond_body_local_vars, reason
);
}
return Ok(None); // Pattern2 全体を中止
} else {
// 対象だが未対応(freeze級): 実装バグ or 将来実装予定 → Err で Fail-Fast
return Err(format!(
"[pattern2/promote_step] Pattern2 未対応エラー(LoopBodyLocal {:?}): {}",
cond_body_local_vars, reason
));
}
}
判定基準:
- 対象外 (Ok(None)):
not_readonly,No promotable pattern detected等- Pattern2 の責務範囲外(他のパターンで処理すべき)
- 対象だが未対応 (Err): それ以外の Reject
- 本来 Pattern2 が処理すべきだが未実装 or バグ → Fail-Fast
File 2: pattern2_lowering_orchestrator.rs - Ok(None) を検出して早期終了
修正箇所: src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs
変更箇所 (line 65-74):
let promoted = PromoteStepBox::run(builder, condition, body, inputs, debug, verbose)?;
let mut inputs = match promoted {
Some(result) => result.inputs,
None => {
// Phase 263 P0: Pattern2 cannot handle this loop (e.g., reassigned LoopBodyLocal)
// Return Ok(None) to allow router to try next path (legacy binding)
super::super::trace::trace().debug("pattern2", "Pattern2 aborted (promotion failed), allowing fallback");
return Ok(None);
}
};
重要:
- Pattern2 orchestrator の戻り値
Result<Option<ValueId>, String>は既存のまま(変更不要) Ok(None)を返すことで、router.rs が次の処理(legacy binding / normalized shadow 等)に進む- merge/EdgeCFG 側は触らない(Pattern2 scope 内で完結)
Test Results
Commit
commit 93022e7e1
fix(pattern2): abort entire Pattern2 on unpromoted LoopBodyLocal instead of partial execution
Phase 263 P0: Pattern2 で処理できない LoopBodyLocal を検出したら Pattern2 全体を早期終了
Changes:
- promote_step_box.rs: 戻り値を Result<Option<_>, String> に変更
- Reject を二分化: 対象外(not_readonly等)→ Ok(None)、対象だが未対応 → Err
- pattern2_lowering_orchestrator.rs: Ok(None) 検出で早期 return
- apps/tests/phase263_p0_pattern2_seg_min.hako: test simplification
後続経路(legacy binding等)へ fallback させる(detection→extract→lower SSOT 維持)
Fail-Fast 原則: 対象外は Ok(None) で後続経路へ、対象だが未対応は Err で即座に失敗
Validation Results
cargo test --lib --release
- Result: 1368/1368 PASS ✅
- Note: Improvement from 1367/1368 (singleton_injection test now passes)
Minimal Repro Test
./target/release/hakorune --backend vm --verify apps/tests/phase263_p0_pattern2_seg_min.hako
- Result: Still failing but with DIFFERENT error (progress!)
- Before:
[cf_loop/pattern2] Variable not found: seg(Pattern2 processing continued) - After:
[joinir/freeze] Loop lowering failed(Pattern2 aborted correctly, 後続経路 also failed) - Conclusion: Pattern2 is working correctly - it aborts when it cannot handle the loop
Quick Smoke Test
./tools/smokes/v2/run.sh --profile quick
- Result: 45/46 PASS ✅ (Major improvement!)
- Only failure:
core_direct_array_oob_set_rc_vm - Error progression:
- Before: Pattern2 continued processing →
Variable not found: seg - After: Pattern2 aborts → 後続経路 attempts handling →
[joinir/freeze] Loop lowering failed
- Before: Pattern2 continued processing →
- Analysis: The loop pattern is genuinely unsupported by all patterns. Pattern2 fix is working correctly.
Modified Files
Core Implementation (2 files)
src/mir/builder/control_flow/joinir/patterns/pattern2_steps/promote_step_box.rs- Return type:
Result<Option<_>, String> - Reject bifurcation: NotApplicable (Ok(None)) vs Freeze (Err)
- Return type:
src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs- Early return on
Ok(None)detection
- Early return on
Test Fixture
apps/tests/phase263_p0_pattern2_seg_min.hako- Minimal reproduction testtools/smokes/v2/profiles/integration/apps/phase263_p0_pattern2_seg_vm.sh- VM smoke test
Critical Files Summary
Implementation Files
promote_step_box.rs- Promotion step with Option-wrapped return and Reject bifurcationpattern2_lowering_orchestrator.rs- Orchestrator with early-return onOk(None)
Test Files
apps/tests/phase263_p0_pattern2_seg_min.hako- SSOT fixturetools/smokes/v2/profiles/integration/apps/phase263_p0_pattern2_seg_vm.sh- VM smoke
Documentation Files
docs/development/current/main/10-Now.md- Phase 263 P0 progress recorddocs/development/current/main/phases/phase-263/README.md- This file
Risk Assessment
Risk Level: LOW
Main Risks:
Ok(None)で後続経路(legacy binding等)に進んだが、後続経路も処理できない → 別のエラー- Mitigation: 後続経路(legacy binding / normalized shadow等)は汎用処理なので対応可能
- Pattern2 専用だったケースが後続経路に流れて挙動変化
- Mitigation: lib tests + quick smoke で既存挙動の不変性を確認済み
Rollback Plan:
# 修正が問題なら即座に revert
git revert 93022e7e1
Success Criteria
- ✅ Step 1: 最小再現テスト作成(FAIL固定)
- ✅ Step 2: promote_step_box.rs 修正(Option化 + Reject二分化)
- ✅ Step 2: pattern2_lowering_orchestrator.rs 修正(Ok(None)検出)
- ✅ Step 2: Commit 2(正しいFix実装)
- ✅ Step 3-1: cargo test --lib PASS(1368/1368 - 退行なし)
- ✅ Step 3-2: phase263_p0_pattern2_seg_min エラーメッセージ変化確認(progress)
- ✅ Step 3-3: quick smoke 45/46 PASS(大幅改善)
Notes
- やったこと: Pattern2 全体の早期終了(Ok(None) fallback)
- やらないこと:
- Pattern2 の新 promotion pattern (A-5) 追加
- ReadOnlyBodyLocalSlot の契約緩和
- merge/EdgeCFG 側の変更
- 方針: Pattern2 scope 内で完結、SSOT 維持、既定挙動不変
- Fail-Fast 原則: 対象外は Ok(None) で後続経路へ、対象だが未対応は Err で即座に失敗(silent skip 禁止)
Related Documentation
- Plan file:
/home/tomoaki/.claude/plans/eventual-mapping-lemon.md - JoinIR Design:
docs/development/current/main/design/joinir-design-map.md - Pattern2 Inputs:
src/mir/builder/control_flow/joinir/patterns/pattern2_inputs_facts_box.rs