Builds the browser game around the existing Rust runtime: a window into the universe, not a second simulation. Pure std, no external crates. New crates: - protocol: versioned, hashable client/server messages + hand-rolled JSON value and total parser (malformed packet -> Err, never panic). - game_runtime: authoritative match state. Resolves turns through the INDEPENDENT interpreter (runtime_under_test::native_resolve), not the reference engine; filters visibility/knowledge; records and regenerates replays. A match is a pure function of (seed, roster, ordered inputs). - web_assets/web_client: embedded browser client (arena, rune editor, knowledge panels, replay viewer) + static HTTP delivery. - server: std::net HTTP + WebSocket (hand-rolled SHA-1/base64/RFC-6455 framing), turn timer, disconnect handling, panic-proof dispatch, poison-tolerant lock. - web_tests: dependency-free WebSocket test client + Phase H gates. Trust hardening per review: - game_runtime no longer delegates to reference_runtime::execute; it runs the independent interpreter that the runtime-equivalence gate proves correct. - Protocol/socket/replay/visibility/resilience gates are merge-blocking (added to the merge_group-required job in merge-gates.yml): 1k matches/0 drift, 10k fuzz/0 panics, 100 headless socket E2E, 0 hidden-state leaks. - Rendered-browser E2E is marked EXTERNAL-BLOCKED: Playwright runs advisory-only (continue-on-error, artifacts) until CI infrastructure with a browser exists; it is treated as unsatisfied, not green. The headless 100-match gate is labeled protocol-level coverage, not rendered-browser coverage. - README documents the hand-rolled crypto/parser audit risk explicitly. Fixes an integer-overflow panic in observed-volatility inference (i64 sum / abs near i64::MIN) that could poison the server mutex. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
262 lines
4.6 KiB
Markdown
262 lines
4.6 KiB
Markdown
|
|
Web Game Implementation Plan
|
|
Prime Directive
|
|
Build the browser game around the already-defined Rust simulation/testing system.
|
|
|
|
The web game must be:
|
|
|
|
Browser-first
|
|
Server-authoritative
|
|
Replayable
|
|
Deterministic
|
|
Test-gated
|
|
Playable before pretty
|
|
No web feature may bypass the Rust runtime contract.
|
|
|
|
Architecture
|
|
Rust simulation core
|
|
↓
|
|
Authoritative server
|
|
↓
|
|
WebSocket protocol
|
|
↓
|
|
Browser client
|
|
↓
|
|
UI / arena / rune editor
|
|
Browser never decides truth.
|
|
|
|
Browser only sends:
|
|
|
|
intent
|
|
movement choice
|
|
rune program
|
|
library slot selection
|
|
inspection request
|
|
Server returns:
|
|
|
|
world snapshot
|
|
visible observations
|
|
turn result
|
|
trace excerpts
|
|
replay hash
|
|
legal player-facing diagnostics
|
|
Crates
|
|
crates/
|
|
world_model
|
|
rune_ir
|
|
trace_model
|
|
reference_runtime
|
|
game_runtime
|
|
replay_corpus
|
|
protocol
|
|
server
|
|
web_client
|
|
web_assets
|
|
web_tests
|
|
Phase A — Protocol First
|
|
Define all client/server messages before UI.
|
|
|
|
ClientMessage
|
|
JoinMatch
|
|
SubmitTurn
|
|
EditRuneProgram
|
|
InspectTarget
|
|
RequestReplay
|
|
Ping
|
|
|
|
ServerMessage
|
|
MatchState
|
|
TurnStarted
|
|
TurnResolved
|
|
ObservationResult
|
|
ValidationReport
|
|
ReplayChunk
|
|
ErrorEvent
|
|
Rules:
|
|
|
|
All messages versioned
|
|
All messages serializable
|
|
All messages replay-testable
|
|
All server outputs hashable
|
|
No client-only game truth
|
|
Phase B — Authoritative Match Server
|
|
Server owns:
|
|
|
|
match state
|
|
turn timer
|
|
submitted actions
|
|
rune execution
|
|
visibility filtering
|
|
knowledge filtering
|
|
replay recording
|
|
disconnect handling
|
|
Server loop:
|
|
|
|
Create match
|
|
Send visible snapshot
|
|
Start turn timer
|
|
Collect actions
|
|
Resolve through runtime
|
|
Persist replay event
|
|
Send filtered results
|
|
Advance turn
|
|
Hard gates:
|
|
|
|
same inputs produce same replay hash
|
|
late input rejected deterministically
|
|
disconnect does not corrupt match
|
|
invalid client packet cannot panic server
|
|
client cannot mutate hidden state
|
|
Phase C — Browser Client Shell
|
|
Client responsibilities:
|
|
|
|
connect
|
|
authenticate anonymously/dev
|
|
join match
|
|
render visible arena
|
|
show entities
|
|
show turn timer
|
|
edit rune program
|
|
submit action
|
|
display results
|
|
display observations
|
|
play replay events
|
|
Do not implement complex art yet.
|
|
|
|
Use debug visuals:
|
|
|
|
grid
|
|
tokens
|
|
panels
|
|
logs
|
|
timers
|
|
entity markers
|
|
domain indicators
|
|
Phase D — Rune Editor
|
|
The rune editor is the core UI.
|
|
|
|
Required:
|
|
|
|
keyboard-bound rune input
|
|
token grid / sequence view
|
|
library slot panel
|
|
syntax-neutral execution preview
|
|
visible cost/risk diagnostics
|
|
submission lock on timer expiry
|
|
Important:
|
|
|
|
The editor must not pretend to know full truth.
|
|
It can show observed diagnostics only.
|
|
Player-facing diagnostics should say:
|
|
|
|
known reads
|
|
known writes
|
|
observed risks
|
|
unknown listeners
|
|
previous outcomes
|
|
Not:
|
|
|
|
guaranteed damage
|
|
guaranteed success
|
|
full hidden state
|
|
Phase E — Arena Interaction
|
|
Each turn, player can:
|
|
|
|
move
|
|
inspect
|
|
cast rune program
|
|
use stick/basic attack
|
|
wait
|
|
All actions become server commands.
|
|
|
|
Client-side previews are advisory only.
|
|
|
|
Phase F — Visibility / Knowledge Layer
|
|
Server sends filtered state:
|
|
|
|
VisibleWorldSnapshot {
|
|
observed_domains,
|
|
observed_entities,
|
|
observed_environment,
|
|
known_history,
|
|
inferred_markers,
|
|
hidden_state_redactions,
|
|
}
|
|
Knowledge must be game state, not UI notes.
|
|
|
|
Client displays:
|
|
|
|
known
|
|
unknown
|
|
suspected
|
|
contradicted
|
|
newly observed
|
|
Phase G — Replay System
|
|
Every match produces:
|
|
|
|
initial seed
|
|
player inputs
|
|
turn boundaries
|
|
runtime hashes
|
|
visible outputs
|
|
trace excerpts
|
|
final hash
|
|
Browser replay consumes the same protocol stream.
|
|
|
|
CI gate:
|
|
|
|
recorded replay equals regenerated replay
|
|
browser replay event order matches server order
|
|
Phase H — Web Testing
|
|
Required test layers:
|
|
|
|
Rust protocol tests
|
|
server integration tests
|
|
browser protocol tests
|
|
Playwright end-to-end tests
|
|
replay determinism tests
|
|
fuzzed packet tests
|
|
disconnect/reconnect tests
|
|
timer edge tests
|
|
Minimum web CI gates:
|
|
|
|
1,000 simulated matches
|
|
10,000 protocol fuzz cases
|
|
100 browser E2E matches
|
|
0 server panics
|
|
0 replay hash mismatches
|
|
0 hidden-state leaks
|
|
Phase I — Vertical Slice
|
|
First playable slice:
|
|
|
|
2 players or 1 player + dummy opponent
|
|
small arena
|
|
turn timer
|
|
movement
|
|
inspection
|
|
basic attack
|
|
rune submission
|
|
multicast execution
|
|
visible consequences
|
|
replay viewer
|
|
No progression.
|
|
No accounts.
|
|
No cosmetics.
|
|
No marketplace.
|
|
No complex content.
|
|
|
|
Acceptance Criteria
|
|
Web phase is accepted only when:
|
|
|
|
A player can join a browser match.
|
|
A turn timer runs.
|
|
The player can inspect, move, attack, or cast.
|
|
Rune programs execute only on the server.
|
|
Results return as filtered observations.
|
|
Replay can reproduce the match.
|
|
Browser cannot alter hidden truth.
|
|
CI proves protocol, replay, visibility, and server authority.
|
|
Core rule:
|
|
|
|
The web game is just a playable window into the Rust universe.
|
|
It must not become a second simulation. |