Files
hakorune/docs/development/current/main/phases/phase-263/README.md
tomoaki e3dd1bbecb docs: Phase 263 P0 完了記録(Pattern2 fallback 修正)
- 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 することを確認
2025-12-21 10:39:48 +09:00

9.6 KiB
Raw Blame History

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

  1. bundle_resolver loop (Stage-B JSON) が "seg" 変数を使用
  2. Pattern2 の PromoteStepBox が routing:
    • A-3 (Trim): マッチせず FAIL
    • A-4 (DigitPos): マッチせず FAIL
    • ReadOnlyBodyLocalSlot: seg = ... 代入があるため契約違反 FAIL
  3. 全ルート 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 (探索結果)

  1. Pattern routing order (router.rs):
    • Pattern1 は Pattern2 の前に試されるPattern1 が先、Pattern2 が後)
    • Pattern2 が失敗しても Pattern1 には fallback しないPattern1 は既に試された後)
    • Pattern2 の Ok(None) は後続経路legacy binding / normalized shadow 等)に進む
  2. 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
  • Analysis: The loop pattern is genuinely unsupported by all patterns. Pattern2 fix is working correctly.

Modified Files

Core Implementation (2 files)

  1. 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)
  2. src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs
    • Early return on Ok(None) detection

Test Fixture

  1. apps/tests/phase263_p0_pattern2_seg_min.hako - Minimal reproduction test
  2. tools/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 bifurcation
  • pattern2_lowering_orchestrator.rs - Orchestrator with early-return on Ok(None)

Test Files

  • apps/tests/phase263_p0_pattern2_seg_min.hako - SSOT fixture
  • tools/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 record
  • docs/development/current/main/phases/phase-263/README.md - This file

Risk Assessment

Risk Level: LOW

Main Risks:

  1. Ok(None) で後続経路legacy binding等に進んだが、後続経路も処理できない → 別のエラー
    • Mitigation: 後続経路legacy binding / normalized shadow等は汎用処理なので対応可能
  2. 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 PASS1368/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 禁止)
  • 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