Skip to content

Make the Windows downloaded GUI name the cache cause behind exit 3 - #17

Merged
oliverdougherC merged 4 commits into
mainfrom
codex/windows-exit3-20260921
Sep 22, 2026
Merged

oliverdougherC merged 4 commits into
mainfrom
codex/windows-exit3-20260921

Conversation

@oliverdougherC

Copy link
Copy Markdown
Owner

What broke

The published 1.3.0-rc.2 Windows GUI showed Run failed (exit code 3) on the reporter's machine with no cause. Two independent defects combined:

  1. Silence: every preparation/preflight/batch gate printed only to stderr — invisible in the --windowed PyInstaller build — and the GUI done-handler replaced any reported cause with the bare exit code.
  2. The actual cause: an extraction root under .suite-pack created by an administrator-privileged (or foreign-account) run carries a DACL with no normal-user ACE. os.path.exists then reports it missing, so every normal run re-downloads and re-extracts the whole pack, and the final swap is refused (WinError 5) behind shutil.rmtree(..., ignore_errors=True) — a guaranteed exit 3 that no cleanup can end.

Reproduction (native, published rc.2 binaries)

Replica of the reporter's default cache (identical bytes, same SYSTEM/Administrators/OWNER RIGHTS DACL) driven under a normal (Limited) token:

Unable to prepare suite clip : [WinError 5] Access is denied:
 '...\\.suite-pack\\suite-pack-iuryl85_' -> '...\\.suite-pack\\d40bff56...'
exit 3

The replica pack itself is hash-valid; the same cache with open ACLs completes end-to-end (2 encodes, exit 0) — isolating the ACL state, not the data.

Changes

  • client/main.py: run_error events with the full causal message at every gate the GUI can reach; last cause retained; status/event log now read Run failed (exit code N): <cause>.
  • client/suite.py: _suite_pack_target_access_error() classifies an unreadable/foreign-ACL cache before burning the multi-gigabyte re-extraction (names the folder and the recovery), and the staging swap failure reports the target path instead of dying silently.
  • Regression tests: three causal-event GUI tests, two cache-swap classification tests, cause-retention through the done handler.
  • Version freeze 1.3.0-rc.3 / client/0.3.2; protocol 7.1 and PROTOCOL_MINIMUM_CLIENT_VERSION unchanged.

Verification

  • Full client suite: baseline 4 environment-only test_runtime_lock errors (missing local libsvtav1), no new failures.
  • Native bounded acceptance on candidate build: clean-cache real run, mid-encode Stop, queue isolation; genuine --submit sweep produced durable campaign evidence + two server receipts (see lane handoff).

ofhd added 4 commits September 22, 2026 00:18
The packaged windowed client has no visible stderr: the suite-preparation,
preflight, and batch-gate returns printed only there, so a first-run
preparation failure surfaced as nothing but "Run failed (exit code 3)",
and the worker's done handler overwrote even a reported cause with that
bare exit code. Emit run_error events with the full causal message at
every gate the GUI can reach (sweep planner and suite preparation,
compatibility/runtime-integrity preflight, v7 clip preparation and
argument gates, batch identity/budget checks), retain the last cause in
the app, and compose "Run failed (exit code N): <cause>" into both the
status line and the event log when a run ends failed.

Adds causal-event regressions for the three exit-3 sites and cause
retention through the GUI done handler.
An extraction root created by an administrator-privileged or foreign-account
run is invisible to os.path.exists and undeletable by the normal user, so
every normal run re-downloaded, re-verified, and then lost the swap with
WinError 5 behind a generic 'suite unavailable' and exit 3. Classify the
unreadable/foreign-ACL cache before burning a re-extraction, report the
target path plus the actionable delete instruction when the swap itself is
refused, and stop swallowing the swap failure behind ignore_errors.
Protocol 7.1 and the minimum-client gate are unchanged; the bump only makes
the cache-cause fix distinguishable in submission metadata and download
provenance.
Stamp the rebuilt Windows GUI digest, move rc.2 to the superseded packaged
section with its published digests, keep the rc.1 plain CLI builds reachable
under their own tag, and update the README current-release statements.
macOS/Linux primary digests are unchanged: byte-identical republish.
@oliverdougherC
oliverdougherC merged commit 17c60f9 into main Sep 22, 2026
13 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