Repository navigation
Installer: deterministic cleanup environment and residual version-folder backup (#883) - #1046
Merged
Merged
Conversation
Reproduces the original failure: a Windows PowerShell 5.1 child that inherits a PowerShell 7 PSModulePath cannot resolve Get-FileHash. Runs the real helper from the 64-bit and 32-bit hosts against throwaway fixtures (fake LOCALAPPDATA, HKCU test namespace), fails against the pre-fix module, passes on main. Adds test-only hooks for the registry root, Start-menu folder and camera owner key. Copies in the spec and plan with owner rulings D4/D5 and the Task 1 findings. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…#883) Remove-PreviousInstallations.ps1 now resets PSModulePath for its own process (owner ruling D5), imports Utility/Management/CimCmdlets by absolute manifest path, proves every command it needs resolves, and logs the diagnostics block (PS version, bitness, language mode, PSHOME, inherited and effective path) to %LOCALAPPDATA%\CoreVideoPro\installer-logs\<release>-retire.log. A failure names the command and is logged before it is rethrown (exit 1). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Get-OwnedInstallMetadataNames is now the single metadata list (adds the .camera-desktop-registration-before.json that stranded 29 folders) and the registered retirement uses it. Get-ResidualInstallationPlan classifies every file of an unregistered version folder as metadata, hash-proven payload or unknown, skips running versions and the folder the camera points into, and retains (never enters) anything with a reparse point. Read-only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ing it (#883) Remove-ResidualInstallation (owner ruling D4) moves every unknown file of a residual version folder into a dated retired-install-remnants-<stamp>-<id> folder, same volume only, with backup-manifest.json written before the first move; then deletes proven payload and owned metadata one file at a time and removes empty directories non-recursively. Collisions get a numeric suffix; any failure keeps the folder retained with the reason. -LeaveUnknown keeps operator content in place for manual runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Remove-PreviousInstallations.ps1 runs the residual sweep after the registered
retirement, writes previous-installations-cleanup.json as
{summary, registered, residual} (copy in installer-logs), and prints one line per
retained or left-in-place folder, the backup folder when files were moved, and a
final 'retired / backed up / retained' count of folders. Exit 0 clean, 2 clean
with operator files moved, 1 retained. installer.nsi passes -ReleaseId and shows
the backup location in an information box (owner ruling D4) or the summary in
the existing warning; /SD IDOK kept.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sts in CI installer.md records the reproduced root cause, the pinned environment and log, the shared metadata list, the residual sweep and backup layout (rulings D4/D5), the report schema and exit codes. CI native-shell-windows runs Test-ResidualInstallations.ps1 and Test-CleanupEnvironment.ps1. BACKLOG #883 now says what shipped and that installed acceptance (plan Task 7, owner) is open; the plan carries exact owner instructions for it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he repro proves (#883) Review of #1046: a folder that moved some operator files and then failed (for example on a locked file) is retained with moved > 0; summary.backupFolder, filesBackedUp and the 'MOVED, not deleted, to:' line now come from moved > 0 regardless of status, and that line is printed before the Retained lines because nsExec keeps only the head of stdout. New end-to-end case: partial move then failure carries the backup folder in both stdout and the JSON (fails on the old reporting). The 32-bit retire log notes that System32 entries resolve to SysWOW64. Docs: the suite bites with the Get-FileHash planner restored and the pin removed; PS7 inheritance is a proven mechanism, not the proven cause of the 2026-10-13 incident (no PowerShell 7 on the dev box). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…plan/spec copy)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #883
What was wrong
The Get-FileHash failure: reproduced. In Windows PowerShell 5.1,
Get-FileHashis a script function that module auto-loading has to find. Compiled cmdlets such asConvertTo-Jsonare always loaded, which is why only this one command failed. When setup is launched from a PowerShell 7 shell, the cleanup helper inherits PS7'sPSModulePath. nsExec passes it through unchanged, and 5.1 then bindsGet-FileHashto PS7's Core-only Utility module. The result is exactly the issue text: "The term 'Get-FileHash' is not recognized". I reproduced it through a realnsExec::ExecToStack, on both the 32-bit (SysWOW64) and 64-bit hosts. None of these reproduce it: empty, missing or stray module paths, a corrupt analysis cache, or__PSLockdownPolicy. This is a proven mechanism, not the proven cause of the 2026-10-13 incident. No PowerShell 7 exists on the dev box (the repro borrowed PS7 7.4.6'sModulesfrom a downloaded zip), and the environment that launched that install was never captured.Stale folders: still open on main. A read-only measurement on the dev box found 32 unregistered version folders: 29 holding only
.camera-desktop-registration-before.json(it was missing from the inline metadata list), 2 holdingRecordings\(12 files), and 1 full unregistered payload. The registered pass enumerates uninstall keys, so it cannot see any of them.What changed
PSModulePathfor its own process only. It then imports Utility, Management and CimCmdlets by absolute path and checks that every command it uses resolves. Every run writes a diagnostics block (bitness, language mode,$PSHOME, inherited and effective path) to%LOCALAPPDATA%\CoreVideoPro\installer-logs\<release>-retire.log. If a command does not resolve, the error names it.Get-OwnedInstallMetadataNames, used by both passes.%LOCALAPPDATA%\CoreVideoPro\backups\retired-install-remnants-<yyyyMMdd-HHmmss>-<id>\<release>\..., on the same volume only.backup-manifest.json(source, destination, length, sha256, status) is written before the first move. A name collision gets a numeric suffix. Any failure keeps that folder and records the reason.previous-installations-cleanup.jsonis now{summary, registered, residual}, with a copy ininstaller-logs. The last stdout line counts folders, not uninstall entries.-ReleaseId./SD IDOKis kept.Tests
Test-PreviousInstallations.ps1Test-PreviousInstallations.ps1 -WithoutHashCommandTest-ResidualInstallations.ps1(new)Test-CleanupEnvironment.ps1(new; runs the real helper in 64-bit and 32-bit child hosts)With the
Get-FileHashcall restored and the pin removed (the Task 1 helper, run with the planner module from91db55bf^), the suite fails with the issue text: the old version isretainedwith "Get-FileHash is not recognized". That proves the test bites. It embeds PS7 7.4's Utility manifest verbatim, because a hand-trimmed look-alike does not reproduce the failure. When a real PS7 is installed, as on the CI image, it also uses thatModulesdirectory. Both new tests run in CI undernative-shell-windows.installer.nsicompiles with makensis (exit 0) against a stub staging tree. The newest local beta zip predates #1033, sopackage-alpha-installer.ps1could not package it.Not done: installed acceptance (plan Task 7, owner)
The exact steps are in
docs/superpowers/plans/2026-10-23-installer-cleanup-883.mdunder "Task 7 owner instructions". In short:summary.retained = 0; a backup manifest listing the 12 recording files with matching SHA-256; a retire log showingis64Bit=Falseand the pinned path; shortcuts and camera ownership pointing at the new install; settings hashes unchanged.A dry run with
-InspectOnlyagainst the real root (read-only) gave 32 residual plans, allready: 29 metadata-only, 2 with recordings (10 + 2 files), and 1 with 875 proven payload files and 0 unknown.Spec (with rulings D4/D5 and the Task 1 findings) and plan are in
docs/superpowers/.docs/reference/installer.mdand the BACKLOG #883 row are updated.🤖 Generated with Claude Code