16 KiB
Phase 280: ExitKind+Frag Composition SSOT (A→B→C)
Status: ✅ Complete (2025-12-23) Phase Number: 280 Type: Design-First (Documentation → Minimal Code)
Executive Summary
Goal: Stop pattern number enumeration proliferation by establishing Frag composition API as the Single Source of Truth (SSOT) for structured control flow → CFG lowering.
Strategy: Three-phase approach (A→B→C):
- Phase A: Document SSOT positioning (docs-only, no code) ✅ Complete
- Phase B: Solidify composition API contract (minimal test-based verification) ✅ Complete
- Phase C: Prepare Pattern6/7 for composition API (documentation-only, defer migration to Phase 281) ✅ Complete
Key Insight: Pattern numbers (1-9+) are symptom labels for regression tests, NOT architectural concepts. The architectural SSOT is Frag composition rules (seq/if/loop/cleanup).
Phase 280 Goal: SSOT positioning + 導線固定 (NOT full migration - that's Phase 281)
Purpose
What this phase achieves:
- Establish Frag composition API as THE absorption destination for pattern proliferation
- Document composition SSOT positioning in architecture docs (edgecfg-fragments.md, joinir-architecture-overview.md)
- Solidify composition API contract through verification and testing
- Identify Pattern6/7 hand-rolled Frag construction locations for future migration
- Create clear導線 (guidance) for Phase 281+ migration work
Why this is needed:
- Pattern numbers became architectural decision points (17+ patterns across JoinIR/Plan routes)
- CFG construction logic duplicated across patterns
- Adding new loop shapes required full-stack pattern additions
- Need convergence point to absorb pattern-specific knowledge
Non-Goals
What this phase does NOT do:
- ❌ Migrate Pattern6/7 to use composition API (deferred to Phase 281)
- ❌ Remove hand-rolled Frag construction (documentation-only in Phase 280 C)
- ❌ Change router behavior (routing remains unchanged)
- ❌ Add new composition functions (seq/if/loop already exist)
Rationale: Phase 280 is about SSOT positioning, NOT full migration. 行動は最小が正解.
SSOT References
Primary Documentation
-
Frag Composition SSOT:
docs/development/current/main/design/edgecfg-fragments.md- Status: Active SSOT (updated Phase 280 A1)
- 5 new sections: Composition SSOT, Rules, Laws, Fail-Fast, Ownership
-
JoinIR Architecture Overview:
docs/development/current/main/joinir-architecture-overview.md- Section 0.2: Pattern Number Absorption Destination (Phase 280) (updated Phase 280 A2)
- Comparison: JoinIR vs Plan (different extraction, same SSOT)
-
Phase 280 Plan:
/home/tomoaki/.claude/plans/elegant-wondering-stroustrup.md- Full implementation plan with A→B→C breakdown
Related Documentation
- Phase 273 (Plan Line SSOT): Pattern6/7 Plan-based routing completed
- Phase 264 (歴史/別案件): BundleResolver loop fix (separate scope)
- Phase 265-268: Frag composition API creation and terminator SSOT
Three-Phase Approach (A→B→C)
Phase A: Design SSOT Solidification (Docs-Only) ✅ COMPLETE
No code changes - documentation only
A1: Update edgecfg-fragments.md to "Composition SSOT" ✅
Changes Made:
- Header:
Status: Draft→Status: Active SSOT - Added 5 new sections (after line 103):
- Composition SSOT (Phase 280): Why it's SSOT, input/output contract
- Composition Rules: seq/if/loop/cleanup with composition laws
- Composition Laws (Invariants): Wires/Exits Separation, Terminator Uniqueness
- Fail-Fast Invariants: Two-level verification (verify_frag_invariants vs strict)
- Ownership (Who Allocates What): 3-tier model (Normalizer/Composition/Lowerer)
- Updated "実装入口" section: Phase 280 entry added, Phase 264 separated as history
File: docs/development/current/main/design/edgecfg-fragments.md
A2: Update joinir-architecture-overview.md with "Pattern Number Absorption Destination" ✅
Changes Made:
- Added section 0.2: Pattern Number Absorption Destination (Phase 280)
- Content:
- Problem: Pattern enumeration proliferation
- Solution: Frag Composition SSOT
- JoinIR vs Plan comparison table (different extraction, same SSOT)
- Pattern absorption status table (Pattern6/7 highlighted as Phase 280 targets)
- Absorption timeline (Phase 280-283+)
File: docs/development/current/main/joinir-architecture-overview.md
A3: Create Phase 280 README ✅
This file - Full roadmap documentation with:
- Purpose / Non-Goals
- SSOT References
- Three-Phase Approach breakdown
- Execution Order
- Acceptance Criteria
- Risks and Mitigation
- Critical Files
Phase B: Frag Combiner Minimal API Design
Minimal code changes - documentation + tests only
B1: Document compose.rs Entry Points
File: src/mir/builder/control_flow/edgecfg/api/compose.rs
Changes Required:
-
Add module-level documentation explaining:
- Composition SSOT (Phase 280)
- Entry points: seq(), if_(), loop_(), cleanup()
- Contract: Input/Output Frag, No Allocation, Pure CFG Transform
- Usage example
-
Add function-level "Phase 280: Composition SSOT" sections documenting:
- Constraints (caller allocates X, composition wires Y)
- Composition laws (input → output transformation)
Acceptance:
- Module-level docs added
- Each function has "Phase 280" constraint section
- Composition laws documented
B2: Verify Composition API Implements Contract
File: src/mir/builder/control_flow/edgecfg/api/compose.rs
Action: Documentation-only verification (checklist)
Verification Checklist:
seq() Contract ✓:
- a.Normal → b.entry (wires): Line 42-51
- Non-Normal propagate: Line 54-58
- Tests exist
if_() Contract ✓:
- header → t.entry/e.entry (BranchStub): Line 114-122
- t/e.Normal → join (wires): Line 131-169
- Tests exist
loop_() Contract ✓:
- Continue → header (wires): Line 224-233
- Break → after (wires): Line 236-245
- Tests exist
cleanup() Contract ⏸:
- TODO placeholder (Phase 280+ scope)
Acceptance:
- Checklist complete (all seq/if/loop verified)
- No missing contract implementations discovered
B3: Add Tests for Composition Invariants
File: src/mir/builder/control_flow/edgecfg/api/compose.rs (test module)
Action: Gap analysis + add tests if needed
Current Coverage: 13 tests exist (seq: 2, if: 2, loop: 5, emit: 1, basic: 3)
Gap Analysis:
-
Output Determinism (BTreeMap ordering)
- Check: Verify exits/wires maintain ordering
- Status: Implicit (BTreeMap used, not explicitly tested)
- Action: Add test if gap confirmed
-
Wires/Exits Separation
- Check: Verify wires target=Some, exits target=None
- Status: Partially covered
- Action: Add explicit test if gap confirmed
Decision: Check if gaps exist, add tests only if gaps confirmed
Acceptance:
- Gap analysis complete
- Tests added if gaps found
cargo test --lib --releasePASS
Phase C: Prepare Pattern6/7 to Use Composition API
Behavior-preserving refactor OR documentation
✅ USER DECISION: Option 2 (Documentation-Only) - Recommended
Rationale:
- Phase 280 goal is SSOT positioning + 導線固定 (NOT full migration)
- Pattern6: early-return doesn't naturally fit
compose::if_()model - Pattern7: 挙動不変保証が難しい、得られる差分が小さい
- 行動は最小が正解 - Full migration deferred to Phase 281
C1: Identify Hand-Rolled Frag Construction Locations
File: src/mir/builder/control_flow/plan/normalizer.rs
Pattern6 (ScanWithInit):
- Function:
normalize_scan_with_init() - 識別コメント: Search for
// Step 12: Build CoreLoopPlanorlet branches = vec![...]nearBranchStub { from: header_bb, cond: cond_loop - Structure: 5 blocks (preheader, header, body, step, found, after)
- Hand-rolled: 2 BranchStub + 2 EdgeStub
- Composition opportunity: Hand-rolled clearer (early exit breaks if_ model)
Pattern7 (SplitScan):
- Function:
normalize_split_scan() - 識別コメント: Search for
// Build Frag with branches and wiresorlet branches = vec![...]nearBranchStub { from: header_bb, cond: cond_loopin split context - Structure: 6 blocks (preheader, header, body, then, else, step, after)
- Hand-rolled: 2 BranchStub + 3 EdgeStub
- Composition opportunity: Defer to Phase 281 (挙動不変保証が難しい)
Acceptance:
- Pattern6 location identified (function name + 識別コメント)
- Pattern7 location identified (function name + 識別コメント)
- Composition opportunities assessed (both defer to Phase 281)
C2: Document Hand-Rolled Construction (Defer Migration to Phase 281)
Scope: Add TODO comments showing future refactor path
Example Documentation (Option 2 - DEFAULT):
Pattern6 (normalize_scan_with_init):
// Phase 280 TODO: Hand-rolled Frag construction for early exit pattern
// Reason: `found` is early Return, doesn't fit compose::if_() model
// Future: Consider compose::cleanup() for early exit normalization (Phase 281+)
Pattern7 (normalize_split_scan):
// Phase 280 TODO: Hand-rolled Frag construction for split scan pattern
// Target (Phase 281): compose::if_(body_bb, cond_match, then_frag, else_frag, step_frag)
// Reason deferred: 挙動不変保証が難しい、Phase 280 は SSOT positioning 優先
// Migration: Phase 281+ で compose::if_() への移行を検討
Implementation:
- Search for hand-rolled locations using function name + 識別コメント (from C1)
- Add TODO comments above hand-rolled construction
- Document: (a) current structure, (b) future compose target, (c) defer reason
Acceptance:
- TODO comments added to both Pattern6 and Pattern7
- Comments document: current structure + future target + defer reason
- No behavior change (documentation-only)
C3: Verify No Behavior Change (Smoke Tests - Optional)
Status: Optional (Phase C is documentation-only, no code changes)
Test Strategy: If desired, run representative smokes to verify baseline
Pattern6 Smoke (Optional):
bash tools/smokes/v2/profiles/integration/apps/phase258_p0_index_of_string_llvm_exe.sh
Pattern7 Smoke (Optional):
# Find Pattern7 smokes (split)
tools/smokes/v2/run.sh --profile integration --filter "*split*"
Quick Profile (Optional):
tools/smokes/v2/run.sh --profile quick
# Expected: 45/46 PASS (baseline maintained)
Acceptance:
- Smoke tests run if desired (optional - docs-only change)
- Behavior unchanged (guaranteed - no code modifications in Phase C)
Execution Order (Critical!)
MUST execute in strict A→B→C order:
-
Phase A (Docs-only, no code) ✅ COMPLETE:
- A1: Update edgecfg-fragments.md ✅
- A2: Update joinir-architecture-overview.md ✅
- A3: Create phase-280/README.md ✅
- Verify: No code changes made ✅
-
Phase B (API solidification):
- B1: Add compose.rs module docs
- B2: Verify contract checklist
- B3: Add missing tests if needed
- Verify:
cargo test --lib --releasePASS
-
Phase C (Pattern preparation - Documentation-only):
- C1: Identify hand-rolled locations (function name + 識別コメント)
- C2: Add TODO comments (Option 2 - default, defer migration to Phase 281)
- C3: Run smoke tests (optional - no code change, behavior guaranteed)
- Verify: No regression (docs-only, no behavior change)
-
Final Verification:
- All acceptance criteria met
- Smoke tests PASS
- No regression
Acceptance Criteria
Phase A (Docs) ✅ COMPLETE
- edgecfg-fragments.md updated (5 sections, Active SSOT)
- joinir-architecture-overview.md updated (absorption section + table)
- phase-280/README.md created
- All docs cross-reference each other
- No code changes
Phase B (API) ✓ When all checked:
- compose.rs module-level docs added
- Function constraints documented
- Composition contract verified
- Missing tests added if gaps found
cargo test --lib --releasePASS
Phase C (Pattern Prep) ✓ When all checked:
- Hand-rolled locations identified (function name + 識別コメント)
- Documentation-only (Option 2) executed (TODO comments added)
- Smoke tests PASS (optional - no code change expected)
- Behavior unchanged (guaranteed - docs-only)
Overall ✓ When all checked:
- No regression (all tests/smokes PASS)
- SSOT positioning clear
- Pattern6/7 prepared for Phase 281
Risks and Mitigation
Risk 1: Composition API Doesn't Match Hand-Rolled Exactly
- Impact: Behavior change, regression
- Likelihood: Medium
- Mitigation: Phase A (docs-only) first, Phase C Option 2 (document) is fallback
- Phase 280 Decision: Documentation-only (Option 2), defer refactor to Phase 281
Risk 2: Pattern6/7 Have Hidden Dependencies
- Impact: Refactor breaks edge cases
- Likelihood: Low (well-tested)
- Mitigation: C3 runs both Pattern-specific and quick profile smokes
- Phase 280 Decision: No refactor, only documentation
Risk 3: Smoke Tests Miss Edge Cases
- Impact: Regression not caught
- Likelihood: Low (45+ tests in quick profile)
- Mitigation: Run both VM and LLVM backends if needed
- Phase 280 Status: Optional (docs-only change)
Critical Files
Phase A (Documentation) ✅
docs/development/current/main/design/edgecfg-fragments.md✅docs/development/current/main/joinir-architecture-overview.md✅docs/development/current/main/phases/phase-280/README.md✅ (this file)
Phase B (Code: API)
src/mir/builder/control_flow/edgecfg/api/compose.rs
Phase C (Code: Pattern Prep - Documentation-only)
src/mir/builder/control_flow/plan/normalizer.rs- Pattern6:
normalize_scan_with_init()function - Pattern7:
normalize_split_scan()function - Action: Add TODO comments (no code changes)
- Pattern6:
Related Phases
Predecessor Phases
- Phase 273 (P0-P4): Plan line SSOT for Pattern6/7 (DomainPlan → CorePlan → Frag → emit_frag)
- Phase 265-268: Frag composition API creation, terminator SSOT (emit_frag)
- Phase 264: BundleResolver loop fix (歴史/別案件, separate scope)
Successor Phases (Planned)
- Phase 281: Full Pattern6/7 absorption (replace hand-rolled with compose_*)
- Phase 282: Router shrinkage (pattern numbers → test labels)
- Phase 283+: Pattern8 and beyond
Status Summary
Phase A: ✅ COMPLETE (2025-12-23)
- A1: edgecfg-fragments.md updated ✅
- A2: joinir-architecture-overview.md updated ✅
- A3: phase-280/README.md created ✅
Phase B: ⏳ In Progress
- B1: compose.rs module docs (pending)
- B2: Verify composition contract (pending)
- B3: Add missing tests if needed (pending)
Phase C: ⏸ Pending
- C1: Identify hand-rolled locations (pending)
- C2: Add TODO comments (pending)
- C3: Run smoke tests (optional)
Overall: 33% complete (Phase A done, Phases B+C remaining)
End of Phase 280 README