Skip to content

bd init mode switch silently creates empty store, orphaning existing data #633

@sjarmak

Description

@sjarmak

Summary

When switching a beads store between server mode and embedded mode (or vice versa), bd init creates a fresh empty database in the new location (embeddeddolt/ or dolt/) without migrating data from the existing store. The old store remains on disk, unreferenced by the new metadata.json, and users silently lose access to their issues until they manually discover and reconcile the split.

Neither gc doctor nor bd doctor detects this condition afterward, so users only discover it through manual investigation.

Reproduction

# Start with an embedded store containing real data
bd init  # creates embeddeddolt/ with issues
bd create --title "important issue"
bd list  # shows the issue

# Switch to server mode
bd init --server --server-host 127.0.0.1 --server-port 43677
bd list  # empty — all previous issues are in embeddeddolt/, not the server

# Doctor doesn't catch it either
bd doctor  # passes — no check for split stores

The reverse (server → embedded) has the same problem.

What happens

  1. bd init --server writes a new metadata.json with dolt_mode: server
  2. A new database is created on the dolt sql-server (empty)
  3. The old embeddeddolt/ directory with all existing issues is left untouched
  4. bd list now reads from the empty server database
  5. User sees zero issues with no error or warning
  6. Both dolt/ and embeddeddolt/ now coexist with divergent data, undetected

What should happen

Prevention: warn or migrate during mode switch

bd init should detect an existing store in the other mode and either:

  1. Prompt for migration: "Found existing embedded store with 43 issues. Export and import into the new server store? [Y/n]"
  2. Auto-migrate: Run bd export from the old store, bd import into the new one
  3. At minimum, warn: "Existing embedded store with 43 issues will NOT be migrated. Run bd export -o backup.jsonl first."

The bd export / bd import pipeline already supports this — the tooling exists, it just isn't wired into the mode-switch path.

Detection: doctor check for split stores

Add a bd doctor (or gc doctor rig) check that:

  1. Scans .beads/ for the presence of BOTH dolt/ and embeddeddolt/ directories
  2. If both exist, queries each for issue count
  3. Flags a warning if counts diverge, with the delta and which store is authoritative per metadata.json

Example output:

⚠ split-store — both dolt/ (43 issues) and embeddeddolt/ (4 issues) exist.
  Active store: embeddeddolt (per metadata.json dolt_mode=embedded)
  Inactive store dolt/ has 39 issues not in active store.
  Run: bd export from inactive store, bd import to reconcile.

Impact

Found across 4 rigs in a multi-rig Gas City workspace:

Rig old store (orphaned) new store (active) Data at risk?
Rig A 51 (server) 82 (embedded) No — active is superset
Rig B 8 (server) 17 (embedded) No — active is superset
Rig C 49 (server) 153 (embedded) No — active is superset
Rig D 43 (server) 4 (embedded) Yes — 39 issues orphaned for weeks

Rig D's data loss went undetected until manual investigation. A doctor check would have caught it immediately.

Suggested fix

In bd init, after determining the new mode:

if new_mode != current_mode && existing_store_has_data:
    warn("Existing {current_mode} store has {N} issues")
    prompt("Export to {new_mode} store? [Y/n]")
    if yes:
        bd export -o .beads/pre-migration.jsonl  # from old store
        # switch mode
        bd import .beads/pre-migration.jsonl     # into new store

And in bd doctor / gc doctor:

if both dolt/ and embeddeddolt/ exist in .beads/:
    count_active = query active store
    count_inactive = query inactive store
    if count_inactive > 0 && sets differ:
        warn("split-store detected")

Environment

  • bd v0.63.3
  • gc v0.13.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions