Skip to content

fix: reload config fresh to prevent stale-snapshot profile loss#24

Merged
cpaczek merged 1 commit into
cpaczek:mainfrom
Co-Messi:fix/profile-persistence
Apr 3, 2026
Merged

fix: reload config fresh to prevent stale-snapshot profile loss#24
cpaczek merged 1 commit into
cpaczek:mainfrom
Co-Messi:fix/profile-persistence

Conversation

@Co-Messi
Copy link
Copy Markdown
Contributor

@Co-Messi Co-Messi commented Apr 3, 2026

Problem

When generating multiple buddies, profiles created earlier could go missing from the saved-buddies gallery.

Two stale-snapshot writes were clobbering data that had already been written by a fresh saveProfile() call:

runBuddiesisDefault case
saveProfile(outgoing) performs a fresh load → write to snapshot the outgoing buddy's current name/personality.
Then savePetConfigV2(config) overwrites the file with the stale config captured at the very top of runBuddies(). Any profile data written by the intervening saveProfile call is silently lost.

applyDesiredTraitsSequential — final identity update
The code read configV2.profiles[result.salt] from a snapshot loaded before the patch step. If loadPetConfigV2() returned null at that point (e.g. a transient read error) the fallback used profiles: {}, which then got saved, wiping all existing profiles. Even without the null case, the snapshot could be stale relative to what saveProfile() had just written.

Fix

Both sites now reload the config fresh immediately before writing:

// buddies.ts — isDefault case
const freshConfig = loadPetConfigV2();
if (freshConfig) {
  freshConfig.previousSalt = freshConfig.salt;
  freshConfig.activeProfile = null;
  freshConfig.salt = newSalt;
  ...
  savePetConfigV2(freshConfig);
}

// interactive.ts — final profile identity update
const freshConfig = loadPetConfigV2();
const saved = freshConfig?.profiles[result.salt];
if (saved) { ... saveProfile(saved, { activate: true }); }

Test plan

  • Create two buddies back-to-back — both appear in any-buddy buddies
  • Switch a buddy, switch back to Original — verify both buddy profiles still present
  • pnpm test — all 203 tests pass

In two places a config snapshot loaded at function start was being
written back after a saveProfile() call had already done a fresh
load+write in between, meaning the intervening write was clobbered.

- buddies.ts (isDefault case): saveProfile(outgoing) writes fresh data,
  but savePetConfigV2(config) then overwrote it with the stale snapshot
  captured at the top of runBuddies. Fixed by reloading before the
  activeProfile→null update.

- interactive.ts: the final profile identity update read
  configV2.profiles[result.salt] from a snapshot taken before the
  patch step; if that snapshot missed the newly saved profile the
  activate:true save was silently skipped. Fixed by reloading fresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cpaczek cpaczek merged commit 21e5c31 into cpaczek:main Apr 3, 2026
7 checks passed
@cpaczek
Copy link
Copy Markdown
Owner

cpaczek commented Apr 3, 2026

@Co-Messi thank you for PR merged

Co-Messi added a commit to Co-Messi/any-buddy that referenced this pull request Apr 4, 2026
Hook install gaps (from code review of PR cpaczek#31):
- apply.ts: hook was only installed in the ORIGINAL_SALT fallthrough path;
  the previousSalt and ORIGINAL_SALT early-return branches inside !oldSalt
  both returned before reaching it. Extract autoInstallHook() helper and
  call it before every successful-patch return.
- apply.ts: --no-hook flag was silently dropped — runApply() had no noHook
  param so the flag was ignored. Add noHook param and pass it from cli.ts.
- buddies.ts: runBuddies() patched the binary but never installed the hook.

Stale-snapshot write (missed in PR cpaczek#24):
- buddies.ts isDefault branch: config was the snapshot from the top of
  runBuddies(), read before saveProfile(outgoing) wrote to disk. Reload
  fresh immediately before savePetConfigV2 to avoid clobbering that write.
- buddies.ts incoming profile read: after switchToProfile() writes to disk,
  reload fresh config to read the incoming profile rather than the stale
  pre-switch snapshot.

preview.ts edge case (from code review of PR cpaczek#26):
- cols - 4 can be negative when stdout.columns < 4 (piped output, very
  narrow TTY). String.repeat throws RangeError on negative values.
  Wrap with Math.max(0, cols - 4).
Co-Messi added a commit to Co-Messi/any-buddy that referenced this pull request Apr 4, 2026
Hook install gaps (from code review of PR cpaczek#31):
- apply.ts: hook was only installed in the ORIGINAL_SALT fallthrough path;
  the previousSalt and ORIGINAL_SALT early-return branches inside !oldSalt
  both returned before reaching it. Extract autoInstallHook() helper and
  call it before every successful-patch return.
- apply.ts: --no-hook flag was silently dropped — runApply() had no noHook
  param so the flag was ignored. Add noHook param and pass it from cli.ts.
- buddies.ts: runBuddies() patched the binary but never installed the hook.

Stale-snapshot write (missed in PR cpaczek#24):
- buddies.ts isDefault branch: config was the snapshot from the top of
  runBuddies(), read before saveProfile(outgoing) wrote to disk. Reload
  fresh immediately before savePetConfigV2 to avoid clobbering that write.
- buddies.ts incoming profile read: after switchToProfile() writes to disk,
  reload fresh config to read the incoming profile rather than the stale
  pre-switch snapshot.

preview.ts edge case (from code review of PR cpaczek#26):
- cols - 4 can be negative when stdout.columns < 4 (piped output, very
  narrow TTY). String.repeat throws RangeError on negative values.
  Wrap with Math.max(0, cols - 4).
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