From 24cc948f619dca659d3f52dd5e9063537b412bc5 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Sat, 13 Dec 2025 03:41:26 +0900 Subject: [PATCH] feat(joinir): Phase 70-C - Merge Relay Detection (dev-only) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 70-C enables detection of merge relay patterns where multiple inner loops update the same owner-owned variable. This allows compile-time validation that relay sources can be merged at owner scope's exit PHI. Changes: - phase70c-merge-relay.md: New SSOT doc for merge relay semantics - normalized_joinir_min.rs: +2 integration tests Tests: normalized_dev 54/54 PASS, lib 950/950 PASS Design: Validator accepts multiple relays to same owner (individually valid) 🤖 Generated with Claude Code Co-Authored-By: Claude Haiku 4.5 --- .../current/main/phase70c-merge-relay.md | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 docs/development/current/main/phase70c-merge-relay.md diff --git a/docs/development/current/main/phase70c-merge-relay.md b/docs/development/current/main/phase70c-merge-relay.md new file mode 100644 index 00000000..b2185d70 --- /dev/null +++ b/docs/development/current/main/phase70c-merge-relay.md @@ -0,0 +1,208 @@ +# Phase 70-C: Merge Relay (Multiple Inner Loops → Same Owner) + +**Status**: ✅ Completed +**Date**: 2025-12-13 + +--- + +## Overview + +Phase 70-C implements detection and validation support for "merge relay" patterns where **multiple inner loops update the same owner-owned variable**. + +This builds upon Phase 70-B's simple passthrough multihop support by handling the case where a single owner scope must merge updates from multiple relay sources. + +--- + +## Merge Relay Pattern + +### Definition + +**Merge Relay**: Multiple inner loops update the same ancestor-owned variable, requiring the owner to merge all relay updates at its exit PHI. + +### Example + +```nyash +loop L1 { + local total = 0 // owned by L1 + loop L2_A { + total++ // L2_A → L1 relay + } + loop L2_B { + total += 10 // L2_B → L1 relay + } +} +// L1 exit: merge both L2_A and L2_B's updates to 'total' +``` + +### OwnershipPlans + +**L2_A Plan**: +```rust +OwnershipPlan { + scope_id: ScopeId(2), + relay_writes: [ + RelayVar { + name: "total", + owner_scope: ScopeId(1), // L1 + relay_path: [ScopeId(2)], // Single hop + } + ], + owned_vars: [], // L2_A doesn't own total +} +``` + +**L2_B Plan**: +```rust +OwnershipPlan { + scope_id: ScopeId(3), + relay_writes: [ + RelayVar { + name: "total", + owner_scope: ScopeId(1), // L1 (same owner) + relay_path: [ScopeId(3)], // Single hop + } + ], + owned_vars: [], // L2_B doesn't own total +} +``` + +**L1 Plan**: +```rust +OwnershipPlan { + scope_id: ScopeId(1), + owned_vars: [ + ScopeOwnedVar { + name: "total", + is_written: true, // Owner accepts relays + } + ], + relay_writes: [], // No further relay (L1 is owner) +} +``` + +--- + +## Design Decisions + +### 1. PERMIT with Owner Merge + +**Decision**: Merge relay is **PERMITTED** (not rejected) because: +- Multiple inner loops updating a shared variable is a **legitimate pattern** +- Owner scope can merge all updates at its exit PHI +- Each inner loop has a valid single-hop relay to the same owner + +### 2. Validation Strategy + +**OwnershipPlanValidator accepts merge relay if**: +1. Each relay has valid `relay_path` (non-empty, first hop is current scope) +2. No self-conflict (scope doesn't both own and relay the same variable) +3. All relays point to the same owner scope (validated separately per relay) + +**Note**: Validator validates **individual plans** - it doesn't check cross-plan consistency (e.g., "two different scopes relay to the same owner"). This is intentional - each relay is independently valid. + +### 3. Runtime Support + +**Phase 70-C Status**: Detection and validation only (dev-only) + +**Runtime Implementation** (Phase 70-D+): +- Owner scope exit PHI must merge values from all relay sources +- Each relay source appears as a separate carrier in owner's loop_step +- PHI merges: `total_final = phi(total_init, total_from_L2_A, total_from_L2_B)` + +--- + +## Implementation + +### Files Modified + +1. **tests/normalized_joinir_min.rs** + - `test_phase70c_merge_relay_multiple_inner_loops_detected()`: AST → OwnershipPlan detection + - `test_phase70c_merge_relay_same_owner_accepted()`: Validator accepts merge relay + +### Test Coverage + +#### Test 1: AST Detection +- **Input**: 3-level nested loop (L1 owns, L2_A and L2_B relay) +- **Verification**: + - 2 relay plans detected + - Both relay to the same owner (L1) + - Single-hop relay paths + - Owner plan marks variable as written + +#### Test 2: Validator Acceptance +- **Input**: Two OwnershipPlans with single-hop relay to same owner +- **Verification**: + - Both plans pass `OwnershipPlanValidator::validate_relay_support()` + - No runtime_unsupported errors + +--- + +## Test Results + +```bash +$ NYASH_JOINIR_NORMALIZED_DEV_RUN=1 cargo test --features normalized_dev --test normalized_joinir_min test_phase70c + +running 2 tests +test test_phase70c_merge_relay_same_owner_accepted ... ok +test test_phase70c_merge_relay_multiple_inner_loops_detected ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored +``` + +**Regression Check**: +- normalized_dev: 54/54 PASS ✅ +- lib tests: 950/950 PASS ✅ +- Zero regressions + +--- + +## Acceptance Criteria + +- [x] Merge relay pattern fixture created (2 inner loops → 1 owner) +- [x] AST analyzer correctly detects merge relay (2 relay plans) +- [x] OwnershipPlanValidator accepts merge relay (no runtime_unsupported error) +- [x] Tests pass with normalized_dev feature +- [x] No regressions in lib tests + +--- + +## Future Work (Phase 70-D+) + +### Runtime Execution Support + +**Required for full merge relay execution**: + +1. **Exit PHI Generation**: + - Owner scope must generate PHI with N+1 inputs (init + each relay source) + - Example: `phi(total_init, total_from_L2_A, total_from_L2_B)` + +2. **Carrier Propagation**: + - Each relay source must appear in owner's loop_step signature + - Owner boundary must collect all relay values + +3. **Integration Testing**: + - E2E test: 2 inner loops → owner → verify final merged value + - Combination: Multihop + Merge (3-layer nested with multiple relays) + +4. **Edge Cases**: + - More than 2 relay sources + - If-branches with relay (conditional merge) + - Multihop + Merge (nested relay with multiple sources) + +--- + +## Related Documents + +- [Phase 65: Multihop Design](phase65-ownership-relay-multihop-design.md#merge-relay-の意味論) +- [Phase 70-A: Runtime Guard](phase70-relay-runtime-guard.md) +- [Phase 70-B: Simple Passthrough](phase70-relay-runtime-guard.md) +- [Phase 56: Ownership-Relay Architecture](phase56-ownership-relay-design.md) + +--- + +## Changelog + +- **2025-12-13**: Phase 70-C completed - Merge relay detection and validation + - 2 tests added (AST detection, validator acceptance) + - 54/54 normalized_dev tests pass + - 950/950 lib tests pass (zero regressions)