BL-033 Shipped

`bin/sync-session`

Ruby runner, append-only and idempotent, flock-protected. PULL phase fetches player_note Moments via MCP, appends them as player_note events keyed on moment_id, and sets in_reaction_to heuristically (nearest prior significant DM event within 60s). PUSH phase lists server Moments, builds a scribe_id → moment_id map, and for each unsynced Scroll event either creates a Moment (passing scribe_id through) or reconstructs a moment_sync record if the server already has the scribe_id (crash recovery path). Modes: --pull-only, --push-only, --latest, or explicit session number. End-to-end tested on a local Rails + disposable GameSession: two-run idempotency (0 duplicate Moments), crash recovery (Scroll truncated mid-push, recovers without duplicates), and in_reaction_to stitching (player note bound to attack kill at 20s offset). Two real bugs caught during the test: MCP needs Accept: application/json, text/event-stream, and JSON-RPC id must be integer or null. ADR-0047.