From b3de4cac4b448ae3fd835c0ed528ac9de6232264 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Wed, 3 Dec 2025 08:42:45 +0900 Subject: [PATCH] feat(phase93): with_core_from_registry implementation complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 93 完了: UnifiedBoxRegistry 統合実装 & 起動パス統合 **実装内容**: - with_core_from_registry() 実装 - UnifiedBoxRegistry.has_type() で core Box の存在確認 - 不足時は CoreInitError::MissingService を返す - ダミー Service 実装で CoreServices を構築 - ダミー Service 実装を pub に - DummyStringService, DummyIntegerService 等を公開 - Phase 94 の実変換までの橋渡し - CoreServices::dummy() ヘルパー追加 - フォールバック用ダミー実装 - initialize_runtime() 実装(環境変数制御) - NYASH_USE_PLUGIN_HOST=1 で PluginHost 有効化 - 環境変数なしで従来通り動作(後方互換性) - selfhost に PluginHost 初期化追加 - CoreInitError 発生時は fail-fast - 既存ロジックは変更なし **Fail-Fast 設計**: - 起動時に core Box 不足を即座に検出 - CoreInitError で明示的なエラーメッセージ - デバッグ容易(ランタイムエラーではなく起動時エラー) **テスト結果**: - test_with_core_from_registry_missing_box 追加 - 7件全て成功 - ビルド成功(1分4秒) - 526 passed(既存36失敗は Phase 93 と無関係) **動作確認**: - 環境変数なし: 従来通り動作 ✅ - NYASH_USE_PLUGIN_HOST=1: PluginHost 初期化成功 ✅ - selfhost: fail-fast 動作確認済み ✅ **ドキュメント更新**: - Section 10 追加(77行) - 段階的展開戦略、Fail-Fast 設計を文書化 **次のステップ**: Phase 94 (実際の Box → Service 変換) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../current/main/core_boxes_design.md | 80 ++++++++++++++++ src/runner/selfhost.rs | 15 +++ src/runtime/core_services.rs | 13 +++ src/runtime/mod.rs | 29 ++++-- src/runtime/plugin_host.rs | 92 ++++++++++++------- 5 files changed, 189 insertions(+), 40 deletions(-) diff --git a/docs/development/current/main/core_boxes_design.md b/docs/development/current/main/core_boxes_design.md index 6d044ddb..10ae0eae 100644 --- a/docs/development/current/main/core_boxes_design.md +++ b/docs/development/current/main/core_boxes_design.md @@ -467,3 +467,83 @@ pub fn initialize_runtime(ring0: Arc) -> Result, + registry: &UnifiedBoxRegistry, + ) -> Result { + // Phase 93: 各 core_required Box が registry に存在するか確認 + for id in CoreServices::required_ids() { + let box_name = id.name(); + if !registry.has_type(box_name) { + return Err(CoreInitError::MissingService { + box_id: *id, + message: format!("{} not found in registry", box_name), + }); + } + } + + // Phase 93: ダミー Service 実装で CoreServices を構築 + let core = CoreServices { + string: Arc::new(DummyStringService), + integer: Arc::new(DummyIntegerService), + bool: Arc::new(DummyBoolService), + array: Arc::new(DummyArrayService), + map: Arc::new(DummyMapService), + console: Arc::new(DummyConsoleService), + }; + + Ok(PluginHost { + ring0, + core, + optional: HashMap::new(), + }) + } +} +``` + +### 10.2 段階的展開戦略 + +**Phase 93 アプローチ**: +- 環境変数 `NYASH_USE_PLUGIN_HOST=1` で有効化 +- ダミー Service 実装で動作確認 +- selfhost のみ統合(hack_check は Phase 94) + +**Phase 94 計画**: +- 実際の Box → Service 変換実装 +- 環境変数削除(デフォルトで有効化) +- 全起動パスへの展開 + +### 10.3 Fail-Fast 設計 + +**メリット**: +- 起動時に core Box の不足を即座に検出 +- CoreInitError で明示的なエラーメッセージ +- デバッグ容易(ランタイムエラーではなく起動時エラー) + +### 10.4 動作確認方法 + +```bash +# Phase 93 動作確認 +NYASH_USE_PLUGIN_HOST=1 ./target/release/nyash apps/tests/selfhost_min.hako + +# Phase 93 では環境変数なしで従来通り動作 +./target/release/nyash apps/tests/selfhost_min.hako +``` + +### 10.5 実装されたファイル + +1. `src/runtime/plugin_host.rs`: with_core_from_registry() + ダミー Service 実装 +2. `src/runtime/core_services.rs`: CoreServices::dummy() ヘルパー +3. `src/runtime/mod.rs`: initialize_runtime() 実装(環境変数制御) +4. `src/runner/selfhost.rs`: PluginHost 初期化追加 + diff --git a/src/runner/selfhost.rs b/src/runner/selfhost.rs index 3cb07abb..eca3df9d 100644 --- a/src/runner/selfhost.rs +++ b/src/runner/selfhost.rs @@ -43,6 +43,21 @@ impl NyashRunner { pub(crate) fn try_run_selfhost_pipeline(&self, filename: &str) -> bool { use std::io::Write; + // Phase 93: PluginHost 初期化(環境変数で制御) + if std::env::var("NYASH_USE_PLUGIN_HOST").ok().as_deref() == Some("1") { + let ring0 = crate::runtime::ring0::get_global_ring0(); + match crate::runtime::initialize_runtime(ring0) { + Ok(_plugin_host) => { + eprintln!("[selfhost] PluginHost initialized successfully"); + } + Err(e) => { + eprintln!("[selfhost] CoreInitError: {}", e); + // Phase 93: fail-fast(エラー時は即座に終了) + return false; + } + } + } + // Phase 25.1b: guard selfhost pipeline to Ny-only sources. // `.hako` / other extensionsは Stage‑B / JSON v0 bridge 側の責務なので、 // ここでは Ny/Nyash 拡張子以外は即座にスキップする。 diff --git a/src/runtime/core_services.rs b/src/runtime/core_services.rs index ce6ce13c..62c9ee2a 100644 --- a/src/runtime/core_services.rs +++ b/src/runtime/core_services.rs @@ -79,6 +79,19 @@ impl CoreServices { // Phase 91 では trait が空なので何もしない // Phase 92 以降で各 Service の初期化を検証 } + + /// Phase 93: ダミー実装(Phase 94 で削除予定) + pub fn dummy() -> Self { + use crate::runtime::plugin_host::*; + Self { + string: Arc::new(DummyStringService), + integer: Arc::new(DummyIntegerService), + bool: Arc::new(DummyBoolService), + array: Arc::new(DummyArrayService), + map: Arc::new(DummyMapService), + console: Arc::new(DummyConsoleService), + } + } } #[cfg(test)] diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index fb61d651..7502222f 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -59,18 +59,31 @@ pub use unified_registry::{ // Use unified plugin loader (formerly v2) // pub use plugin_loader::{PluginLoaderV2 as PluginLoader, get_global_loader_v2 as get_global_loader}; // legacy -/// Runtime 初期化(Phase 92: 接続ポイント決定) +/// Runtime 初期化(Phase 93: 実装完了) /// -/// Phase 93 で実装予定の接続ポイント。 -/// Phase 92 では skeleton のみ(todo!() を呼ぶ)。 -#[allow(dead_code)] +/// 環境変数 NYASH_USE_PLUGIN_HOST=1 で PluginHost を有効化。 pub fn initialize_runtime(ring0: std::sync::Arc) -> Result { use crate::box_factory::UnifiedBoxRegistry; - let registry = UnifiedBoxRegistry::new(); + let registry = UnifiedBoxRegistry::with_env_policy(); - // Phase 92: 接続ポイント決定(実装は Phase 93) - let plugin_host = plugin_host::PluginHost::with_core_from_registry(ring0, ®istry)?; + // Phase 93: 環境変数で有効化(段階的展開) + let use_plugin_host = std::env::var("NYASH_USE_PLUGIN_HOST") + .ok() + .and_then(|v| if v == "1" { Some(()) } else { None }) + .is_some(); - Ok(plugin_host) + if use_plugin_host { + let plugin_host = plugin_host::PluginHost::with_core_from_registry(ring0, ®istry)?; + plugin_host.ensure_core_initialized(); + Ok(plugin_host) + } else { + // フォールバック(Phase 94 で削除予定) + let core = core_services::CoreServices::dummy(); + Ok(plugin_host::PluginHost { + ring0, + core, + optional: std::collections::HashMap::new(), + }) + } } diff --git a/src/runtime/plugin_host.rs b/src/runtime/plugin_host.rs index d93e255d..ad2f4c08 100644 --- a/src/runtime/plugin_host.rs +++ b/src/runtime/plugin_host.rs @@ -90,17 +90,40 @@ impl PluginHost { /// UnifiedBoxRegistry から core_required Box を取得して CoreServices を初期化 /// - /// Phase 92: skeleton のみ(Phase 93 で実装) - #[allow(dead_code)] + /// Phase 93: ダミー Service 実装(存在確認のみ) + /// Phase 94: 実際の Box → Service 変換実装予定 pub fn with_core_from_registry( ring0: Arc, - _registry: &UnifiedBoxRegistry, + registry: &UnifiedBoxRegistry, ) -> Result { - // Phase 93 で実装予定 - // TODO: registry から core_required Box を取得 - // TODO: 各 Box を対応する Service trait に変換 - // TODO: CoreServices を構築 - todo!("Phase 93: UnifiedBoxRegistry から CoreServices への変換実装") + // Phase 93: 各 core_required Box が registry に存在するか確認 + for id in CoreServices::required_ids() { + let box_name = id.name(); + + // Phase 93: has_type() で存在確認 + if !registry.has_type(box_name) { + return Err(CoreInitError::MissingService { + box_id: *id, + message: format!("{} not found in registry", box_name), + }); + } + } + + // Phase 93: ダミー Service 実装で CoreServices を構築 + let core = CoreServices { + string: Arc::new(DummyStringService), + integer: Arc::new(DummyIntegerService), + bool: Arc::new(DummyBoolService), + array: Arc::new(DummyArrayService), + map: Arc::new(DummyMapService), + console: Arc::new(DummyConsoleService), + }; + + Ok(PluginHost { + ring0, + core, + optional: HashMap::new(), + }) } /// core_required が全て揃っているか検証 @@ -109,6 +132,25 @@ impl PluginHost { } } +// Phase 93: ダミー Service 実装(Phase 94 で削除予定) +pub struct DummyStringService; +impl super::core_services::StringService for DummyStringService {} + +pub struct DummyIntegerService; +impl super::core_services::IntegerService for DummyIntegerService {} + +pub struct DummyBoolService; +impl super::core_services::BoolService for DummyBoolService {} + +pub struct DummyArrayService; +impl super::core_services::ArrayService for DummyArrayService {} + +pub struct DummyMapService; +impl super::core_services::MapService for DummyMapService {} + +pub struct DummyConsoleService; +impl super::core_services::ConsoleService for DummyConsoleService {} + #[cfg(test)] mod tests { use super::*; @@ -132,25 +174,6 @@ mod tests { // panic しないことを確認 } - // ダミー Service 実装 - struct DummyStringService; - impl StringService for DummyStringService {} - - struct DummyIntegerService; - impl IntegerService for DummyIntegerService {} - - struct DummyBoolService; - impl BoolService for DummyBoolService {} - - struct DummyArrayService; - impl ArrayService for DummyArrayService {} - - struct DummyMapService; - impl MapService for DummyMapService {} - - struct DummyConsoleService; - impl ConsoleService for DummyConsoleService {} - #[test] fn test_core_services_all_fields() { let services = CoreServices { @@ -223,14 +246,19 @@ mod tests { } #[test] - #[should_panic(expected = "Phase 93")] - fn test_with_core_from_registry_todo() { - // Phase 92: todo!() を返すことを確認 + fn test_with_core_from_registry_missing_box() { + // Phase 93: registry が空の場合はエラーを返すことを確認 use crate::runtime::ring0::default_ring0; let ring0 = Arc::new(default_ring0()); let registry = UnifiedBoxRegistry::new(); - let _result = PluginHost::with_core_from_registry(ring0, ®istry); - // Phase 93 で実装後はこのテストを削除 + let result = PluginHost::with_core_from_registry(ring0, ®istry); + assert!(result.is_err()); + + // エラーメッセージに "not found" が含まれることを確認 + if let Err(e) = result { + let msg = format!("{}", e); + assert!(msg.contains("not found")); + } } }