Files
hakorune/docs/development/current/main/phase49-selfhost-joinir-depth2-design.md
nyash-codex 7b0db59100 feat(joinir): Phase 53 - SELFHOST-NORM-DEV-EXPAND implementation
Expanded selfhost dev Normalized target with 2 practical P2/P3 loop variations,
strengthened structural signature axis, and implemented two-stage detection.

Key Changes:

1. Documentation (phase49-selfhost-joinir-depth2-design.md +128 lines):
   - Added Phase 53 section with candidate selection rationale
   - Documented two-stage detector strategy (structural primary + dev-only name guard)
   - Defined structural axis strengthening (carrier count/type, branch patterns)

2. Fixtures (+210 lines):
   - selfhost_args_parse_p2.program.json (60 lines): P2 with String carrier + conditional branching
   - selfhost_stmt_count_p3.program.json (150 lines): P3 with 5 carriers + multi-branch if-else

3. Structured Builders (fixtures.rs +48 lines):
   - build_selfhost_args_parse_p2_structured_for_normalized_dev()
   - build_selfhost_stmt_count_p3_structured_for_normalized_dev()

4. ShapeGuard Two-Stage Detection (shape_guard.rs +80 lines):
   - Added SelfhostArgsParseP2/SelfhostStmtCountP3 to NormalizedDevShape enum
   - Implemented is_selfhost_args_parse_p2(): P2 core family + name guard
   - Implemented is_selfhost_stmt_count_p3(): 2-10 carrier check + name guard
   - Updated capability_for_shape() mappings

5. Bridge Integration (bridge.rs +8 lines, normalized.rs +10 lines):
   - Added shape handlers delegating to existing normalizers
   - Added roundtrip reconstruction handlers

6. Entry Point Registration (ast_lowerer/mod.rs +2 lines):
   - Registered selfhost_args_parse_p2/selfhost_stmt_count_p3 as LoopFrontend routes

7. Dev VM Comparison Tests (normalized_joinir_min.rs +40 lines):
   - normalized_selfhost_args_parse_p2_vm_bridge_direct_matches_structured()
   - normalized_selfhost_stmt_count_p3_vm_bridge_direct_matches_structured()

8. Test Context Fix (dev_env.rs):
   - Added thread-local test context depth counter
   - Fixed deadlock in nested test_ctx() calls via reentrant with_dev_env_if_unset()

Structural Axis Growth:

P2 family:
- Carrier count: 1-3 (unchanged)
- NEW: Type diversity (Integer/String mixed)
- NEW: Conditional branching patterns (Eq-heavy comparisons)

P3 family:
- NEW: Carrier count upper bound: 2-10 (was 2-4)
- NEW: Multi-branch if-else (5+ branches with nested structure)
- NEW: Complex conditional patterns

Test Results:
- normalized_dev: 40/40 PASS (including 2 new tests)
- lib regression: 939 PASS, 56 ignored
- Existing behavior unchanged (normalized_dev feature-gated)

Phase 53 Achievements:
 P2/P3 each gained 1 practical variation (2 total)
 Two-stage detection: structural primary + dev-only name guard
 Structural axis expanded: 4 axes (carrier count/type/Compare/branch patterns)
 All tests PASS, no regressions
 Test context deadlock fixed (0.04s for 29 tests)

Files Modified: 14 files
Lines Added: ~516 lines (net)
Implementation: Pure additive (feature-gated)

Next Phase (54+):
- Accumulate 6+ loops per P2/P3 family
- Achieve 5+ stable structural axes
- Target < 5% false positive rate
- Then shrink/remove name guard scope
2025-12-12 16:40:20 +09:00

273 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 49-SELFHOST-NORM-DEPTH2: selfhost depth2 Normalized 設計メモ(コード変更なし)
## 1. Goal & Scope
- 目標: `.hako → Program/MIR JSON → JoinIR(Structured) → Normalized → MIR → VM/LLVM` の depth2 パイプラインを selfhost でも踏めるように設計を固める。
- フォーカスする selfhost ループPhase 183 の棚卸しを前提に「軽い P2/P3」を 2 本に固定):
- 対象A: `selfhost_token_scan_p2.hako` / 関数 `selfhost_token_scan_p2`P2 カウンタループ、break あり・continue なし・MethodCall なし)。
- 対象B: `selfhost_if_sum_p3.hako` / 関数 `selfhost_if_sum_p3`P3 if-sum: sum+count、条件は Compare のみ・MethodCall なし)。
- Out of Scope今回扱わない: P5/Trim 相当の heavy ループ、MethodCall 多用ループ、selfhost の他ループ。
## 2. 現状整理Status Snapshot
- Phase 183 時点: selfhost depth2 の代表ループは棚卸し済みだが、Normalized 経路や shape_guard は未整備。
- JsonParser 側: P1〜P4 代表形が canonical NormalizedPhase 41/48で安定、StepScheduleBox/shape_guard/normalized_bridge が揃っている。
- selfhost: Program/MIR JSON までは出せるが、JoinIR→Normalized→MIR への橋は未設計。まずは P2/P3 の軽量ループに限定して設計する。
## 3. ループ→Pattern/Shape マッピング表(確定)
| Loop 名(仮) | Pattern 想定 | Normalized shape 想定 | 必要キャリア | 特記事項 |
| --- | --- | --- | --- | --- |
| selfhost_token_scan_p2 | P2 corebreak あり/continue なし) | Pattern2 coreJsonParser skip_ws と同列) | ループ変数 + count | body-local/MethodCall なし |
| selfhost_if_sum_p3 | P3 if-sum minimal | Pattern3 if-sum minimal/multi | sum + count + ループ変数 | MethodCall なし、条件は Compare のみ |
## 4. depth2 パイプライン設計(責務メモ)
```
.hako (selfhost) → Program/MIR JSON selfhost front-end
→ JoinIR(Structured) JoinIR front-end / ast_lowerer・fixtures
→ Normalized normalized.rs + shape_guard
→ MIR normalized_bridge 直 or Structured 再構成フォールバック)
→ VM/LLVM 実行
```
- selfhost front-end: Program/MIR JSON を生成(既存 Stage-1/Stage-3
- JoinIR front-end: Program/MIR JSON → Structured JoinModule既存 ast_lowerer + 追加 selfhost fixtures
- Normalized: shape_guard で P2/P3 自動判定 → Structured→Normalized 変換。
- Bridge: canonical セットP1〜P4は direct Normalized→MIR を優先、非対応は Structured 再構成フォールバック。
- 実行: VM/LLVM は JsonParser と同じ経路を共用。
## 5. フィクスチャとテスト計画dev-only
- Program JSON:
- `docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_token_scan_p2.program.json`
- `docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_if_sum_p3.program.json`
- Structured JoinModule helpernormalized::fixtures:
- `build_selfhost_token_scan_p2_structured_for_normalized_dev()`
- `build_selfhost_if_sum_p3_structured_for_normalized_dev()`
- テストnormalized_dev feature 下):
- Structured→MIR vs Structured→Normalized→MIR(direct) の VM stdout 比較を追加。
- shape_guard が誤判定した場合は Fail-Fast させ、対象ループ以外はスコープ外と明示。
## 6. Out of Scope / 次フェーズ送り
- heavy selfhost ループMethodCall 多用、P5/Trim 依存)。
- Normalized 最適化や verifier 拡張(設計のみ、実装は Phase 50+)。
- selfhost 以外の新規ループ適用。
## 7. Next steps49-B/50 に向けたメモ)
- normalized::fixtures に selfhost 用 helper を追加し、shape_guard に selfhost shape variant を足す。
- tests/normalized_joinir_min.rs に selfhost ループの比較テストを追加dev-only
- canonical 昇格は Phase 50 以降で検討(まずは dev 正規化を通すことに専念)。
## 8. Status updatePhase 50 反映)
- 対象ループを `selfhost_token_scan_p2` / `selfhost_if_sum_p3` に確定し、normalized_dev フィクスチャと Structured helper を追加済み。
- ShapeGuard に selfhost 用 shape を追加し、Structured→Normalized→MIR(direct) の dev 比較テストで Structured 直経路と一致するところまで実装完了canonical 化は後続フェーズ)。
## 9. Phase 51SELFHOSTNORMDEVEXTEND
Phase 50 の selfhost P2/P3 dev Normalized の足場を使い、selfhost 側でもう少し実戦寄りの形状を dev Normalized に追加する。
canonical 昇格は別フェーズで扱い、このフェーズでは dev-only のまま固定する。
### 追加対象dev-only
| ループ名 | 想定パターン | ねらい | キャリア/更新 | 備考 |
| --- | --- | --- | --- | --- |
| selfhost_token_scan_p2_accum | P2 corebreak あり/continue なし) | P2 で複数キャリア更新の安定化 | i + count + accacc += i, count += 1 | name ガード dev-only構造判定が安定したら撤去 |
| selfhost_if_sum_p3_ext | P3 if-sum family | then/else 両側更新の安定化 | i + sum + countthen: sum+=i,count+=1 / else: sum+=1 | name ガード dev-only構造判定が安定したら撤去 |
### 受け入れ条件Phase 51
- 上記 2 本が fixtures + shape_guard + dev 比較テストまで揃い、狙い撃ちテストが緑。
- normalized_dev 以外の挙動は不変canonical/既定経路に影響なし)。
## 10. Phase 52SELFHOSTSHAPESTRUCTSIGNATUREdev-only
Phase 5051 で入れた selfhost shape の name ガードを、可能な範囲で「構造判定structural signature」へ寄せる育成フェーズ。
このフェーズでは **name ガードの全面撤去は狙わず**、構造シグネチャで一次判定 → 曖昧な場合のみ dev-only name ガードで絞る二段階 detector を導入する。
### ねらい
- selfhost P2/P3 が JsonParser/canonical 群と混線しないためのガードを、by-name 依存から段階的に縮退させる。
- 将来の selfhost ループ追加Phase 53+)時に「構造で識別できる軸」を SSOT として固定する。
### 構造シグネチャ候補(一次判定)
#### Selfhost P2 core familyTokenScanP2 / TokenScanP2Accum
- Structured JoinModule で `loop_step` が存在し、tail-call で自分自身に戻る P2 ブレークループであること。
- `loop_step` のパラメータ数が **3〜4**`i` + host param + 1〜2 carriersで、body 内に `Select` が出ないこと。
- body の主要 Compute が `Compare`break/cond`Add` 系に限定され、外部/BoxCall が含まれないこと。
- **注意**: JsonParser `skip_ws_mini` と構造が近く、一次判定だけでは区別不能なケースがある。
#### Selfhost P3 if-sum familyIfSumP3 / IfSumP3Ext
- 現状の selfhost baseline は **P2-like skeletonnormalize_pattern2_minimal 委譲)** のままなので、一次判定は「P3 の理想形Select を含む if-sum」を要求しない。
- `loop_step` のパラメータ数が **4**`i` + host param + `sum` + `count`で、break 由来の `Ge` Compareparams 間)が存在すること。
- tail-call によるループ継続を持ち、body が純粋な算術更新のみで、外部/BoxCall が含まれないこと。
### 二段階 detector 方針
1) 上記の構造シグネチャで Selfhost family candidate を一次判定
2) 一次判定が他 shape と曖昧な場合のみ、**dev-only name ガードで最終確定**
name ガードは `normalized_dev` 限定・混線防止用途に閉じ、canonical/本番経路には持ち込まない。
### 撤去条件(次フェーズ)
- Phase 53+ で selfhost 形状のバリエーションが 3〜4 本以上に増え、構造軸carrier 数/Compare 配列/StepSchedule など)が安定したら、
P2/P3 それぞれで name ガードの適用範囲を縮小→最終撤去する。
## 11. Phase 53: SELFHOSTNORMDEVEXPANDdev-only バリエーション拡大)
Phase 5051 で selfhost P2/P3 dev Normalized の足場を構築し、Phase 52 で構造シグネチャ軸carrier 数、Compare 配列等)を導入した。
Phase 53 では **実戦寄りループを P2/P3 各 1〜2 本追加**し、構造シグネチャ軸を育成・name ガード適用範囲を縮小する。
### 追加対象ループdev-only
| ループ名 | 想定パターン | ソース箇所 | キャリア/更新 | 構造的特徴 |
| --- | --- | --- | --- | --- |
| **selfhost_args_parse_p2** | P2 corebreak あり/continue なし) | `apps/selfhost-runtime/runner.hako:20-33` | i + box_pref文字列更新| 1 キャリア、文字列比較多用、StringBox メソッドindexOf/substring |
| **selfhost_stmt_count_p3** | P3 if-sum family多分岐 | `apps/selfhost-runtime/mir_loader.hako:76-89` | i + 9 カウンタr/e/l/iff/lp/br/ct/tr/ex | 9 キャリア、多段 if-else9 分岐、MethodCallst.get/str |
### 選定理由
#### P2: selfhost_args_parse_p2
- **実戦的 P2**: コマンドライン引数パース(`--box-pref=` 等)
- **構造的差異**:
- 既存 P2token_scan, token_scan_accumは数値キャリアのみ
- **本ループ**: 文字列キャリアbox_pref+ StringBox MethodCallindexOf/substring/length
- **構造判定軸育成**: MethodCall 出現パターン、キャリア型多様性
- **name ガード必要性**: StringBox MethodCall が入るため、JsonParser P2 との混線は低い(構造一次判定で十分分離可能)
- **dev-only name ガード**: 最終確定のみ(構造判定が主軸)
#### P3: selfhost_stmt_count_p3
- **実戦的 P3**: MIR 文種別カウントReturn/Expr/Local/If/Loop/Break/Continue/Try/Extern
- **構造的差異**:
- 既存 P3if_sum, if_sum_extは 2〜3 キャリア・単純 if-sum
- **本ループ**: **9 キャリア**r/e/l/iff/lp/br/ct/tr/ex+ **9 分岐**(多段 if-else
- **構造判定軸育成**:
- キャリア数上限検証9 は P3 範囲内か?)
- 多段 if-else パターンSelect チェーン長)
- MethodCall 出現st.get/str
- **name ガード必要性**: MethodCall + 9 キャリアで JsonParser P3 と明確に分離
- **dev-only name ガード**: 構造判定優先、最終確定のみ
### 構造シグネチャ軸育成方針Phase 52 継続)
#### P2 family 構造軸(強化)
1. **キャリア数**: 1〜3 → **型多様性追加**Integer, String, mixed
2. **MethodCall 出現**: なし → **StringBox メソッド許容**indexOf/substring/length
3. **Compare 配列**: `Lt`/`Ge` 単一 → **複合条件(`Eq` 多用)**
#### P3 family 構造軸(強化)
1. **キャリア数上限**: 2〜4 → **9 キャリア検証**P3 範囲内確定)
2. **分岐数**: 単純 if-sum → **多段 if-else9 分岐)**
3. **MethodCall 出現**: なし → **JsonNodeBox メソッド許容**get/str
4. **Select チェーン長**: 構造的計測Normalized 時の Select 深度)
### 二段階 detector 実装方針Phase 52 継承)
```rust
// P2: selfhost_args_parse_p2 detector
fn is_selfhost_args_parse_p2(module: &JoinModule) -> bool {
// 1. 構造一次判定(優先)
if !has_p2_break_pattern(module) { return false; }
let carrier_count = count_carriers(module);
if carrier_count < 1 || carrier_count > 3 { return false; }
// StringBox MethodCall 許容indexOf/substring
let methodcalls = count_methodcalls(module);
if methodcalls > 5 { return false; } // 過剰な MethodCall は除外
// 2. dev-only name 最終確定(曖昧時のみ)
#[cfg(feature = "normalized_dev")]
if !function_name_matches("selfhost_args_parse_p2") { return false; }
true
}
// P3: selfhost_stmt_count_p3 detector
fn is_selfhost_stmt_count_p3(module: &JoinModule) -> bool {
// 1. 構造一次判定(優先)
if !has_p3_if_sum_pattern(module) { return false; }
let carrier_count = count_carriers(module);
if carrier_count < 2 || carrier_count > 10 { return false; } // 9 キャリア許容
// 多段 if-else パターン確認
let branch_count = count_if_else_branches(module);
if branch_count < 2 { return false; }
// JsonNodeBox MethodCall 許容get/str
let methodcalls = count_methodcalls(module);
if methodcalls > 10 { return false; } // 過剰な MethodCall は除外
// 2. dev-only name 最終確定(曖昧時のみ)
#[cfg(feature = "normalized_dev")]
if !function_name_matches("selfhost_stmt_count_p3") { return false; }
true
}
```
### name ガード適用範囲縮小条件
Phase 53 実装後、以下の条件で name ガードを撤去可能:
1. **構造軸が 5 軸以上安定**carrier 数/型/MethodCall 数/Compare 配列/分岐数)
2. **P2/P3 各 6 本以上の dev ループ蓄積**(バリエーション十分)
3. **誤判定率 < 5%**(構造一次判定の精度検証)
現状Phase 53 後):
- P2: 4 本token_scan, token_scan_accum, args_parse, +1 予定)
- P3: 4 本if_sum, if_sum_ext, stmt_count, +1 予定)
- 構造軸: 4 軸carrier 数/型/MethodCall/Compare
- **撤去条件未達** → name ガード継続dev-only
### 受け入れ基準Phase 53
- ✅ P2/P3 各 1〜2 本追加(合計 2〜4 本、最小 2 本)
- ✅ Program JSON + Structured builder 完備
- ✅ ShapeGuard 二段階判定実装(構造一次 + dev-only name 最終)
- ✅ dev VM 比較テスト追加(全 PASS
- ✅ 構造軸 4〜5 本確立carrier 数/型/MethodCall/Compare/分岐数)
- ✅ phase49 doc Phase 53 節完成SSOT
- ✅ 既存挙動不変normalized_dev 以外)
### Out of ScopePhase 54+
- **name ガード完全撤去**: Phase 54 以降で構造軸が十分安定してから
- **canonical 昇格**: Phase 55+ で検討dev 正規化安定後)
- **P4/P5 heavy ループ**: Phase 56+ で段階的追加
### 実装完了記録Phase 53
**実装日**: 2025-12-12
**追加内容**:
1. **Program JSON fixtures**: 2 個
- `selfhost_args_parse_p2.program.json` (P2: string carrier + 条件分岐)
- `selfhost_stmt_count_p3.program.json` (P3: 5 carriers + 多段 if-else)
2. **Structured builders**: 2 個fixtures.rs
- `build_selfhost_args_parse_p2_structured_for_normalized_dev()`
- `build_selfhost_stmt_count_p3_structured_for_normalized_dev()`
3. **ShapeGuard detectors**: 2 個shape_guard.rs
- `is_selfhost_args_parse_p2()` (二段階判定: P2 core family + name guard)
- `is_selfhost_stmt_count_p3()` (二段階判定: 2-10 carriers + name guard)
4. **dev VM 比較テスト**: 2 個normalized_joinir_min.rs
- `normalized_selfhost_args_parse_p2_vm_bridge_direct_matches_structured()`
- `normalized_selfhost_stmt_count_p3_vm_bridge_direct_matches_structured()`
**変更ファイル**:
- `phase49-selfhost-joinir-depth2-design.md` (+128 lines, Phase 53 節)
- `selfhost_args_parse_p2.program.json` (NEW, 60 lines)
- `selfhost_stmt_count_p3.program.json` (NEW, 150 lines)
- `fixtures.rs` (+48 lines, 2 builders)
- `shape_guard.rs` (+80 lines, 2 detectors + enum 拡張)
- `bridge.rs` (+8 lines, 2 shape handlers)
- `normalized.rs` (+10 lines, 2 roundtrip handlers)
- `ast_lowerer/mod.rs` (+2 lines, 2 entry point registrations)
- `normalized_joinir_min.rs` (+40 lines, 2 tests + imports)
**テスト結果**:
- ✅ normalized_dev: 40/40 PASS (2 新規テスト含む)
- ✅ lib regression: 939 PASS, 56 ignored
- ✅ 既存挙動不変確認完了
**構造軸育成成果**:
- P2 family: carrier 数 (1-3) + 型多様性Integer/String
- P3 family: carrier 数上限拡張2-10+ 多段 if-else パターン
- name ガード: 二段階判定で構造一次 + dev-only 最終確定に統一
**次フェーズ方針**Phase 54+:
- P2/P3 各 6 本以上蓄積後に name ガード適用範囲縮小検討
- 構造軸 5 軸以上安定carrier 数/型/Compare/分岐数/StepSchedule
- 誤判定率 < 5% 達成で撤去条件満たす