Skip to content

bmo import drops relations and misattaches parents/comments (no ID remapping) #15

Description

@erewok

Summary

bmo import reads only 2 of the 6 collections in an ExportBundle, and does no
ID remapping. As a result bmo export → bmo import is not a round trip: all
dependency links are silently lost, and importing into a non-empty database
attaches parents and comments to unrelated issues with no error or warning.

Both behaviours are long-standing — import_from_bmo is unchanged — but they are
now more prominent, because the docket importer removed in #15 was the only path
that built an old-id → new-id map and imported relations.

1. Relations, activity, and top-level labels/files are dropped

ExportBundle (src/model/export.rs) declares six collections. import_from_bmo
(src/cli/import.rs) consumes bundle.issues and bundle.comments only:

Bundle field Imported?
issues yes
comments yes (but see §2)
relations no — silently dropped
activity no — silently dropped
labels (top-level) no (per-issue issue.labels do survive)
files (top-level) no (per-issue issue.files do survive)

Reproduction

bmo init
bmo create --title Parent          # BMO-1
bmo create --title Child --parent BMO-1
bmo create --title Blocker         # BMO-3
bmo link add BMO-3 blocks BMO-1
bmo export > exp.json              # relations: [{from_id: 3, to_id: 1, kind: blocks}]

cd ../fresh && bmo init
bmo import ../exp.json             # "Imported 3 issue(s) and 1 comment(s)"
bmo link list BMO-1                # => "No relations."   <-- edge lost

2. No ID remapping: parents and comments reattach to the wrong issues

repo.create_issue assigns fresh autoincrement IDs, but parent_id and
comment.issue_id are written straight from the exported IDs. On an empty
database with a contiguous export this coincidentally lines up. On a non-empty
database it silently misattaches.

Reproduction

bmo init
bmo create --title "Pre-existing A"   # BMO-1
bmo create --title "Pre-existing B"   # BMO-2
bmo import exp.json                   # export's ids are 1,2,3
bmo list --all

Observed:

BMO-1  parent=None  Pre-existing A
BMO-2  parent=None  Pre-existing B
BMO-3  parent=None  Parent        <- the real parent landed here
BMO-4  parent=1     Child         <- but parent_id=1 points at "Pre-existing A"
BMO-5  parent=None  Blocker

Child's parent is now an unrelated pre-existing issue. Likewise the comment
exported against issue_id: 1 ("Parent") attached to "Pre-existing A":

$ bmo show BMO-1
  Comments (1):
    [2026-09-03] unknown: a comment

Exit code is 0 and the message reads Imported 3 issue(s) and 1 comment(s).
Nothing signals that anything went wrong.

Impact

  • bmo export is not a usable backup: restoring it loses the entire dependency
    graph, which is what bmo plan, bmo next, and bmo graph are built on.
  • Importing into a non-empty database corrupts it silently — wrong parents, and
    comments on unrelated issues. There is no guard against this.

Existing test gives false confidence

export_import_roundtrip in tests/import_export.rs passes today, but asserts
only issue count and titles. It never checks relations, parent_id, or
comment attachment — precisely the parts that are broken.

Suggested fix

  1. Build an old_id -> new_id: HashMap<i64, i64> as issues are created.
  2. Resolve parent_id through it. Because a child can be created before its
    parent, either import parents first (topologically) or do a second pass that
    sets parent_id once every issue exists.
  3. Resolve comment.issue_id through it, and skip comments whose issue is absent.
  4. Import bundle.relations, mapping both endpoints through it and skipping any
    edge with an unresolvable endpoint. The removed docket importer did exactly
    this — see import_from_docket at 746d209:src/cli/import.rs for a working
    reference implementation.
  5. Decide explicitly whether bundle.activity should replay or stay excluded,
    and document it either way.
  6. Report skipped rows via the warnings field the --json envelope already
    carries (currently always empty).
  7. Strengthen export_import_roundtrip to assert relations, parent links, and
    comment attachment, and add a case that imports into a non-empty database.

Environment

bmo 0.7.1, macOS (darwin 25.6.0), SQLite backend.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions