Skip to content

feat(native): interrupted-install route from a strict GetInstallRecovery read - #621

Merged
hanthor merged 1 commit into
mainfrom
claude/cool-hopper-zwie7w-winui-c-startup-interrupted
Oct 15, 2026
Merged

hanthor merged 1 commit into
mainfrom
claude/cool-hopper-zwie7w-winui-c-startup-interrupted

Conversation

@hanthor

@hanthor hanthor commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Phase C step 1 for #344: the native shell reads the interrupted-install classification (#287) and routes to it. The Wails relaunch already does this; the native shell had neither the read nor the route.

Engine

  • GetInstallRecovery joins ProtocolMethods and the assessment-session allowlist. It accepts no parameters and runs startupValidate first, like GetLastRun and GetRecoveryVerdict. A drift refuses it with the same fixed message.
  • It returns a new InstallRecoverySummary: class, cause, image, known step IDs, the engine's fixed title and message, the safe actions and the resume facts. It leaves out evidence, the step error and the raw observation, because those can hold paths and free-form error text.
  • Strict read (native). A bounded read of the audited root: journal.json with no duplicate, unknown or null fields, a known outcome and catalogue step IDs; markers and root.disk by Lstat, regular files only; blob counting without reading bundle.json. It uses the same classifyInstall as the relaunch, and a test checks that both paths give the same summary.
  • Journal owner identity. A live journal owner must have been created before the journal started (GetProcessTimes). processAlive compares executable names, which can't match the legacy installer from wootc-engine.exe. A PID reused after a reboot was created later, so it doesn't pass.

Shell

  • StartupRoute.Interrupted for resumable, failed and needs-repair. A boot verdict still wins, as in the legacy relaunch. An unknown class is refused.
  • The decoder accepts only the exact field set, enumerated values and bounded text. An absent attempt can't carry actions, and an interrupted one needs engine text and at least one safe action.
  • The window shows the route, Install: <class> and the engine's title and message. No action runs: resume, retry and remove need the install route (step 2).

Checks

Local, head b1f469f:

Check Result
go vet ./..., GOOS=windows go vet ./..., GOOS=windows go test -c pass
go test ./... pass; new: strict reader, 10 journal refusals, irregular markers, relaunch parity, owner identity, RPC contract, engine goldens
go generate DTOs current (InstallRecoverySummary, InstallRecoveryActions)
dotnet test Wootc.Shell.Tests (Linux) 60 passed (13 new route tests)
Wootc.Shell.NativeTests decode and stage tests, run on Linux 40 passed; a mutant without the exact field-set check fails the 3 leak cases
Wootc.Shell.NativeTests and Wootc.Shell.UiTests builds (EnableWindowsTargeting) build
actionlint, docs-truth.bats, STE on docs/winui-shell.md clean; 0 new findings

Hosted on b1f469f, all green, in existing jobs (no new workflow or job):

  • run 38815900635 native-build: Wootc.Shell.NativeTests 61 passed (43 before). StartupWindowTests 2/2, including the real interrupted-install window case. The branded package bazzite shows Install: none installed.
  • run 38815900537 readonly-cli-status: every new TestStatusInstallRecovery… and TestStatusJournalOwner… control passed on Windows.
  • Configuration, assessment RPC, standard-user ACL, fast tier, lint and STE also pass.

What each hosted check covers:

  • readonly-cli-status: the Go TestStatus… controls on Windows, including GetProcessTimes.
  • winui-preview native-build: the native decode tests, and StartupWindowTests with the real engine and window. A fresh runner must show Install: none. Then a real C:\wootc with a staged state and a running journal whose PID is 4 (alive, but created at this boot) must show the Interrupted route and the engine's text, with the state bytes and ACL unchanged.
  • The branded package job: Install: none on an installed package.

Not in this PR

  • Any action from the Interrupted screen (resume, retry, remove): that needs the install route, step 2.
  • A route for in-progress (another legacy installer window is running). It keeps the existing route, as the legacy relaunch does.
  • An attempt with only a journal on a volume other than the selected root: as in the legacy relaunch, selection still needs state.json.

🤖 Generated with Claude Code

https://claude.ai/code/session_01F5v5GG4NYnpzMrfPCo3vWN


Generated by Claude Code

…ery read

Phase C step 1 (#344). The Wails relaunch routes an interrupted install
(#287) to its own screen; the native shell had no such read or route.

Engine
- GetInstallRecovery joins ProtocolMethods and the assessment-session
  allowlist. It takes no parameters and runs startupValidate first, like
  the other startup reads.
- It returns InstallRecoverySummary: class, cause, image, known step IDs,
  the engine's fixed title and message, the safe actions and the
  resume facts. Evidence lines, the step error and the raw observation
  stay out, because they can hold paths and free-form error text.
- The native (strict) path reads the audited root with bounded strict
  readers: journal.json without duplicate, unknown or null fields, with a
  known outcome and catalogue step IDs; markers and root.disk by Lstat as
  regular files only; blob counting without reading bundle.json. The
  classification is the same classifyInstall the relaunch uses, and a
  test checks the two agree.
- The journal owner is live only when its PID was created before the
  journal started (GetProcessTimes). processAlive compares executable
  names, which cannot work for wootc-engine.exe, and a PID that Windows
  reused after a reboot was created later.

Shell
- StartupRoute.Interrupted for resumable, failed and needs-repair, after
  a boot verdict, as in the legacy relaunch. An unknown class is refused.
- The decoder accepts the exact field set only, enumerated values and
  bounded text; an absent attempt cannot carry actions, and an
  interrupted one needs engine text and a safe action.
- The window shows the route, "Install: <class>" and the engine's text.
  No action runs; the actions need the install route (step 2).

Proof
- Go: strict reader, refusals, parity with the relaunch classifier, owner
  identity, RPC contract, and goldens of the engine bytes. The Windows
  "TestStatus" controls run them in readonly-cli-status.
- C#: route tests (Linux), and decode tests over the same goldens with 16
  refusal cases (native-build).
- StartupWindowTests drives the real engine and window against a real
  C:\wootc with a staged state and a running journal whose PID is 4: it
  must show the Interrupted route and the engine's text, and leave the
  state bytes and ACL unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F5v5GG4NYnpzMrfPCo3vWN
@hanthor
hanthor merged commit 2f7a846 into main Oct 15, 2026
24 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.

2 participants