Skip to content

feat(desktop): debug-only nuke & fresh start with full local wipe - #2954

Merged
benjaminshafii merged 17 commits into
devfrom
feat/debug-nuke-fresh-start
Jul 21, 2026
Merged

feat(desktop): debug-only nuke & fresh start with full local wipe#2954
benjaminshafii merged 17 commits into
devfrom
feat/debug-nuke-fresh-start

Conversation

@benjaminshafii

Copy link
Copy Markdown
Member

Why

Early enterprise testers can accumulate state across many pre-release builds (desktop profile, OpenWork runtime DB, OpenCode sessions/auth, MCP OAuth, orchestrator credentials, browser storage). The existing Danger-zone "nuke" only removed Electron userData and called app.exit(0); it skipped most state roots, skipped graceful shutdown, could leave children rewriting files, and could not reliably delete Windows-locked Chromium/SQLite state.

What changed

  • Debug settings → Danger zone now has Nuke & fresh start behind existing Developer Mode gating.
  • Proper AlertDialog previews every path that will be deleted / preserved and requires typing NUKE.
  • Best-effort cloud sign-out, then ordered local wipe: quiesce UI control + runtime children + sidecars + sandbox containers; clear default + persist:openwork-browser Chromium storage; sanitize bootstrap; delete/verify filesystem roots; write a receipt; relaunch.
  • Wipes Electron profile, OpenWork config/runtime/token/env files, OpenCode auth/MCP auth/session DB/log/cache/config roots, orchestrator credentials, brand/updater state, and Windows brand shortcut.
  • Preserves app binary, ~/.opencode/bin, user workspace folders (including workspace .opencode), and a sanitized org bootstrap containing only deployment URL, require-signin, branding, and fresh writtenAt. Handoff grants, claim-link tokens, and prepared metadata are stripped.
  • Malformed/BOM bootstrap handling fails closed: BOM JSON is normalized/sanitized; truly malformed files are deleted rather than accidentally preserved with secrets.
  • Windows locked paths use a persistent sentinel. Sentinel is retained until paths are actually deleted.
  • Because Electron cannot delete its live Chromium profile in-process, a safe detached ELECTRON_RUN_AS_NODE cleanup worker waits for parent exit, finishes deletion, and only then relaunches OpenWork. Worker payload allowlists paths/PID only—no auth/env secrets or arbitrary commands.
  • CDP port is intentionally reprobed after cleanup; ephemeral debug state is not carried into the fresh process.
  • Receipts include deleted/pending/errors, bootstrap status, and direct-vs-worker relaunch mode.

Explicit non-goals / limitations

  • Does not delete user workspace folders or ~/.opencode/bin.
  • Does not remove Chromium's OS keychain "Safe Storage" entry (Electron has no supported removal API); browser/session contents are cleared.
  • Clean runtime files such as a new hashed owner tokens.json may be regenerated after relaunch; proof verifies none of the old seeded state survives.

Automated verification

  • pnpm --filter @openwork/desktop test99 pass, 1 expected skip, 0 fail
  • Focused nuke suite covers macOS/Linux/Windows manifests, dev/userData overrides, bootstrap secret stripping/BOM/malformed fail-closed, sentinel persistence across partial cleanup, cleanup worker payload safety/spawn/fallback/direct modes.
  • pnpm --filter @openwork/desktop typecheck:electron → pass
  • pnpm --filter @openwork/app typecheck → pass
  • pnpm --filter @openwork/types build → pass
  • Native Windows x64 GitHub build: https://github.com/different-ai/openwork/actions/runs/29818338334 (Windows job success; product code unchanged after this run—later commits are eval harness only).

Real Windows Daytona proof

Tested a native Windows CI artifact on Daytona Windows VM c502b6da-baff-43f4-8902-c7f76f605fdf, interactive Administrator session 1, driven via packaged Electron CDP. The flow seeds all state roots, real localStorage, provider/MCP auth files, runtime DBs, orchestrator auth, and bootstrap secrets.

debug-nuke-fresh-start result: PASSED — all 5 frames + voiceover

  1. Every state root visibly seeded.
  2. Debug-only manifest dialog + typed NUKE.
  3. Out-of-process cleanup + branded forced-sign-in relaunch; auth/developer/seeded preferences gone.
  4. No seeded filesystem state survives; bootstrap keeps org identity but strips handoff/claim/prepared secrets; fresh runtime credentials contain no seed markers.
  5. An exclusive Windows FileStream lock forces retry evidence; sentinel survives the locked boot; after locker release, an out-of-band fresh Windows boot removes both locked DB and sentinel.

Artifact: evals/results/2026-07-21T10-00-06-584Z/fraimz.html. A follow-up PR comment will post a second live run via pnpm fraimz --flow debug-nuke-fresh-start --pr.

Bugs found and fixed during real Windows validation

  • Windows cmd 8,191-char / quoting limitations in eval harness.
  • PowerShell 5.1 UTF-8 BOM fixture and CLIXML/JSON serialization issues.
  • Malformed bootstrap could have been preserved unsanitized.
  • Sentinel was removed before verifying locked path deletion.
  • Live Chromium userData cannot be removed by the owning Electron process; required external cleanup worker.
  • Reusing inherited CDP port races lingering Chromium sockets; fresh process now reprobes.

No claims are based only on unit tests; these failure modes were reproduced and repaired on the Windows VM.

@benjaminshafii

Copy link
Copy Markdown
Member Author

fraimz — ✅ PASSED

1 passed · 0 failed · 0 skipped — run 2026-07-21T10-04-59-101Z

Full frame proof with validated screenshots: evals/results/2026-07-21T10-04-59-101Z/fraimz.html (re-run: pnpm fraimz --flow debug-nuke-fresh-start)

✅ debug-nuke-fresh-start — Debug nuke wipes Windows local state and relaunches to sanitized sign-in

User-facing flow demo

  1. The Windows tester profile has seeded OpenWork, OpenCode, bootstrap, orchestrator, Chromium, and renderer state

    🎙 A tester's machine starts out full of real local state. We attach to the running Windows desktop app, seed every local OpenWork and OpenCode state root with recognizable fixtures and bootstrap secrets, then show the app is alive while the filesystem and localStorage witnesses prove the state is present.

    • ✅ Seeded %APPDATA%\opencode root exists
    • ✅ Seeded opencode directory lists auth.json
    • ✅ Seeded opencode directory lists mcp-auth.json
    • ✅ Seeded opencode directory lists opencode.db
    • ✅ Seeded %LOCALAPPDATA%\openwork root exists
    • ✅ Seeded LOCALAPPDATA openwork directory lists env.json
    • ✅ Seeded LOCALAPPDATA openwork directory lists tokens.json
    • ✅ Seeded LOCALAPPDATA openwork directory lists desktop-bootstrap.json
    • ✅ Seeded profile .openwork\openwork-orchestrator root exists
    • ✅ Seeded orchestrator directory lists openwork-orchestrator-auth.json
    • ✅ Seeded %APPDATA%\com.differentai.openwork userData root exists
    • ✅ Seeded userData directory lists eval-userdata-marker.txt
    • ✅ Renderer localStorage accepted the seeded fake openwork.den.authToken after reload
    • ✅ Renderer localStorage accepted the seeded active organization after reload
    • ✅ %APPDATA%\opencode\auth.json exists
    • ✅ %APPDATA%\opencode\mcp-auth.json exists
    • ✅ %APPDATA%\opencode\opencode.db exists
    • ✅ %APPDATA%\com.differentai.openwork seeded marker exists
    • ✅ %APPDATA%\openwork seeded server/env/tokens/runtime files exist
    • ✅ %LOCALAPPDATA%\openwork env.json and tokens.json exist
    • ✅ %LOCALAPPDATA%\openwork\desktop-bootstrap.json exists
    • ✅ %LOCALAPPDATA%\openwork\desktop-bootstrap.json exists in configHome probe
    • ✅ profile .openwork\openwork-orchestrator auth exists
    • ✅ profile .local\share\opencode data marker exists
    • ✅ profile .cache\opencode cache marker exists
    • ✅ Renderer localStorage has openwork.developerMode = 1
    • ✅ Renderer localStorage has openwork.preferences with hasCompletedOnboarding
    • ✅ Renderer localStorage had the seeded fake openwork.den.authToken immediately after reload
    • 📸 debug-nuke-fresh-start-01-stateful-machine-before-nuke.png — 5 validations passed
    debug-nuke-fresh-start-01-stateful-machine-before-nuke.png
  2. Debug settings exposes the Danger zone nuke dialog with delete/survive lists and typed confirmation

    🎙 In Debug settings, the tester opens the Danger zone. The dialog says exactly what will be deleted, what will survive, and asks for the typed word NUKE before the destructive button can run.

    • ✅ Visible text includes "Danger zone"
    • ✅ Visible text includes "Nuke & fresh start"
    • ✅ Visible text includes "Nuke local state and start fresh?"
    • ✅ Visible text includes "This removes local OpenWork, OpenCode, browser, token, runtime, cache, and orchestrator state on this device."
    • ✅ Visible text includes "WILL DELETE"
    • ✅ Visible text includes "WILL SURVIVE"
    • ✅ Visible text includes "Type NUKE to confirm"
    • ✅ Visible text includes "Chromium storage cleared: default, persist:openwork-browser"
    • ✅ Visible text includes "Nuke & relaunch"
    • 📸 debug-nuke-fresh-start-02-debug-danger-zone-nuke-dialog.png — 10 validations passed
    debug-nuke-fresh-start-02-debug-danger-zone-nuke-dialog.png
  3. Typing NUKE executes the cleanup, relaunches Electron, preserves required sign-in, and clears seeded Chromium storage

    🎙 One typed word wipes the machine. After NUKE is entered, OpenWork relaunches; because the bootstrap kept require-sign-in, the app comes back on the branded sign-in screen, and the seeded browser storage keys are gone.

    • ✅ Visible text includes "Welcome to Nuke Proof Work"
    • ✅ Visible text includes "Sign in to get started with your workspace."
    • ✅ Visible text includes "Sign in to Nuke Proof Work"
    • ✅ Visible text includes "Paste sign-in code"
    • ✅ Seeded openwork.den.authToken is gone after Chromium storage clear
    • ✅ openwork.preferences contains no seededBy or runTag after Chromium storage clear
    • ✅ openwork.preferences does not preserve completed onboarding after Chromium storage clear
    • ✅ Seeded openwork.developerMode is gone after Chromium storage clear
    • 📸 debug-nuke-fresh-start-03-fresh-start-forced-signin.png — 8 validations passed
    debug-nuke-fresh-start-03-fresh-start-forced-signin.png
  4. Filesystem witnesses show seeded markers are gone, clean runtime credentials may be recreated, sanitized desktop-bootstrap.json survived, and the nuke receipt recorded deleted paths

    🎙 No seeded state survived the cleanup. The Windows filesystem witnesses show seeded markers and run tags gone from OpenWork and OpenCode roots, allow clean runtime credential files to be recreated without fixture data, and keep desktop-bootstrap.json sanitized with baseUrl, requireSignin, and brandAppName while stripping handoff and claim-link secrets.

    • ✅ %APPDATA%\com.differentai.openwork lost the seeded userData marker after relaunch
    • ✅ %APPDATA%\opencode is gone after the nuke
    • ✅ %APPDATA%\openwork no longer contains seeded server/env/runtime files
    • ✅ %APPDATA%\openwork contains no seeded marker/runTag even if clean tokens.json is recreated
    • ✅ No seeded marker or runTag survived in post-nuke seeded file probes
    • ✅ %LOCALAPPDATA%\openwork survives only as the preserved config directory
    • ✅ %LOCALAPPDATA%\openwork contains only desktop-bootstrap.json
    • ✅ .nuke-pending.json is absent after the unlocked nuke
    • ✅ Seeded LOCALAPPDATA env.json and tokens.json were removed
    • ✅ desktop-bootstrap.json still exists
    • ✅ desktop-bootstrap.json parses as sanitized JSON
    • ✅ desktop-bootstrap.json keeps baseUrl https://openwork-poc.example.test
    • ✅ desktop-bootstrap.json keeps requireSignin true
    • ✅ desktop-bootstrap.json keeps brandAppName Nuke Proof Work
    • ✅ desktop-bootstrap.json no longer contains secret-grant
    • ✅ desktop-bootstrap.json no longer contains secret-token
    • ✅ desktop-bootstrap.json no longer contains the seeded marker or runTag
    • ✅ desktop-bootstrap.json strips handoff, claimLinks, and prepared
    • ✅ The newest openwork-nuke-receipt JSON has a non-empty deleted[]
  5. A locked runtime.sqlite is recorded for retry, then the boot guard removes it after the locker is killed and the app relaunches

    🎙 Even a locked database cannot silently survive. We lock a runtime database with an exclusive Windows handle, run the nuke again through the same Debug UI, verify the retry receipt or pending file names the locked path, kill the locker, relaunch once more, and require the boot guard to remove both the pending marker and the locked file.

    • ✅ PowerShell holds an exclusive FileShare.None handle on %LOCALAPPDATA%\openwork\runtime.sqlite
    • ✅ Renderer localStorage accepted the seeded fake openwork.den.authToken after reload
    • ✅ Renderer localStorage accepted the seeded active organization after reload
    • ✅ The detached locker process has a PID
    • ✅ The locked runtime.sqlite still exists immediately after the locked nuke
    • ✅ The second nuke wrote a new receipt
    • ✅ The pending retry file or newest receipt names the locked runtime.sqlite/config root
    • ✅ Stop-Process terminated the detached PowerShell locker
    • ✅ The runtime.sqlite exclusive handle was released before the retry boot
    • ✅ Harness discovered the main OpenWork.exe path before stopping the app
    • ✅ Interactive scheduled task launched a fresh OpenWork process without inherited remote debug port env
    • ✅ After the retry boot, .nuke-pending.json is gone
    • ✅ After the retry boot, the formerly locked runtime.sqlite is gone
    • ✅ Script frame 1 narrated: "A tester's machine starts out full of real local state. We attach to the running Windows"
    • ✅ Script frame 2 narrated: "In Debug settings, the tester opens the Danger zone. The dialog says exactly what will b"
    • ✅ Script frame 3 narrated: "One typed word wipes the machine. After NUKE is entered, OpenWork relaunches; because th"
    • ✅ Script frame 4 narrated: "No seeded state survived the cleanup. The Windows filesystem witnesses show seeded marke"
    • ✅ Script frame 5 narrated: "Even a locked database cannot silently survive. We lock a runtime database with an exclu"

@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openwork-app Ready Ready Preview, Comment Jul 21, 2026 10:14am
openwork-den Ready Ready Preview, Comment Jul 21, 2026 10:14am
openwork-den-worker-proxy Ready Ready Preview, Comment Jul 21, 2026 10:14am
openwork-diagnostics Ready Ready Preview, Comment Jul 21, 2026 10:14am
openwork-landing Ready Ready Preview, Comment, Open in v0 Jul 21, 2026 10:14am

@benjaminshafii

Copy link
Copy Markdown
Member Author

Additional independent Windows Daytona validation

A second fresh Windows VM also passed the complete flow (not a rerun on the original profile):

  • Sandbox: 9a2e36be-690b-400d-a235-769393abb3a6 (Windows medium, interactive Administrator session)
  • Native x64 artifact from Actions run https://github.com/different-ai/openwork/actions/runs/29818338334
  • Initial CDP was auto-probed at 9224 (not the first VM's fixed 9222), exercising dynamic relaunch-port discovery
  • Result: PASSED — all 5 frames + voiceover
  • Run: 2026-07-21T10-16-09-071Z
  • Local artifact: evals/results/2026-07-21T10-16-09-071Z/fraimz.html

This independently reconfirmed normal wipe/relaunch, sanitized bootstrap, absence of seeded state, exclusive Windows file-lock retry, retained sentinel, and cleanup on the next true out-of-band boot.

@benjaminshafii
benjaminshafii merged commit 4b8caee into dev Jul 21, 2026
16 checks passed
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.

1 participant