# Phase 81: Pattern2 ExitLine Contract Stabilization **Status**: Design Phase **Created**: 2025-12-13 **Priority**: P1 (Blocking Phase 82+) --- ## Goal Pattern2(DigitPos/Trim)の promoted carriers を含む ExitLine 接続契約を堅牢化し、E2E テストで安定性を固定する。 --- ## Background ### Current Issue Phase 74-80 で BindingId migration が完了し、Pattern2/3/4 で BindingId lookup が operational になった。しかし、Pattern2 の promoted carriers(DigitPos/Trim パターンで生成される `is_digit_pos`, `is_ch_match` 等)の ExitLine 接続には以下の問題がある: 1. **ExitLine 接続タイミングの不確実性**: - Promoted carriers は promoter が生成するが、ExitLine reconnection が適切に行われているか検証不足 - Exit PHI での promoted carriers の接続契約が明示されていない 2. **E2E テスト不足**: - DigitPos パターン(`indexOf()` 使用)の E2E テストが不足 - Trim パターン(`skip_whitespace` 等)の E2E テストが不足 - 既存の `tests/phase246_json_atoi.rs` が Phase 80 完了後も安定していない可能性 3. **Contract 不明確**: - Promoted carriers が ExitLine reconnection でどのように扱われるべきか不明確 - CarrierRole (LoopState vs ConditionOnly) による処理の違いが文書化されていない ### Symptoms 以下の症状が観測される可能性がある(Phase 80 完了時点では未検証): - `tests/phase246_json_atoi.rs` テスト失敗(DigitPos pattern 使用) - Exit PHI で promoted carriers が正しく接続されない - ExitLine reconnection で ValueId が undefined になる - ConditionOnly carriers が Exit PHI に含まれて不整合が起こる --- ## Reproduction ### Minimal Test Case ```rust // DigitPos pattern with promoted carrier local p = 0 local s = "123" local sum = 0 loop(p < s.length()) { local digit_pos = s.indexOf("0", p) // Promoted to is_digit_pos (ConditionOnly) if digit_pos >= 0 { // Break condition uses promoted carrier sum = sum + 1 } p = p + 1 } return sum ``` **Expected behavior**: - `digit_pos` → `is_digit_pos` promotion succeeds - `is_digit_pos` is ConditionOnly (not in exit_bindings) - Exit PHI correctly includes `sum`, `p` (LoopState carriers) - Exit PHI does NOT include `is_digit_pos` (ConditionOnly) - Final result is correct **Failure mode** (if contract violated): - Exit PHI includes `is_digit_pos` → type mismatch or ValueId undefined - Exit PHI missing `sum` or `p` → incorrect final result - ExitLine reconnection fails → compilation error --- ## Invariants ### ExitLine Contract for Promoted Carriers 1. **CarrierRole Discrimination**: - `LoopState` carriers: MUST be in exit_bindings, MUST have Exit PHI - `ConditionOnly` carriers: MUST NOT be in exit_bindings, MUST NOT have Exit PHI 2. **Promoted Carrier Handling**: - All promoted carriers have `CarrierVar.binding_id` set by CarrierBindingAssigner - Promoted carriers follow same CarrierRole rules as non-promoted - ExitMetaCollector includes all carriers (LoopState + ConditionOnly) for latch incoming - ExitLineReconnector only processes LoopState carriers (skip ConditionOnly) 3. **ExitLine Reconnection Timing**: - Promoted carriers are in CarrierInfo BEFORE ExitLine reconnection - CarrierRole is determined BEFORE reconnection (via promoter) - Reconnection uses CarrierRole to filter carriers 4. **BindingId Registration Completeness**: - All LoopState carriers have BindingId registered in ConditionEnv - ConditionOnly carriers may have BindingId registered (for condition lowering) - Registration happens AFTER ValueId allocation, BEFORE condition lowering --- ## Design ### Verification Strategy **Phase 81 focuses on verification, NOT new features.** 1. **Audit ExitLine Reconnection**: - Verify `ExitLineReconnector` correctly skips ConditionOnly carriers - Verify `ExitMetaCollector` includes all carriers for latch - Verify exit_bindings filter is correct 2. **Add E2E Tests**: - DigitPos pattern test (`indexOf()` with promoted `is_digit_pos`) - Trim pattern test (`skip_whitespace` with promoted `is_ch_match`) - Verify Exit PHI structure matches contract 3. **Document Contract**: - Create SSOT for ExitLine + promoted carriers interaction - Document CarrierRole-based filtering rules - Link to existing Phase 78-80 BindingId docs ### Implementation Tasks **Task 81-A: ExitLine Audit** (analysis only) - Read `ExitLineReconnector` code - Read `ExitMetaCollector` code - Verify CarrierRole filtering is correct - Document findings **Task 81-B: E2E Tests** (high priority) - Add DigitPos E2E test to `tests/normalized_joinir_min.rs` - Add Trim E2E test to `tests/normalized_joinir_min.rs` - Verify `tests/phase246_json_atoi.rs` passes (existing test) - All tests dev-only (`#[cfg(feature = "normalized_dev")]`) **Task 81-C: Contract Documentation** (medium priority) - Update this doc with audit findings - Create exit_line_promoted_carriers.md if needed - Link from phase80-bindingid-p3p4-plan.md **Task 81-D: Smoke Tests** (verification) - Run `tools/smokes/v2/run.sh --profile quick` - Verify no regressions in existing tests - Document any failures --- ## Acceptance Criteria ### Minimum Requirements 1. ✅ **E2E Tests Pass**: - `cargo test --release` includes DigitPos E2E test (PASS) - `cargo test --release` includes Trim E2E test (PASS) - `tests/phase246_json_atoi.rs` PASS 2. ✅ **Smoke Tests Pass**: - `tools/smokes/v2/run.sh --profile quick` no regressions - Existing Pattern2 tests continue to PASS 3. ✅ **Contract Documented**: - ExitLine + promoted carriers contract documented - CarrierRole filtering rules documented - Audit findings recorded ### Success Metrics - All lib tests PASS (970/970 baseline, +2 new E2E tests = 972/972) - All smoke tests PASS (existing baseline) - Zero production impact (dev-only tests) - Contract clarity increased (documentation) --- ## Out of Scope ### Phase 81 does NOT include: 1. **New Features**: - No new BindingId registration - No new promoted carriers - No changes to promotion logic 2. **Architecture Changes**: - No ExitLine reconnection refactoring - No CarrierRole enum changes - No ConditionEnv API changes 3. **Pattern3/4 Work**: - Phase 81 focuses on Pattern2 only - Pattern3/4 ExitLine is out of scope --- ## Risk Assessment ### Low Risk: - All changes are verification (tests + docs) - No production code changes expected - Audit is analysis-only ### Potential Issues: 1. **Existing Contract Violation**: - If audit finds ExitLine currently violates contract → need fix - Mitigation: Fix is localized, well-documented 2. **Test Failures**: - If E2E tests fail → indicates real bug - Mitigation: Fix bug, document root cause 3. **Smoke Test Regressions**: - If quick smoke tests fail → need investigation - Mitigation: Classify as Phase 81 target or out-of-scope --- ## References ### Related Documentation - **Phase 80**: `phase80-bindingid-p3p4-plan.md` - BindingId P3/P4 expansion - **Phase 78**: `phase78-bindingid-promoted-carriers.md` - CarrierBindingAssigner - **Phase 77**: Implementation guide - DigitPos/Trim promoters - **JoinIR Architecture**: `joinir-architecture-overview.md` - ExitLine/Boundary overview ### Key Code Files - `src/mir/builder/control_flow/joinir/merge/exit_line_reconnector.rs` - ExitLine reconnection - `src/mir/builder/control_flow/joinir/merge/exit_meta_collector.rs` - Exit metadata collection - `src/mir/join_ir/lowering/carrier_info.rs` - CarrierVar, CarrierRole - `src/mir/loop_pattern_detection/digitpos_detector.rs` - DigitPos detection - `src/mir/loop_pattern_detection/trim_detector.rs` - Trim detection ### Test Files - `tests/normalized_joinir_min.rs` - Add Phase 81 E2E tests here - `tests/phase246_json_atoi.rs` - Existing DigitPos test (verify PASS) --- ## Next Steps **After Phase 81 Complete**: 1. **Phase 82 (optional)**: Pattern3/4 carrier BindingId registration in後段 - Extend BindingId registration to carrier join_id determination points - Reduce fallback usage further 2. **Phase 83 (optional)**: Debug flag cleanup - Deprecate `NYASH_JOINIR_DEBUG` in favor of new naming - Migrate tests to recommended env var --- ## Implementation Notes ### Task Ordering Execute in this order: 1. Task 81-A (Audit) - Understand current state 2. Task 81-B (E2E Tests) - Verify contract 3. Task 81-D (Smoke Tests) - Regression check 4. Task 81-C (Documentation) - Record findings ### Commit Strategy **Single commit** for Phase 81: ``` feat(joinir): Phase 81 - Pattern2 ExitLine contract verification (dev-only) Task 81-A: ExitLine audit findings - ExitLineReconnector correctly skips ConditionOnly carriers - ExitMetaCollector includes all carriers for latch - CarrierRole filtering verified correct Task 81-B: E2E tests for promoted carriers - test_phase81_digitpos_exitline_contract(): DigitPos pattern - test_phase81_trim_exitline_contract(): Trim pattern - Verified Exit PHI excludes ConditionOnly carriers Task 81-D: Smoke test verification - tools/smokes/v2/run.sh --profile quick PASS - No regressions in existing tests Task 81-C: Contract documentation - ExitLine + promoted carriers contract documented - CarrierRole filtering rules clarified Tests: 972/972 PASS (970 baseline + 2 new E2E) Smoke: quick profile PASS (no regressions) Design: Verification-only, zero production impact ``` --- ## Status Tracking - [ ] Task 81-A: ExitLine Audit (analysis) - [ ] Task 81-B: E2E Tests (DigitPos + Trim) - [ ] Task 81-C: Contract Documentation - [ ] Task 81-D: Smoke Tests Verification **Current Phase**: Phase 81 Design (this document) **Next Action**: Task 81-A (ExitLine Audit)