Self-hosted Gitea Actions has no Windows runner; the four Windows jobs
sat in 'Waiting' indefinitely. Linux-only matrix keeps CI green on a
single act_runner.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pure-inference ONNX Runtime SDK; src/ layout; bundled weights;
training/server/eval moved to tools/; new public API
(MouseModel/ScrollModel + cached generate/generate_scroll helpers).
See CHANGELOG.md for details.
Drop the pre-migration PyTorch inference pipeline now that the ONNX-backed
MouseModel/ScrollModel in mouse.py and scroll.py are wired up through the
public ai_mouse API.
Deleted:
* src/ai_mouse/generator.py (legacy torch flow ODE + post-processing)
* src/ai_mouse/coord.py (legacy public coord transforms,
superseded by ai_mouse._coord)
* src/ai_mouse/_scroll_legacy.py (legacy torch scroll VAE inference)
* scripts/build_golden_*.py (one-shot capture scripts, no longer
needed once goldens are committed)
* tests/unit/test_generator.py (legacy module gone)
* tests/unit/test_scroll_generator.py (legacy module gone)
* tests/unit/test_coord.py (legacy module gone; ai_mouse._coord is
tested by test__coord.py)
* scripts/ (empty, removed)
Tools migrations:
* tools/trainer.py: import encode_trajectory from ai_mouse._coord
instead of the deleted ai_mouse.coord
* tools/server/routes_verify.py, tools/server/routes_scroll.py: route to
the public ai_mouse.generate / generate_scroll. They no longer accept
a model_dir override — the bundled ONNX is the source of truth, and a
fresh export goes through `python -m tools.export_onnx`.
* tools/eval/__main__.py: same migration; model_dir CLI arg retained as
a deprecation shim but ignored.
Final src/ai_mouse/ layout (matches plan):
__init__.py, _assets.py, _coord.py, _model_cache.py, _postprocess.py,
errors.py, mouse.py, py.typed, scroll.py, assets/
Test suite: 188 passed (was 188 before deletion; obsolete suites cleaned
out alongside the modules they covered).
64 parametrised cases (8 routes/scrolls x 4 seeds each) compare the
rewritten ORT/NumPy pipeline against captures from the pre-migration
PyTorch implementation.
The pre-migration captures used torch.manual_seed + torch.randn for the
flow-ODE noise; the rewrite uses np.random.default_rng. These RNGs
produce different random numbers for the same seed, so the per-point
trajectories cannot match bit-for-bit. The suite therefore guards
*structural* equivalence:
* mouse: identical shape, start/end snapping, xy diff within
max(30 px, 20% of move distance), timestamp diff within 700 ms
* scroll: identical shape (skip with reason on quantum boundary
drift), identical deltaMode, identical total signed scroll
distance, per-event delta within 2 wheel quanta, timestamp diff
within 700 ms
Observed worst-case in this run: ~170 px xy diff on a 1681 px move
(~10% of distance, well under the 20% envelope) and ~600 ms timestamp
drift. All 64 cases pass; 0 skipped.
Goldens stored as compressed .npz under tests/unit/data/ and tracked
via Git LFS-free vanilla blobs (each file is ~kB).
Provide bundled_path() and resolve() helpers that locate ONNX
weights and JSON metadata via importlib.resources, falling back to
a user-supplied directory. Missing assets raise ModelLoadError.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce AiMouseError base class plus ModelLoadError and
GenerationError subclasses so downstream consumers can catch the
umbrella or specific failure modes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy of coord.py (which is already pure numpy) into the private
underscored module to be consumed by upcoming mouse.py rewrite.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Hatchling's already picks up assets/;
force-include duplicated each asset and emitted a build warning once
real ONNX files landed. onnxscript is a transitive runtime dep of
torch.onnx.export (PyTorch 2.11+) — make it explicit.