- Manual check finds no newer version: status message becomes "Redline X.Y.Z is up to date, checked HH:MM Dubai"
- Manual check stages a newer version: status message becomes "Update to X.Y.Z is ready"
- Automatic (scheduled) checks keep original silent behaviour when up to date
- Add snapshot-only seams for testing: snapshotPreviousVersionOverride and snapshotUsesPreviousVersionOverride
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012ZiTXPbPCSjzPVsfoweAbp
30s/600s URLSession timeouts on the update session (was 15s/15s, too tight for
a real zip download). Every staged and installed payload is now verified with
the Security framework (SecStaticCodeCheckValidityWithErrors, strict + all
architectures + nested code) against bundle id ai.flowmaster.shotdeck and an
allowed-team set (PWMCBMX5M8, L3N9S54CN3; overridable via REDLINE_ALLOWED_TEAMS
for the self-test only) — an unsigned or wrongly-signed update is discarded
before checkNow ever offers it, and installStaged re-verifies what actually
landed on disk as defense in depth.
installStaged is now atomic: ditto into an itemReplacementDirectory, then
FileManager.replaceItemAt swaps it into place, keeping exactly one
Redline.app.previous rollback copy (older ones are dropped first). Added
revertToPrevious(target:) to swap that copy back in (itself reversible — the
replaced version becomes the new .previous), and previousVersion(target:) to
read its CFBundleShortVersionString. Relaunch is now a detached
"wait for this PID to exit, then open -n" shell handoff instead of a
synchronous open+terminate, so there is never a moment with two instances
running. checkNow(manual:) now says "Redline X is up to date." when the user
asked directly, and exposes isCheckingNow/lastCheckedAt for the UI.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>