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:
@@ -152,6 +152,10 @@ def run_game(
|
||||
draw = bool(terminal.get("isDraw", winner is None))
|
||||
return {"seed": seed, "winner": winner, "draw": draw, "turns": turns}
|
||||
|
||||
def display_name(snake: str) -> str:
|
||||
"""Short engine display name, e.g. PrismBattleSnake_GPT_5_6_Sol -> Prism."""
|
||||
return snake.split("_", 1)[0].removesuffix("BattleSnake") or snake
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--games", type=int, default=20, help="Number of unique seeds")
|
||||
@@ -163,37 +167,39 @@ def main() -> None:
|
||||
parser.add_argument("--timeout", type=int, default=500)
|
||||
parser.add_argument("--base-port", type=int, default=9301)
|
||||
parser.add_argument("--cli", default=str(ROOT / ".testing/tools/battlesnake-cli/battlesnake"))
|
||||
parser.add_argument("--snake-a", default="ApexBattleSnake", help="Registry name of the first snake")
|
||||
parser.add_argument("--snake-b", default="PrismBattleSnake_GPT_5_6_Sol", help="Registry name of the second snake")
|
||||
parser.add_argument("--json-output")
|
||||
args = parser.parse_args()
|
||||
if args.snake_a == args.snake_b:
|
||||
raise SystemExit("--snake-a and --snake-b must differ")
|
||||
|
||||
cli = Path(args.cli)
|
||||
if not cli.is_file():
|
||||
raise SystemExit(f"Battlesnake CLI not found: {cli}. Run: just build-battlesnake-cli")
|
||||
|
||||
apex_port, prism_port = args.base_port, args.base_port + 1
|
||||
apex_proxy_port, prism_proxy_port = args.base_port + 2, args.base_port + 3
|
||||
snakes = (args.snake_a, args.snake_b)
|
||||
servers: list[subprocess.Popen] = []
|
||||
proxies: list[tuple[ThreadingHTTPServer, Thread]] = []
|
||||
results: list[dict] = []
|
||||
started = time.perf_counter()
|
||||
try:
|
||||
servers = [
|
||||
start_server("ApexBattleSnake", apex_port),
|
||||
start_server("PrismBattleSnake_GPT_5_6_Sol", prism_port),
|
||||
]
|
||||
proxies = [
|
||||
start_proxy(apex_proxy_port, apex_port),
|
||||
start_proxy(prism_proxy_port, prism_port),
|
||||
]
|
||||
urls = {
|
||||
"Apex": f"http://127.0.0.1:{apex_proxy_port}",
|
||||
"Prism": f"http://127.0.0.1:{prism_proxy_port}",
|
||||
}
|
||||
urls: dict[str, str] = {}
|
||||
labels = [display_name(snake) for snake in snakes]
|
||||
if len(set(labels)) != len(labels):
|
||||
labels = list(snakes)
|
||||
for index, (snake, label) in enumerate(zip(snakes, labels)):
|
||||
server_port = args.base_port + index
|
||||
proxy_port = args.base_port + len(snakes) + index
|
||||
servers.append(start_server(snake, server_port))
|
||||
proxies.append(start_proxy(proxy_port, server_port))
|
||||
urls[label] = f"http://127.0.0.1:{proxy_port}"
|
||||
names = tuple(urls)
|
||||
for offset in range(max(1, args.games)):
|
||||
seed = args.seed_start + offset
|
||||
# Swap engine slots for every seed. This controls for deterministic map
|
||||
# spawn positions and gives each strategy both initial placements.
|
||||
for order in (("Apex", "Prism"), ("Prism", "Apex")):
|
||||
for order in (names, names[::-1]):
|
||||
result = run_game(
|
||||
cli=cli, seed=seed, game_type=args.gametype, map_name=args.map,
|
||||
players=[(name, urls[name]) for name in order],
|
||||
@@ -219,6 +225,7 @@ def main() -> None:
|
||||
"unique_seeds": max(1, args.games),
|
||||
"gametype": args.gametype,
|
||||
"map": args.map,
|
||||
"snakes": list(snakes),
|
||||
"wins": dict(wins),
|
||||
"win_rates": {
|
||||
key: value / len(results) for key, value in wins.items()
|
||||
|
||||
Reference in New Issue
Block a user