P1: Carrier Initialization Builder (HIGH) ✅ - New module: carrier_init_builder.rs (197 lines, 8 tests) - Refactored loop_header_phi_builder.rs (-34 lines) - Centralized CarrierInit value generation (SSOT) - Eliminates scattered match patterns across header PHI, exit line - Consistent debug output: [carrier_init_builder] format - Net: -34 lines of duplicated logic P2: Remaining DebugOutputBox Migration (QUICK) ✅ - Migrated carrier_info.rs::record_promoted_binding() - Uses DebugOutputBox for JOINIR_DEBUG checks - Maintains JOINIR_TEST_DEBUG override for test diagnostics - Consistent log formatting: [context/category] message - Net: +3 lines (SSOT migration) P3: Error Message Centralization (LOW) ✅ - New module: error_tags.rs (136 lines, 5 tests) - Migrated 3 error sites: * ownership/relay:runtime_unsupported (plan_validator.rs) * joinir/freeze (control_flow/mod.rs) * (ExitLine errors were debug messages, not returns) - Centralized error tag generation (freeze, exit_line_contract, ownership_relay_unsupported, etc.) - Net: +133 lines (SSOT module + tests) Total changes: - New files: carrier_init_builder.rs (197), error_tags.rs (136) - Modified: 6 files - Production code: +162 lines (SSOT investment) - Tests: 987/987 PASS (982→987, +5 new tests) - Phase 81 ExitLine: 2/2 PASS - Zero compilation errors/warnings Benefits: ✅ Single Responsibility: Each helper has one concern ✅ Testability: 13 new unit tests (8 carrier init, 5 error tags) ✅ Consistency: Uniform debug/error formatting ✅ SSOT: Centralized CarrierInit and error tag generation ✅ Discoverability: Easy to find all error types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
JoinIR Lowering (ExprLowerer / ScopeManager / Envs)
このディレクトリは JoinIR lowering の中でも、条件式や環境まわりの箱(ExprLowerer, ScopeManager, ConditionEnv, LoopBodyLocalEnv, UpdateEnv など)を扱う層だよ。コードを触るときは、以下の最小ルールを守ってね。
- ExprLowerer は ScopeManager 経由のみ で名前解決する。ConditionEnv / LoopBodyLocalEnv / CapturedEnv / CarrierInfo に直接触らない。
- 条件式から UpdateEnv を参照しない。UpdateEnv はキャリア更新専用で、header/break/continue 条件は ScopeManager→ConditionEnv で完結させる。
- ConditionEnv は「条件で参照する JoinIR ValueId だけ」を持つ。body-local を直接入れず、必要なら昇格+ScopeManager に解決を任せる。
- Fail-Fast 原則: Unsupported/NotFound は明示エラーにして、by-name ヒューリスティックや静かなフォールバックは禁止。
名前解決の境界(SSOT)
このディレクトリの ScopeManager は「JoinIR lowering の中で」名前を ValueId に解決するための箱だよ。
同じ “名前” でも、MIR 側の束縛寿命とは問題が違うので混ぜない。
- MIR(SSA/束縛寿命):
src/mir/builder/vars/*が{...}のレキシカルスコープとlocalのシャドウイングを管理する。 - JoinIR lowering(この層):
ScopeManagerがConditionEnv/LoopBodyLocalEnv/CapturedEnv/CarrierInfoを束ねて解決順序を固定する。 - 解析箱:
LoopConditionScopeBoxは「条件が参照して良いスコープか」を判定する箱で、名前解決そのものはしない。
詳しい境界ルールは docs/development/current/main/phase238-exprlowerer-scope-boundaries.md を参照してね。***