feat: add Zenith strategy and move latency tracing
Build and Push Docker Container / build-and-push (push) Successful in 2m18s
Build and Push Docker Container / build-and-push (push) Successful in 2m18s
- Register Zenith 1.1 with balanced duel verdicts and forced-outcome overrides. - Prioritize permanent-trail space in Constrictor and health-aware hazard routes. - Deduct executor queue delays and return fallback directions on move timeouts. - Correlate response headers, replay timings, and sampled structured trace logs. - Move shared metrics publication off the response path without losing local counts. - Allow configurable tournament opponents and add a psql helper recipe. - Preserve empty latency values through compact replay encoding and migration. - Update Arena game links and use default assets for missing customizations. - Cover strategy, HTTP lifecycle, tracing, replay codecs, and dashboard behavior. - Validate with 260 passing Python tests, 4 skips, and 2 passing JavaScript tests.
This commit is contained in:
@@ -100,6 +100,28 @@ Run it with:
|
||||
SNAKE=PrismBattleSnake_GPT_5_6_Sol python main.py
|
||||
```
|
||||
|
||||
## ZenithBattleSnake_ClaudeOpus5_5
|
||||
`ZenithBattleSnake_ClaudeOpus5_5` builds on Prism and keeps its engine. Prism
|
||||
only runs the exact duel search on near-tied heuristic candidates. Zenith adds a
|
||||
root verdict pass in duels: every safe move is resolved against all
|
||||
simultaneous enemy replies using the shared transposition table. A move whose
|
||||
search proves a forced loss is replaced by the best surviving move. A move whose
|
||||
search proves a forced win is played even if the heuristic preferred another
|
||||
move. Its public Battlesnake API name is `ZenithBattleSnake`.
|
||||
|
||||
Version 1.1.0 adds permanent-trail space scoring for Constrictor (free capacity
|
||||
is not compared against the already occupied body length), balanced root-search
|
||||
budgets, and health-cost routes for hazard escape and food. It reserves at least
|
||||
180 ms for non-search work. The HTTP move path also deducts executor queue wait
|
||||
from the strategy budget and returns a legal-direction fallback instead of null
|
||||
when its request budget expires. This is best-effort deadline handling, not a
|
||||
hard real-time guarantee under CPU saturation.
|
||||
|
||||
Run it with:
|
||||
```sh
|
||||
SNAKE=ZenithBattleSnake_ClaudeOpus5_5 python main.py
|
||||
```
|
||||
|
||||
Benchmark Apex and Prism against sampled positions from a gameplay database:
|
||||
```sh
|
||||
python scripts/benchmark_snakes_from_db.py \
|
||||
@@ -129,12 +151,41 @@ Run paired seeded games through the official local Battlesnake rules engine:
|
||||
just bench-snake-tournament games=20 gametype=standard map=standard
|
||||
```
|
||||
|
||||
Each seed is played twice with Apex and Prism swapping initial engine slots. The
|
||||
Pick other opponents with `snake_a=` and `snake_b=`, for example
|
||||
`just bench-snake-tournament snake_a=PrismBattleSnake_GPT_5_6_Sol snake_b=ZenithBattleSnake_ClaudeOpus5_5`.
|
||||
|
||||
Each seed is played twice with both snakes swapping initial engine slots. The
|
||||
report includes wins, draws, win rates, and average game length. Save all
|
||||
per-game results with `output=data/tournament-report.json`. The tournament starts
|
||||
both snake servers with gameplay persistence disabled, adds the engine identity
|
||||
header required by the API, and shuts them down when finished.
|
||||
|
||||
## Move tracing and latency diagnosis
|
||||
Every `/move` response includes `X-Move-Trace-ID`. Replay thinking contains a
|
||||
small `move_trace` object: JSON parse, runtime lookup, executor queue wait,
|
||||
strategy execution, handler/response encoding, bookkeeping queue wait, and
|
||||
metrics publication timings. No board payloads are copied into traces.
|
||||
|
||||
Structured application log lines start with `move_trace` and include the same
|
||||
ID, game ID and turn, plus persistence and dashboard-publication duration once
|
||||
background work finishes. These last two timings cannot be included in the
|
||||
record being written itself. Timed-out workers may finish later; missing
|
||||
`strategy_ms`/`worker_finished` means they had not finished at that snapshot.
|
||||
|
||||
- `MOVE_TRACE_SAMPLE_EVERY=100`: approximately 1% of normal requests logged;
|
||||
use `1` for all, `0` to disable normal sampling.
|
||||
- `MOVE_TRACE_SLOW_MS=300`: always log a trace if any measured stage exceeds
|
||||
this threshold. Timeouts and metrics publication failures are always logged.
|
||||
- Metrics counters update locally before responding; shared metrics backend
|
||||
publication now runs in ordered background bookkeeping, not on `/move`'s
|
||||
response path.
|
||||
|
||||
These are lightweight local timings, not exported OpenTelemetry spans. Handler
|
||||
time starts inside the route and excludes middleware, socket delivery and
|
||||
reverse-proxy/network delay. Compare with client-observed latency. Background
|
||||
stage times can include event-loop scheduling delays; production improvements
|
||||
must be verified after deployment under representative concurrency.
|
||||
|
||||
## Compact gameplay database
|
||||
Gameplay storage keeps game results in `games` and snake identity (name,
|
||||
customizations) once per game in `game_snakes`. Replay data is stored compactly:
|
||||
|
||||
Reference in New Issue
Block a user