SIGN IN SIGN UP

feat(schema): self-heal databases left on an older schema without losing database-only data

Every command refused a tracker database on an older schema, and the
reviewed migration only accepts schemas 13-18, so the unversioned schema-0
databases of early br / Go bd (and schemas 4/7/11) had no working path at
all: even `br sync --import-only --rebuild` hit the same refusal. On one
workstation 118 of 151 trackers were blocked.

Startup now audits a stale database against issues.jsonl, schema-agnostic
(plain SELECTs over whatever columns exist). An issue row is represented
when the JSONL carries it as a tombstone, carries equivalent content, or
carries a copy at least as new while the row was never marked dirty.
- Everything represented: upgrade and continue, one stderr notice line.
  Schemas 13-18 use the reviewed migration (recovery bundle, undo);
  older ones rebuild from the audited JSONL snapshot, old family kept in
  .beads/.br_recovery. Explicitly read-only invocations never upgrade.
- Anything database-only (absent from JSONL, unflushed edit, newer than
  JSONL, unreadable): mutations refuse, naming the issues and the single
  command `br doctor migrate-schema heal`; read-only commands read the
  JSONL directly (as --no-db) with clean JSON stdout.
- New `br doctor migrate-schema heal [--dry-run] [--discard-db-only]`:
  migrates 13-18 in place, or rebuilds older schemas and re-adds the
  database-only issues as unflushed changes (#394 rule: superseded older
  edits stay in the backup only).

Also:
- Import verification now mirrors the orphan cleanup: a JSONL dependency
  edge to an issue that exists nowhere is dropped on import, but both
  post-import verifiers compared the raw payload (and the rebuild checked
  the raw dependency count), so every import or rebuild of such a JSONL
  failed; five real trackers carried such edges.
- GH #520 follow-up: startup WAL-index recovery is gated on
  STARTUP_WAL_INDEX_RECOVERY (engine reads -shm AND the quarantine lock
  exists: linux/android/macos/ios), matching RecoveryLock::acquire, so
  FreeBSD and other Unix targets no longer enter a recovery that can only
  fail as unsupported. A new test pins the engine's reaction to the index
  stock SQLite writes (read-only BusyRecovery, filed as
  Dicklesworthstone/frankensqlite#431).
- main records the process actor for the last-touched guard (GH #518).

Tests: tests/e2e_schema_heal.rs with fixtures written by the released
br 0.1.27 binary (schema 4) plus the shipped schema-16 fixture; unit tests
for the classifier and legacy timestamp decoding; updated migration and
chokepoint e2e expectations for the read-only fallback.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
J
Jeff Emanuel committed
91c61db30e39a390d0c48c3be8817fd0fc907cce
Parent: bbde2e4