Current architecture, input/output contract, and limits
Jev selects one maneuver for one enemy vehicle—or optionally Clu in autoplay—from a list generated by the game. The game supplies the vehicle's recorded knowledge, nearby allies, local wall geometry, and candidate destinations/routes. Jev returns a candidate ID and confidence. Local simulation executes the selected maneuver using inertial movement, collision checks, and existing weapon/attack rules.
This describes the implementation as of September 21, 2026. Jev does not currently invent routes, set throttle/yaw each frame, coordinate a whole squad in one request, or generate game content. Those would be extensions of this design.
The browser defaults to Tactical + Jev with the full enemy population. Shift+T provides Classic, Tactical — local, and Tactical + Jev modes. The optional small encounter is off by default. Tactical modes disable repeating pursuit reinforcements; Classic retains the 20-second reinforcement interval.
September 22 flight correction: executing a selected maneuver no longer waits for near-perfect heading alignment before applying thrust. Recognizers turn while moving, reduce approach speed when the remaining distance cannot accommodate a broad arc, and pass through straight route segments without stopping at each waypoint. Arrival, confined descent and attack clearance still use local geometry and braking; this changes the local controller, not the JEV request/response contract.
There is no persistent provider conversation or shared Jev session. Each request contains its own snapshot, including recent acoustic observations. Persistent memory, maneuver revisions, and execution state belong to the game.
Press U or the top-left HUD button to enable autoplay (off by default). Autoplay stays selected until U or its HUD button is toggled. Held driving/turret inputs temporarily override their respective channels; Space and mouse firing combine with pilot firing while navigation continues. Gunner/camera controls remain available. Releasing held controls restores pilot input, while existing cruise and aim-lock modes retain their normal behavior. Pausing aborts pending requests and freezes simulation. Restart clears the current plan while retaining the explicitly selected autoplay mode. The button labels whether the current maneuver came from Jev or the local planner, and displays service warnings. Network errors, timeouts and service/limit failures disengage autoplay and clear its plan. It stays off until explicitly re-enabled; known provider cooldowns prevent enabling it. Enemy AI continues using its local fallback.
Player snapshots have controller: "clu", self (pose, speed, health, turret yaw), visibleEnemies, known data-beam objectives, nearby wall polygons, recent positions, and up to eleven maneuver choices. Contacts are limited to 350 m with unobstructed line of sight from Clu; this initial sensor is omnidirectional, independent of camera direction. Enemy private state/memory/intent is excluded. Candidate routes include short swept evasion/exploration segments, a bounded ground route toward a data beam or maze opening, and hold. The player prompt explicitly asks Jev to turn every red data beam blue while surviving. objective contains remaining/total counts and activation rules (stop within 7 m, at most 0.3 m/s, wait approximately 12.667 seconds); each objectives entry includes red/transitioning/blue state and remaining transfer seconds. A transitioning beam still counts as uncollected. After all are blue, Clu continues exploring. The planner still provides only bounded local routes, not guaranteed multi-maze completion; it is separate from the enemy prompt. Local rankings are supplied, so this remains constrained maneuver selection rather than unrestricted motor control.
src/simulation/autoplay.js replans every three simulation seconds, before a temporary movement endpoint enters the braking zone, or after teleport. Local controls regulate speed for turns and required stops, carry momentum through straight waypoints, and aim at the visible target or along the route when no contact remains. Target-switch hysteresis reduces camera swings. They fire only when the existing cannon solution identifies that target. Obstacles are rechecked ahead of the tank and ordinary collisions remain authoritative. It automatically uses turbo on long clear aligned runs, reserving boosted travel plus braking distance before the next turn or stop. Rejected/late/uncertain responses retain the local choice. The one shared JevClient alternates player and enemy opportunities when both are eligible; player requests also work when enemies are in Classic/local mode. Existing quota/cooldown and pause/reset protections apply to both. This is an experimental observer mode, not a demonstrated optimal player.
Deploy the updated Worker player prompt together with any public client that exposes autoplay. Local Vite uses the shared protocol automatically.
A unit must have a recorded Clu position no older than 38 simulation seconds, or an unknown sound report no older than 10 simulation seconds, within one maze length horizontally of its current position. A fresh target memory takes precedence over sound for this gate. This uses a sighting/radio memory or an estimated sound location, never Clu's hidden live position. MAZE_LENGTH is the larger transformed dimension of the base maze, not the distance across all maze sites. Its multiplier is TACTICAL.jevRangeMazeLengths, currently 1.
The unit must also be alive, outside materialization/teleport, not in a committed aircraft attack, and have a fresh maneuver revision that has not already been requested. The game must be running in Jev mode and Clu must not be destroyed. Distant or unaware enemies still move and make decisions using local tactics.
The scheduler scans Recognizers first, then ground tanks, taking the first eligible unit. It is currently not round-robin. Under load, later units may miss their request window and remain on local decisions.
The browser sends this object as JSON to POST /api/jev/decision. The values below are illustrative, not a recorded encounter. Routes/facts are shortened for readability; actual requests contain all generated candidates and their route poses.
{
"time": 12,
"units": "meters, seconds, radians; x/s horizontal, y up; forward=(-sin(yaw),cos(yaw))",
"self": {
"id": 2,
"kind": "recognizer",
"x": -5000,
"s": -5000,
"y": 80,
"yaw": 0,
"vx": 0,
"vs": 30,
"vy": 0,
"yawVelocity": 0,
"fold": 0,
"health": 3,
"canSee": true
},
"target": {
"x": -5000,
"s": -4800,
"vx": 0,
"vs": 22,
"seenAt": 11.8,
"source": 2,
"age": 0.2
},
"allies": [],
"map": [],
"current": "pursue",
"options": [
{
"id": "m0",
"kind": "pursue",
"goal": {"x": -5000, "s": -4780, "y": 80, "yaw": 0},
"route": [{"x": -5000, "s": -4780, "y": 80, "yaw": 0}],
"facts": {
"travelMeters": 220,
"goalDistanceToLastKnownTarget": 15.6,
"occludedFromLastKnownTarget": false,
"nearbySupport": 0
},
"localScore": 88
},
{
"id": "m1",
"kind": "hold",
"goal": {"x": -5000, "s": -5000, "y": 80, "yaw": 0},
"route": [{"x": -5000, "s": -5000, "y": 80, "yaw": 0}],
"facts": {
"travelMeters": 0,
"goalDistanceToLastKnownTarget": 204.4,
"occludedFromLastKnownTarget": false,
"nearbySupport": 0
},
"localScore": 10
}
]
}| Field | Meaning and source |
|---|---|
time | Simulation time when the candidate set was generated, not necessarily the time the request is sent. |
self | Own position, heading, velocity, angular velocity, leg fold, health, and current visual-contact flag. Ground tanks use kind: "ground"; undefined properties may be omitted by JSON serialization. |
target | Copy of recorded target memory plus its age. Position/velocity refer to the observation, not current hidden Clu state. source identifies the observer when present. No target orientation is explicitly sent; velocity provides travel direction. |
sounds | Recent acoustic reports, with sound type, noisy bearing and amplitude-derived distance. See Hearing input below. |
allies | Active friendly units within one active-maze-width radius in three dimensions. Each entry includes id, kind, x, s, y, yaw, vx, vs, health, state, intention, and its own dated memory or null. |
map | Up to 48 nearby wall polygons selected within a 240 m query radius. Each entry has height and points: [{x,s}, ...]. This is static map knowledge, not a camera image or the full world map. |
search | Search origin, whether it has been checked, and inspected locations; null outside an active lost-contact search. |
replanReason | Why this candidate revision was generated: sight loss/reacquisition, reported/expired contact, target maneuver/displacement, injury, or ordinary scheduling. |
current | Locally selected maneuver kind at snapshot construction. |
options | Candidate IDs, kinds, destinations, route poses, precomputed facts, and local scores. Search candidates also carry searchPath, a tank-passable corridor hypothesis from the search origin (distinct from the aircraft execution route). IDs such as m0 are meaningful only within this candidate revision. |
The simulation uses horizontal coordinates x/s, altitude y, meters, seconds and radians. Its forward direction is (-sin(yaw), cos(yaw)) in x/s; rendering converts to Three.js coordinates. Route poses are {x,s,y,yaw}. Ground candidates normally have route: null; the ground controller supplies its existing route handling.
Candidate facts are measurements, not predictions of success. goalDistanceToLastKnownTarget and occlusion use the planner's bounded extrapolation of recorded memory. nearbySupport counts known allies within 150 m horizontally of the destination. travelMeters sums route segments; for ground candidates without a route it is a direct-distance estimate. localScore is a hand-authored preference, not a probability.
Snapshots contain no screenshots, unrestricted live player object, or global enemy knowledge. Ally reports keep original observation ages. The aircraft planner can consult local static geometry beyond the subset sent in map; the supplied routes carry the resulting movement choices.
sounds is an array on the snapshot, empty when nothing recent was audible. Each report is an observation made at heardAt, not a continuous tracker. The following example is illustrative:
{
"type": "cannon fire",
"heardAt": 12,
"age": 0.5,
"bearing": -1.52,
"relativeBearing": -0.52,
"elevation": -0.2,
"amplitude": 0.03,
"estimatedDistance": 230,
"distanceUncertainty": 69,
"affiliation": "unknown",
"estimatedPosition": {"x": -4775, "s": -4988}
}Bearing and elevation are radians. bearing is in world heading coordinates; relativeBearing uses the listener's heading at hearing time. estimatedDistance is a slant distance in meters; estimatedPosition projects that noisy range/bearing onto the horizontal plane from the receiver's position at hearing time. No exact emitting position, source ID, or target velocity is sent. amplitude is normalized perceived pressure, not calibrated decibels. distanceUncertainty is a heuristic radius, not a statistical confidence interval.
| Sound | Unobstructed starting range |
|---|---|
| Clu's engine | 35 m at rest, rising to 100 m at normal maximum speed |
| Friendly ground engine | 100 m |
| Aircraft engine | 150 m |
| Cannon fire | 650 m |
| Impact | 200 m |
| Explosion/destruction or data-wave release | 950 m |
Engines emit sensor samples once per simulation second. Impulses come from simulation events and are consumed once even if rendering retains the event array. Pressure falls with inverse distance. A blocked line between source and listener multiplies pressure by 0.25, reducing detectable range to one quarter and increasing the inferred distance. The estimator uses nominal engine loudness, so a quiet idle engine can seem farther away. Deterministic per-listener noise perturbs bearing/elevation and range without altering gameplay random seeds.
This is a lightweight gameplay approximation: no sound-speed travel delay, echoes, multiple-wall attenuation, diffraction/path tracing, frequency spectrum, Doppler, or background-noise masking is simulated. The sensor operates independently of Web Audio and the player's mute/volume setting.
Each unit keeps at most six reports, expiring after 10 simulation seconds. New reports replace earlier reports of the same type and affiliation. Known friendly vehicle engines and cannon fire are labeled friendly; their listener's own engine/shot is ignored. Destruction and impacts are unidentified acoustic events. Friendly sounds stay in the input but do not trigger investigation or qualify a unit for Jev by themselves.
The local controller investigates an unknown sound only when it lacks target memory. Ground units use a nearby free map opening when the estimate falls inside a wall. Hearing does not set canSee, populate visual memory, reveal Clu's identity, broadcast a false sighting, or authorize cannon/stomp attacks. A hearing-only Jev request has target: null, sounds, and an investigate-sound candidate. The prompt explicitly describes these as uncertain cues. Sound reports expire with simulation time; teleport departure clears them, and a fresh run has none.
Constants live in src/game/hearing.js; Shift+T exposes moving-engine, cannon and explosion range controls. Sound collection and estimation live in src/simulation/hearing.js. tests/hearing.test.js verifies audibility, muffling, estimation, expiry, event deduplication, information separation and investigation. tests/hearing-browser.mjs checks an actual player cannon event through local and mocked Jev selection without making a paid API call.
| Maneuver | Intended behavior |
|---|---|
pursue | Close on recorded/predicted contact above the roof; offset supporting aircraft when another unit is preparing a nearby strike. |
search-track | Move toward the bounded predicted last-known path after losing visual contact. |
search-branch | Inspect a plausible nearby opening, preferring the last observed travel direction and avoiding recently checked locations. |
strike | Reach an oriented overhead attack pose, then attempt the existing crush attack. |
low-approach | Follow a checked low-altitude corridor route toward an attack pose. |
low-cover | Descend into a reachable broad opening near the target memory. |
pressure | Ground-tank movement toward recorded contact. |
retreat | Move away from known danger; favored at health 1 or lower. |
regroup | Move toward a known ally farther from the recorded target. |
ambush | Move toward a nearby opening, preferring occlusion from the target memory. This is a positioning heuristic, not a full coordinated ambush state machine. |
investigate-sound | Inspect the estimated location of an unknown sound without treating it as a sighting or authorizing an attack. |
patrol | Move toward an opening in the unit's maze when there is no valid target memory. Normally handled locally unless an unknown sound enables a request. |
hold | Remain near the current location at safe altitude. |
Only candidates valid for the unit and current geometry are included. Aircraft use conservative oriented hull checks and swept translation/rotation tests. The overhead planner generates climb/turn/travel/align stages; the bounded low-flight search includes heading in its state. Above the roof, execution skips obsolete stationary starting poses so momentum does not send a pursuing unit back to its route origin.
Candidate generation remains a substantial local decision layer: it chooses destinations, offsets, landing orientations, and the routes Jev can select. Jev can override the local ranking, but cannot choose a destination or tactic absent from the candidate set. It also sees that ranking through current and localScore, so this is not an independent, unbiased comparison of two planners.
The aircraft controller applies acceleration, drag, yaw acceleration and lift at the fixed simulation timestep. Swept collision validation remains authoritative after Jev selects a route. A strike still requires the attack system's own fresh visual/geometry conditions. Ground tanks retain local navigation and weapon logic; retreat/regroup suppresses their firing. Jev does not directly press the fire button.
The relay calls POST https://api.typesafe.ai/v1/systemone with server-side bearer authorization. The default model is jev-latest, overridable with TYPESAFE_MODEL.
The following is JavaScript describing the actual JSON envelope; snapshot is the object above:
{
model: 'jev-latest',
state: JSON.stringify(snapshot),
questions: {
maneuver: {
type: 'choice',
instructions: '...tactical instructions...',
criteria: Object.fromEntries(snapshot.options.map(option => [
option.id,
JSON.stringify({
maneuver: option.kind,
destination: option.goal,
route: option.route,
localScore: option.localScore
})
]))
}
}
}state and each criterion value are strings containing JSON, inside the outer request JSON. The instructions ask the unit to use recorded observations and their ages, favor survival/positioning/coordination, withdraw when wounded, exploit feasible low approaches, and commit rather than oscillate. The full prompt is in server/jev.js.
The relay accepts 1–12 candidates with unique IDs matching m followed by one or two digits, short maneuver names, and finite horizontal goal coordinates. This is deliberately a bounded choice interface, not a generated-code or arbitrary-action interface. It validates these required fields rather than applying an exhaustive schema to every snapshot property.
An illustrative provider response is:
{
"answers": {
"maneuver": {
"choice": "m0",
"confidence": 0.72,
"probabilities": {"m0": 0.72, "m1": 0.28}
}
},
"usage": null
}The relay checks that choice belongs to this request and confidence is finite and between 0 and 1. It then returns:
{
"id": "m0",
"confidence": 0.72,
"probabilities": {"m0": 0.72, "m1": 0.28},
"usage": null
}probabilities and usage are passed through for diagnostics; they do not control movement and are not fully schema-validated. No explanation or free-form plan is requested. Confidence is provider-reported, not an established probability that the maneuver will succeed.
The browser accepts the choice only if its run/mode/request epoch is still current, the unit is active and still has nearby fresh knowledge, the maneuver revision matches, the request is at most 2.5 simulation seconds old, confidence meets aiConfidence (default 0.25), and the target memory has not moved more than 45 m from the planning target. Wounded units may accept only retreat, regroup, or ambush. Teleport clears the maneuver state; pause/reset/mode changes invalidate pending work.
An accepted response restarts the chosen route at index zero, marks its source jev, and extends its earliest replanning time to at least three simulation seconds after acceptance. A rejected response leaves local execution in place.
| Setting | Current behavior |
|---|---|
| Simulation | Fixed 1/60-second steps; independent of network latency. |
| Local replanning | Nominally every 4 simulation seconds. Significant perception events bypass this gate with a 0.65-second event cooldown; injury also interrupts. With no such event, an unfinished route may be retained for up to 20 seconds. |
| Request eligibility | Candidate set less than 2.5 simulation seconds old; one request per unit/revision. |
| Browser scheduling | One request in flight across all units; at least 0.6 simulation seconds between starts. |
| Relay scheduling | One upstream request at a time; at least 600 wall-clock milliseconds between starts. |
| Timeout | Relay 2,200 ms; browser 2,500 ms, both wall-clock timers. |
| Request body | Maximum 65,536 bytes. Oversized snapshots are rejected rather than automatically shrunk. |
| Provider budget | $1 USD over the previous hour, shared by tabs of one local relay. Ledger persists across restarts. |
| Errors | Local control continues; network/HTTP/timeout failures delay the next client request by 10 simulation seconds. |
| Uncertain/stale answer | Local control continues; ordinary scheduling resumes without the error backoff. |
These limits mean Jev does not make a fresh decision for every unit every frame, or even necessarily at every local replan. The client does not retry the same candidate revision after a failed request. A snapshot may already be some simulation time old when scheduled; the response-age test uses send time, while revision and target-shift checks provide additional protection.
Local replanning now reacts to meaningful observation changes. Perception updates roughly every 0.2 simulation seconds. A first qualifying change can replace the maneuver on the next planning update; subsequent event interruptions are limited to one per 0.65 simulation seconds. The planner compares current knowledge to the observations used for its last plan, so a change during the cooldown remains eligible afterward.
| Event | Response |
|---|---|
| Lose or regain visual contact | Generate fresh search or pursuit candidates. |
| Observe a turn, stop or acceleration changing the target velocity vector by at least 8 m/s | Recompute the maneuver from that observed velocity. |
| Recorded target position shifts at least 45 m from the planning observation | Recompute the approach without waiting for the normal four-second gate. |
| Gain contact through radio or lose it to expiry/confirmed destruction | Reconsider the plan from the new knowledge state. |
| No significant event, route still unfinished | May retain the maneuver for up to 20 seconds from planning time. |
| Health reaches the retreat threshold | Interrupt a non-retreat/non-regroup plan when the tactical planner next runs. |
| Movement fails swept collision validation | Stop invalid motion and clear the plan for replacement. |
| Hear an unknown sound without target memory | Clear the plan subject to the separate four-second hearing interruption cooldown. |
These changes preserve velocity and yaw momentum. An aircraft already executing its committed attack follows the existing attack state machine rather than switching tactics mid-drop. Ground units refresh their route when they receive a new tactical plan.
When a healthy unit loses sight, local scoring favors search-track and search-branch over waiting or regrouping. Track prediction uses the recorded velocity, a two-second search lead, and at most five seconds of total extrapolation. It stops at mapped obstructions. Once near that estimate, it marks the origin checked and does not reinstate the return-to-origin maneuver merely because the unit moves away. Candidate locations come from a bounded corridor graph: cardinal 8 m steps, a 160 m path-length budget and at most 1,800 nodes, with every edge swept against walls using the tank footprint. This excludes nearby but disconnected spaces. Choices favor nearby unchecked locations and the recorded travel direction, and penalize destinations already selected by nearby allies. Both aircraft and ground units record completed checks for this search episode. A new visual contact or materially displaced recorded contact resets the search; expired knowledge ends it.
Aircraft already above the roofs inspect these corridor locations from above without descending at every checkpoint. A settled low aircraft may use a feasible low route. The graph describes where Clu could travel; the aircraft execution route is separately checked against its own hull. searchPath exposes the hypothesis to Jev, while route remains the actual vehicle maneuver. Arrival advances the search without waiting for exact final yaw or a full stop. The planner omits stale attack-pose candidates when visual contact is absent and stops offering direct pursuit back to an already checked origin. No hidden Clu position enters this search, and searching alone never authorizes a stomp or cannon attack. Wounded units still favor withdrawal.
A new candidate revision becomes eligible for Jev under the existing range/rate rules. Replies are rejected if sight/contact state or the observed velocity/position has materially changed, even before the event cooldown allows another plan. Revision checks also reject answers to superseded plans. Network scheduling remains serial; local reactions do not wait for a provider reply.
The Vite dev/preview plugin reads TYPESAFE_API_KEY, including Vite's environment loading, or falls back to the raw key in credentials/Typesafe.txt. Credentials stay server-side; those files are ignored by Git and denied by Vite file serving. Restart the server after changing the key. No key is stored in browser preferences, snapshots, or the built JavaScript.
GET /api/jev/status returns {configured, model, remaining} without the key. POST /api/jev/decision accepts the snapshot. The relay rejects mismatched Origin hosts when that header is present; it is a local development service, not a complete authenticated public gateway.
Earlier direct-browser tests found TypeSafe rejecting localhost CORS preflights, so the client uses the same-machine relay. That is an observed integration constraint, not a claim about all future provider configurations. The public GitHub Pages build now uses the Cloudflare relay described below; local development retains the same-machine relay.
Public builds set VITE_JEV_API_BASE=https://tron-jev.tron-canyon-run.workers.dev. The browser sends the same snapshot contract to /api/jev/decision there. The fixed model and question are assembled on the server using shared shared/jev-protocol.js; the client cannot supply an upstream URL, credential or question template. The Worker bounds incoming JSON to 32 KiB and serialized provider input to 64 KiB, enforces a 2.2-second provider timeout, validates the returned candidate/confidence, and never returns the key. /api/jev/status exposes only configured/model. See README for deploy and key rotation commands.
workers/jev/budget.js uses a single globally named SQLite Durable Object and synchronous transactions to reserve requests before calling the provider. The initial limits are 1,000 calls and 16 MB of submitted input per UTC day globally; 300 calls/day and 60/minute per IP; 750 ms minimum spacing; one pending call per IP and four globally. Failed calls count. Reservations expire after ten seconds if release fails. Limits survive Worker restarts/deployments; the next UTC day starts a fresh allowance. Missing or failed budget storage denies the request without contacting Jev. Only counters, daily keyed IP hashes and short-lived leases are stored, not snapshots or raw IP addresses. These bounds limit request volume, not exact dollar spend.
CORS allows only the two website origins, but public clients are anonymous and Origin is not authentication. Non-browser abuse can still exhaust the shared budget; the persistent caps bound provider usage. Players behind the same IP share limits. Public clients space request starts by at least 1,200 ms of wall time. The browser honors the exposed Retry-After header using wall time, even across simulation resets, and continues local tactics. Provider failure also retains local control. Disable calls with JEV_ENABLED=false or adjust the named quota variables and redeploy. The game remains static on GitHub Pages; only Jev decisions use Cloudflare.
The production HUD shows a small top-right warning when Jev is deliberately off, unavailable, or rate limited. Service notices persist during pause/reset/retry and clear on a successful reply, even if its choice is too uncertain to apply. Normal idle or low-confidence decisions do not produce a service warning. Local enemies continue running. The keyed warning area can also display other explicitly reported warnings/errors.
Shift+T shows AI mode, status and the latest decision details. The development state exposes up to 12 recent responses with unit ID, request snapshot, response, acceptance flag and measured wall-clock latency. This is in-memory diagnostic history, not a persistent replay log. Changing AI mode via Apply restarts the run.
| Source | Responsibility |
|---|---|
src/simulation/recognizers.js | Perception, dated radio sharing, aircraft updates. |
src/simulation/tactical.js | Candidate generation, local choice, snapshots, acceptance and aircraft execution. |
src/simulation/search-routes.js | Connected corridor hypotheses for lost-contact search. |
src/simulation/maneuver-geometry.js | Hull checks, swept clearance, overhead and corridor routes. |
src/simulation/ground-tanks.js | Ground tactical goals and weapon behavior. |
src/ai/jev-client.js | Decision coordination, round/request tickets, acceptance and diagnostic history. |
src/ai/jev-transport.js, jev-request-policy.js, jev-participants.js | HTTP/deadlines, pacing/retries/cooldowns, and information-limited participant selection. |
shared/jev-errors.js, shared/jev-pricing.js | Typed relay failures and common cost calculation. |
server/jev.js | Local credential loading, relay and development service limits. |
shared/jev-protocol.js | Shared validated provider question. |
workers/jev/index.js, workers/jev/budget.js | Public proxy, CORS and persistent usage budget. |
src/game/tactical.js | Named tactical/request tunables. |
src/app/game-app.js, development-tools.js | Browser composition, preferences, lifecycle and detached development inspection. |
Run node --test tests/tactical.test.js tests/jev.test.js for geometry, pursuit, hidden-information invariants, range gating, answer acceptance and relay/client behavior. tests/tactical-browser.mjs covers mode switching, wall-side attack, fallback and lifecycle; its optional --live mode permits one provider request. See Validation for commands, recorded results and unresolved human review.
The current boundary gives Jev tactical selection but leaves much tactical creativity inside candidate generation. A useful next experiment is to let it request an intent plus a bounded destination/heading/altitude, then ask the local planner to find a feasible route and report failure. Squad-level assignments, explicit timing/coordination, and fair scheduling would be additional extensions. These are proposals, not implemented behavior.
Keep movement integration and collision enforcement local in those experiments. The opening-pursuit defect demonstrated why: a correct tactical choice cannot compensate for an executor that brakes and returns to an obsolete waypoint. Compare decision quality separately from route execution, and measure latency, rejection rates and per-unit service coverage before attributing behavior to the model.
Local client requests now have a 650 ms wall-clock minimum, retained across resets. Local 429 responses distinguish in-flight requests, spacing and the rolling-hour dollar budget and include Retry-After. Purchased JEV credits do not reset this game-owned budget. The status endpoint reports spent/remaining USD over the rolling hour.
Local spend accounting uses usage.input_tokens at $0.042 per million input tokens; output is free (TypeSafe pricing). The rate is named in shared/jev-pricing.js and must be updated if provider pricing changes. Before sending, reserve a conservative estimate of two tokens per serialized payload byte plus 4,096 overhead tokens. Replace the estimate with reported billable input usage on a parsed successful response, even if its decision is invalid. Unknown/failed outcomes retain reservations until expiry. This is local cost accounting, not an account-wide provider-enforced billing cap; unreported usage and tokenizer overhead are estimates. .local/jev-spend.json is written before dispatch and retained across restarts. Use one local relay process per ledger. Tracking begins with adoption; previous requests cannot be reconstructed. Public Worker quotas are unchanged. Configure JEV_HOURLY_BUDGET_USD (default 1); the old request-limit setting is no longer used.
Player objectives expose every beam’s red/transitioning/blue state, distanceMeters and hull-relative bearingRadians (zero ahead, positive right). objective.activeBeamId identifies the persistent destination. The prior 500 m routing cutoff is removed. A coarse graph around maze bounds links swept local A* routes across the open grid. The pilot retains the chosen beam and remaining route across replans, changes destination after collection, and retries unreachable routes after 15 seconds. In the absence of maneuver threats, the available choice is the active mission route (or hold during transfer); short exploration is a fallback only when no beam route can be found or all beams are blue. Combat still offers evasive maneuvers. This is intentional mission commitment in the local planner, not additional independent navigation intelligence demonstrated by JEV.
Autoplay continues through window blur and hidden-tab transitions. The hidden loop skips rendering and uses a 250 ms timer with fixed simulation steps and at most one second of catch-up per callback. Explicit pause is respected; if JEV failure disables autoplay while unattended, the simulation pauses. Browser/OS suspension can still limit progress.
The motor preserves waypoint progress when the current choice is confirmed, skips visible intermediate waypoints, brakes for tight turns, and creeps into blind intermediate corners at up to 2 m/s and retains steering down to 2 cm before requiring the next leg to be visible. Uncollected beams within 2 km supersede a distant commitment. Turbo state is exposed in self.turbo; local safe-runway checks trigger normal turbo input and regulate the boosted speed. Manual driving overrides suppress automatic turbo activation.
Post-combat correction: visibleEnemies remains all observed contacts; threatIds identifies contacts within 100 m or within 250 m moving toward Clu faster than 2 m/s. Only those threats enable escape choices. Threat appearance/disappearance triggers immediate replanning and clears failed-route cooldowns; late escape responses are rejected when no threat remains. While red beams remain, peaceful route failure allows maze-entry recovery or hold/retry instead of aimless exploration. These thresholds are local tactical heuristics and use observed velocity, never enemy private pursuit state.
Blueprint routing correction: browser play defaults to the blueprint maze, while historic Node fixtures default to the authored maze. Autoplay now first searches outward from the beam with 8 m cells, a 12,000-node cap and 4 km detour allowance, reversing the result for Clu. This avoids exhausting an inward search in the open exterior before entering the blueprint corridors. Swept wall clearance remains mandatory. tests/autoplay-blueprint.test.js explicitly selects the browser layout and verifies local beam capture from its opening position.
Timeouts now allow two retries before disengaging autoplay (three consecutive timeouts). Minimum backoff is 0.5 then 1 second, respecting existing request pacing. The local pilot continues during retry, and successful responses reset the streak. Budget/authentication/other service failures still disengage immediately. Pause/reset cancellation does not count as failure.
Top-right JEV statistics count every client decision attempt this round, including enemy, player and retry requests. Requests/sec uses a trailing ten-second window. Cost uses reported usage.input_tokens at the shared $0.042/million rate; pending or unreported outcomes retain conservative payload-based estimates and show a ~ prefix. Failed requests may therefore overestimate spend. Totals survive pause and mode toggles; a new run starts a new stats object so late responses from prior rounds cannot contaminate the new totals. This display is per client round, not the persistent server-wide rolling-hour ledger or the provider’s full account bill.
The gameplay candidate/input/output contract remains unchanged. AutoplayMission builds player options while RouteFollower exclusively owns their execution cursor; JEV confirmation cannot restart an accepted route. Enemy and player request snapshots are detached from live state. A request ticket captures the round, unit identity, plan and teleport revisions, and observation time; obsolete responses cannot mutate a new round or replaced unit.
The client separates cancellation, scheduling reset and round reset. Provider cooldowns survive round reset; round statistics restart only for a new round, and late usage updates settle the original accounting object. Local and Worker error bodies carry typed timeout/cancelled/unavailable/limited/invalid codes; only timeouts receive the existing two retries. Legacy relay timeout text remains a compatibility fallback. The transport wraps browser fetch and timers to preserve their native calling convention, fixing the Safari “Window.fetch” receiver regression. No credentials enter shared modules or browser snapshots.
The current implementation/validation and ownership map are maintained in Refactoring and Validation. Live-provider decision quality and the later-maze autoplay stall remain separate from transport correctness.
Escorts with no fresh target or sound investigation now return to the carrier through a dedicated local controller in every AI mode. The tactical planner no longer replaces this duty with maze patrol. Air escorts climb to roof clearance and track the moving formation slot without treating it as a stop waypoint. Ground escorts commit to separated routes around the maze perimeter, release the detour on reaching the far side, and use up to 1.4× ordinary speed only while returning to escort formation. Fresh target observations still interrupt escorting and use the existing tactical/JEV selection.
Player snapshots now include visibleDebris: at most 24 nearest currently observed pieces within 160 m and unobstructed wall visibility. Each record contains id, x, s, y, vx, vs, vy, planar bounding radius, halfHeight, gravity (m/s²), and sleeping. These are detached physics observations, not enemy intent or hidden state. The player prompt asks JEV to avoid the predicted debris path and notes that supplied routes are wall-checked, not guaranteed safe from moving wreckage.
src/simulation/debris-avoidance.js guards the selected motor command every simulation tick. It predicts 2.5 seconds of tank acceleration, turbo, braking and steering against ballistic piece motion and ground-level wreckage. If the desired command intersects a hazard, it compares braking and left/right avoidance commands, rejects wall-crossing paths, and disables a new turbo request. It retains turret/fire inputs and uses the ordinary vehicle physics. At rest, braking does not become unintended reverse. Normal motion resumes when the path clears, including after debris removal. Manual controls still override their channels.
The prediction omits future contact impulses and changing debris orientation, so it is conservative about bounds but cannot guarantee immunity from debris. Local avoidance does not wait for JEV; model snapshots update at the existing plan cadence. No provider limit, request interval, or damage rule changed.
src/game/communication.js defines a radio radius of one MAZE_LENGTH for the active world, rather than 304.8 m. The same radius gates target/neutralization broadcasts, newly materialized units’ awareness and tactical ally snapshots. Observation timestamps and message delays are unchanged. This is a radius, not a diameter; it scales per scenario and does not reveal hidden Clu movement.
Within 140 m of a recorded target, aircraft with radio contact and compatible memories reserve an attack lead for up to twelve seconds. The lead must have visual contact and be healthy and ready to strike; a committed attack retains ownership. Distance fluctuations alone do not replace a valid reservation. Blocked, destroyed, injured, cooling-down or visually disconnected leads yield; an expired reservation gives another eligible aircraft a turn.
The enemy snapshot’s attackAssignment records lead ID, lease times, heading and support slot. Supporters get separated flank goals, omit strike/low-approach candidates while supporting, and cannot initiate a stomp even if a delayed choice arrives. Assignment changes invalidate the previous tactical plan/revision. Close physical separation moves the supporter aside instead of displacing the lead. Distant pursuit still uses the existing intercept behavior. The automated two-aircraft encounter now allows one attacker to complete a stomp without simultaneous competing drops.
Blueprint ground patrol spawns now require a swept route to the maze exterior. The blueprint contains enclosed free-floor pockets; checking only hull clearance previously allowed tanks to spawn where they could never join a pursuit. Checks are cached per world and hull radius.
Tank route execution retains a valid route while its destination remains close to the route's original target. If the normal 12 m search fails during pursuit, a bounded 8 m search allows larger detours. If no complete route is found, it can approach the closest explored reachable point that improves distance by at least 12 m. Every segment still has swept hull clearance; a genuinely inaccessible contact cannot authorize crossing a wall. These changes use recorded sightings/radio reports and static geometry, and apply in Classic, local and JEV modes without changing the API contract.
Enemy ground A* now runs incrementally through GroundRoutePlanner, sharing 192 search steps per simulation tick in round-robin slices of 24. A unit follows its existing usable path while a replacement is pending; stale destinations and removed units discard pending work. Startup validation and player mission planning retain a synchronous adapter. Priority queues replace full frontier sorts in ground and aircraft route search.
Aircraft and tanks share a budget of one newly generated tactical candidate set per simulation tick. Pending units retain their current maneuver; their motors, perception, radio and collision updates still run at the fixed simulation rate. First plans and replans may therefore be delayed by a few ticks under load. The expensive lost-contact search map is constructed when that planning work is admitted. Budgets and pending searches are round-local and do not enter API snapshots. Provider scheduling, billing and the JEV input/output contract are unchanged.
Recognizers may deliberately land to block Clu’s path and create a crush opportunity for an ally. Landing to rest is also acceptable. These are approved future maneuver choices, not yet implemented options in the candidate list. A stationary grounded unit should be evaluated by its intent and progress, rather than automatically classified as stuck. Coordination must continue to use observed or communicated information.
The game now generates strike destinations using nearby wall-edge headings and a bounded two-ring search in sixteen directions around the predicted contact. This gives JEV feasible choices in angled corridors and beside walls, without changing the input/output contract. Offsets stay inside the existing attack trigger with an arrival margin. Execution settles within 0.35 m and brakes yaw before descent, retaining full collision clearance, fresh visible observations, lead/support coordination and the existing damage radius. Local tactical control uses the same candidates and controller. Classic is unchanged. Landing searches run only for visible contacts and remain subject to the shared per-tick planning budget.
The coordination layer recruits nearby informed aircraft and retains their assignments while they move to support positions, within radio contact and the existing target-memory lifetime. The lead retains exclusive stomp authority; satellites no longer abandon support merely because they have moved beyond 140 m or lost personal line of sight. One satellite is designated spotter and the others cover separated ground-connected branches near the recorded contact. If no branch is available, distinct overhead positions provide a fallback. Goals are cached until the formation or recorded target shifts; roles and goals appear in the existing attackAssignment snapshot. These are positioning roles, not new weapons or permission to see hidden Clu. Existing lead leases, blocked/dead lead handoff, fresh-sighting attack gates and wounded retreat remain active.
A leader now renews its twelve-second lease after five meters of measurable combined horizontal closure and descent toward the recorded target. Previously the fixed deadline swapped two approaching aircraft between lead and support, repeatedly cancelling the approach. This renewal is local coordination shared by Tactical and JEV, not a change to the provider contract. Blocked, destroyed, ineligible and genuinely stalled leaders still hand off.
N switches between JEV and local tactical enemy control without restarting the round, aborting pending requests. Turning JEV off also disengages Clu autoplay; U explicitly enables JEV again when starting autoplay. The stats box shows the toggle and its state. Request/cost totals remain for the current round.
Pursuit now ends at an available wall-aligned stomp pose. Local execution can initiate a stomp during pursue, strike or low-approach when the actual pose is safe; it does not depend on the provider selecting strike. Leadership, healthy condition, fresh personal sight, cooldown, angular braking, predicted landing drift and full swept clearance still gate commitment. Supporting and retreating units cannot take this opportunity. The request/response schema is unchanged.
Historical experiment, now superseded by restoring original motion above: maximum yaw rate is 120°/s (one revolution per three seconds at full speed), with 240°/s² acceleration/braking and the normal smooth heading response. All flight uses the same limit, including close attacks. Close-attack speed reduces when a turn needs a tighter radius, avoiding repeated orbits. A turn from rest includes acceleration and settling time, so a backwards-facing attacker can exceed the four-second stomp target. Eight-heading tests verify bounded yaw rate/acceleration and successful stomps; aligned attacks retain the four-second check.
Recognizers can thrust sideways and backward independently of yaw, in local/JEV navigation, Classic navigation and carrier escort flight. The acceleration vector shares the original 24.2 m/s² budget across all directions (no diagonal bonus); drag, braking, speed caps and angular inertia remain unchanged. Tight-corridor planning includes lateral/reverse translations with swept hull clearance. A wall-aligned hull can slide into position without first turning broadside. Existing pursuit-to-stomp opportunity checks and support assignments remain active.
Autonomous cycles on both teams now share the JEV client while the player is in the arena. The human cycle is excluded. Each eligible bike can request a corridor destination every four seconds, with fair oldest-request-first scheduling under the existing global rate limits. controller: "cycle" selects the light-cycle prompt in the shared local/public relay protocol.
Snapshots contain arena-local meter coordinates, self pose and reserves, nearby unobstructed cycle observations and up to three currently clear corridor destinations. Responses bias local direction scoring for up to six seconds. Blocked cells and cramped-space avoidance remain local; this is strategic guidance rather than frame-by-frame remote steering. Stale replies (over 2.5 simulation seconds), low confidence, death, escape and reset invalidate choices. Pause cancels requests; switching to local clears goals. Network failure leaves local driving active. Teammate turbo conservation and human controls are unchanged. Road-mode cycles still use local driving.
The updated Worker must be deployed with the client to enable the cycle-specific production prompt. Automated tests use mocked decisions; live JEV driving quality is not yet validated.
The user requested that TypeSafe balance control total public usage. wrangler.jsonc now sets DAILY_REQUESTS, DAILY_INPUT_BYTES, IP_DAILY_REQUESTS and IP_MINUTE_REQUESTS to unlimited. This supersedes the prior daily quotas. The relay retains only per-request size/timeout rules and short-term overlap/pacing controls. Local development's hourly dollar cap is separate and unchanged. A browser that received a previous daily-cap cooldown should reload to clear that in-memory cooldown after deployment.