Skip to content

Commit 2d6680a

Browse files
author
nyash-codex
committed
docs: finalize plugin policy & birth unification rules; runner default auto; boot no-cache disabled; ensure_loaded reprobe(FileBox); VM always birth after new; CURRENT_TASK updated
1 parent 6d1163e commit 2d6680a

6 files changed

Lines changed: 52 additions & 12 deletions

File tree

CURRENT_TASK.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,34 @@ apps/selfhost/hakorune-vm/
336336
- 既存 from の互換(非strict)を維持、strict で Fail‑Fast が働く
337337

338338
- Builtin callAsync true async implemented (HAKO_CALLABLE_ASYNC=1): job queue + VM polling; added smoke quick/core/callable_async_builtin_vm.sh.
339+
340+
---
341+
342+
## Plugin Policy & Birth Unification (Phase 15.7) — Plan & Status
343+
344+
Goals
345+
- Default plugin policy = auto (ON). If no providers configured, no side-effects.
346+
- VM unifies lifecycle: new → birth(me,args) always (birth missing = no-op, idempotent)
347+
- Plugin init: load-time nyash_plugin_init() (optional) and first-birth ensure_ready() (Once)
348+
- Provider resolution single order: Plugin → Builtin → Registry; on-demand reprobe for T
349+
- Boot disabled state is not cached (allow later retry when policy flips to ON)
350+
351+
Done
352+
- Runner: default policy auto (None/unknown → auto)
353+
- Boot: policy off no longer cached as success (returns false; retry later)
354+
- ProviderBox: reprobe list extended to include FileBox
355+
- VM: always attempt birth after new (ignore missing method)
356+
- Smokes: plugins/filebox_write_read_vm added; quick/core/filebox stabilized (SKIP when unavailable)
357+
- Docs updated: docs/reference/plugin-system/vm-plugin-integration.md (final rules)
358+
359+
Next
360+
- Determinism guard (deny IO caps like FileBox when HAKO_DETERMINISTIC=1)
361+
- Error ergonomics: ProviderNotFound/PluginInitFailed/BirthFailed with provenance
362+
- Optional: on-demand reprobe toggle for deterministic mode (off)
363+
364+
Acceptance
365+
- plugins profile: all smokes green (callable/map/string/array/json/filebox)
366+
- quick profile: filebox_basic is PASS or SKIP (plugin missing)
367+
- Runner: default plugin policy is auto; no regressions
368+
- VM: new→birth unified; no double-birth
369+

docs/reference/plugin-system/vm-plugin-integration.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
Note: Terminology updated — “Nyash ABI” is now referred to as “Hako ABI (formerly Nyash ABI)”.
44

5+
## Policy & Lifecycle — Final Rules (Phase 15.7)
6+
7+
- Plugin Policy: default ON (auto). If no plugins are configured in hako.toml/nyash.toml, nothing is loaded (no side‑effects). CI などで完全遮断したい場合のみ `NYASH_DISABLE_PLUGINS=1` を使う。
8+
- Creation: `new T(args…)` is always followed by `birth(me,args…)` by VM. When `birth` is not implemented, it is treated as no‑op (idempotent). Builder の auto‑birth は既定OFF。
9+
- Plugin Init: two idempotent stages are allowed (optional)
10+
- Load‑time: `nyash_plugin_init()` called once per library when present
11+
- First‑birth: plugin may call `ensure_ready()` guarded by `Once`
12+
- Provider Resolution: single order — `PluginProvider(T) → BuiltinProvider(T) → Registry/Fallback(T) → error`. Before resolving, the registry performs on‑demand re‑probe for `T` to avoid timing issues.
13+
- Boot Disabled Non‑cache: boot() no longer caches “disabled” as success (allows later retry when policy flips to ON). Operationally we run with policy=auto by default so this path is rarely used.
14+
15+
516
## 🎯 概要
617

718
NyashのVMバックエンドとプラグインシステム(BID-FFI v1)の統合に関する技術仕様。Everything is Box哲学に基づき、**すべてのBox型(ビルトイン、ユーザー定義、プラグイン)**をVMで統一的に扱えるようにする。

src/backend/mir_interpreter/handlers/boxes/newbox.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ impl MirInterpreter {
2424
self.regs.insert(dst, created_vm.clone());
2525
if let VMValue::BoxRef(arc_box) = &created_vm { self.scope.register_box(arc_box.clone()); }
2626
crate::backend::mir_interpreter::helpers::lifecycle_contracts_box::LifecycleContractsBox::mark_new(self, dst, box_type, args.len());
27+
// Always attempt birth; ignore missing method
28+
let _ = self.handle_box_call(None, dst, "birth", args);
2729
crate::backend::mir_interpreter::helpers::lifecycle_contracts_box::LifecycleContractsBox::born_if_no_birth(self, dst, box_type, args.len());
2830
return Ok(());
2931
}
@@ -93,14 +95,8 @@ impl MirInterpreter {
9395
// Centralized lifecycle observation (contracts + traces)
9496
crate::backend::mir_interpreter::helpers::lifecycle_contracts_box::LifecycleContractsBox::mark_new(self, dst, box_type, args.len());
9597

96-
// Dev-only: optional auto birth after NewBox to unblock selfhost paths
97-
// Guarded by NYASH_VM_AUTO_BIRTH_DEV=1. In production, builders must
98-
// materialize explicit birth calls.
99-
if super::super::VmConfig::global().auto_birth_dev {
100-
// Dev: call birth with the same args that were provided to NewBox
101-
// This covers user-defined boxes that rely on birth parameters
102-
let _ = self.handle_box_call(None, dst, "birth", args);
103-
}
98+
// Always attempt birth after creation; ignore missing method to keep no-op semantics.
99+
let _ = self.handle_box_call(None, dst, "birth", args);
104100

105101
// C++-style constructor mode (interim): optionally invoke ModuleFunction
106102
// "Class.birth/N" immediately after NewBox, using fully qualified name.

src/runner/plugins.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ impl NyashRunner {
2424
// Plugins (guarded)
2525
// Default policy: OFF (plugins disabled) unless explicitly set to auto/force.
2626
// Aliases handled by env core bootstrap (HAKO_* → NYASH_*), but we defensively read both.
27+
// Policy: default ON (auto). Unknown/empty -> treat as auto.
2728
let policy = std::env::var("NYASH_PLUGIN_POLICY").ok().or_else(|| std::env::var("HAKO_PLUGIN_POLICY").ok());
2829
let disable_by_policy = match policy.as_deref() {
29-
None => true, // default OFF in Hakorune build
3030
Some(s) if s.eq_ignore_ascii_case("off") => true,
3131
Some(s) if s.eq_ignore_ascii_case("auto") || s.eq_ignore_ascii_case("force") => false,
32-
_ => true, // unknown → OFF
32+
None => false, // default to auto
33+
_ => false, // unknown → consider auto (fail-open; providers may still be empty)
3334
};
3435
if !disable_by_policy && std::env::var("NYASH_DISABLE_PLUGINS").ok().as_deref() != Some("1") {
3536
runner_plugin_init::init_bid_plugins();

src/runtime/plugin_boot_box/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ fn policy_on() -> bool {
2020
pub fn boot() -> bool {
2121
if let Some(v) = BOOTED.get() { return *v; }
2222

23+
if !policy_on() { return false; }
24+
2325
let ok = (|| {
24-
if !policy_on() { return true; } // treat as success when policy off
2526

2627
// Choose config candidates (prefer explicit override)
2728
let mut tried: Vec<String> = Vec::new();

src/runtime/provider_box/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn ensure_loaded(_config_path: Option<&str>) {
1717
if crate::runtime::env_gate_box::plugins_disabled() { return; }
1818
if !crate::runtime::env_gate_box::plugin_policy_on() { return; }
1919
let _ = crate::runtime::plugin_boot_box::boot();
20-
let _ = crate::runtime::plugin_boot_box::reprobe_providers_for(["ArrayBox", "MapBox", "StringBox"].as_ref());
20+
let _ = crate::runtime::plugin_boot_box::reprobe_providers_for(["ArrayBox", "MapBox", "StringBox", "FileBox"].as_ref());
2121
}
2222

2323
/// Create a box using Plugin → Registry → Embedded order (best‑effort)

0 commit comments

Comments
 (0)