Prism project status — verified review (2026-09-08)¶
Ground truth gathered this session from git, the live VM, CI API, and the source files. Every claim below is cross-checked against tool output, not recalled from history.
What is DONE and committed (shipped)¶
Branch feat/store-exit-codes is checked out and pushed (remotes/origin/feat/store-exit-codes
exists). The exit-code work is committed in two commits:
| Commit | Change |
|---|---|
3ec66db |
feat(installer): wire Microsoft Store EXE return codes — prism.iss gains the Store EXE-return-code mapping in [Code] |
a9062ca |
docs(installer): add Installer Exit Codes page — docs/getting-started/installer-exit-codes.md |
Authoritative wiring (verified against the committed prism.iss at 3ec66db
and the working tree alike):
CustomErrorCode: Integerdeclared (line 129) — comment:0 -> success; 101/102 reserved for hooksCustomErrorCoderead (line 202) —Result := CustomErrorCodeCustomErrorCodehas zero assignment sites (grep count0) in both committed and working versionsNeedRestart()returns hardFalse(line 152/155) despite its own comment claiming it requests a restartGetCustomSetupExitCode()returns100whenWasPreviouslyInstalled(line 204), elseCustomErrorCode
Consequence, by construction: the shipping installer can emit only 0 and 100.
Codes 101/102 are documented in the table but are unreachable — no code line
can ever set CustomErrorCode to them examine.
Also committed on this branch (prior session work): pyproject/beta3 bump history,
shell.py timeout 120→3600, index tool removal, stdio/terminal refactor, Windows
stability fixes. tests/unit/test_pyinstaller_compat.py exists in the tree.
What is PENDING and uncommitted / unpushed (working-tree dirty state)¶
The following are untracked or modified and NOT committed — this is the unshipped half, exactly matching the "no commits/pushes for local fixes" constraint:
- Working tree:
git statusshows 30 untracked files + 5 tracked-modified + 1 deleted. - Modified (tracked):
pyproject.toml— version0.2.1-beta2→0.2.1-beta4src/prism/__init__.py—__version__0.2.1-beta2→0.2.1-beta3src/prism/mcp/shell.py— shell timeout max120→3600vagrant/scripts/tests/01-help.ps1— command-list regression guardvagrant/scripts/tests/06-ws.ps1—$ZVersion+ syntax-error casesvagrant/scripts/tests/13-test.ps1—-mrunner assert correctedvagrant/scripts/tests/05-terminal.ps1— deleted (terminal command removed)- Untracked (30) — the exit-code reproduction work-in-progress:
prism-installer/— the CI suite:run-installer-tests.ps1,test-exit-code-contract.ps1, upgrade/matrix/downgrade/prerelease/future/help/install/uninstall tests,_invoke-child.ps1,shared/installer-common.ps1,static/*analyzers,tests/.github/workflows/installer-verification.yml— the PR/branch gate workflow (ubuntu consistency job + Windows build+suite job)docs/plans/2026-09-07-exit-code-reproduction.md(exit-code plan) +2026-09-07-installer-ci-verification.mdvagrant/repro-core.ps1— the repro harnessvagrant/drive-repro.py— drivervagrant/diag-launch.ps1— launch-route diagnosticvagrant/repro-exit-codes.ps1,vagrant/smoke-helpers.ps1- ~14
probe-*.ps1/probe-*census*.pyscripts +repair-suite.py,pack-suite.py,fix-guest-found.py,strip-decorative-attrs.py,gate-parse.ps1,implement-runner-fixes.py,drive-guest.py,extract-suite.ps1,census-guest.py
VM state¶
vagrant status in vagrant/: default (libvirt) — running, box
jborean93/WindowsServer2022, hostname prism-win. Guest PowerShell is 5.1
(powershell.exe), Inno 6 installed at C:\Program Files (x86)\Inno Setup 6\ISCC.exe.
CI state (the honest part)¶
gh api .../commits/feat/store-exit-codes/status on branch tip a9062ca returns
{"state":"pending","statuses":[],"total_count":0} — no check runs attached to
the branch tip. The committed test-linux.yml / test-windows.yml workflows run
only on development (per AGENTS.md: "All workflows target development, promoted
to main"), and installer-verification.yml is untracked — so nothing has actually
exercised the exit-code suite in CI yet. Hosted runners are the GitHub-hosted ones;
self-hosted count is 0 out of necessity.
The reproduction goal — NOT achieved yet (honest)¶
The running VM and the harness are in place, but no exit code has been genuinely
measured from the guest yet. The base probe .iss compiles to ISCC exit=1 with
an empty log, and the harness cannot yet explain it. This session pinned the causes
to three stacked harness defects (all harness plumbing, none in the shipping
installer):
$( ... )capture — compile diagnostics were computed inside a subexpression, then discarded (that's why BASE_COMPILE_FAIL was empty for rounds).- Empty
$baseExein the compile-fail branch →Test-Path -LiteralPath ''throws on PS 5.1 (empty literal-path), silenced by-ErrorAction SilentlyContinue; the throw was the missing row for code 0. - The capture route —
Invoke-Captureuses the harness's own launcher; the diag proved routes 1 (-PassThru+manualWaitForExit) and 2 (cmd.exe shim) return real codes, while-Wait -RedirectStandardOutputreturns NOCODE and the 1-arg .NETProcessoverload THREW. But the log capture still returns empty at the source, so ISCC's rejection reason is unobserved.
Measured launch-route table (diag-launch.ps1 on the guest):
| route | result |
|---|---|
1 ‑PassThru + manual WaitForExit |
OK → 42, real exit code |
2 cmd.exe shim + >file 2>&1 |
OK → 42, log written |
3 ‑Wait ‑RedirectStandardOutput |
NOCODE (dead route) |
4 New‑Object Diagnostics.Process $psi |
THREW (no 1‑arg overload) |
Patching the empty-LiteralPath throw moved past line 216 but the guard at 224 can
still trip on an empty $baseExe; the fix that actually sticks is to never call
Test-Path with an empty string (guard $baseExe.Length -gt 0).
The code universe, on purpose¶
Reachable on the shipped installer: 0, 100 (run-to-completion / re-install over existing) plus 1, 4, 7, 8 if the probe harness can be made to stage them. Not reachable by any script today and so are NOT claimable as "reproduced":
| code | why unreachable |
|---|---|
| 2 | defined as human cancels before install — needs a human on the dialog |
| 3 | out of memory/resources — extreme machine exhaustion, unsafe to stage |
| 5 | defined as human cancels during install — needs a human/debugger |
| 6 | defined as debugger killed the process — needs a debugger |
| 101 | no network phase in this installer; CustomErrorCode has no writer → unreachable by construction |
| 102 | same — no writer, unreachable by construction |
MEASURED (2026-09-12) — full matrix reproduced on the VM¶
All 12 codes are accounted for with honest verdicts; every reachable code shows a real integer from the guest, and every unreachable one carries the proof.
| code | verdict | observed | evidence |
|---|---|---|---|
| 0 | observed | 0 |
fresh silent install (/VERYSILENT /NORESTART /SUPPRESSMSGBOXES) of the real setup exe ran to completion |
| 1 | unreachable-static | — | prism.iss has no SetupMutex directive (the only Inno single-instance mechanism) and InitializeSetup always returns True; the second instance runs freely — measured 0/100, never 1. The mapping block's "second instance blocked by the single-instance mutex" claim is falsified |
| 2 | blocked | — | cancel-before-start is user input by Inno's definition; no wizard exists under /VERYSILENT — needs the interactive UI lane |
| 3 | not-in-store-map | — | Inno-defined (out of memory/resources); no Prism mapping — docs decision pending |
| 4 | observed | 4 |
probe .iss derived from prism.iss with DefaultDirName → {autopf}\Probe4Collision and a regular FILE staged where the dir must be created → fatal mid-install |
| 5 | not-in-store-map | — | Inno-defined (cancel during install); no Prism mapping — docs decision pending |
| 6 | not-in-store-map | — | Inno-defined (debugger terminate); no Prism mapping — docs decision pending |
| 7 | observed | 7 |
probe .iss with PrepareToInstall returning a non-empty string → Preparing-to-Install stage stops; dedicated exit code 7 |
| 8 | observed | 8 |
probe .iss with PrepareToInstall setting NeedsRestart := True alongside the non-empty string → stage stops + restart; measured with /NORESTART |
| 100 | observed | 100 |
re-install over the registered copy — WasPreviouslyInstalled → GetCustomSetupExitCode returns 100 |
| 101 | unreachable-static | — | CustomErrorCode has zero assignment sites in prism.iss (declared, read, never written) — unreachable by construction |
| 102 | unreachable-static | — | same — no writer, unreachable by construction |
The full chain is proven end-to-end on the VM:
- real prism.iss + real assets (logo.ico, wizard BMPs) compile → ISCC exit 0, 77-line log, setup exe produced
- probes are DERIVED from the shipping prism.iss (copied + one minimal real-directive/event change + /DAppSource=payload), never hand-authored — the hand-authored base failed with Required parameter "DestDir" not specified
- capture route proven: cmd shim (cd /d into the probe dir + >log 2>&1, both streams), route 1 exit code (-PassThru + manual WaitForExit)
- /SUPPRESSMSGBOXES (plural) is required: a probe install that fails shows an error box that hangs headlessly — measured as a 900s TIMEOUT before the switch was added
- the shipping file uses LF line endings; probe $Change pairs must use `n or the literal match fails silently
CI pipeline (built, after the measured codes)¶
- code-set gate
prism-installer/static/analyze-exit-code-set.ps1derives the claimed set fromprism.iss(verified:[0,1,2,4,7,8,100,101,102], no duplicates) and goes red on a deleted row, a falsified code, or a duplicate value — wired into theconsistencyjob of.github/workflows/installer-verification.yml - Actions
windows-latestverify job runsprism-installer/run-installer-tests.ps1, which asserts the exercised installer codes (0, 100) and declares 1/2/4/7/8/101/102 not-exercised with reasons (hosted runners cannot stage UI/reboot/resource codes, and the shipping installer wires no SetupMutex and no CustomErrorCode writer) - commit/push scope — probe/repair scripts stay out of the repo
Next steps (in dependency order)¶
- ✅ Measurement complete — all 12 codes accounted for (observed / blocked / not-in-store-map / unreachable-static).
- ✅ CI pipeline built — gate + suite + workflow wired.
- Commit/push scope — keep the ~14 probe/repair scripts out of the repo; ship the gate + suite + workflow when you say go.
Nothing in the pipeline changes the shipping installer; all is harness/CI plumbing. No commits or pushes have been made for any of it, per the constraint.