## Summary
Adds early Fail-Fast contract verification to prevent Phase 135 P0 issues from recurring.
Two new verifiers catch allocator SSOT violations and boundary inconsistencies before --verify.
## Changes
### Step 1: verify_condition_bindings_consistent
**Location**: `src/mir/builder/control_flow/joinir/merge/contract_checks.rs`
**Contract**: condition_bindings can have aliases (multiple names for same join_value),
but same join_value with different host_value is a violation.
**Example Error**:
```
[JoinIRVerifier/Phase135-P1] condition_bindings conflict:
join_value ValueId(104) mapped to both ValueId(12) and ValueId(18)
```
**Catches**: ConditionLoweringBox bypassing SSOT allocator before BoundaryInjector
### Step 2: verify_header_phi_dsts_not_redefined
**Location**: `src/mir/builder/control_flow/joinir/merge/contract_checks.rs`
**Contract**: Loop header PHI dst ValueIds must not be reused as dst in non-PHI instructions.
Violation breaks MIR SSA (PHI dst overwrite).
**Example Error**:
```
[JoinIRVerifier/Phase135-P1] Header PHI dst ValueId(14) redefined by non-PHI instruction in block 3:
Instruction: Call { dst: Some(ValueId(14)), ... }
```
**Catches**: ValueId collisions between header PHI dsts and lowered instructions
### Integration
**Location**: `src/mir/builder/control_flow/joinir/merge/mod.rs`
Added to `verify_joinir_contracts()`:
1. Step 1 runs before merge (validates boundary)
2. Step 2 runs after merge (validates func with PHI dst set)
### Documentation
- Updated `phase135_trim_mir_verify.sh` - Added P1 contract_checks description
- Updated `phase-135/README.md` - Added P1 section with contract details and effects
## Acceptance
✅ Build: SUCCESS
✅ Smoke: phase135_trim_mir_verify.sh - PASS
✅ Regression: phase132_exit_phi_parity.sh - 3/3 PASS
✅ Regression: phase133_json_skip_whitespace_llvm_exe.sh - PASS
## Effect
- **Prevention**: Future Box implementations catch SSOT violations immediately
- **Explicit Errors**: Phase 135-specific messages instead of generic --verify failures
- **Unbreakable**: Debug builds always detect violations, enforced by CI/CD
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Smokes v2 — Minimal Runner and Policy
Policy
- Use [SKIP:] prefix for environment/host dependent skips.
- Examples: [SKIP] hakorune not built, [SKIP:env] plugin path missing
- Keep reasons short and stable to allow grep-based canaries.
- Prefer JSON-only output in CI: set
NYASH_JSON_ONLY=1to avoid noisy logs. - Diagnostics lines like
[provider/select:*]are filtered by default inlib/test_runner.sh.- Toggle: set
HAKO_SILENT_TAGS=0to disable filtering and show raw logs.HAKO_SHOW_CALL_LOGS=1also bypasses filtering.
- Toggle: set
Helpers
tools/smokes/v2/lib/mir_canary.shprovides:extract_mir_from_output— between [MIR_BEGIN]/[MIR_END]assert_has_tokens,assert_skip_tag,assert_order,assert_token_count
tools/lib/canary.shprovides minimal, harness-agnostic aliases:extract_mir_between_tags— same asextract_mir_from_outputrequire_tokens token...— fail if any token missing
Notes
- Avoid running heavy integration smokes in CI by default. Use
--profile quick. - When a test depends on external tools (e.g., LLVM), prefer
[SKIP:<reason>]over failure. - Stage‑B/selfhost canaries(
stage1_launcher_*,phase251*など)は Stage‑3 デフォルト環境で安定しないため、quick プロファイルでは[SKIP:stageb]として扱い、必要に応じて別プロファイル(integration/full)で個別に実行する。 - Selfhost quick カバレッジは最小 1 本(
core/selfhost_minimal.sh)に絞り、Stage‑3 + JoinIR 前提で Stage‑B→VM を通るかだけを確認する。 - S3 backend 向けの長尺テスト群も quick 向きではないため、timeout を短く保ちたい場合は
[SKIP:slow]にして別途ローカルで回すことを推奨する。
Quick tips
- EXE-heavy cases (e.g.,
phase2100/*) may take longer. When running quick with these tests, pass a larger timeout like--timeout 120. - Smokes v2 auto-cleans temporary crate EXE objects created under
/tmp(pattern:ny_crate_backend_exe_*.o) after the run.
Developer Notes
- JoinIR If/Select (Phase 33): A/B test with
NYASH_FEATURES=stage3 HAKO_JOINIR_IF_SELECT=1 ./target/release/hakorune apps/tests/joinir_if_select_simple.hako(dev-only、CI対象外。NYASH_JOINIR_CORE は deprecated/無視)