Skip to content

Collection-scale: cfg export + import --from, bulk --dry-run, adopt-all nudge#19

Merged
AusafMo merged 4 commits into
mainfrom
feat/export-and-bulk-collection-scale
Jul 26, 2026
Merged

Collection-scale: cfg export + import --from, bulk --dry-run, adopt-all nudge#19
AusafMo merged 4 commits into
mainfrom
feat/export-and-bulk-collection-scale

Conversation

@AusafMo

@AusafMo AusafMo commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Addresses the post-0.2.0 feedback (cfgit_suggestion_email.md) — the "back up + bulk-replace a whole collection" story now lives entirely inside cfgit instead of half in pymongo side-scripts. All three suggestions were verified against 0.2.0 before building.

What

  • cfg export [record] [--out file] — read-only portable snapshot of live docs, each stamped with its cfgit head seq/oid (engine.export_records). The restore-me-later artifact the email's pymongo json.dump was standing in for.
  • cfg import --from <export.json> [--dry-run] — inverse of export: writes docs back through the drift-guarded bulk-commit path, so the restore itself is recorded in history. Accepts a cfg-export artifact or a bare [{record, doc}] list.
  • commit --bulk-from --dry-run — previews every record's delta (would_commit/noop/changed_outside_cfgit) without writing. Fixes a footgun: --dry-run was silently ignored on --bulk-from and the batch wrote. Matters most for collection-scale replaces.
  • doctor --status adopt-all nudge — when a large share of tracked records drifted, it suggests cfg adopt --all to baseline, so restore has a clean baseline and edits stop needing a per-record adopt.
  • MCP: cfg_export, cfg_import(from_export, dry_run), cfg_bulk_commit(dry_run).

Design note: two rollback paths, documented

  • cfg tag + cfg restore --tag / --as-of = in-tool versioned rollback (no file).
  • cfg export/import --from = portable file backup; its write-back is audited in history.

Testing

  • 133 pass / 1 skip (Postgres, no PG), ruff clean. New test_export_import.py (11): export shape/stamp/no-write, round-trip restore, import --from dry-run + garbage rejection, bulk-preview per-record + no-write + drift flag, nudge threshold.
  • Live E2E vs Mongo replica set: import baseline → export --out--bulk-from --dry-run (writes nothing, verified) → apply → import --from backup.json restore (history shows the restore, live reverted) → forced 15/20 drift → doctor --status nudges adopt --all.

Follows 0.2.0; suggest releasing as the next minor (0.3.0).

AusafMo added 4 commits July 26, 2026 20:57
…-dry-run, adopt-all nudge

Addresses the 0.2.0 follow-up feedback — the back-up-and-bulk-replace-a-collection story now
lives entirely inside cfgit:

- cfg export [record] [--out file]: read-only portable snapshot of live docs, each stamped with
  its cfgit head seq/oid (engine.export_records). The restore-me-later artifact.
- cfg import --from <export.json> [--dry-run]: inverse of export — writes the docs back through
  the drift-guarded bulk-commit path, so the restore itself is recorded in history. Accepts a
  cfg-export artifact or a bare [{record,doc}] list.
- commit --bulk-from --dry-run: previews every record's delta (would_commit/noop/drift) without
  writing (bulk_commit_preview). Fixes a footgun — --dry-run was silently ignored on --bulk-from
  and the batch WROTE. Matters most for collection-scale replaces.
- doctor --status: nudges 'run cfg adopt --all to baseline' when a large share of tracked records
  drifted, so restore has a clean baseline and edits stop needing a per-record adopt.
- MCP: cfg_export, cfg_import(from_export, dry_run), cfg_bulk_commit(dry_run).

Distinction: cfg tag + restore --tag remain the in-tool versioned rollback; export/import is the
portable-file backup whose write-back is audited.

Tests: test_export_import.py (11) — export shape/stamp/no-write, round-trip restore, import --from
dry-run + garbage rejection, bulk preview per-record + no-write + drift flag, nudge threshold.
Full live E2E vs Mongo replica set: import→export→bulk-dry-run→apply→restore-from-backup (history
shows the restore)→drift nudge. 133 pass / 1 skip, ruff clean.
…seline

README + USAGE + SKILL: cfg export snapshot + cfg import --from restore (with the tag/restore vs
export/import distinction), commit --bulk-from --dry-run (fixing the 'bulk is invisible' feedback),
and the doctor adopt-all baseline nudge. Add cfg_export to the MCP tool lists.
Two robustness gaps from review:
- cfg export warns (soft, never a hard cap) when a snapshot exceeds ~2000 records OR ~50MB
  serialized — a strong signal the config points at a data-plane collection (events/content/jobs)
  cfgit is not built to version. Prints to stderr; export still completes; stdout stays clean.
- commit_many (the import --from / bulk write path) now catches KeyboardInterrupt — a mid-write
  cancel returns a clean {state: partial, cancelled: true} with results + pending instead of dying
  silently. KeyboardInterrupt is BaseException, so it previously escaped the Exception handler and
  left the operator guessing about DB state. Each apply() is atomic, so rerun resumes.

Tests: +4 (size-warning absent/count/bytes, cancel→clean-partial). Live E2E: 2100-record export
warns on stderr with clean JSON stdout. 136 pass / 2 skip, ruff clean.
…ulk-commit preview)

bulk_commit_preview returns state=dry_run, which shared the restore-phrased remedy 'this is what
a restore would change' — misleading for a bulk commit preview. Made it neutral. Surfaced by the
exhaustive live E2E (22/22).
@AusafMo
AusafMo merged commit dbdd491 into main Jul 26, 2026
2 checks passed
AusafMo added a commit that referenced this pull request Jul 26, 2026
Minor bump for the collection-scale release (#19): cfg export + import --from round-trip,
commit --bulk-from --dry-run, export size warning, cancellation-safe bulk writes, doctor
adopt-all nudge. Additive features, nothing removed. Widen plugin cfgit pin to >=0.3.0,<0.4.0.
Both build + twine check clean locally.

Co-authored-by: AusafMo <AusafMo@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant