Skip to content

Add selective per-dynasty sidecar merge (C8 phase 2) - #88

Open
KevinBigham wants to merge 1 commit into
mainfrom
feat/selective-sidecar-merge
Open

Add selective per-dynasty sidecar merge (C8 phase 2)#88
KevinBigham wants to merge 1 commit into
mainfrom
feat/selective-sidecar-merge

Conversation

@KevinBigham

Copy link
Copy Markdown
Owner

Understanding

C8 phase 2 (Fable board #6): sidecar archive import used to replace whole stores, which could surprise-wipe local dynasties absent from the archive. Phase 1 (preview + never-replace-absent-stores) shipped 2026-07-06; this completes the selective per-dynasty import/merge with conflict summary.

What changed

Lib (apps/web/src/lib/dynasty-sidecar-archive.ts)

  • planDynastySidecarMerge(payload, selection, current?) — pure dry-run: per-dynasty, per-store added/overwritten outcomes with detail strings, plus notes (unknown selection ids ignored, empty selection, rivalry policy).
  • mergeDynastySidecarPayloads(imported, current, selection) — pure per-dynasty merge across all five dynasty-scoped stores; career totals recompute on write via existing replaceCareerMeta normalization.
  • mergeDynastySidecarArchiveJson(raw, { dynastyIds }) — parse → plan → merge → write → fresh summary + plan.
  • Rivalry heat is league-scoped, not per-dynasty: selective merge never touches it (note in every plan); the wholesale importDynastySidecarArchiveJson remains the rivalry path and is unchanged.

UI (DynastyCartridge.tsx)

  • Sidecar import preview now lists archive dynasties with checkboxes (default: all selected) and live conflict hints: "overwrites local: Hall of Fame archive…" vs "new — no local data conflicts" vs "excluded — archive data stays out, local untouched".
  • Confirm button reads "Import X of Y Dynasties" and disables at zero selection; merge-safety copy states unselected dynasties are left byte-identical.
  • Status line reports merged dynasties + stores added/overwritten. Combined Backup preview flow is untouched (selection prop is optional).

Verification

Check Result
pnpm --filter @mfd/web test -- src/lib/dynasty-sidecar-archive.test.ts src/features/dynasty-cartridge 4 files / 42 tests ✅ (6 new merge tests incl. the 3 required fixtures: subset archive, older no-rivalry archive, conflicting ids; 2 new preview render contracts)
web tsc --noEmit
Full web suite not run locally (>5 min); runs on this PR as the required test check

What did not change

  • No GameState/save schema/migrations/SAVE_VERSION, no engine source, no wholesale import behavior, no combined-backup path.

Rollback

Revert this commit; sidecar import returns to whole-store replace with preview.

Sidecar archive import is now a per-dynasty merge instead of a
whole-store replace: players pick which archive dynasties to import,
each with an added/overwritten conflict hint computed against live
local stores. Unselected dynasties — local or archive — stay
byte-identical, so imports can never surprise-wipe local history.
Rivalry heat is league-scoped and stays untouched in selective mode
(wholesale import remains that path); career totals recompute on
write. Adds 6 lib merge tests (subset, conflicts, legacy no-rivalry
archive, unknown ids, empty selection, dry-run plan) and 2 preview
render contracts.
@KevinBigham
KevinBigham enabled auto-merge (squash) August 3, 2026 01:32

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e05af51fc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +535 to 538
const result = mergeDynastySidecarArchiveJson(
exportDynastySidecarArchiveJson(pendingSidecarImport.payload),
{ dynastyIds: sidecarSelection },
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore rivalry data on standalone archive import

When a user restores a standalone Complete Dynasty Sidecars archive, confirmation now always calls mergeDynastySidecarArchiveJson, which deliberately never writes the archive's rivalry payload. The panel still exports and advertises rivalry heat, but a repo-wide caller search shows the wholesale importer is otherwise reachable only through the combined-backup journal and tests; there is no standalone “full-archive import” control despite the preview directing users to one. The import therefore reports success while silently retaining unrelated local rivalry records, so this flow needs either a full-import option or an explicit way to apply the archived rivalry store.

Useful? React with 👍 / 👎.

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.

2 participants