diff --git a/src/runtime/plugin_loader_v2/enabled/loader/library.rs b/src/runtime/plugin_loader_v2/enabled/loader/library.rs index 25363f71..52ece2aa 100644 --- a/src/runtime/plugin_loader_v2/enabled/loader/library.rs +++ b/src/runtime/plugin_loader_v2/enabled/loader/library.rs @@ -11,12 +11,50 @@ use std::sync::Arc; pub(super) fn load_all_plugins(loader: &PluginLoaderV2) -> BidResult<()> { let config = loader.config.as_ref().ok_or(BidError::PluginError)?; - for (lib_name, lib_def) in &config.libraries { - load_plugin(loader, lib_name, lib_def)?; + + // Phase 134 P0: Best-effort loading + // Failures don't stop the entire load process + let mut loaded_count = 0; + let mut failed_count = 0; + + // Load libraries in deterministic order (sorted by name) + let mut lib_items: Vec<_> = config.libraries.iter().collect(); + lib_items.sort_by_key(|(name, _)| *name); + + for (lib_name, lib_def) in lib_items { + match load_plugin(loader, lib_name, lib_def) { + Ok(()) => loaded_count += 1, + Err(_) => { + failed_count += 1; + // Log already printed by load_plugin, continue + } + } } - for (plugin_name, root) in &config.plugins { - load_plugin_from_root(loader, plugin_name, root)?; + + // Load plugins in deterministic order (sorted by name) + let mut plugin_items: Vec<_> = config.plugins.iter().collect(); + plugin_items.sort_by_key(|(name, _)| *name); + + for (plugin_name, root) in plugin_items { + match load_plugin_from_root(loader, plugin_name, root) { + Ok(()) => loaded_count += 1, + Err(_) => { + failed_count += 1; + // Log already printed by load_plugin_from_root, continue + } + } } + + // Phase 134 P0: Log summary + if failed_count > 0 { + get_global_ring0().log.warn(&format!( + "[plugin/init] loaded {} plugins, {} failed", + loaded_count, failed_count + )); + } + + // Continue with singleton prebirth even if some plugins failed + // This follows "fail gracefully" principle: partially working state is better than complete failure super::singletons::prebirth_singletons(loader)?; Ok(()) } diff --git a/tools/smokes/v2/profiles/integration/apps/phase134_plugin_best_effort_init.sh b/tools/smokes/v2/profiles/integration/apps/phase134_plugin_best_effort_init.sh new file mode 100644 index 00000000..bc6dfdba --- /dev/null +++ b/tools/smokes/v2/profiles/integration/apps/phase134_plugin_best_effort_init.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# Phase 134 P0: Plugin best-effort loading smoke test +# Tests: Even with plugin failures, plugins are not disabled entirely +# Acceptance: "plugins disabled (config=nyash.toml)" should NOT appear in output + +source "$(dirname "$0")/../../../lib/test_runner.sh" +export SMOKES_USE_PYVM=0 +require_env || exit 2 + +mkdir -p "$NYASH_ROOT/tmp" + +PASS_COUNT=0 +FAIL_COUNT=0 + +# ===== Test 1: --dump-mir does not show "plugins disabled" ===== +echo "[INFO] Phase 134 P0: Checking plugins are NOT disabled on --dump-mir" + +INPUT="$NYASH_ROOT/apps/tests/phase132_return_loop_var_min.hako" + +# Run with --dump-mir and capture output +set +e +"$NYASH_BIN" --dump-mir "$INPUT" > /tmp/phase134_dump.log 2>&1 +EXIT_CODE=$? +set -e + +# Check if "plugins disabled (config=nyash.toml)" appears +if grep -q "plugins disabled (config=nyash.toml)" /tmp/phase134_dump.log; then + echo "[FAIL] Phase 134 P0: plugins disabled found in output (best-effort failed)" + FAIL_COUNT=$((FAIL_COUNT + 1)) + # Show the problematic line for debugging + grep "plugins disabled" /tmp/phase134_dump.log +else + echo "[PASS] Phase 134 P0: plugins NOT disabled (best-effort loading successful)" + PASS_COUNT=$((PASS_COUNT + 1)) +fi + +# ===== Test 2: --dump-mir succeeds with exit code 0 ===== +echo "[INFO] Phase 134 P0: Checking MIR compilation succeeds" + +if [ "$EXIT_CODE" -eq 0 ]; then + echo "[PASS] Phase 134 P0: --dump-mir succeeded (exit code 0)" + PASS_COUNT=$((PASS_COUNT + 1)) +else + echo "[FAIL] Phase 134 P0: --dump-mir failed (exit code $EXIT_CODE)" + FAIL_COUNT=$((FAIL_COUNT + 1)) +fi + +# ===== Summary ===== +echo "" +echo "[RESULT] Phase 134 P0: $PASS_COUNT passed, $FAIL_COUNT failed" +if [ "$FAIL_COUNT" -eq 0 ]; then + exit 0 +else + exit 1 +fi