fix(ledger/b3): S2 tree cycle DoS + migration txn + length cap
S2: tree() had no visited set; cyclic parent_branch rows → infinite
loop. Added HashSet visited + MAX_TREE_DEPTH=1024 breaker. Returns
LedgerError::MaxDepthExceeded instead of OOM.
M2 migration txn: apply_one() wraps DDL + user_version bump in
BEGIN IMMEDIATE / COMMIT / ROLLBACK. Partial failure can no longer
leave user_version at N-1 with N's schema applied.
L1 length cap: branch + parent_branch strings capped to 256 chars
via 3-layer defence: clap value_parser!(parse_branch), client-side
check_branch_lens, schema v3 BEFORE INSERT/UPDATE triggers.
New src/error.rs (46 LOC) — LedgerError + MAX_TREE_DEPTH. SELECT_COLS
const DRY'd 4 duplicated column lists (list, by_id, children_of).
Schema v3 uses triggers (not table CHECK — SQLite can't retrofit
CHECK on existing tables without rebuild).
Tests: 13/13 (was 10, +3 audit). All 3 fixes exercised.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>