fix(persist): use project-object identity to stop forked-bank cross-contamination
M4's GUID-only classifier read a tab-switch between two Save-As forks (shared copied GUID, different paths) as a Save-As and clobbered a bank. Thread sameProjectObject into classifyProjectTransition: a different object always Loads, never relocates; a forked sibling gets re-GUID'd to diverge.
This commit is contained in:
+17
-18
@@ -105,30 +105,29 @@ BankRelocation deriveRelocationPlan(const std::string& oldProjectDir,
|
||||
return r;
|
||||
}
|
||||
|
||||
ProjectTransition classifyProjectTransition(const std::string& lastGuid,
|
||||
ProjectTransition classifyProjectTransition(bool sameProjectObject,
|
||||
const std::string& lastGuid,
|
||||
const std::string& lastPath,
|
||||
const std::string& currentGuid,
|
||||
const std::string& currentPath) {
|
||||
// A changed GUID is the unambiguous signal of a different project — load it.
|
||||
// This is the whole point of the content-based identity: it survives pointer
|
||||
// recycling that the old pointer-equality check could not distinguish from a
|
||||
// Save-As.
|
||||
if (currentGuid != lastGuid) {
|
||||
// A DIFFERENT project object is a tab-switch / open / recycled pointer — load
|
||||
// ITS index; NEVER relocate a bank. This is the load-bearing safety fix: it
|
||||
// holds even when currentGuid == lastGuid, which is exactly the forked-sibling
|
||||
// case (Save-As copied our GUID, so two distinct projects share it on disk).
|
||||
// The GUID is deliberately NOT consulted here — the object identity alone
|
||||
// decides, and it cannot be fooled by a copied GUID.
|
||||
(void)lastGuid;
|
||||
(void)currentGuid;
|
||||
if (!sameProjectObject) {
|
||||
return ProjectTransition::Load;
|
||||
}
|
||||
|
||||
// Same GUID from here on. If it is empty, we have NO proof the two ticks saw
|
||||
// the same project (an unsaved project can't carry a stored GUID). A path
|
||||
// change under an empty GUID is therefore a first-save or a switch between
|
||||
// unsaved projects — load, never relocate (relocating would copy the wrong
|
||||
// bank over a real one, the defect being fixed).
|
||||
if (currentGuid.empty()) {
|
||||
return (currentPath == lastPath) ? ProjectTransition::NoOp
|
||||
: ProjectTransition::Load;
|
||||
}
|
||||
|
||||
// Same NON-EMPTY GUID: proven same project. A path change is a genuine
|
||||
// Save-As to a new location; an unchanged path is Save-in-place / idle.
|
||||
// Same object from here on: identity is PROVEN by the pointer. A path change is
|
||||
// a Save-As (or a first save, when the old path was empty); an unchanged path
|
||||
// is Save-in-place / idle. Note SaveAsRelocate is safe even for a first save:
|
||||
// the old project dir is empty, so deriveRelocationPlan makes `needed` false
|
||||
// and nothing is physically relocated (empty-GUID safety preserved), while
|
||||
// poll() still mints a GUID on that branch.
|
||||
return (currentPath == lastPath) ? ProjectTransition::NoOp
|
||||
: ProjectTransition::SaveAsRelocate;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user