fix(ledger): DNA UNIQUE constraint + v5 migration (HIGH audit)
1 HIGH audit fix: agents.dna had no UNIQUE constraint → duplicate
DNAs accepted silently → kei-replay ambiguous.
- schema.rs: v5 migration adds CREATE UNIQUE INDEX idx_agents_dna_unique
with pre-check. If existing DB has dna duplicates, migration surfaces
typed LedgerError::DnaMigrationBlocked { duplicates: Vec<(String, usize)> }
instead of silently dropping rows.
- error.rs: +DnaCollision { dna } (runtime insert violation at fork).
Caller regenerates nonce and retries.
+DnaMigrationBlocked (migration-time precheck failure) with
resolution hint in doc-comment.
- ledger.rs: classify_insert_error distinguishes DNA-violation vs
duplicate-id vs generic SQL error.
- NULL handling: multiple NULL dnas allowed (SQLite default UNIQUE
semantics), preserves v2 "dna optional" contract.
+5 tests, 23/23 kei-ledger green.
Constructor Pattern: source files <=192 LOC, all functions <=25 LOC.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>