From 4f3d99c65bad9796f903102825c493def5f9beea Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 15 Sep 2026 15:34:04 +0200 Subject: [PATCH] fix: a deploy always names the head it left behind, and pins a base only when it can claim one Co-Authored-By: Claude Opus 5 (1M context) --- .../lib/components/apps/editor/AppEditorHeader.svelte | 11 +++++++++-- .../src/lib/components/apps/editor/appDeploy.test.ts | 4 ++-- .../lib/components/raw_apps/RawAppEditorHeader.svelte | 10 ++++++---- .../(logged)/apps_raw/edit/[...path]/+page.svelte | 10 +++++----- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index ed6737c159..1ba20d4d11 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -398,12 +398,19 @@ workspace: $workspaceStore!, path: npath }) - version = versionThisDeployWrote(appHistory, $userStore?.username, headBefore?.version) + // `version` is what is deployed now, which is the deploy guard's fallback head and + // must stay set; the pin below is the version this deploy can prove it wrote. + version = appHistory[0]?.version // Re-pin the fork base to the version just written: the editor stays open, so a // follow-up deploy (or a new edit) would otherwise compare against the now- // superseded base and falsely warn. parent_version is in // DRAFT_COMPARE_IGNORED_FIELDS, so this write can't spawn a spurious draft. - if ($app) $app.parent_version = version + if ($app) + $app.parent_version = versionThisDeployWrote( + appHistory, + $userStore?.username, + headBefore?.version + ) closeSaveDrawer() sendUserToast('App deployed successfully') diff --git a/frontend/src/lib/components/apps/editor/appDeploy.test.ts b/frontend/src/lib/components/apps/editor/appDeploy.test.ts index f468cd331e..c699c6d67c 100644 --- a/frontend/src/lib/components/apps/editor/appDeploy.test.ts +++ b/frontend/src/lib/components/apps/editor/appDeploy.test.ts @@ -20,8 +20,8 @@ describe('versionThisDeployWrote', () => { }) it('claims nothing it cannot tell apart from another deploy', () => { - // The same account deploying from elsewhere is indistinguishable by author, so - // the entry has to sit on the head this deploy read, and this one does not. + // Two entries of the caller's sit above the head it read, so neither can be shown + // to be this deploy's: taking either would pin a version it may not have written. expect(versionThisDeployWrote([alice(9), alice(7), bob(6)], 'alice', 6)).toBe(undefined) expect(versionThisDeployWrote([bob(8), bob(6)], 'alice', 6)).toBe(undefined) expect(versionThisDeployWrote([], 'alice', 6)).toBe(undefined) diff --git a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte index a8787ec61d..54a73a8263 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte @@ -552,9 +552,11 @@ workspace: opWorkspace!, path: npath }) - // The version this deploy wrote, not the head: they differ when someone else's - // deploy landed in between, and this becomes the next draft's base below. - version = versionThisDeployWrote(appHistory, $userStore?.username, headBefore?.version) + // Two different things: `version` is what is deployed now, which is what the deploy + // guard compares against and must stay set, and `claimed` is the version this deploy + // can prove it wrote, which is the next draft's base. + const claimed = versionThisDeployWrote(appHistory, $userStore?.username, headBefore?.version) + version = appHistory[0]?.version closeSaveDrawer() sendUserToast('App deployed successfully') @@ -569,7 +571,7 @@ if (appPath !== npath) { onSavedNewAppPath?.(npath) } - onDeploy?.({ path: npath, version, head: appHistory[0]?.version }) + onDeploy?.({ path: npath, version: claimed, head: version }) } async function setPublishState(message?: string) { diff --git a/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte index b7922d5d06..c63d04479d 100644 --- a/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte @@ -658,11 +658,11 @@ onDeploy={({ version, head }) => { // The version this deploy wrote is the base the next autosave carries; the // head is what is deployed now. They differ when another deploy landed - // beside this one, and the next draft is then behind from the start. - if (version != null) { - parentVersion = version - draftBaseVersion = String(version) - } + // beside this one, and the next draft is then behind from the start. A + // deploy that could not claim a version leaves the base unknown rather + // than keeping the one it just superseded. + parentVersion = version + draftBaseVersion = version != null ? String(version) : undefined if (head != null) { deployedHeadVersion = String(head) }