The Simulator Boundary Is a Windows Agent
The hard integration is not the dashboard. It is the simulator boundary. The Tauri agent has to run on Windows, open Assetto Corsa shared-memory pages, read packed C-compatible structs, and convert them into the protocol the relay and browser understand.
The agent does not invent fake telemetry when the maps are unavailable. If the simulator is off or the shared-memory pages cannot be read, there is no sample. That absence is a better system behavior than a pretty dashboard fed by lies.
const PHYSICS_MAP: &str = "acpmf_physics";
const GRAPHICS_MAP: &str = "acpmf_graphics";
const STATIC_MAP: &str = "acpmf_static";
impl TelemetryProvider for AcSharedMemProvider {
fn sample(&mut self) -> Option<TelemetrySample> {
self.try_open();
let physics = self.physics.as_ref()?.read();
let graphics = self.graphics.as_ref()?.read();
let static_info = self.static_info.as_ref().map(|info| info.read());
if graphics.status == AC_STATUS_OFF {
return None;
}
Some(TelemetrySample {
car: Car {
speed_kph: physics.speed_kmh,
gear: physics.gear,
rpm: physics.rpms as f32,
throttle: physics.gas,
brake: physics.brake,
steer_angle_rad: physics.steer_angle,
},
session: Session {
track: static_info.map(|info| to_string(&info.track)).unwrap_or_default(),
car_model: static_info.map(|info| to_string(&info.car_model)).unwrap_or_default(),
status: map_flag_to_status(graphics.flag),
},
})
}
}One Room, One Agent, Many Viewers
The relay model is narrow on purpose. A room has one active agent and many viewers. Agent telemetry is the source of truth for live state. Viewers receive the latest telemetry immediately on connect, then receive each new sample. Viewer callouts are validated and routed back to the agent.
That simplicity matters because the v1 relay is a single instance. Live routing is in memory, while session history is persisted. Horizontal room coordination would be a different system. The current design keeps authority, routing, and persistence legible.
if (role === "agent") {
if (room.agent) {
ws.close(1008, "Agent already connected");
return;
}
setAgent(roomId, ws);
room.sessionId = startSession(roomId);
return;
}
addViewer(roomId, ws);
if (room.lastTelemetry) {
ws.send(JSON.stringify(room.lastTelemetry));
}Replay Makes Advice Auditable
Replay is the difference between a live tool and an evidence tool. The relay stores rooms, sessions, telemetry samples, and callouts in SQLite. Agent connection starts a session. Agent disconnect ends it. Replay loads the session and reconstructs the timeline.
That gives technical feedback an object to inspect. A missed fuel read, late callout, or bad tire-pressure judgment can be reviewed against the data stream instead of remembered from a call.
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
room_id TEXT NOT NULL,
started_at INTEGER NOT NULL,
ended_at INTEGER
);
CREATE TABLE IF NOT EXISTS telemetry (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id INTEGER NOT NULL,
ts INTEGER NOT NULL,
seq INTEGER NOT NULL,
payload TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS callouts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id INTEGER NOT NULL,
ts INTEGER NOT NULL,
text TEXT NOT NULL,
priority TEXT NOT NULL
);Auth and Updates Belong to the Boundary
The practical production work is part of the system, not deployment trivia. The relay moved viewer authentication from token-bearing URLs to room-scoped session cookies. The agent moved its WebSocket token into a bearer header. The relay also serves updater metadata for the Windows app, which matters because the agent is the piece that must sit next to the game.
The commit history shows the experiment tightening around operational reality: Bun-native relay serving with SQLite, Remix asset fixes, Windows shared-memory correction, richer telemetry payloads, room-scoped viewer sessions, bearer auth for the agent, and a version bump to 0.0.2.
The V1 Shape Is Deliberate
The boundary is honest. V1 assumes one relay instance. Room state is in memory. Auth is shared-token based, not an account system. Replay stores telemetry JSON without solving large-session export or pagination. The visible CI builds the relay, container, agent UI, and Rust core, but the repo does not contain a broad test suite.
Those constraints are acceptable because the project is testing the right thing: whether remote technical help becomes more valuable when the shared artifact is structured state. On that axis, the answer is clear. Screen sharing ends when the call ends. Telemetry can be replayed.