docs: restore docs/private/roadmap from 7b4908f9 (Phase 20.31)

This commit is contained in:
nyash-codex
2025-10-31 18:00:10 +09:00
parent 1d49e24bf0
commit 8fd3a2b509
433 changed files with 108935 additions and 0 deletions

View File

@ -0,0 +1,386 @@
# Phase31 — Box NormalizationStatic→Singleton 正規化)
最終更新: 20251022Verifier 移行表追加quick profile の intern 監視を静音化)
## サマリ
- ねらい: すべてのメソッド呼び出し形を「me + args」に統一し、static box を型ごとのシングルトンインスタンス(`Type.singleton`)に正規化する。
- 効果: ルータ分岐削減、receiver 有無によるバグ根絶(今回の ArrayBox(1) 類、Extern/HostBridge 経路の単純化、AOP/計測の注入点の一元化。
- 方式: Builder で `Static(Type.method(args)) → Instance(Type.singleton.method(args))` に書換。ルータは常に receiver を渡す。Verifier で逸脱を FailFast。
- 導入: フラグ既定OFFで段階導入A→B→C。プラグイン側で `len`/`length` エイリアスを正規化(トランポリン撤退済み)。
### 追加計画Phase31 取り込み)— MIR 正規化とアーキ境界の固定
- MirCall 一本化(最小カノニカル形)
- 許可: `Method` / `ModuleFunction("Box.m/arity")` / `Constructor` / `Extern`(補助: `Value`/`Closure`
- 禁止: Legacy `BoxCall/ExternCall/Print/生 NewBox`、Box Eq/NeEnum は `.equals()`、その他は `nyrt.ops.op_eq`
- 参考: `docs/development/architecture/mir/mir-canonical-calls.md`
- Three RingsCore/Meta/Domainで責務を分離
- Meta は「プラグイン様式で実装」だが既定は内蔵LTO/inline。Domain は外部プラグイン。Core は不可抜き。
- 参考: `docs/development/architecture/three-rings.md`
- 二層エクスポートStable ABI + Inlinable API
- 既知先は直呼びKnown/Rewrite未知先は rt_boxcall 集約。Intern安定IDで解決子を決定化。
- 参考: `docs/development/architecture/abi/two-layer-export.md`
実施方針段階導入・既定OFF
- Phase ADocs/型定義のみ): 文書の追加・MirCall::CallFlags の拡張may_throw/tail_ok/inline_hint
- Phase BBuilder/Verifierの小正規化: NewBox→Constructor、Print撤退、Box Eq/Ne 正規化strictガードは既存を拡張
- Phase CKnown/Rewrite 最適化・Metaのみ: Enum/Callable の純粋メソッドを直呼び(パリティスモーク追加)
- Phase D恒久化: レガシー禁止を既定ON、Intern ID 既定ONダンプは name+id 併記)
### Phase C.1Selfhost Parity — MirCall/Static Box/Constructor
- 目的: Rust 線Builder/VM/LLVMの MirCall 正規形と SelfhostHakorune Scriptの Compiler/VM を同形に揃えるSSOT
- 範囲:
- Selfhost VM: ModuleFunction 名を受理時に `Box.method/arity` へ正規化(将来は Emitter 側で常時 `/arity` 付与)。
- Selfhost VM: `Callee::Constructor{box_type}` を処理し birth 呼び出しまでを担当。legacy `NewBox` は不可。
- Selfhost Emitter: ModuleFunction 発行ヘルパを追加し、`/arity` の付与を一元化。
- 非目標:
- Stage1 JSON の糖衣→正規形RewriteKnown 本実装)は次フェーズで導入。
- 検証:
- quick/integration スモークのパリティ回帰ゼロModuleFunction `/arity` 有無・Constructor 0/1/2/3
### 今日の更新P0仕上げP1 部分)
- host anchors: `nyash_array_new_h` を既定ONfeature gate 撤去)。
- extern_adapter(Array/Map): `nyrt.array.size` 受領者の HostHandle unwrapMap.keys/values/size の dev ログ追加。
- Router 再配線: `PluginBoxV2` の Array/Map スロットを表テーブル前提で正規に通すbuiltin/plugin 両経路)。
- env 読み統一: runtime 配下の直 `std::env::var``env_gate_box` に寄せ(進行中)。
- Router/Adapter 回帰テスト: `map_host_keys_values_return_arrays` / `map_remove_returns_removed_array_len` などを追加し、HostSlot/Plugin 両経路で ArrayBox が返ることを固定。
- Type ID 単一起点: Router/extern/loader から直 `builtin_type_id("MapBox")` や固定値参照11/12/13を排除し、`crate::types::ids::{map,array,string,by_name}` へ統一。rg 監視で再発チェックを継続。
- Reentrant Guardhost slot 中の再入許可): Map.values() → Array.set の再入を slot 配下のみ許可し、連鎖を安定化。
- 実装: `host_api::nyrt_host_call_slot` 実行中に threadlocal `IN_HOST_SLOT=true` を設定し、`plugin_loader_unified` のガードを `recursed && !in_slot` に変更。
- 効果: values→Array.set→Array.size の連鎖が正しく成立。代表スモーク `map_values_array_element_vm` は PASS。
#### Runtime meta 層Callable/Futureの箱化追加
- ねらい: 言語機能の足場Callable/Futureをホスト所有の薄い箱として分離し、プラグイン/外部I/Oの逆流を構造で防止。
- 実装: `src/runtime/meta/{callable,future}/` を新設。README と LAYER_GUARD で責務を明記。
- 互換: 既存の `runtime::{callable_box,future_box}` re-export は撤去済み。新規・既存ともに `runtime::meta::{callable,future}` を使用。
- 影響: plugin-only/legacy いずれのビルドでも Callable/Future が安定router/scheduler への依存のみ)。
#### HostHandle -14 検知(境界テストの安定化・追加)
- ENV: `HAKO_HOSTHANDLE_TEST_RET_MISMATCH=1`(互換 `NYASH_HOSTHANDLE_TEST_RET_MISMATCH=1`)で String.len 経路を -14 として観測。
- 実装: VM の HostSlot/Extern で rc を stdout に `hosthandle-test rc=-14` として出力(テスト専用)。
- スモーク: `tools/smokes/v2/profiles/plugins/hosthandle_boundary_suite_vm.sh` は一時ファイルに退避してから `-14` を grepPIPE 経由の出力欠落を回避)。
#### P1 安定化(今回分)
- builtin ルータ: ARRAY/MAP の host route 判定を devonly ログで観測可能に(`HAKO_DEBUG_HOST_SLOT=1`)。
- extern_adapter: Array/Map のレガシー分岐を撤去し、HostHandle unwrap をハブ化。`nyrt.array.size`/`nyrt.map.{keys,values,size}` の戻り値を正規化。
- 回帰テスト追加:
- ParameterGuardBoxENV ON/OFF
- ループヘッダ PHI 即時挿入(先頭固定・更新 inplace
- DCE: Method 受け手Closure captures の Copy 温存。
- Router/Adapter今回追記:
- `map_host_keys_values_return_arrays` — HostSlot 強制下で keys/values → ArrayBox → len が成立することを固定(ユニット)。
- `map_remove_returns_removed_array_len` — remove が削除値ArrayBoxを返し、直後に len を呼べることを固定(ユニット)。
### 次の一手B段— プラグイン互換トランポリン撤退(完了)
- 旧互換ラッパ(`HAKO_PLUGIN_TRAMPOLINE`)は 2025-10-18 時点で撤去。
- len/length エイリアスは各プラグインArrayBox/MapBox/StringBoxが直接解決済み。
- 追加ガードは不要。以降はプラグイン本体と Router テーブルで整合を維持する。
## スコープ / 非対象
- 対象
- 呼び出し形状の統一MIR/Builder/Router/Verifier
- プラグイン/Extern/HostBridge の呼び出し規約整合
- selfhost 側の静的メソッドHako→ instance 形の糖衣
- 非対象(今回やらない)
- 言語仕様の新規拡張(デフォルト引数・可変長シンタックスなど)
- 既存最適化のチューニング(導入後に計測して別フェーズ)
## ゴール(受け入れ基準)
- すべての static 呼び出しが MIR 上で `receiver=Type.singleton` に正規化される。
- ルータは receiver を常に受ける前提で動作し、static/instance の分岐が無い。
- Verifier が「receiver 欠落」や「static 直呼び」を検出して FailFast開発時
- プラグイン ABI は各 Box resolver が直接エイリアスを提供トランポリンなし。既存スモークquick→plugins→full緑。
- HostBridge/Extern の呼び出しは `me + args` 規約に統一。引数正規化(プリミティブ化)で再発無し。
## 非機能(性能/安定)
- LLVM/VM: `me` 未使用は inlining + DCE で最終的に消える(同一バイナリ/LTO 前提)。
- 動的リンク(.so越し: 追加 1 引数のコストは微小。必要箇所は旧 ABI のエイリアスを維持。
---
## 設計(構造)
### 1) 呼び出し正規化Builder
- 変換規則(疑似):
- `Call ModuleFunction("Type.method/N", args)` かつ `method != birth``Callee::Method { box_name: "Type", receiver: Some(Type.singleton), method }`
- 既に instance の場合は変換無し。
- 影響ファイル(予定):
- `src/mir/builder/calls/method_resolution.rs`
- `src/mir/builder/builder_calls/*`ModuleFunction 経路)
### 2) ルータVM/ランタイム)
- 常に `receiver` を渡す前提に一本化static/instanceの分岐を削除
- 不変: `birth()` の取り扱い(自動/明示)は既存契約維持。
- 影響(例):
- `src/backend/mir_interpreter/handlers/calls/function.rs`ModuleFunction ブリッジ)
- `src/backend/mir_interpreter/handlers/boxes/legacy/mod.rs`BoxCall ディスパッチ)
- `src/runtime/method_router_box/*`(外部/Plugin 経路の期待形)
### 3) VerifierFailFast
- ルール:
- ModuleFunction 直呼びstatic 形)が残っていたらエラー。
- Method の `receiver=None` は禁止。
- static 正規化の `me` は観測不可(反射禁止)…観測を試みるパスを警告/エラー。
- 影響: `src/mir/verify/*`
### 4) プラグイン ABI 互換(直接 alias
- len/length などの互換は各プラグインの `resolve` 実装で提供。
- 追加トランポリンや自動生成スクリプトは不要。
### 5) HostBridge/Extern橋渡しの一元化
- 規約: `Extern(iface.method)` のハンドラは常に `me + args` 形に揃える(必要なら内部で `singleton` を補う)。
- 引数正規化: BoxRefArrayBox 等)→プリミティブ化は既存の `normalize_extern_arg`VMへ集約。
---
## ガード/フラグ
- `HAKO_STATIC_AS_SINGLETON=1`NYASH_* alias 可) … 既定OFF、A/B/C 段階で切替。
- CLI 既定は変更しない。ENV は短命(導入〜安定化まで)。
## ドキュメント / LAYER_GUARD
- `docs/development/proposals/` に本設計の背景と対処(この文書を索引)。
- LAYER_GUARD意図
- Router 層: 「receiver 必須」。ModuleFunction の直参照禁止。
- Builder 層: static→singleton 正規化必須。抜けはテストで遮断。
- Extern 層: プリミティブ引数化と `me+args` 契約。
---
## 段階導入A/B/C
### Phase A実験・既定OFF
- 実装
- Builder 正規化static→singleton
- ルータ分岐の掃除receiver 常時)
- Verifier 追加(開発時のみ Fail
- プラグイン resolver の alias 対応を確認
- スモーク
- static/instance 同名メソッドの一致
- HostBridge 経路externでの等価性
- 成果: quick 緑 + plugins 代表 PASS
### Phase B小正規化・互換検証
- Builder 正規化
- ModuleFunction の `me` 注入を emit 段に集約。Builder 出力はユーザ引数のみ。
- Print を入口で `env.console.log` 経路へ統一(`MirInstruction::Print` 撤退)。
- `NewBox` 発行を Constructor 呼び出しに統一tests では `crate::tests::support::constructor_call` で固定)。
- Eq/Ne の Box 比較は既定で `nyrt.ops.op_eq`Enum は `.equals()` 正規化。プリミティブのみ Compare を維持。
- Verifier 強化
- Legacy 禁止リストに `NewBox` を追加既定ON
- static ModuleFunction の `me` 欠落/型不一致を Fail-Fast する検査を追加。
- Optimizer / Runtime
- Constructor callee を VM handler で取り扱い(既存 `handle_new_box` に委譲)。
- Lifecycle ガードNewBox→birthの検査を Constructor 経路にも対応。
- テスト
- 既存 MIR ユニットを Constructor 経路に移行し、受領者/Alloc 効果を固定。
### Phase C完了: Meta Known + Intern 観測)
- Meta Known/Rewrite
- `EnumBox` 純粋メソッドtag/arity/get/equals/toStringを ModuleFunction 経由で統一 → Optimizer が `Method(receiver=Type.singleton)` に縮約。
- `ArrayBox`/`StringBox` `methodRef/2` を ModuleFunction 呼び出しへ統一し、CallableBox 経路の素材化を一本化。
- `CallableBox.arity/0` は READ 効果に固定call/async pipeline と分離)。
- Gate: `NYASH_REWRITE_META_KNOWN`既定ONoptout: `=0`)。
- Intern 観測
- `NYASH_DUMP_INTERN=1` で ModuleFunction/Extern 名 ↔ 64bit 安定ID を逐次ダンプ(デバッグ向け)。
- `NYASH_DUMP_INTERN_TABLE=1` で関数単位の集計を1回ダンプ必要時に quick profile で opt-in
- SelfhostHakorune Scriptラインも同じ MirCall 正規形で出力し、Rust VM/LLVM とパリティ確保済み。
### Phase D恒久化へ移行中
- Verifier
- Legacy 禁止Print / 生 NewBox / Box Eq・Ne / ModuleFunction `me` 注入違反を既定ONに固定。strict モードは警告専用へ移行。
- Optimizer
- Builder で完了した Print/Constructor 正規化の重複Rewriteを撤去し、統一経路のみ残す。
- Known/Rewrite の safe whitelist をメタ箱全般に拡張CallableBox など追加分を段階導入)。
- Intern
- Stable ID 採用Callee payloadに name+id を併記)への布石として API/ドキュメントを整備。
- スモーク/プロファイル
- integration profile の自己ホスト parity 期待値を現行 resolver 診断に合わせて更新し、常緑化を完了。
- quick profile は既定で quiet`NYASH_DUMP_INTERN_TABLE=0`)。観測が必要なときのみ opt-in する。
- 20251022 時点: quick profile で `userbox_birth_to_string_vm` など 9 件が未緑。
- `setField` が static singleton 正規化前の経路を通っており、Phase31 B/C の follow-upUserBox/Enum マクロ)で修正予定。
- HakoruneJsonCursorBox.* の `/arity` 付与、using strict 系の exit code/nyash.toml 整理も同バッチで扱う。
- Integration 既定env/log ポリシー):
- `HAKO_QUIET=1`, `HAKO_DISCOVER_MODULES=0`, `NYASH_NYRT_SILENT_RESULT=1`
- Meta Known/Rewrite 既定ON`NYASH_REWRITE_META_KNOWN=1`Intern Table は既定OFF
- Macro runner の子プロセスを無効化argv超過/ノイズ抑止)
- `NYASH_MACRO_BOX_CHILD=0`, `NYASH_MACRO_BOX_CHILD_RUNNER=1`, `NYASH_NY_COMPILER_TIMEOUT_MS=4000`
- ランナーの `filter_noise``[macro]` 系/`-- child stderr --` を抑制(詳細は env ガイド参照)
### P0直近の仕上げ — 小さく強い箱の固定化)
- UsingResolver の SSOT 化(入口一本化)
- `UsingResolver.resolve(entry) -> ModuleSet` を runner/CLI/tests の単一起点にする。
- ENV の解釈は UsingResolver 内に集約。下流は `ModuleSet` のみを受領。
- Verifier 既定ONの拡張
- Legacy 命令Print/BoxCall/ExternCall/生 NewBoxを禁止既定ON
- Box Eq/Ne の Compare を禁止Enum は `.equals()`/その他は `nyrt.ops.op_eq`)。
- ModuleFunction `me` 注入違反(欠落/型不一致)を FailFast。
- LLVM Resolver 健全性ガードdebug
- ret 値が Exit 内定義 or ExitPHI の不変条件を debug_assert で検査。
- ExitPHI 作成時に preds と incoming が一致することを検査。
#### Verifier 移行表strict → 既定ON
| チェック内容 | strict 導入 | 既定ON | 備考 |
| --- | --- | --- | --- |
| `MirInstruction::Print` 検出Print 経路の禁止) | Phase Bdev gate | Phase D | Builder/Emitter で `env.console.log` 正規化済み。 |
| `NewBox` 命令の禁止Constructor 経路のみ許容) | Phase B | Phase B | Builder 正規化と同時に既定ON。 |
| Box Eq/Ne の直接 Compare 禁止Enum は `.equals` | Phase B | Phase D | `NYASH_ENUM_STRICT` 併用で Enum の診断を強化。 |
| ModuleFunction `me` 注入違反(欠落/型不一致) | Phase B | Phase D | `emit_guard` 側での receiver 素材化と連動。 |
| Enum Compare(Eq/Ne)`.equals` 以外の経路) | Phase B | (開発フラグ) | `NYASH_ENUM_STRICT=1` で強制。将来 Phase32 で既定ON 予定。 |
---
## 変更対象(実施済/予定ファイル・開始行)
- Builder
- `src/mir/builder/calls/method_resolution.rs`(静的→受領者注入)
- VM/Router
- `src/backend/mir_interpreter/handlers/calls/function.rs`
- `src/backend/mir_interpreter/handlers/boxes/legacy/mod.rs`
- `src/runtime/method_router_box/*`
- Verifier
- `src/mir/verify/*`(新規/既存拡張)
- プラグイン/Extern
- `src/backend/mir_interpreter/handlers/calls/legacy/extern_handler.rs`(規約コメント追加・整合)
---
## テスト計画
- 単体
- static→singleton 正規化の生成確認MIR 形状)
- receiver 欠落時の Verifier エラー
- 結合
- Routerbuiltin/pluginでの一貫ディスパッチ
- HostBridgeextern経路の文字列/数値/配列の正規化
- スモーク
- quick→plugins→full の差分比較(代表)
- selfhost 側の静的 APIHako
- meta 層の代表確認plugins プロファイル):
- `tools/smokes/v2/profiles/plugins/callable_async_plugin_vm.sh`Future 表示安定)
- `tools/smokes/v2/profiles/plugins/plugin_map_len_vm.sh`len エイリアス整合)
- `tools/smokes/v2/profiles/plugins/set_bad_arity_vm.sh`arity ガード FailFast
- 受け入れ基準
- 既存スモーク緑 + 新規スモークstatic/instance 等価)緑
- LLVM/VM 出力差異がゼロ/許容範囲
---
## リスクと対策
- 互換性リスク(プラグイン): resolver alias を Fail-Fast 方針で維持。段階導入。
- 反射の観測: LAYER_GUARD と Verifier。ドキュメントで未定義化を宣言。
- 性能劣化: ベンチで観測し、必要ならホットパスのみ旧 ABI 直呼びエントリを併存。
## ロールバック
- `HAKO_STATIC_AS_SINGLETON=0` で旧挙動へ即時復帰。
---
## 実装 TODOP0→
1. Builder に static→singleton 正規化を実装(最小: String/Array/Map 代表)
2. Router の receiver 常時渡しを再点検(不要分岐の撤去)
3. Verifier 追加ModuleFunction 直呼び/receiver 欠落の Fail
4. スモーク追加static/instance 等価、extern 経路)
5. Docs 反映(ガイド/リファレンス/ENV 記載)
### 本日の優先P0追記
- Array.size 正規化の徹底Builder normalize → `Extern("nyrt.array.size")` 固定、Optimizer で巻き戻し禁止)
- EmitGuard 後の LocalSSA 素材化の再確認values→size 連鎖で未定義参照を出さない)
## 付録(インターフェース最小定義)
- `Type.singleton(): &Type`(内部/once 初期化、外部観測不可)
- 呼び出し正規化: `Static(Type.method(args)) → Method(Type.singleton, args)`
- Verifier: ModuleFunction 直呼び/receiver=None を禁止
---
> 補足: 今回のバグArrayBox(1) 漏れの根は「受け渡し規約が2通りあった」こと。構造で1通りに揃えるのが再発防止の最短路だよ。
---
## 進捗(実装済み)
### Phase A1b — 関数スコープのシングルトン・キャッシュ導入(完了)
- 目的: `emit_static_me_placeholder()` を各所で都度呼ぶ“分散生成”をやめ、関数内で 1 回だけ生成して再利用する。
- 実装:
- `MirBuilder.current_fn_singletons: HashMap<String, ValueId>` を追加。
- 関数開始時にスコープを作り、関数終了時に復元(キャッシュは関数単位で生存)。
- `maybe_prepend_static_me()` から `current_fn_singleton(box_name)` を利用し、ModuleFunction 経由の静的呼び出しに一貫して `me` を付与。
- 変更点(主な参照):
- `src/mir/builder.rs:176, 448-468` — キャッシュ本体とプレースホルダ生成の単一ルート。
- `src/mir/builder/builder_calls/build.rs:39-46, 138-149, 232-241, 249-258, 265-274``maybe_prepend_static_me()` による受領者注入。
- `src/mir/builder/builder_calls/lowering.rs` — メソッド/静的メソッドを関数化する際にキャッシュを save/restore。
- `src/mir/builder/lifecycle.rs:50``main` 構築時のキャッシュ初期化。
- 効果:
- 同一関数内の静的メソッド連続呼び出しで `me` プレースホルダの重複生成が解消。
- 将来の OnceLock 実体置換を 1 箇所で行える導線ができた。
### Phase A1c — ModuleFunction alias 整備 & Verifier 補強(完了)
- 目的: ModuleFunction 経由の静的呼び出しで receiver 欠落を早期検出し、VM 側も常に receiver あり前提に揃える。
- 実装:
- Verifier: `ModuleFunction(box.method/arity)` で Known かつ Box 型の受領者が無い場合に FailFast。
- Runtime: MethodRouter が Void 受領者を即時 InvalidInstruction とし、legacy fallback も receiver 前提に統一。
- ModuleFunction alias: `handlers/calls/trampolines.rs` を追加し、Array/Map/String/Console の ModuleFunction → Method 変換を表駆動化。
### Phase A1d — LegacyCallBridgeBox 導入(完了)
- 目的: `emit_instruction(MirInstruction::Call)` の直叩きを Builder から排除し、ガード済みの入口に集約する。
- 実装:
- `src/mir/builder/calls/legacy_bridge/` に LegacyCallBridgeBox を新設し、旧 `emit_legacy_call` の本体を移設。
- すべてのレガシー Call 発行を `emit_call_with_guard`EmitGuard経由に統一するヘルパ `emit_call()` を追加。
- BoxCall/PluginCall も `emit_boxcall()` でローカルSSA素材化→`emit_box_or_plugin_call` へ流すようガード化。
- `src/mir/builder/builder_calls/emit.rs``emit_legacy_call` は Box への委譲のみとし、モジュール境界でレガシー経路を閉じ込めた。
- 効果:
- Guard を通さない Call が発生しなくなり、Extern/Method/Global いずれも素材化漏れを検出可能に。
- レガシー経路が単一ファイルに箱化されたことで、段階的削除将来的なフェーズB/Cや差分追跡が容易に。
### Phase A2 — singleton 実体lazy 初期化)導入(完了)
- 目的: `emit_static_me_placeholder()` が生成する Void const を実体 BoxRef に置き換える。
- 実装:
- `runtime/static_singleton.rs` を追加し、`OnceCell<Mutex<…>>` で Box 名ごとのシングルトンを lazy 作成。
- Interpreter `handle_const``MirType::Box(..)` を検知した場合に `static_singleton::get()` を参照し、`VMValue::BoxRef` を登録。
- 効果:
- MIR 側は Box 型として `me` を扱い、VM 実行時に実体 Arc<NyashBox> が注入される。後続のマクロ/Verifier 強化に備えて受領者が具体化された。
### Phase A3 — ループヘッダー PHI の「真のループキャリア変数」化(完了)
- 目的: ループ条件で一時文字列(例: `ch`)が PHI 化され、`i < s.size()` が誤って `ch < s.size()`String vs Integerになる問題を根治する。
- 実装:
- `build.rs` 側で preheader の変数スナップショットを取得し、事前スキャンで得た `assigned_vars` との積を取って PHI 対象を決定。
- 実装箇所: `src/mir/loop_builder/build.rs:36` 付近preheader_vars キャプチャと loop_carried 生成)、`src/mir/loop_builder/phi.rs:14-48`PHI 対象の retain
- 効果:
- ループ条件の比較型が安定。`tools/smokes/v2/profiles/quick/apps/json_query_vm.sh` が PASS以前の `String("0") < 1` 失敗が消失)。
### 残タスクPhase A 継続)
-**ParameterGuardBox 拡張**
Builderpending entry copy を含む)と optimizer `repair_*``dst ∈ params` を禁止済み。v%0 上書き事故を構造的に遮断。
-**Verifier 層の追加**
`check_no_parameter_reassignment` を追加し、MIR 完成後もパラメータ再定義を FailFast。
- **EmitGuard 後の ArrayBox.size 固定(継続中)**
`map.values()``.size()` の連鎖を `nyrt.array.size` へ確実に正規化し、EmitGuard の一度だけで素材化が済むよう整理するNormalizer で Method 巻き戻し禁止)。現在 json_query_vm で `String("0") < 1` という残バグを追跡中。
- **RouterPolicy のログ拡張**
`Route::BoxCall` 強制時の理由を mat-trace に記録し、Singleton 正規化後の逸脱調査を容易にする。
### Phase A1e — Map.size 正規化 & Extern 安定化(完了)
- 目的: `MapBox.(size|len|length)``Extern("nyrt.map.size")` に統一し、Method 形の残存で起きる受領者素材化漏れを排除。
- 実装:
- `src/mir/builder/normalize/map_length.rs` 新設。`normalize::apply_all` に組み込み。
- Optimizer 側で `nyrt.map.size` の Method への巻き戻しを抑止。
- Lowering で `MapBox.size/0``nyrt.map.size(recv)` の直下ろしを追加。
- 効果: plugins プロファイルの `parity_map_size_has_vm` / `strict_plugin_map_size_vm` が PASS。
### Phase A1f — Map.keys/values と remove の整備(完了)
- 目的: `Map.values()` の戻り値を ArrayBox として統一し、`.size()` 連鎖で未定義値HostHandle 漏れが発生しないよう構造化。
- 実装:
- `extern_adapter/collections.rs` を新設し、HostHandle unwrap をハブ化。`nyrt.map.{keys,values}` / `nyrt.array.size` が常に実体 Box を扱うよう統一。
- Extern adapter を host slot テーブル経由+ PluginV2 経路の二本で正規化し、両経路で `VMValue::BoxRef` を返却。
- Map プラグインの `remove()` を HostHandle/TLV 返却へ統一し、削除した値を呼び出し元で即利用できるよう調整。
- テスト:
- `map_host_keys_values_return_arrays` / `map_remove_returns_removed_array_len` を追加し、HostSlot 強制と plugin route の双方で ArrayBox が返る・`len()` が成立することを固定。
- `map_values_array_element_vm.sh` / `map_remove_returns_value_vm.sh` / `plugin_map_len_vm.sh` で代表スモークを常時監視。
### Known issues20251019 時点)
- me 注入の誤適用により plugin ModuleFunction へ影響する懸念。
- 対処: `method_index.static_signature()` に該当する静的シグネチャのみ `me` 合成を許可Builder/VM 双方でガード)。
- FileBox 系の `use of undefined value` は引数素材化の漏れが原因。
- 対処: mir_call 作成前後の LocalSSA を全発行経路に適用済みかスイープし、欠落箇所を補強EmitGuard で統一)。
- Plugin ABI: 既存 C ABI 互換エントリを registry に登録し、外部呼び出し経路を段階移行resolver alias で完結)。
- Docs/Tests: Phase-31 変更点のドキュメント整備とスモーク追加singleton/Verifier 回り)。
### 現在の既知問題dev
- quick→plugins→full でのカテゴリ 2/3出力差・モジュール解決の再確認が未実施。LegacyCallBridgeBox 導入後、差分の再スキャンが P05 で残っている。
- Plugin ABI の追加トランポリンは不要。残りは resolver/Router 側の整合性チェックのみ。