← Tactical Air

Prototype contract

The portable crate is an engine-independent contextual bandit. Hosts supply finite roles, contexts, legal actions, and observed outcomes. The Rust library never reads a world, renders, calls an LLM, or changes combat parameters. This is inspired by the constraints and learning separation discussed in Ink; it is not an Ink integration or proof system.

Rust API and JSON bridge

Engine::new(Config) -> Result<Engine, Error>; Engine::request(&mut self, request_json: &str) -> String returns a JSON envelope { "ok": true, "data": ... } or { "ok": false, "error": "..." }. Direct typed APIs may also exist.

Config:

{"seed":42,"roles":[{"id":"vanguard","actions":["rush","hold"]},{"id":"flanker","actions":["flank_left","flank_right"]},{"id":"ranger","actions":["aim","lead"]}],"contexts":["arena"],"learning_rate":0.22,"exploration":0.16,"temperature":0.3,"decay":0.025,"max_update":0.16}

Operations:

Wrappers: wasm-bindgen TacticalEngine(config_json: string), .request(json): string; native opaque ta_engine_new(const char), ta_engine_request(handle,const char), ta_string_free(char*), ta_engine_free(handle). Error ownership and pointer safety documented in C header. Engine instances are independent, single-owner mutable objects. JSON is a prototype boundary, never per render frame.

Arena

Separate browser sample: TypeScript and Canvas. Three roles above, six authored tactics. Fixed combat rules and visible telegraphs. Real collisions and line of sight; no attacks or training evidence through walls. Memory persists between encounters. Start with a readable top-down geometric arena inspired by our diagram. Include manual play, automatic demonstration, frozen baseline, memory reset, and inspectable scores. Make adaptation timing and baseline mode clear. Auto demonstration must run the same world/combat/outcome code as manual play, not preset score changes. Learning has no hard-coded player-style-to-tactic lookup.

The policy.ts adapter owns initialization of Wasm and a typed request helper; the simulation consumes an injected policy interface so simulation tests can run without the DOM. Root integrator owns that adapter and workspace tooling. Arena implementer owns the rest of apps/arena.

Validation

Meaningful library tests: reward-driven preference (including reversed reward mapping), adaptation after change, legal masks, unobserved/baseline/duplicate feedback, bounded commits, deterministic snapshot/replay, hostile snapshot rejection. Native C smoke test. Browser must load actual compiled Wasm and complete encounters through the same core. Controlled benchmark results are evidence of algorithm behavior, not proof the game is fun. Human counterplay playtest remains necessary.