feat(phase93): with_core_from_registry implementation complete

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 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-03 08:42:45 +09:00
parent 2f54e64d27
commit b3de4cac4b
5 changed files with 189 additions and 40 deletions

View File

@ -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)]

View File

@ -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<Ring0Context>) -> Result<plugin_host::PluginHost, CoreInitError> {
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, &registry)?;
// 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, &registry)?;
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(),
})
}
}

View File

@ -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<Ring0Context>,
_registry: &UnifiedBoxRegistry,
registry: &UnifiedBoxRegistry,
) -> Result<Self, CoreInitError> {
// 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, &registry);
// Phase 93 で実装後はこのテストを削除
let result = PluginHost::with_core_from_registry(ring0, &registry);
assert!(result.is_err());
// エラーメッセージに "not found" が含まれることを確認
if let Err(e) = result {
let msg = format!("{}", e);
assert!(msg.contains("not found"));
}
}
}