diff --git a/plan/README.md b/plan/README.md index 0a2ca44..14dec45 100644 --- a/plan/README.md +++ b/plan/README.md @@ -60,6 +60,7 @@ frontmatter keys every other epic carries, run the script, stage both. | [artillery](artillery.md) | A shell fired this round lands next round | open | ev, beliefs | | [battle-armor](battle-armor.md) | Battle armor plays, mounted and on foot | open | unit-types, candidates | | [bridges](bridges.md) | A bridge is a floor above the ground | open | protocol | +| [browser](browser.md) | The bot plays on lance.blue, then in the player's browser | open | contract, latency | | [buildings](buildings.md) | Buildings are terrain the bot can see, enter and destroy | open | los, protocol | | [c3](c3.md) | A C3 lance shoots from where its friends can see | open | los, candidates | | [candidates](candidates.md) | Propose positions, not four verbs | open | los, ev, features | diff --git a/plan/browser.md b/plan/browser.md new file mode 100644 index 0000000..8e2eff8 --- /dev/null +++ b/plan/browser.md @@ -0,0 +1,73 @@ +--- +id: browser +title: The bot plays on lance.blue, then in the player's browser +status: open +dependsOn: [contract, latency] +exitCriterion: > + A lance.blue match can seat sds in place of Princess from its launch + manifest, and sds-core built for wasm answers a recorded observation with + the decision the native build gives. +--- + +# browser + +`Cargo.toml` says why `sds-core` has no dependencies: it has to run in a +browser eventually, because the cheapest bot is one that runs on the player's +machine and costs nothing to host. Nothing checks that it still can, and +nothing in the sibling repositories plans to give it an observation to answer. + +Two facts settle the starting point. `cargo check --target wasm32-unknown-unknown -p sds-core` +passes today, in twelve seconds. It would not run: four `std::time::Instant::now()` +calls panic on that target at run time, and `stands.rs:1759` is unconditional, +so every sweep would die on its first line. The others are `stands.rs:1860` +and `volley.rs:1862`, `1893`, all feeding counters and none feeding a +decision. + +And arena is not a MegaMek in the browser. It is a JVM in a container - +server, one Princess per bot slot constructed in-process +(`arena/src/arena/MatchHost.java:243-259`), and the Swing client - drawn into +the page by Suramadu. The launch manifest says `players[].control: human|bot` +and every slot that is not human gets Princess +(`headquarters/docs/launch-manifest.md:92-93`). No CheerpJ, no TeaVM, no wasm +anywhere in it. `headquarters/plan/setup-tree.md` wants a scenario `bot:` +node that picks a Princess behaviour and notes arena ignores it. + +## Three steps, each useful on its own + +1. **Server side, no wasm.** `SdsClient` is a `BotClient` and connects over + loopback exactly as Princess does. Put `sds.jar` and a static `sds-bot` + in the arena image and let `MatchHost` seat one for `control: sds`. No + protocol change, and it is the step that puts the bot in front of players. + What is not known: the runtime stage is `debian:bookworm-slim` with a JRE, + so the bot needs a musl or otherwise static build; the task already + contends for two vCPUs with Princess (`arena/TODO.md:849`), and a + unit-decision is seconds today, which is what [latency](latency.md) is + for. +2. **Thinking in the browser.** `sds-core` built for wasm, driven by a small + JavaScript loop in place of `sds-bot`'s tokio runtime, fed the same NDJSON + over a WebSocket from a thin `SdsClient` variant in the arena JVM. + `Observation.java` stays where it is; only the thinking moves. What is not + known: arena exposes one port, so a second socket is an infra change; the + per-decision budget against the host's ten-second timeout; how the bot's + socket is tied to the same player as the Suramadu session. +3. **A solo game with no server.** Needs MegaMek itself in the browser, which + no repository has attempted. Out of scope here; named so nobody mistakes + step two for it. + +## What sds has to do first + +The wasm build cannot be tested against a live JVM in CI, so a recorded +observation corpus is its contract: the one [contract](contract.md) +records for its drift test. A Node script in the shape of helm's +`crates/helm-wasm/smoke.mjs` feeds each recorded observation to the wasm build +and to the native build and fails on any difference in the reply. That is +the whole test of step two on this side, and it is the exit criterion's +second half. + +- [ ] A `clock` shim: no-op on `wasm32`, `Instant` elsewhere; the four call sites through it +- [ ] `cargo check --target wasm32-unknown-unknown -p sds-core` in the prek cargo hooks +- [ ] A `sds-wasm` crate exposing propose and command over the line protocol, as helm does +- [ ] The Node smoke: recorded observations through wasm and native, replies compared +- [ ] Arena: `control: sds` in the manifest, `sds.jar` and a static bot in the image, a seat in `MatchHost` - an epic in arena and a plan entry in headquarters +- [ ] Infra: the socket for step two, once step one is playing +- [ ] Measure a unit-decision inside the arena task before promising a seat to a player