fix(e12): a bare up -d picks the wrong compose file, and recreates the database
Round four, on round three's diff. 47 -> 34 -> 15 -> 7 raw findings. **The printed restart command could strand the restored data.** Round three replaced `start` with `up -d` because `start` ignores a newly pinned tag — but printed it bare. In the git-clone layout BOTH compose files exist, so the scripts' COMPOSE_FILE fallback never fires and a bare `docker compose up -d` reads `docker-compose.yml`: different volume names, locally built images, no IMAGE_TAG at all. `stop` and `exec` had been fine there (they resolve running containers by project and service), but `up -d` RECREATES — so the operator pastes the hint straight after a successful restore and gets `db` on a new empty volume and a first-run setup wizard, with their data in an orphaned volume. Verified: the two files resolve `siftlode_pgdata` vs `pgdata` and different images. The scripts no longer print a command that recreates from a file they did not resolve. They name the compose file when they resolved one, and otherwise say to start it the way the operator normally does — with the caveats on their own lines rather than in a parenthetical at the end of a very long one. **The reset flag is now decided where the live hash is already parsed.** Round three cleared it in the token effect, which only runs when a NEW verify token arrives — so the back button, or re-pasting an already-consumed verify link, still left the banner promising a recovery whose token was gone. Setting it from the hash on every fragment change is both smaller and closes those. Also: the doc said `start` "still carries the old tag" four lines after "pin the older IMAGE_TAG", where "old" then reads as the tag being rolled back TO — it now reuses the scripts' unambiguous wording; the Windows recipe removes a partially-copied dump before throwing, so a mid-stream `cp` failure cannot leave a truncated file under the final name; and `$WarningPreference` is pinned beside `$ErrorActionPreference` so an inherited SilentlyContinue cannot drop the half-restored warning, with the comment corrected to say what the warning stream actually is. Gate green: vitest 685, pytest 950.
This commit is contained in:
@@ -59,7 +59,13 @@ export function useVerifyEntry(): VerifyEntry {
|
||||
// Both halves of the mailed pair arrive the same way — pasted into a running tab, which is a
|
||||
// same-document navigation the import-time snapshot never sees. The verify half got this
|
||||
// listener in E9.5 S2; the reset half was left out, so it stayed silent (DX-17).
|
||||
if (hash.get("reset")) setResetPending(true);
|
||||
//
|
||||
// Set from the live hash rather than one-way, because the flag must not outlive the token it
|
||||
// describes: navigating away from a `#reset=` (a pasted verify link, the back button) leaves
|
||||
// the banner promising that signing out will resume a reset whose token is gone — and, being
|
||||
// checked first, hiding whatever arrived in its place. `clearEntryUrl`'s own replaceState
|
||||
// fires no hashchange, so this cannot undo the deliberate keep-the-reset-fragment behaviour.
|
||||
setResetPending(!!hash.get("reset"));
|
||||
};
|
||||
// replaceState (how clearEntryUrl strips the fragment) does NOT fire hashchange, so this cannot
|
||||
// feed itself.
|
||||
@@ -68,16 +74,10 @@ export function useVerifyEntry(): VerifyEntry {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Read the fragment BEFORE clearing it: a verify link pasted over a standing reset notice
|
||||
// replaces the whole fragment, so the reset token is already gone and the flag describing it
|
||||
// must go too — otherwise the banner keeps promising a recovery that signing out can no longer
|
||||
// complete, and (being checked first) hides the confirmation that just arrived.
|
||||
const stillHasReset = new URLSearchParams(window.location.hash.replace(/^#/, "")).has("reset");
|
||||
// Clear the address bar even with no token to consume, so a spent one leaves no trace on a
|
||||
// reload. An unspent `#reset=` is the exception and `clearEntryUrl` says why: nothing in a
|
||||
// signed-in tree reads it, so erasing it there is a dead end rather than a cleanup.
|
||||
clearEntryUrl();
|
||||
if (!stillHasReset) setResetPending(false);
|
||||
if (!token || consumed.current.has(token)) return;
|
||||
consumed.current.add(token);
|
||||
// A second link arriving over an unread first outcome must not leave the OLD banner standing.
|
||||
|
||||
Reference in New Issue
Block a user