312 lines
9.7 KiB
Markdown
312 lines
9.7 KiB
Markdown
|
|
# 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)
|