Apply .gitattributes normalization to convert all CRLF line
endings inherited from Windows-origin source files to Unix LF.
175 files, zero content changes.
The bus scan on real hardware returns [0x08, 0x10, 0x51], matching the
firmware source (#define BCM4500_ADDR 0x08), bus-architecture docs, and
boot-debug-findings.md. The 0x61 "BCM3440" entry was speculative and
never appeared on the actual SkyWalker-1 I2C bus.
Updated: server known_devices map, mock_device, and test assertions.
Extract MockSkyWalker1 to shared mock_device.py (used by both unit tests
and server lifespan). Server checks SKYWALKER_MOCK env var at startup —
when set, uses mock device instead of USB hardware, enabling full MCP
transport testing via claude -p without the dongle connected.
Verified: 64 unit tests pass, claude -p integration tests exercise
identify_frequency, get_device_status, and sweep_spectrum through the
complete JSON-RPC pipeline.
Motor watchdog: asyncio background task auto-halts motor after 30s of
continuous drive, fires even if LLM client disconnects. Integrated into
move_dish (start on continuous, cancel on halt/goto/gotox) and lifespan
teardown.
Test suite: 64 tests covering all 17 MCP tools — device status, spectrum
sweep validation, tune/blind-scan boundary checks, motor safety (stepped,
continuous opt-in, watchdog lifecycle), jog/store limits, LNB/I2C, TS
capture, frequency identification, and path traversal protection. Uses
MockSkyWalker1 + MockContext for direct async function testing without
USB hardware.
Fixes: FastMCP 2.x description→instructions constructor change,
parents[4] path resolution for tools directory import.