Add snapshot diff engine (ams package) + tests
Standalone CLI that diffs two engine-surface snapshots across all four axes,
the foundation the FastAPI/DB layer will sit on.
- ams.snapshot : typed access to a snapshot.json
- ams.diff : keyed set-diff per axis (added/removed/changed) + cross-owner
method-move detection; types keyed by (script_name,
via_module_iface) so the dual MULTIARRAY stays stable;
filter_by_owner for per-class focus
- ams.render : human-readable report (+/-/~), owner-grouped
- ams.cli : python -m ams OLD NEW [--owner C] [--only ...] [--json]
6 tests pass, incl. an integration test over the committed golden pair
(asserts BlooMoo adds GRBUFFER/INTERNET, MOUSE grows 104->128, Animo gains
GETFPS, Animo script fields unchanged).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
58
ams/snapshot.py
Normal file
58
ams/snapshot.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""Loading and light typed access to an engine-surface snapshot.json."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class Snapshot:
|
||||
"""Thin wrapper over a parsed snapshot.json. Axes are returned as plain lists of dicts so
|
||||
they round-trip cleanly to JSON; the diff engine works directly on those records."""
|
||||
|
||||
raw: dict[str, Any]
|
||||
|
||||
@classmethod
|
||||
def load(cls, path: str) -> "Snapshot":
|
||||
with open(path, "r", encoding="utf-8") as fh:
|
||||
return cls(json.load(fh))
|
||||
|
||||
@property
|
||||
def binary(self) -> dict[str, Any]:
|
||||
return self.raw.get("binary", {})
|
||||
|
||||
@property
|
||||
def types(self) -> list[dict]:
|
||||
return self.raw.get("types", [])
|
||||
|
||||
@property
|
||||
def methods(self) -> list[dict]:
|
||||
return self.raw.get("methods", [])
|
||||
|
||||
@property
|
||||
def events(self) -> list[dict]:
|
||||
return self.raw.get("events", [])
|
||||
|
||||
@property
|
||||
def fields(self) -> list[dict]:
|
||||
return self.raw.get("fields", [])
|
||||
|
||||
@property
|
||||
def struct_layout(self) -> list[dict]:
|
||||
return self.raw.get("struct_layout", [])
|
||||
|
||||
@property
|
||||
def method_inheritance(self) -> list[dict]:
|
||||
return self.raw.get("method_inheritance", [])
|
||||
|
||||
@property
|
||||
def field_inheritance(self) -> list[dict]:
|
||||
return self.raw.get("field_inheritance", [])
|
||||
|
||||
@property
|
||||
def label(self) -> str:
|
||||
b = self.binary
|
||||
return "{0} [{1}/{2}]".format(
|
||||
b.get("name", "?"), b.get("engine", "?"), b.get("compiler", "?"))
|
||||
Reference in New Issue
Block a user