Files
boxsim-fileformat-rev/tools/selfcheck.py
T
magdevandClaude Fable 5 4737a5bae8 Add boxsim CLI: pure Python codec, netlist extraction, KiCad project generation
Replaces the bpj2ini.py prototype with a packaged tool. The A2F codec is now
reimplemented in Python, so neither Boxsim.exe nor a CPU emulator is needed to
decode a container; the emulator survives as a development-only oracle that the
codec is differentially tested against.

Verified:
- 134 containers decode byte-identically to Boxsim's own decoder, 270 pre-2.0
  files rejected by both implementations (tools/difftest.py --self-test)
- Default.BPJ: 22 components, 14 nets, no dangling terminal
- 22 of 22 parts resolve to library symbols; one series inferred from a
  sibling, two DC resistance deviations reported
- ERC clean and the netlist KiCad extracts from the generated sheet is an
  identical partition to the one derived from the Boxsim grid
- container build byte-identical to the host build
- 32 tests passing, ruff clean

Decode time went 69 s -> 14.5 s (binding emulator hooks to trap addresses)
-> 1.6 s (pure Python).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-29 11:10:43 +02:00

33 lines
979 B
Python

"""Post-install check for the bundled catalogue and symbol library.
Run during the image build so an image can never ship with an incomplete
library or a truncated catalogue. `cross_check` alone is not enough: it proves
only that the catalogue is a subset of the library, so a short catalogue passes
it and then rejects perfectly valid projects at runtime with "not stocked by
Visaton". `check_shape` is what gives this gate teeth.
"""
from __future__ import annotations
import sys
from boxsim import catalog as catalog_mod
from boxsim import symbols as symbols_mod
def main() -> int:
cat = catalog_mod.load()
catalog_mod.check_shape(cat)
lib = symbols_mod.load()
extras = symbols_mod.cross_check(cat, lib)
print(
f"bundled {len(cat)} catalogue parts across "
f"{len(cat.series_names)} series, {len(lib)} symbols; "
f"library-only symbols: {extras or 'none'}"
)
return 0
if __name__ == "__main__":
sys.exit(main())