| … | … | @@ -557,6 +557,24 @@ export class Launcher { | |
| 560 | + | async #writeState(next: ServiceState): Promise<void> { | |
| 561 | + | // `t3 update` without a restart repoints the unit and records its launcher | |
| 562 | + | // runtime while this launcher keeps running, so what the file says wins. | |
| 563 | + | const current = await NodeFSP.readFile(this.#statePath, "utf8").then( | |
🟠 High src/serviceLauncher.ts:563
A concurrent successful install({ start: false }) can have its new launcherVersion overwritten with the old value, leaving service state pointing at launcher A and allowing pruning to remove launcher B even though the unit was repointed to B. #writeState reads the state before the installer writes B, then atomically writes its stale merged state afterward; coordinate this merge and write with the install/repoint operation so the installed version is preserved.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/server/src/serviceLauncher.ts around line 563: |
| 2 | |
| 3 | A concurrent successful `install({ start: false })` can have its new `launcherVersion` overwritten with the old value, leaving service state pointing at launcher A and allowing pruning to remove launcher B even though the unit was repointed to B. `#writeState` reads the state before the installer writes B, then atomically writes its stale merged state afterward; coordinate this merge and write with the install/repoint operation so the installed version is preserved. |