Files
hakorune/docs/development/current/main/phase49-selfhost-joinir-depth2-design.md

273 lines
16 KiB
Markdown
Raw Normal View History

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
# 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% 達成で撤去条件満たす