Desktop database-upgrade proof: Linux x86_64, Electron 44.10.1, Xvfb 1920x1080, light theme.

The fixture is synthetic; no live T3 home was read or copied. seed.mjs invokes the repository migration API through migration 71. populate.py inserts six million synthetic completed turn items (about 23 GiB). Each desktop runs a separate physical copy of this unchanged fixture. No migration names or history are repaired or skipped.

Requirements: repository dependencies, built web/server/desktop, Electron runtime, headless-desktop, ffmpeg, ImageMagick, systemd user manager.
Put these scripts together in a disposable directory. From the directory:
 node seed.mjs <absolute-head-checkout> <absolute-script-directory>/seed.sqlite
 python3 populate.py seed.sqlite
 systemd-run --user --unit=evidence35056-throttle -p CPUQuota=2% /bin/sleep infinity
 headless-desktop node run.mjs <absolute-base-checkout> before
 headless-desktop node run.mjs <absolute-head-checkout> after
 systemctl --user stop evidence35056-throttle

observe.cjs only duplicates backend output to a file and applies a backend CPU cgroup on the actual migration progress line. It requires the unchanged built desktop main. release.mjs restores unrestricted CPU exactly four minutes after migration starts. SQLite executes its real CREATE INDEX during that period. The desktop UI is unrestricted. No backend is paused after readiness. run.mjs records the entire desktop and waits for actual backend-ready output before finishing.

The base run's four-minute CPU release was launched as a separate invocation of release.mjs; the head run launches the identical helper from run.mjs. The base stable screenshot was taken with a separate invocation of stable.mjs; head captures call that same helper. Uploaded scripts consolidate those invocations and replace the original disposable directory with their own directory for portability.

Recordings run at real wall-clock speed, 2 frames/second, with elapsed time. The base recovery footer and the onboarding machine-name line are masked for privacy. Timing transcripts omit private paths. No application behavior, migration implementation, readiness deadline, or displayed failure text was changed.

Crash control: headless-desktop node crash.mjs <checkout> <base-or-head>. crash-observe.cjs sends SIGKILL 500ms after each actual backend child spawn. Both versions report "The server could not start (killed by SIGKILL)." Separate XDG_CONFIG_HOME avoids the Electron single-instance lock. These launches use fresh empty homes and no CPU limit. The head crash still is extracted from its inspected recording; the matching video is the primary evidence.
