Skip to content

Sim realism, goal-based strategy evaluation, regression moments, and on-pitch pictures - #146

Merged
isaac0804 merged 142 commits into
mainfrom
sim-realism-20261016
Oct 17, 2026
Merged

isaac0804 merged 142 commits into
mainfrom
sim-realism-20261016

Conversation

@isaac0804

@isaac0804 isaac0804 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Sim realism measured against real Division B matches, a strategy evaluation system that decides on goals, regression moments, planner and referee fixes, and a set of on-pitch pictures with docs built around them.

Release notes

Strategy evaluation

  • tools/evaluation/evaluate.py: is a candidate stronger than the champion of a fixed reference pool (pools/pool_v1.json)? It plays rounds under seeded sim noise, decides on paired goal differences and stops once the answer is clear. Every match goes into a ledger (replays/eval/ledger.jsonl), with ratings over all of it. Goals only: shots, xG and the other signals were tested as rankers and rejected.
  • --explain draws candidate-vs-champion pictures before the replays are removed: positions with and without the ball, shots and fouls, plus summary.json and a triage of the candidate's two worst matches.
  • Fingerprints ignore comments, docstrings and formatting, so cached matches survive cosmetic edits.
  • The scenario bench and the ladder are retired.

Seeing the game

  • docs/visual_guide.md: the game drawn on the pitch from real replays, with what each picture has shown us and the command that draws it. It names and shows the position maps and shot maps of every strategy.
  • New picture tools:
    • tools/pitch_maps.py: position, shot and foul maps per strategy.
    • tools/match_timeline.py: one match window as swimlanes (referee, each robot's tactic, possession, distance to the ball).
    • tools/restart_picture.py: where the referee override sends each robot at a restart.
    • tools/plan_snapshot.py and tools/plan_trace.py: the fast-path planner's decision on one tick, and over a window.
    • tools/motion_planning_benchmark.py --figures: trajectories and a summary per scenario.
    • tools/package_graph.py and docs/architecture.md: the package dependency graph, with the replay/analysis import rule checked.
  • tools/triage.py RUN_DIR: start here when a strategy plays badly. It takes each strategy's worst matches, collects every flagged problem and pictures the worst. Output: index.md, findings.jsonl and pictures.
  • --findings on the picture tools: one shared JSON format (utama_core/analysis/findings.py), so agents can filter problems without reading images.
  • Architecture pictures drawn in one style (docs/img/diagram_style.py) instead of Mermaid: one tick of StrategyRunner (in the README), the match data flow, the tactic-kernel model, the referee and its state machine, one rsim tick, the planner control schemes and the real robot path. Each comes from a make_*.py script, and a test checks every class and path a picture names still exists.
  • docs/signal_report.md was redrawn as figures that explain results instead of rank colours.

Sim realism

  • A realism scorecard against real 2025–26 Division B matches (utama_core/analysis/realism), covering ball deceleration, robot motion, dropouts, shots and xG.
  • Real logs can be kept raw: convert_ssl_log --keep-raw, with resume and memory caps.
  • SimNoise: seeded per-robot latency, kick speed and direction noise, vision noise, and physics knobs (off by default).
  • pixi now builds rc-robosim from our fork in vendor/rSim.
  • Plan and results: docs/sim_realism.md.

Regression moments and debugging

  • Regression moments: replayed or hand-made field states with a fixed check (tools/moments.py, utama_core/tests/moments/), run in pixi run test.
  • replay_trace --events/--json, repro_from_replay --summary, moments fouls --by/--json, and tools/setup_worktree.sh for parallel agents.
  • docs/STRATEGY_DEVELOPMENT.md, "Debugging a foul or failure": the workflow, and the bugs it has found.

Fixes

  • Planner: a robot inside the ball's keep-out is pushed past the edge (to 0.85 m) instead of parking on it; a robot pressed against another may drive straight away.
  • Referee:
    • a free kick is taken once the ball moves 0.05 m;
    • push-out targets in a corner stay on the pitch;
    • our ball placer routes round the ball.
  • The rolling-ball receive point is clamped to the field.
  • carry_exhausted counts reaction time before braking.

Repo hygiene

  • Unused helpers, scenario banks v5/v6 and a duplicate GUI demo removed.
  • strategy_runner split into modules.
  • README cleaned up, and a new drawn one-tick pipeline picture (docs/img/pipeline/one_tick.png, from make_one_tick.py) replaces the outdated 2025 drawio one in the README and pipeline_method.md; the Mermaid version moved to docs/architecture.md.
  • Pre-commit ruff bumped to v0.15.12.

Known, not fixed here

  • Tactic flip-backs: most strategies that split attack and defence on possession take a tactic for under 1 s and revert about 5 times per live minute, and press_and_pass 13. The tactic_thrash finding flags it.
  • Restart clearing stops short: the step that clears robots out of the keep-out at a restart stops 1 cm short, leaving them at 0.79 m (keep_out_short).
  • Unexplained lines: the vertical GiveAndGoTactic lines in the position maps.
  • Restart findings are slow: about 45 s per match, so triage scans restarts only with --restarts.

Testing

  • pixi run test: 12857 passed, 85 xfailed.
  • pixi run lint clean.
  • No round-robin was rerun for this last batch: the picture and triage tools only read replays.

isaac0804 and others added 30 commits October 14, 2026 17:29
Match pixi.toml and the CI ruff-action pin, and move ignore/fixable
under [lint] so ruff 0.15 stops warning about top-level keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
motion_stats imported it from tools/evaluation/round_robin.py, but tools/
is not part of the installed package. The table now lives in
utama_core/analysis/strategy_table.py; round_robin.py imports it from
there, and the tournament summary test imports it from the new location.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Delete align_defenders, to_defense_parametric, find_likely_enemy_shooter,
velocity_to_orientation, and RSimVSS, is_our_command, to_polygons: each
was referenced only by its own definition (git grep -w). Also drop the
helpers only they used (predict_goal_y_location, clamp_to_parametric,
ccw, ang_between, step_curve, EPS) and the imports they orphaned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only bank_v8 is loaded (tools/scenario_bench.py, bench_vs_standings.py,
docs). v5/v6 stay in git history; docs mentioning them as calibration
history are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-status modules

Pure move, no logic change: SideRuntime and the _turned/_mirrored frame
transforms go to run/side_runtime.py; the rsim teleport-settle, placement
and frozen-field recovery to run/sim_recovery.py (SimRecoveryMixin); the
browser vision stream and its commentary/roster to
run/vision_stream_status.py (VisionStreamStatusMixin); and the rich live
status panel to run/live_status.py (LiveStatusMixin). StrategyRunner
inherits the mixins, and the names tests import stay importable from
strategy_runner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h tools

motion_planning_benchmark and scenario_bench each had an identical
_git_revision (short HEAD, None outside a checkout). Move it to
utama_core/global_utils/git_utils.py. The scenario_bench copy in
hand_authored_scenarios.py returns "unknown" instead of None, so it stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…essing path

The Doc column named a TODO and a bare data_processing/ path. Point it at
utama_core/team_controller/README.md (brief) and fix the path to
utama_core/data_processing/. CLAUDE.md is a symlink to AGENTS.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pixi.toml defined main = "python -m main" both at the root and again under
[target.linux-64.tasks] with the identical command, so the target entry
changed nothing and is removed. docs/tools.md's task table gains the
build-planner task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The block printed values test_vector.py already asserts. The one check it
added, Vector2D.dot as a method, is now an assertion in
test_vector2d_operations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing references assets/images/pipeline.drawio.png; the README and
docs/pipeline_method.md use pipeline_new.drawio.png.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kalman.py had type-signature comments above three call sites, and
game.py had a stray '# def predict_/' stub. None of it is code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
utama_core/tests/referee/demo_referee_gui_rsim.py is an older copy of
examples/demo_referee_gui_rsim.py (WanderingTactic instead of tiki_taka_plus).
It is not a test (pytest would not collect it), nothing imports it, and
only its own docstring names it. wandering_strategy.py stays: other files
import it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om replays

Phase 1 of docs/sim_realism.md, for converted official logs and our own
matches alike: deceleration by ball speed and time since a kick, rolling
segment fits, per-robot speed, acceleration, braking and turn-rate
percentiles, and dropped detections, with between and within spreads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…_core/analysis/realism

Ports the 2026-10-14 xG analysis (~/dev/ssl/xg-analysis) into the repo. Shots, goal
linking (real goals via operator-confirmed GOAL events), shot outcomes and the xG fit are
unchanged; per-match output is identical to the old scripts on a real and a sim match.
tools/realism_scorecard.py builds the real reference from converted logs and scores a
round-robin against it, row by row with 95% bootstrap intervals over matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
SimNoise (rsoccer_simulator/src/Utils/sim_noise.py) holds ranges and a seed, all
off by default. Per match it draws each robot's command latency (whole ticks) and
kick-speed offset; kicks add their own spread, drawn when a kick command starts
and held while it lasts; vision noise and dropped detections come from a stream
per tick. Draws depend on the seed, colour and robot id only, so every pairing in
a run gets the same physics. Same seed, byte-identical match.

Wired through SSLStandardEnv, StrategyRunner(sim_noise=...), match.run_match and
round_robin.py --sim-noise JSON. Recorded in each columnar replay
(load_sim_noise) and summary.json; enters match_key only when set.

Fix: vision noise was added to env.frame in place. Teleports write that frame
back into the physics, so with noise on every ball placement moved every robot
by its noise. Noise now goes on the observation only (regression test in
test_sim_noise.py).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
Keeps HEAD's wording; the other side still described the status labels
removed on 2026-10-10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECXiwf3VYxBTMmrLaexRQK
…(with repo hygiene base)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
A shortened run cached its matches under the full-length key, so a later
full-length --reuse run would have served them as full matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
54 matches, 1059 attempts, 217 scored; held-out AUC 0.819.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…detections as sidecars

The converter dropped data the sim-realism work needs. Each converted log now
also writes <stem>.kicks.json (the tracker's KickedBall reports, once per
kick) and <stem>.tracker.zip (per-tick visibility and angular velocity);
--raw-vision adds <stem>.vision.zip with every camera detection. Kicks and
visibility come from whichever tracker source sends them (in 2026 ER-Force,
the busiest, sent neither). --backfill-extras adds the sidecars to replays
converted earlier without rewriting them. The archives are named .zip so
replay globs (*.npz) skip them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…w vision

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy

# Conflicts:
#	docs/tools.md
…t, more rows

- Shot outcomes split wide / post / crossed with no goal (crossing point interpolated to
  the goal line; a bounce near a post counts, including the frame the next kick is
  detected on). Wide shots record how far outside the post.
- reaction.py: keeper and nearest-defender time from the kick to a velocity change, and
  to moving toward the shot line, with the window the shot left to react.
- passes.py: a softer kick detector for passes, the inferred receiver's offset from the
  kick's line, and completion.
- New rows: open-play and set-piece attempts, attempt distance, keeper saves in every xG
  band, aim outside the posts, wide miss distance, reaction shares and medians, pass
  offset and completion. The broken-tracker match is excluded. --sim-cache option.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
isaac0804 and others added 26 commits October 17, 2026 21:25
tools/match_timeline.py REPLAY.npz T0 T1 [--side friendly|enemy] draws the
referee command band, one lane per robot coloured by the tactic it was in
(ticks at switches, a strip where it had the ball), each robot's distance to
the ball, and goals, fouls and shots along the top. It prints tactic switches
per minute and the longest tactic span per robot. Events come from
replay_trace.events; shots from turnover_breakdown.analyse_match.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
tools/restart_picture.py draws, for one restart in a replay, the target each
friendly robot is commanded to by RefereeOverride.tick: the ball and its keep-out,
the placement or free-kick spot, roles (kicker, placer, keeper), and red flags on
targets inside the keep-out or a defence area they must avoid. --all-restarts
draws one small panel per restart command in the referee sidecar.

Targets are captured by swapping move/turn_on_spot in custom_referee.actions for
recorders during the call only; no engine or planner code changes. The pitch,
palette and game-from-scenario helpers move into plan_snapshot unchanged in API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
tools/plan_trace.py runs FastPathPlanner._path_to on every sampled tick of a
replay window and draws the robot's path (coloured by time) with each tick's
carrot, the ball path, and time panels for robot-to-ball distance,
robot-to-carrot length, speed and the referee command. --json prints the
per-tick rows. The trace function takes a game-per-time callback, so it is
testable without a replay.

plan_snapshot.py: pitch styling, pitch, obstacle, ball and robot drawing moved
into shared helpers that plan_trace reuses; its public API and picture are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
plan_trace replays recorded states, it does not re-simulate: say so, and
read the kick-off example right. Recorded before the push-out fix, the
robot stays 0.80 m from the ball, while the current planner's carrot from
those states is the push-out point 0.85 m out. The short-carrot annotation
now tells a push-out from a parked robot (short_carrot_label, with a test
at the 258 s state). The open-play example is dropped: its target was a
guess the robot never followed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
Positions with and without the ball, shots (struck from, and conceded) and
fouls by rule, drawn on a pitch for every strategy of a round-robin run. Each
panel attacks right; a team that attacks left is rotated 180 degrees.

Shot records from ChanceTracker now carry the origin ("xy") they are drawn at.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
Four pitch figures from the tournament_20261017_151052 run, with the
observations they support, in docs/signal_report.md "On the pitch".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…hampion

tools/evaluation/explain.py writes positions (with and without the ball), shots for and
against, fouls by rule and a summary.json for a candidate and the champion, from the
replays in a run dir (a round-robin's or an evaluate.py run's). A match is picked by its
file stem (<config_a>_vs_<config_b>[_s<seed>]); the scores come from the replay's final
referee state and the fouls from the match's .stats.json. The pictures explain a verdict
and never make one.

pitch_maps.py: the per-match jobs now go through views_for_matches(), so explain builds its
views the same way; run_views and the RUN_DIR behaviour are unchanged. Two-strategy
figures get one row of two panels.

evaluate.py --explain (off by default) keeps each match's files until explain has written
replays/eval/explain/<candidate>_<run id>/; a failure is printed and never loses a verdict.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
STRATEGY_DEVELOPMENT.md (Evaluating a strategy) and tools.md describe --explain and
explain.py: the pictures explain a verdict, goals stay the verdict. The example is
split_shape against clear_press_plus from tournament_20261017_151052, made by
tools/evaluation/explain.py without playing any match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…s write findings

Each tool's flags go to JSON lines (--findings PATH, - for stdout), so agents filter on the JSON and open a picture only to understand it. match_timeline: tactic_thrash at THRASH_PER_MIN (4) switches per minute of live play, plus timeline_findings() without drawing. plan_trace: parked and pushed_out runs of at least PARKED_MIN_S (1 s); the short-carrot label now uses the same classifier. pitch_maps: six zone_share facts per strategy, no threshold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…is 1 cm

--findings PATH writes one finding per flag on a flagged target for every restart in the match (each occurrence, not drawn): target_in_keep_out, keep_out_short and target_in_defense_area, with the measured value and its limit. restart_findings(replay, side) is the callable form. The deadband flag now covers 0.79-0.80 m (1 cm, as the comment in actions.py says) instead of 0.78-0.80 m.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
Most strategies switch tactic 10-25 times per live minute by design, so a
switch-rate threshold flagged nearly all of them. A flip-back (a tactic held
under 1 s, then reverted) separates them: median 0-0.5 per minute for the
steady strategies, 4.6-5.6 for most possession-split ones, 13.4 for
press_and_pass. The finding fires at 2 per live minute.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
One page that walks through every pitch picture from real replays: how
each strategy stands, shoots and fouls; a candidate against the champion;
one match over time; a restart; the planner on fixed scenarios and on one
recorded tick and window. For each: how to read it, what it has shown so
far (flip-backs, the 1 cm keep-out shortfall, the pre-fix parked robot,
dwa's collisions) and the command that draws it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
For each strategy, its N worst matches by goal difference (friendly side, config_a)
are analysed: tactic_thrash over the whole match, stall windows from stuck_detector
(with plan_trace's parked / pushed_out findings for each oscillating robot), and with
--restarts the restart flags. Every finding goes to findings.jsonl; the top K with a
picture source are drawn with the picture tool for their kind; index.md is the report.

The match-file helpers move from tools/evaluation/explain.py to
utama_core/analysis/matches.py so triage and explain share them. explain also runs
triage on the candidate's two worst matches into <out>/triage/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
docs/tools.md: the triage row at the top of "Debugging a match". STRATEGY_DEVELOPMENT.md,
"Debugging a foul or failure": the index.md, findings, picture and numbers steps, and
the config_a-only limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…race

plan_trace needs the robot's target and the replay does not record it; with
the robot's final position as the target the carrots meant nothing and
`parked` could never fire. A stall now gets match_timeline from 10 s before
to 10 s after it (tactics, possession and distances, all recorded), and
plan_trace stays a hand tool for when the target is known. The docs row
also says triage covers only matches a strategy played as config_a.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…es are

The README shows the position and shot maps of every strategy, named in the
AGENTS.md glossary. The visual guide and signal report say which tactic
draws the vertical lines: in our half mostly BlockShape's fixed-depth
screen (robots still about 60% of the time, the ball 2-3 m ahead); the
GiveAndGo lines are not explained yet. Roadmap: the match timeline as a
dashboard panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
The one-tick Mermaid diagram moves to docs/architecture.md (which pointed
back to the README for it) and the README describes the tick in five
steps. The outdated 2025 drawio pipeline picture is removed. A row for
seeing what the robots did (visual guide, triage), the badge under the
title, tighter map captions, and the one-entry Milestones section dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
…ethod

In the style of the old drawio diagram (sources, receivers, buffers, the
refiner chain on the main loop, then strategy, motion and output), with
today's class and module names, drawn by docs/img/pipeline/make_one_tick.py
so it can be redrawn when a name changes. The README's System design shows
it; the Mermaid version with every module path stays in architecture.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
docs/img/diagram_style.py holds the boxes, receivers, arrows, main-path
line, key and palette of the one-tick picture, so further architecture
pictures share them. Each picture script lists the classes, functions,
constants and paths it shows in NAMES; test_diagram_names.py checks they
still exist. It caught one already: the referee receiver is
RefereeMessageReceiver, not RefereeReceiver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
The match data flow, the tactic-kernel model, the referee's architecture
and state machine, one rsim tick, the planner control schemes and the
real robot path, in the one-tick picture's style (docs/img/diagram_style.py),
each from its own make_*.py whose NAMES the name test checks.

Drawn from today's code, which corrected the old diagrams: command noise
runs inside SSLStandardEnv.step and _get_commands and physics parameters
are set once; the defense-area rules each have a stopping and a
non-stopping branch; the real path has one-slot buffers, and GameFrame
lives in game_frame.py. Step-by-step flowcharts, the generated package
graph and the detailed one-tick Mermaid stay as they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
@isaac0804 isaac0804 added the release:minor Minor changes to main label Oct 17, 2026
CI's runners failed test_corner_route_arrives[28]; here it arrives at tick
64 after 14 carrot reversals, on the edge of the known detour-side flip
(roadmap item 5). The code is identical (main has not moved) and generic
numba codegen does not reproduce it, so the difference is the host's float
results. A non-strict xfail lets either outcome pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4M4hMLtZTUGNu6jThP1gy
@isaac0804
isaac0804 merged commit 49f29eb into main Oct 17, 2026
4 of 5 checks passed
@isaac0804
isaac0804 deleted the sim-realism-20261016 branch October 17, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:minor Minor changes to main

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant