Verified NYASH_JOINIR_LOWER_GENERIC=1 does not break Stage-B:
- generic OFF: joinir_json 10 PASS, joinir_stageb 6 PASS
- generic ON: joinir_json 10 PASS, joinir_stageb 6 PASS,
auto_lowering 2 PASS
- No guard additions needed - existing code is stable
- Stage-B execution remains on VM Route A (JoinIR as canary only)
L-2.2 is now fully complete (Step-1 through Step-5).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Expose `convert_joinir_to_mir` as `pub(crate)` for test access
- Add `joinir_stageb_body_structure_test` and
`joinir_stageb_funcscanner_structure_test` to `joinir_json_min.rs`
- Verify: JoinIR lowering succeeds, JoinIR→MIR conversion succeeds,
function count matches, each function has >= 1 block
- Result: Both Stage-B functions produce 2 JoinIR functions
(entry + loop_step) with appropriate block counts
- Note: Current tests verify handwritten JoinIR→MIR bridge layer,
not full MIR→JoinIR roundtrip (future improvement)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add Stage-B BodyExtractor and FuncScanner to JoinIR VM bridge dispatch:
- Import stageb_body and stageb_funcscanner lowering functions
- Add routing for StageBBodyExtractorBox.build_body_src/2
- Add routing for StageBFuncScannerBox.scan_all_boxes/1
- Add try_run_stageb_body() and try_run_stageb_funcscanner() (lowering verification only)
Also cleanup unused imports in funcscanner_trim.rs and stage1_using_resolver.rs
Note: Stage-B functions use lowering verification pattern (like Stage-1)
because ArrayBox/MapBox args are not yet supported in JoinValue.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Stage-B minimal JoinIR lowering統一化:
1. Add Case-A helpers to loop_to_join.rs:
- lower_case_a_for_stageb_body (StageBBodyExtractorBox.build_body_src/2)
- lower_case_a_for_stageb_funcscanner (StageBFuncScannerBox.scan_all_boxes/1)
2. Update stageb_body.rs and stageb_funcscanner.rs:
- Replace manual LoopForm construction with construct_simple_while_loopform
- Route through LoopToJoinLowerer like other Case-A functions
- Remove unused imports (LoopForm, MirQuery)
Now all 6 JoinIR lowering modules use the same unified pattern:
- skip_ws, trim, append_defs, stage1_resolver, stageb_body, stageb_funcscanner
All route through LoopToJoinLowerer for consistency.
Test results: JSON snapshot 6/6 PASS
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 32 cleanup:
1. Delete legacy is_supported_case_a_loop function from loop_to_join.rs
- Replaced by is_supported_case_a_loop_view() in Phase 32 Step 3
2. Extract construct_simple_while_loopform helper to common.rs
- Unified LoopForm construction for simple while loops
- Parameters: entry_is_preheader (trim=true, stage1=false)
has_break (trim=true, stage1=false)
- Sets latch=body to satisfy is_simple_case_a_loop check
3. Update lowering modules to use the common helper:
- funcscanner_trim.rs: entry_is_preheader=true, has_break=true
- stage1_using_resolver.rs: entry_is_preheader=false, has_break=false
Test results: JSON snapshot 6/6 PASS, VM bridge trim 2/2 PASS
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 32 L-1: Make JoinIR the default execution path for verified targets.
- Added is_default_joinir_target() function to check default-enabled functions
- FuncScannerBox.trim/1 is now enabled by default (break=[], Case-A verified)
- Main.skip/1 excluded from default (break=[2], needs Case-B support)
- Environment variable NYASH_JOINIR_VM_BRIDGE=1 still works for other targets
Test results:
- trim: Route C (JoinIR) returns correct value "abc"
- trim: Route A (VM) returns "void" due to PHI bug
- JoinIR correctly handles PHI issues that affect direct VM path
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 31 Step 3-A: Add early return using is_case_a_minimal_target() filter
- Check before LoopScopeShape construction for efficiency
- Returns None immediately for non-target functions
Phase 31 Step 3-B: Add structural validation to is_supported_case_a_loop()
- Single exit check: loop_form.break_targets.len() <= 1
- Variable presence check: !carriers.is_empty() || !pinned.is_empty()
- Debug logging for rejection reasons
Also refactored lower_with_scope() from if-else chain to match expression for clarity.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 31 Step 2 complete:
- skip_ws.rs: use LoopToJoinLowerer::lower_minimal_skip_ws_case_a()
- funcscanner_trim.rs: use LoopToJoinLowerer::lower_minimal_trim_case_a()
- funcscanner_append_defs.rs: use LoopToJoinLowerer::lower_minimal_append_defs_case_a()
- stage1_using_resolver.rs: use LoopToJoinLowerer::lower_minimal_stage1_case_a()
Eliminates direct generic_case_a calls, routing through unified box.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove LoopSnapshotManager which was only used by its own internal tests.
No external call sites existed.
- Delete loop_snapshot_manager.rs (~458 lines)
- Update mod.rs to remove module declaration
- Update PHI_BOX_INVENTORY.md and TASKS.md
Analysis showed all other F-2.2 candidates have production dependencies
and must wait for JoinIR coverage expansion:
- PhiBuilderBox - loop_builder.rs
- LoopSnapshotMergeBox - loopform_builder.rs, json_v0_bridge
- if_phi.rs - lifecycle.rs, if_form.rs, loop_builder.rs
- if_body_local_merge.rs - phi_builder_box.rs, loop_builder.rs
- phi_invariants.rs, conservative.rs, phi_input_collector.rs - multiple
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Task A/B/C results:
- Task A: Lowerer files Case A analysis (6 files surveyed)
- Found: all lowerers use empty LoopVarClassBox/LoopExitLivenessBox
- stageb_body/stageb_funcscanner have placeholders only
- Task B: Add VM runner shrinkage plan to TASKS.md F-4.4
- Task C: Add bridge summary to CURRENT_TASK.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add Route B execution tests for Stage-1 UsingResolver:
Results:
- n=0 (no loop): JoinIR returns "init" ✅ vs VM returns "void" (PHI bug)
- n=3 (loop runs): JoinIR errors "IntegerBox.get" - needs ArrayBox support
This proves JoinIR can fix PHI bugs in Stage-1 loops.
Next step: JoinValue extension for ArrayBox/MapBox arguments.
Test: joinir_vm_bridge_stage1_usingresolver_route_b_*
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Quick Win 1: Show available boxes on "Unknown Box type" error
- vm.rs, vm_fallback.rs: Display sorted list of available user-defined boxes
- Before: "Unknown Box type: Foo"
- After: "Unknown Box type: Foo. Available: Bar, Baz, Main"
Quick Win 2: Show stderr on child process timeout
- child.rs, selfhost_exe.rs: Capture and display stderr (up to 500 chars)
- Helps diagnose what went wrong in selfhost compiler child process
Quick Win 3: Simplify Stage-B compiler API (SSOT)
- compiler_stageb.hako: Add StageBDriverBox.compile() as single entry point
- compiler_stageb.hako: Remove StageBMain compatibility wrapper
- compiler.hako: Change from `using ... as StageBMain` to direct import
- compiler.hako: Call StageBDriverBox.compile() directly
Also includes child_env.rs NYASH_MODULES env var for module mapping.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Use --stage-b flag for file-based compilation (Stage-A expects source
content, not path; Stage-B uses FileBox to read files)
- Remove redundant env overrides that conflicted with
apply_selfhost_compiler_env() settings
- Re-enable plugins in selfhost compiler env (NYASH_DISABLE_PLUGINS=0)
so compiler.hako can use FileBox to read source files
Note: Pipeline infrastructure now works, but compiler.hako has a MIR
SSA bug (undefined ValueId(374)) that needs separate investigation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add NYASH_CLI_VERBOSE>=2 observation logs to trace the Ny compiler
child process path (NYASH_USE_NY_COMPILER=1):
- Log when spawning child process
- Log when receiving Program(JSON v0)
- Log before/after maybe_dump_mir with dump path info
- Report whether MIR dump file was created
Key finding: apps/selfhost/compiler/compiler.hako doesn't exist,
so the preferred child process route never fires. This explains
why RUST_MIR_DUMP_PATH doesn't create files in Ny compiler path.
Also update environment-variables.md with:
- NYASH_CLI_VERBOSE=2 level documentation
- Ny compiler observation template for Phase 29
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove #[ignore] from trim test, following skip_ws promotion pattern:
- NYASH_JOINIR_EXPERIMENT=1 toggle controls execution
- Normal cargo test skips via early return (lightweight)
- Two JoinIR standalone tests now available as PHI-independent baselines
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement zero-progress backedge detection for JoinIR loops:
- Create verify.rs module with ProgressError enum
- verify_progress_for_skip_ws() checks BinOp::Add before recursive calls
- Hook into joinir_runner_standalone_skip_ws test (NYASH_JOINIR_EXPERIMENT=1)
- Currently warning-only, will upgrade to error in Phase 30
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>