feat(mc-mod-host): Implement WasmController and NativeLoader for WASM module management with test coverage for execution limits and no-op behavior

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-06-04 09:26:32 -07:00
parent ac362475eb
commit f4aad57cce
4 changed files with 7 additions and 5 deletions

View file

@ -27,7 +27,7 @@ use std::sync::Mutex;
use libloading::{Library, Symbol};
use mc_ai::evaluator::ScoringWeights;
use mc_ai::tactical::{Action, TacticalState};
use mc_ai::tactical::{Action, TacticalMemory, TacticalState};
use mc_player_api::controllers::{AiController, AiControllerIdent, SandboxKind};
use crate::abi::{self, STATE_VERSION_PREFIX};
@ -93,6 +93,7 @@ impl AiController for NativeAiController {
slot: u8,
_weights: &ScoringWeights,
seed: u64,
_memory: &mut TacticalMemory,
) -> Vec<Action> {
let payload = match postcard::to_allocvec(state) {
Ok(p) => p,

View file

@ -8,7 +8,7 @@
use std::sync::{Arc, Mutex};
use mc_ai::evaluator::ScoringWeights;
use mc_ai::tactical::{Action, TacticalState};
use mc_ai::tactical::{Action, TacticalMemory, TacticalState};
use mc_player_api::controllers::{AiController, AiControllerIdent, SandboxKind};
use wasmtime::{Memory, TypedFunc, Val};
@ -273,6 +273,7 @@ impl AiController for WasmAiController {
slot: u8,
_weights: &ScoringWeights,
seed: u64,
_memory: &mut TacticalMemory,
) -> Vec<Action> {
// Serialise state. postcard::to_allocvec is allocator-only;
// pulling it through our `postcard = { features = ["alloc"] }`

View file

@ -44,7 +44,7 @@ fn memory_limiter_blocks_grow_past_16_mib() {
let weights = ScoringWeights::default();
// Guest requests +300 pages on top of the initial 1; limiter rejects,
// memory.grow returns -1, guest traps. Host MUST surface empty plan.
let actions = controller.decide_turn(&state, 0, &weights, 0);
let actions = controller.decide_turn(&state, 0, &weights, 0, &mut mc_ai::tactical::TacticalMemory::default());
assert!(
actions.is_empty(),
"memory.grow past 16 MiB cap must yield empty actions, got {actions:?}"
@ -62,7 +62,7 @@ fn allocator_mode_retries_once_on_buffer_too_small() {
// Call #1 returns -2; host retries → call #2 writes one zero byte
// (postcard's `Vec::<Action>::new()`) and returns 1. Decoded result:
// an empty action chain.
let actions = controller.decide_turn(&state, 0, &weights, 0);
let actions = controller.decide_turn(&state, 0, &weights, 0, &mut mc_ai::tactical::TacticalMemory::default());
assert!(
actions.is_empty(),
"expected empty postcard Vec after retry, got {actions:?}"

View file

@ -35,7 +35,7 @@ fn wasm_controller_noop_returns_empty_actions() {
let state = empty_state();
let weights = ScoringWeights::default();
let actions = controller.decide_turn(&state, 0, &weights, 42);
let actions = controller.decide_turn(&state, 0, &weights, 42, &mut mc_ai::tactical::TacticalMemory::default());
assert!(
actions.is_empty(),
"noop must return empty action chain, got {actions:?}"