Skip to content

[codex] fix desktop update packaging integrity#96

Closed
wizzoapp[bot] wants to merge 6 commits into
mainfrom
wizzo/ada-55-desktop-update-integrity
Closed

[codex] fix desktop update packaging integrity#96
wizzoapp[bot] wants to merge 6 commits into
mainfrom
wizzo/ada-55-desktop-update-integrity

Conversation

@wizzoapp

@wizzoapp wizzoapp Bot commented Jul 6, 2026

Copy link
Copy Markdown

Summary

Fixes the desktop update corruption path by shrinking the Windows unpacked payload, disabling differential updater downloads, adding a launch-time packaged integrity check, and adding CI coverage for a real install N-1 -> update -> relaunch path.

Root cause

The desktop package unpacked the entire production node_modules tree into app.asar.unpacked. Windows in-app updates then had to install thousands of loose files, making silent install slow and increasing the chance of a partial app.asar.unpacked payload after update.

Changes

  • Generate targeted ASAR unpack patterns from the staged pnpm runtime dependency closure, including pnpm linker paths needed by plain Node and WSL.
  • Write a packaged integrity manifest and bootstrap through a startup check before loading main.cjs.
  • Disable runtime differential downloads so updates install full verified payloads.
  • Surface an Installing update state in desktop update UI.
  • Add a Windows CI update smoke: build/install 0.0.900, serve 0.0.901 via mock update feed, drive check/download/install through the packaged app, and verify relaunch at the new version.

Validation

  • scripts/factory/precommit-gate.sh --prepare: PASS (vp run typecheck, vp check, Codex gpt-5.5 autoreview clean)
  • vp test run scripts/build-desktop-artifact.test.ts scripts/desktop-launch-smoke.test.mjs apps/desktop/src/app/PackagedIntegrity.test.ts apps/desktop/src/updates/DesktopUpdates.test.ts apps/desktop/src/updates/updateMachine.test.ts apps/web/src/components/desktopUpdate.logic.test.ts
  • node apps/desktop/scripts/desktop-update-smoke.mjs --help

Note: the true Windows update-path proof is the new CI job; this PR should not be considered fixed until that job passes on GitHub.

@wizzoapp wizzoapp Bot marked this pull request as ready for review July 6, 2026 19:23

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 763a748745

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return new Promise((resolve, reject) => {
const request = NodeHttp.get(
{
hostname: "127.0.0.1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use the same loopback host as the mock update server

In environments where Node resolves localhost to IPv6 (for example Node 24 on this runner binds server.listen(..., "localhost") to ::1), this smoke test never reaches the mock update server: scripts/mock-update-server.ts listens on localhost, but the new readiness probe always dials 127.0.0.1, so waitForUpdateServer times out before the update flow starts. Please make the mock server and probe use the same explicit host, or probe localhost here.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8cbcb3544

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread scripts/build-desktop-artifact.ts Outdated
Comment on lines +2350 to +2353
rootPackageNames: [
...Object.keys(resolvedServerDependencies),
...Object.keys(platformFffNativeDependencies),
...Object.keys(linuxWslFffNativeDependencies),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include desktop native files in integrity manifest

When packaging Windows/macOS builds, stageClerkPasskeyNativeBinaries copies Clerk passkey .node files into the desktop runtime package, but this manifest seed only walks server/fff dependencies. If an update leaves one of those smart-unpacked desktop native files missing from app.asar.unpacked, the new bootstrap integrity check still passes and the app can fail later while initializing createClerkBridge({ passkeys: true }), which defeats the incomplete-install diagnostic this change is adding. Please include the desktop native unpack roots (at least @clerk/electron-passkeys) in the required-file manifest.

Useful? React with 👍 / 👎.

wizzoapp Bot added a commit that referenced this pull request Jul 6, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 473ccf14d1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return {
...state,
status: "installing",
message: "Installing update. T3 Code will restart when installation is ready.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Don’t mark successful install handoff as an error

When installUpdate() succeeds, DesktopUpdates.install returns the current state after setting this installing message, with { accepted: true, completed: false }. Both the sidebar and settings flows interpret any accepted/non-completed action with a non-empty state.message as an error toast, so a normal install handoff can briefly show “Could not install update” with this installing text before the app restarts. Please keep the installing status message out of the action-error path or special-case installing as non-error.

Useful? React with 👍 / 👎.

@wizzoapp wizzoapp Bot marked this pull request as draft July 7, 2026 12:07
wizzoapp Bot added a commit that referenced this pull request Jul 7, 2026
@wizzoapp wizzoapp Bot marked this pull request as ready for review July 7, 2026 12:07
@wizzoapp wizzoapp Bot force-pushed the wizzo/ada-55-desktop-update-integrity branch from 473ccf1 to 9c0ba5c Compare July 7, 2026 12:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c0ba5c3bd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

}

const missingFiles = manifest.requiredFiles.filter(
(relativePath) => !NodeFS.existsSync(NodePath.join(unpackedRoot, relativePath)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject stale unpacked files

When an update or over-existing install leaves app.asar from the new version but app.asar.unpacked from the previous version, the same runtime paths still exist, so this existence-only check passes and the app continues into a mixed-version install. That is exactly the class of partial desktop update this bootstrap is meant to diagnose; include and verify at least size or hash metadata from the generated manifest so stale unpacked files are treated as integrity failures rather than surfacing later as runtime crashes.

Useful? React with 👍 / 👎.


yield* Ref.set(desktopState.quitting, true);
yield* Ref.set(updateInstallInFlightRef, true);
yield* setState(reduceDesktopUpdateStateOnInstallStart(state));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore state when install is interrupted

When the install effect is interrupted after this transition but before quitAndInstall either succeeds or reports an error, the onInterrupt path below only clears the in-flight/quitting refs and leaves the update state as installing. Because checks and UI controls now treat installing as non-actionable, an app that remains alive after that cancellation can be stuck with update controls disabled and no retry path until restart; restore the prior downloaded state or mark an install failure in the interrupt finalizer.

Useful? React with 👍 / 👎.

@wizzoapp wizzoapp Bot marked this pull request as draft July 7, 2026 12:49
@wizzoapp wizzoapp Bot marked this pull request as ready for review July 7, 2026 12:49
@wizzoapp wizzoapp Bot marked this pull request as draft July 7, 2026 13:32
@wizzoapp wizzoapp Bot marked this pull request as ready for review July 7, 2026 13:32
@wizzoapp wizzoapp Bot marked this pull request as draft July 7, 2026 13:45
@wizzoapp wizzoapp Bot marked this pull request as ready for review July 7, 2026 13:45
@wizzoapp wizzoapp Bot marked this pull request as draft July 7, 2026 14:01
@wizzoapp wizzoapp Bot marked this pull request as ready for review July 7, 2026 14:02
wizzoapp Bot added a commit that referenced this pull request Jul 8, 2026
@wizzoapp wizzoapp Bot force-pushed the wizzo/ada-55-desktop-update-integrity branch from fac5777 to 7b3d358 Compare July 8, 2026 11:13

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7b3d358172

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -0,0 +1,565 @@
#!/usr/bin/env node

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wire the desktop update smoke into CI

This adds the N-1 → update → relaunch smoke test, but it is never invoked: rg desktop-update-smoke only finds this new file, and the touched workflow steps still only run scripts/desktop-launch-smoke.mjs. As a result, the Windows updater path this change is meant to protect can still regress without CI noticing; please add this script to the Windows artifact workflow or to a package script that CI runs.

Useful? React with 👍 / 👎.

Comment thread .github/workflows/ci.yml
}
if ($outputText -notmatch "(?i)(apps/server/dist/bin\.mjs|missing server entry|backend|timed out)") {
throw "Launch smoke failed against the broken packaged artifact, but did not report the expected missing backend entry."
if ($outputText -notmatch "(?i)(installation is incomplete|apps/server/dist/bin\.mjs)") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the incomplete-install diagnostic in the smoke gate

This negative fixture is supposed to prove the new bootstrap integrity check reports the incomplete-installation diagnostic, but the regex also accepts any output containing apps/server/dist/bin.mjs (the same pattern is duplicated in reusable-build-release-artifacts.yml). If bootstrap gets bypassed and the app later dies with a raw missing-module error for the removed file, this step still passes, so the gate no longer verifies the diagnostic it claims to protect.

Useful? React with 👍 / 👎.

async function collectRelativeFiles(input) {
const { root, current, logicalRoot, files, visited } = input;
const realCurrent = await NodeFSP.realpath(current).catch(() => current);
const visitedKey = `${realCurrent}\0${logicalRoot}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Key visited directories by real path

When app.asar.unpacked contains a symlinked directory cycle, including logicalRoot in the visited key makes each traversal of the same real directory look new (root, loop, loop/loop, ...). The manifest walk can then emit many duplicate required paths or hit symlink-depth/path limits during afterPack, blocking desktop artifact builds for pnpm-style dependency symlink cycles; track visited directories by real path before following symlink directories.

Useful? React with 👍 / 👎.

@wizzoapp wizzoapp Bot force-pushed the wizzo/ada-55-desktop-update-integrity branch from 7b3d358 to 13fe6ba Compare July 8, 2026 12:10
@wizzoapp

wizzoapp Bot commented Jul 8, 2026

Copy link
Copy Markdown
Author

Closing per the starved Codex-review recycle recipe. The rebased branch is green on CI at 13fe6ba, including Desktop Linux Package Smoke and Desktop Windows Package Smoke; I will open the fresh replacement PR from the same branch and link it here next.

@wizzoapp wizzoapp Bot closed this Jul 8, 2026
@wizzoapp

wizzoapp Bot commented Jul 8, 2026

Copy link
Copy Markdown
Author

Superseded by #134 from the same branch after the green recycle push. CI on #96 was green at 13fe6ba, including both desktop package smoke jobs; #134 is the fresh PR for Codex review.

wizzoapp Bot added a commit that referenced this pull request Jul 8, 2026
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.

0 participants