Repository navigation
v2.5.78 - Headless servicing
Boot Update Cycle - Release Notes
Current Version: v2.5.78
Release Date: 2026-09-09
Status: STABLE
v2.5.78 (2026-09-09)
Headless-servicing release. v2.5.77 shipped the lab that found its own defects; running that lab against a machine nobody signs into found four more, and one of them was introduced by v2.5.77 itself.
Microsoft documents a machine with no signed-in user as the unblocked servicing path. The updater could not converge there at all. Every fix below is on that path.
Fixed
- A same-boot recovery pass reset the retry budget, so a permanently applicable update retried forever. The monotonic boot instant v2.5.77 added is persisted, and
ConvertFrom-Jsonrehydrates an ISO-8601 string as a[datetime]; coercing that back to text for the comparison uses the current culture, which emits no offset, so a UTC instant parses as local and the delta picks up the machine's entire UTC offset rather than the seconds of jitter the tolerance was sized for. Measured on an Eastern host: 14,398 seconds of phantom skew where the true delta was 1 second. Every same-boot pass therefore read as a fresh boot, which zeroesConsecutiveRetryCount, so the same-boot recovery limit never fired. Lab row B ran seven passes across two real reboots and stopped only when the harness timed out. This is the defect class the boot-session rule already documents; it recurred because a second persisted timestamp was added without routing it throughConvertTo-BootUpdateTimestampString. The comparison now lives in one helper that normalises both sides and types neither as[string], so the two call sites cannot drift apart again. The reboot count stayed truthful only by luck - its increment is gated on the phase beingRebooting, which these retries were not. - The wait for an interactive user was unbounded, so a machine nobody signs into could never finish. User-scope work legitimately defers until a user context exists; with no user ever appearing, that condition never cleared. The wait is now bounded by
-MaxUserIdentityWaits(default 10). On exhaustion the outstanding user-scope work becomes deferred inventory, which produces a qualified convergence claim rather than an unqualified one. A headless machine now reaches a terminal state and says truthfully what it could not do. - The resume account preferred a name over the SID sitting next to it.
LastLoggedOnSAMUserreturns the.\nameform, whichLookupAccountNamecannot map (ERROR_NONE_MAPPED).LastLoggedOnUserSIDis recorded beside it and is unambiguous, so it is now preferred; it also covers theAzureAD\andMicrosoftAccount\forms that no string expansion would fix. - Resume-chain verification compared a SID against a name and failed. A direct regression from the fix above: with the expected principal now a SID,
[NTAccount]::Translatethrows on SID input and the fallback compared a leaf name against a full SID. The cycle registered both tasks and then killed itself one line later - indistinguishable from the original no-user death it was meant to fix. Both sides are now normalised to SIDs before comparison, and the failure message quotes both values. - Pre-flight warned about a healthy Windows Update service. A
Stoppedwuauservwas reported as a problem. It is demand-start: stopped is the normal resting state of essentially every idle Windows machine, and the WU COM client starts it on the first method call. OnlyDisabledis a warning now; the resting state is logged as normal.
Corrections to v2.5.77's notes
- v2.5.77 attributed row B's failure to converge to
wuauservbeing stopped on the guest image, framed as an environmental artefact. That was wrong. A stoppedwuauservis the documented, normal resting state, not a broken image, and the updater started it on demand in every subsequent run. Row B did not converge because of defects in the updater: the unbounded user wait and the retry-budget reset above. - v2.5.77 reported multi-reboot convergence as "four of seven rows". Those seven rows are this project's own decomposition of the gate, not a bar
docs/TESTING.mdsets - the gate is defined there as reported, not blocking, and states no completion criterion. "Four of seven" reads as a score against an external standard, and should not have. - v2.5.77's README framed the
Microsoft-Windows-International-Corerequirement in theoobeSystempass as a discovery. It is documented: Microsoft describes the-WinPEvariant as applying only in thewindowsPEpass and directs you to the non-WinPE component foroobeSystem.
Validation
Unit/process behavior: PASS (392 tests, 0 failed)
User/SYSTEM boundary: PASS
Published launcher upgrade: PASS
Live bootstrap: NOT RUN
Provider integration: NOT RUN
Multi-reboot convergence: PASS (rows A and B, see below)
Release assets: PASS
Both rows ran on a Windows 11 Enterprise LTSC 2024 guest rebuilt during this cycle, so neither inherited state from the v2.5.77 lab.
- Row A, interactive-user continuation across real reboots: PASS. Four passes, three reboots, converged with 2 verified updates; both continuation tasks removed and no state file left. The reboot count the updater claimed equals the OS boot record. The reboots were 67 and 58 seconds apart - inside the 120-second boot-session tolerance - and each was observed exactly once, so the fix above did not buy same-boot stability by going blind to the fast restarts that motivated the monotonic signal in the first place.
- Row B, SYSTEM continuation with nobody signed in: PASS, against a guest verified headless before the row started (no Explorer, active LogonUI, empty console user). The new-boot observation fired exactly once for the one real reboot, where before the fix it fired five times across two. The retry budget therefore accumulated, and the cycle stopped itself: "Same-boot recovery limit 3 reached; incomplete phases: WindowsUpdate. Continuation tasks were removed and verified absent." No continuation tasks remained, and diagnostic state was retained deliberately, as the limit path documents.
Two limits on what row B establishes, stated plainly:
- It reached a truthful terminal state, not convergence.
Update for Windows Security platform - KB5007651reports as installed on every pass and is still applicable on the next scan, so this image cannot converge. Whether that is an environmental re-offer or the phase counting an install that did not happen is filed separately and is not claimed either way here. - The bounded user wait was not exercised by the lab.
-MaxUserIdentityWaitsnever fired, because the recovery limit is reached first on this image. It has unit cover; it does not yet have lab cover.
Rows C, D, E, F and G were NOT RUN for this release. C and E passed under v2.5.77 and were not re-run against the rebuilt guest.
No live update cycle was run on the maintainer's own machine during validation; every reboot was performed on a disposable guest.
v2.5.77 (2026-09-08)
Multi-reboot gate release. The gate defined in docs/TESTING.md was executed on a disposable VM lab for the first time, and it found two P1 defects that every prior release shipped with, including v2.5.76. Neither was visible to the unit suite.
Fixed
- The idle timeout never measured idleness.
Get-ProcessTreeActivitywalkedWin32_Processfrom the provider PID, butProcessId/ParentProcessIdareUInt32while the traversal queue isQueue[int], and aHashtablekeyed byUInt32never matches anInt32probe. Every lookup missed, so the function reported an empty tree with zero CPU for every process it was ever asked about. Zero never exceeds the previous zero, so the idle clock never reset: the idle timeout was a fixed wall-clock kill atIdleTimeoutMinutes, applied to healthy and wedged packages alike. Shipped logs carry the fingerprint plainly —heartbeat: CPU=0s procs=0beside phases that completed normally. On 2026-09-06 it killed an Acrobat Reader upgrade at exactly five minutes, orphaning anmsiexecthat then failed the next six packages with1618, at a cost of three iterations and 39.6 minutes. - An unobservable process tree is no longer treated as an idle one.
msiexecis parented toservices.exe, so an MSI-backed package legitimately does its work outside the tree being watched; killing on that reading is how a healthy install dies. The hard timeout remains the bound. Seedocs/adr/0005. - Parent edges are rejected when the claimed child predates the claimed parent. A reused PID adopted every orphan still naming it; one reading moved from 71 minutes of stranger CPU to 2 seconds of real CPU between consecutive samples, and a total that falls can never exceed the previous high-water mark, so the idle clock advances and kills working software.
- Fast reboots were absorbed by the boot-session tolerance, letting the reboot limit be evaded. Two boots inside the 120-second window counted as one, so the completed-reboot count under-reported and the claim said "2 reboot(s)" where Windows event 6005 recorded three. That count gates the reboot limit, so a loop faster than the tolerance never increments toward the cap. Shrinking the window cannot fix it: jitter is seconds, fast reboots are tens of seconds, and the ranges overlap. The boot instant is now reconstructed by subtracting monotonic uptime from the current time, which is stable within a boot and jumps by the downtime across one.
- A cycle started as SYSTEM with nobody signed in died at task registration. Resume-user discovery falls through to
LastLoggedOnSAMUser, which returns the.\nameform; Task Scheduler cannot map that to a SID andRegister-ScheduledTaskthrows a terminatingCimException. The cycle died immediately after pre-flight leaving a state file and no continuation task at all, so a machine where nobody logs in could never resume. Discovered names are now expanded and SID-checked, and an unresolvable account degrades to the SYSTEM-only registration branch rather than terminating. - Three progress assertions in
tests/TuiExperience.Tests.ps1measured something other than what they claimed and had been failing on real hardware since before v2.5.76. Two demanded an exact count of distinct rendered status lines, which varies with rounding boundaries; the third set a 1.2-second deadline for output that takes a measured 4.0 seconds to appear.
Added
tests/integration/lab/builds and drives the disposable Hyper-V labdocs/TESTING.mdrequires: one call per guest, rows runnable on parallel VMs, and a README recording the traps each script encodes. Guest credentials come fromBOOTUPD_LAB_PASSWORDand are never committed.- Every row records Windows event 6005 beside the updater's own log and reports whether the two agree about how many restarts happened. That comparison found the reboot-accounting defect, and later caught the first fix for it being wrong.
docs/adr/0005-an-unobservable-process-tree-is-not-an-idle-one.md.
Validation
Unit/process behavior: PASS (375 tests, 0 failed)
User/SYSTEM boundary: PASS
Published launcher upgrade: PASS
Live bootstrap: NOT RUN
Provider integration: NOT RUN
Multi-reboot convergence: PARTIAL - four of seven rows, see below
Release assets: PASS
Multi-reboot convergence was executed for the first time, on Windows 11 Enterprise LTSC 2024 guests under Hyper-V. Four of seven rows ran:
-
Row A, two or more real reboots with interactive-user continuation: PASS. Four passes across three real reboots; the claimed reboot count equals the OS boot record; both continuation tasks removed; no state file left.
-
Row B, SYSTEM-fallback continuation with no user logged on: PARTIAL. The mechanism is verified — tasks register, the cycle resumed across four real reboots as SYSTEM with nobody signed in, and user-scope work was deferred rather than claimed. It did not reach a completion claim, because
wuauservis stopped on the guest image and the Windows Update phase cannot finish. The updater withheld the claim rather than asserting convergence, which is the correct behaviour, but the row demonstrates truthful incompleteness rather than truthful completion.Correction (2026-09-09, v2.5.78). The
wuauservattribution above is wrong. A stopped Windows Update service is the normal resting state of an idle machine, not a defect in the guest image, and the updater starts it on demand. Row B did not converge because of two defects in the updater itself: an unbounded wait for an interactive user, and a retry budget that reset on every same-boot pass. Both are fixed in v2.5.78. -
Row C, canceled delayed restart: PASS. With the restart cancelled 13 seconds into a 60-second countdown, the updater did not record a reboot that never happened, did not advance its pass number, and left the resume chain armed. A later reboot resumed and completed it.
-
Row E, delayed reboot signal: PASS, for the after-window case only. The signal was injected 10 seconds after the 20-second settle window closed rather than inside it, so the in-window detection path was not exercised. What the row does establish is the property that matters most: a reboot signal arriving after the probe was not silently ignored. It was caught at the after-updates check, the cycle rebooted, resumed, and completed with a claimed reboot count matching the OS boot record and no state or task residue.
Rows D (failed restart command), F (PowerShell 5.1-only bootstrap) and G (killed-process recovery) are NOT RUN. Row G was attempted and is recorded as not run rather than failed: the injected kill did not match the orchestrator's process, so the run proved nothing about crash recovery. Each remaining row is filed individually and names the checkpoint it starts from.
No live update cycle was run on the maintainer's own machine during validation; every reboot was performed on a disposable guest.
v2.5.76 (2026-08-25)
Truthful-convergence release.
Fixed
- A cycle that finished carrying work it could not attempt claimed unqualified convergence and sent a Success notification.
CONTEXT.mdhas always held that deferred work "does not make a phase fail, but it does prevent an unqualified claim of convergence"; only the first half was implemented.$deferredCount— pinned packages, packages whose installed version cannot be determined, and packages Winget refuses to upgrade in place — existed solely to reconcile the Winget exit code and reached nothing downstream. Observed on real hardware 2026-08-24 17:00: the run loggedWinget machine: deferred inventory - 1 install-technology blockedfor Microsoft Edge, thenBOOT UPDATE CYCLE COMPLETEand a Success toast. Deferred inventory now persists in cycle state and qualifies the completion claim, the notification severity, the completion banner, and the manual repair plan. - The observation is read from the checkpoint rather than from the finishing pass's own provider results. A phase already flagged done does not run again after a reboot or a recovery pass, so a per-run value would be empty at exactly the moment the claim is made.
- Deferred inventory is recorded only for the canonical
userandmachinescopes.Write-WingetScopeSummaryis also called with<scope>-retryand<scope>/<PackageId>labels, which are sub-observations of a scope rather than scopes of their own; recording them double-reported one deferral under a scope name that does not exist and stranded a retry entry that nothing would clear for the rest of the cycle.
Changed
- The completion claim is composed rather than enumerated.
Get-BootUpdateCompletionClaimreplaces a nestedif/elseifthat produced four branches for two qualifiers and would have produced eight for three. This normalises the inconsistentCOMPLETE WITH QUARANTINE AND CLEANUP ADVISORYtoCOMPLETE WITH WINGET QUARANTINE AND CLEANUP ADVISORY; nothing parses past theCOMPLETEprefix, whichExport-BootUpdateDiagnosticsmatches and the composer guarantees stays first. - The exit code is deliberately unchanged and remains
0.upd.cmdand both scheduled tasks read a non-zero exit as failure, and nothing failed; encoding the qualification there would assert the one thing "deferred" forbids. The qualification is carried only by surfaces a human reads. - A cleanup advisory still sends a Success notification, as before. It reports housekeeping that does not block convergence — "updates converged and no restart is required" — so it does not contradict a success claim the way outstanding update work does. It continues to qualify the log claim.
deferredwas overloaded and is now two terms inCONTEXT.md.UserCompletionDeferredis a scope deferral: the machine-scope pass ran and the user-scope pass must run later in user context, which already drives the completion disposition. Deferred inventory is work that cannot be attempted at all. Adds qualified convergence.
Added
docs/adr/0003-deferred-inventory-qualifies-convergence.md, recording why the code was fixed to match the glossary rather than the glossary relaxed to match the code, why blocking completion was ruled out, and why the exit code was not used as the carrier.- Quarantine and deferred inventory are now documented as orthogonal: quarantine is the action taken against the package manager, deferred inventory is the status that action produces.
CONTEXT.mdpreviously called them "distinct", which read as if they were alternatives and blocked the Chocolatey quarantine design.
Validation
- Unit and process behavior: 357/357 Pester tests pass, including 33 new cases across completion-claim composition, deferred-inventory durability across a
ConvertTo-Json/ConvertFrom-Jsonround-trip, notification severity, repair-plan reporting, and canonical-scope recording. - User/SYSTEM security boundary: passed.
- Published launcher upgrade: passed.
- Live bootstrap and provider integration: not run.
- Multi-reboot convergence: not run. This release adds a state-schema field and changes completion claims; it changes no reboot, checkpoint, mutex, or task logic. The gate remains owed from v2.5.74, which did change reboot detection.
- No updater cycle or reboot was performed during validation.
v2.5.75 (2026-08-24)
Chocolatey failure-classification release.
Fixed
- A Chocolatey package whose published checksum no longer matches the artifact the vendor serves fails identically on every pass, but the phase reported only success and a count, so that failure was indistinguishable from a transient one: it consumed the entire retry budget and then stopped without saying why. Chocolatey's
Failuresblock and checksum error are now parsed into per-package records, aggregated into a failure signature, and the phase is marked as a terminal failure on the second consecutive identical signature. The existing completion-disposition seam routes it to manual attention with a repair plan on pass 2 rather than exhausting five passes. - The signature folds in the expected checksum because Chocolatey exits
-1for every failing install script, so package and exit code alone cannot tell a checksum mismatch apart from a disk or network failure of the same package. This also makes the signature self-healing: when the maintainer refreshes the package metadata the expected hash changes, the signature changes, and the retry budget re-arms with no human involved. - The repair plan reports the expected and actual hashes and offers no command.
Write-BootUpdateRepairPlanrenders commands into a copy/paste block, and no remediation for this failure is safe to run before comparing against the vendor's published hash. - Checksums are attributed by the package directory in Chocolatey's cache path rather than by the most recent
[Approved]banner. A package from a source that prints no banner previously wrote its hash into the preceding package's record, corrupting that package's signature while the real offender fell back to name and exit code alone. - The Chocolatey-absent path reported success while leaving the repeat counter armed, sending the next genuine failure to terminal on its first sighting. It now clears the signature, and a resolved repair plan is removed from disk as the Winget path already did.
Added
CONTEXT.md, a domain glossary. Terminal failure, quarantine, and deferred were being used interchangeably despite being distinct states with distinct convergence meanings.- Two architecture decision records:
docs/adr/0001-never-bypass-package-checksum-verification.mdanddocs/adr/0002-checksum-in-chocolatey-failure-signature.md.
Validation
- Unit and process behavior: 324/324 Pester tests pass, including a new
Chocolatey terminal failure classificationgroup covering parsing, signature composition, repeat counting, self-healing, multi-package attribution, and the disposition seam. Chocolatey previously had one test. - User/SYSTEM security boundary: passed.
- Published launcher upgrade: passed.
- Live bootstrap and provider integration: not run.
- Multi-reboot convergence: not run. This release changes no reboot, checkpoint, mutex, or task logic; it is scoped to Chocolatey failure classification.
- No updater cycle or reboot was performed during validation.
v2.5.74 (2026-08-24)
Retry-budget correctness release.
Fixed
- Boot-session identity was compared across a serialization boundary that changed its type, so the same-boot retry budget reset on every recovery pass and
MaxRetryPasseswas never reachable. State is persisted as JSON, andConvertFrom-Jsonrehydrates an ISO-8601 value as[datetime];Test-BootUpdateSameBootSessiondeclared its parameters as[string], so parameter binding rendered that[datetime]in the current culture and dropped the offset. Re-parsing then assumed the local offset, skewing the comparison by the machine's full UTC offset — 14399.5s observed against a 120s tolerance. Every pass therefore reported a new boot session, zeroingConsecutiveRetryCount, clearingExplicitRebootRequests, and discardingWindowsUpdateZeroEvidence. A permanently failing phase retried indefinitely: 42 passes in one observed session with no reboot in between. The jitter tolerance added earlier was itself correct; it was simply never reached. Persisted timestamps are now normalized back to round-trip'o'form byConvertTo-BootUpdateTimestampString, applied at the state-load boundary inUpdate-BootUpdateStateSchemaand again inside the comparison, whose parameters are no longer typed[string]. WindowsUpdateZeroEvidence.ObservedAtUtcshared the same defect through its[datetime]::Parseround-trip, aging same-boot zero evidence out by the local UTC offset and forcing redundant Windows Update rescans. It is normalized by the same helper.
Validation
- Unit and process behavior: 314/314 Pester tests pass, including seven new tests under
Boot session identity survives the state-file round-tripthat exercise theConvertTo-Json/ConvertFrom-Jsonboundary the previous literal-string tests never reached. - User/SYSTEM security boundary: passed.
- Published launcher upgrade: passed.
- Live bootstrap and provider integration: not run.
- Multi-reboot convergence: not run. This release changes reboot-detection logic, so the disposable-VM matrix in
docs/TESTING.mdis applicable and was not exercised. Behavior is covered by the unit and process gates only. - No updater cycle or reboot was performed during validation.
v2.5.73 (2026-08-24)
Winget diagnostics follow-up release.
Fixed
Get-WingetRemediationCommand's-PackageIdparameter was a Mandatory[string], so PowerShell rejected an empty string during parameter binding before the function's own safety check ever ran. A targeted single-package upgrade's output can produce a failure record with no package ID (no preceding(N/M) Found ... [Id]header), and that empty-ID record crashed the entire Winget phase with an uncaught exception in production.-PackageIdis nowAllowEmptyString/AllowNulland the empty/invalid case is handled explicitly instead of throwing.Test-WingetExitReconciledonly reconciled one hardcoded aggregate exit code, so a targeted single-package upgrade returning its own distinct exit code for a fully-accounted stale/absent record always logged a contradictory[Error] partial failure, retry requiredimmediately after telling the user the same stale record would not fail the run. Reconciliation now applies to any non-success/non-reboot-pending exit code once structured output fully accounts for it.
Validation
- Unit and process behavior: 307/307 Pester tests pass, including new coverage for the empty/null package-ID case and per-package exit-code reconciliation.
- User/SYSTEM security boundary: passed.
- Published launcher upgrade: passed.
- Live bootstrap, provider integration, and multi-reboot convergence: not run (no reboot/checkpoint/mutex/task logic changed; fix is scoped to Winget failure-record classification and diagnostic logging).
- No updater cycle or reboot was performed during validation.
v2.5.72 (2026-08-17)
Diagnostics follow-up release.
Fixed
- Scope activity and pending-file cleanup evidence to the latest explicit cycle start in the accumulated log. Historical runs can no longer change the current run's
CaptureState,Iteration, orPendingFileCleanup.Persistentresult. - Re-exporting the 2026-08-17 15:08 diagnostic now reports the six current cleanup fingerprints as persistent (
6before and6after), instead of being contaminated by older archived runs.
Validation
- Diagnostics export regression suite passes, including a mixed historical/current log fixture and re-export of the supplied bundle.
- No updater cycle or reboot was performed during validation.
v2.5.71 (2026-08-17)
Diagnostics and cleanup follow-up release.
Fixed
- Tightened activity metadata parsing so only explicit cycle headers and
Pass:/Iteration:markers set completion, active state, phase, and iteration. Prose such asphase(s)no longer produces false values such ass ran. - Added
PendingFileCleanupevidence to exported diagnostics manifests. The manifest records before/after category counts, redacted fingerprints, and whether the same delete-only cleanup set persisted across the run.
Follow-up scope
- Persistent
PackageManagementPrototypeCleanupentries remain advisory and non-blocking. This release improves evidence for investigation without rewriting Windows' shared pending-file rename queue or forcing a reboot.
Validation
- Diagnostics export and sanitization tests pass, including manifest wiring and persistent cleanup evidence.
- Full local gates run without rebooting the host; the latest run's updater behavior remains unchanged.
v2.5.70 (2026-08-17)
Truthful deferred Winget outcomes and reliable diagnostics evidence
- Reconciles a Winget run when every remaining package is explicitly deferred (for example, pinned inventory or unsupported install technology). The aggregate native exit code is no longer reported as an unexplained failure or used to queue a pointless same-boot retry.
- Makes targeted Winget inventory parsing strict: only validated package-ID rows are accepted, prose and empty rows are rejected, and malformed targeted output fails closed instead of silently broadening into an
--allupdate. - Preserves UTF-8/UTF-16 source-log encoding during diagnostics export, with a safe fallback and warning for invalid bytes so evidence is not silently mojibaked.
- Captures diagnostics from a stability-checked source snapshot and records whether the run was active or complete, its phase/iteration, per-file hashes, and any snapshot warnings in manifest format 2.
- Keeps dotted package versions visible as stable redacted version placeholders while continuing to redact ordinary IPv4 addresses, preserving comparison evidence without leaking exact version data.
- Validation: 299 unit/process tests passed; published-launcher upgrade passed; user/SYSTEM security-boundary gate not run on the development laptop; no live updater cycle or reboot performed.
v2.5.69 (2026-07-27)
Defender signature updates use the serviced platform, not the frozen inbox stub
- Fixes the root cause of the
0x8007007FDefender failures that v2.5.68 correctly stopped retrying. Windows ships two copies ofMpCmdRun.exe: the one underProgram Files\Windows Defenderis the operating-system inbox stub and stays at the version the OS build shipped with, while the serviced platform under%ProgramData%\Microsoft\Windows Defender\Platformupdates independently. The updater always invoked the inbox copy. - On Windows Server 2016 that stub is 4.10.14393.x while the serviced platform had reached 4.18.26060.3008. Driving a modern engine through a stub nine years older cannot resolve an expected export, which is exactly what
ERROR_PROC_NOT_FOUNDreports. The identical command run from the platform directory succeeded on the same machine. - Signature updates now resolve the newest serviced platform copy and fall back to the inbox stub only when no serviced platform is installed. Platform directories are ordered as versions rather than as strings, so a build such as 4.18.9000.1 cannot sort above 4.18.26060.3008.
- The resolved executable path is now logged with the phase, so a future mismatch is visible without reproducing it.
- The terminal classification added in v2.5.68 is unchanged: if
0x8007007Fstill occurs with the correct platform binary, the platform really is broken and the cycle stops for manual attention rather than looping.
v2.5.68 (2026-07-27)
The same-boot recovery limit now actually fires
- Fixes an unbounded recovery loop: the updater compared boot-session identity as an exact string built from
Win32_OperatingSystem.LastBootUpTime. That value is derived rather than stored and drifts by seconds between reads within a single boot on virtual machines and on hosts that resync the clock, so every recovery pass looked like a fresh boot, silently reset the same-boot failure streak, and the configured retry limit could never be reached. A diagnosed 2026-07-27 session ran six passes in eighteen minutes with no restart between them and no exit condition. - Boot-session identity is now a tolerance window rather than string equality, and the recorded identity anchors on the first value observed for that boot so per-read drift cannot accumulate past the tolerance across a long recovery chain. A genuine restart still resets the streak and still counts as a completed reboot.
- Restores same-boot Windows Update evidence, which the same string comparison discarded: a full convergence scan was re-running on every pass.
- Classifies a Defender signature update that fails with
hr=0x8007007F(ERROR_PROC_NOT_FOUND) as a terminal failure in both the parallel-cohort and sequential paths. That code means the loaded Defender platform is broken rather than that content or the network was unavailable, so every same-boot invocation fails identically. The cycle now stops for manual attention with a platform-repair plan instead of queueing retries. Ordinary signature-update failures remain retryable.
v2.5.67 (2026-07-24)
Permanent provider failures stop retrying instead of looping
- Classifies a user-scope (portable) Winget package that elevated Winget definitionally cannot replace as scope-blocked deferred inventory. The aggregate
0x8A15002Cexit reconciles only when structured output accounts for every attempted package as verified success, MSI1605, or scope-blocked; anything unaccounted keeps the exit as failure evidence. - Logs one
[BLOCKED]line per scope-blocked package with two remediation choices: upgrade from a normal non-elevated session, or reinstall machine-scope so elevated runs can manage it. Scope-blocked packages never count as verified updates and never queue retries. - Detects a Python interpreter whose standard library cannot load (
Fatal Python error, missingencodingsmodule, missing platform-independent libraries) in both pip paths and classifies the phase as a terminal failure with a repair-plan attention detail, because identical same-boot retries cannot succeed. Ordinary pip failures remain retryable. - Propagates terminal-failure classification from parallel-cohort phase results to the completion disposition; previously cohort classifications were dropped, so the manual-attention stop could never fire for cohort phases. A diagnosed 2026-07-20 session retried every two minutes for roughly ten hours on exactly these two permanent failures.
- Validated against the sanitized 2026-07-24 diagnostic: a user-scope package failing under elevation every pass, and pip failing 308 times on a broken interpreter.
v2.5.66 (2026-07-22)
- Fixes a circular v2.5.65 check that asked Winget inventory to disprove the same stale record responsible for an MSI 1605 result. Microsoft documents 1605 as
ERROR_UNKNOWN_PRODUCT: Windows Installer says that product code is not installed even when Winget continues to enumerate it. - Learns a fully accounted 1605 outcome by package ID, scope, observed version, and native code. The first occurrence gets one concise
[RESOLVED]line; identical repeats stay out of Normal output without retries or false update counts. - Invalidates learned absence when the package later installs successfully or returns changed failure evidence. Persistence failure remains fail-safe and restores the visible recovery choices.
- Replaces internal completion jargon such as
PackageManagementPrototypeCleanup=6with plain language while retaining exact categories and sanitized fingerprints in Debug output and diagnostics. - Validated against the sanitized 2026-07-22 diagnostic: Winget listed PC Health Check, MSI returned 1605, and the follow-up
winget listrepeated the same stale entry. The six legacy PackageManagement delete requests were unchanged before and after the run.
v2.5.65 (2026-07-22)
- Rechecks an exact Winget package after MSI 1605 and remembers only a confirmed
No installed package foundresult in a sanitized, persistent resolved-absence record. - Shows one concise
[RESOLVED]message the first time, then keeps identical stale results out of Normal output while retaining raw provider evidence and a Debug breadcrumb. - Invalidates the remembered outcome when exact inventory no longer verifies absence. Unresolved or changed evidence continues to show the reinstall, cleanup, and reversible suppression choices.
- Includes the resolved-absence record in sanitized diagnostics and adds behavioral coverage for first observation, repeated suppression, invalidation, persistence failure, and truthful update counts.
- Correctly attributes
ChocolateyPrototype-2.8.5.130delete markers to Microsoft PackageManagement/OneGet's legacy provider rather than the independent Chocolatey CLI, retains them as non-blocking housekeeping, and guards against broad provider-discovery probes in the orchestrator. The updater deliberately does not rewrite Windows' shared pending-rename queue.
v2.5.64 (2026-07-22)
- Reconciles Winget/MSI error 1605 as an already-absent application with stale uninstall inventory rather than a failed update. A fully accounted aggregate result no longer fails the Winget phase or queues an otherwise pointless recovery pass.
- Replaces the generic child-exit and partial-failure cascade with immediate choices: an exact-ID reinstall command when the app is wanted, Microsoft’s incomplete-uninstall cleanup path when removal was intentional, and a reversible blocking-pin command for temporary suppression.
- Keeps real package failures, incomplete provider output, and unaccounted attempts retryable; stale records never inflate verified update totals.
- Adds behavioral phase-level coverage proving that one successful update plus one MSI 1605 result completes Winget without entering the failure classifier.
- Adds Claude Code discovery guardrails: concise shared
CLAUDE.mdinstructions, path-scoped updater/launcher/public-privacy rules, a provider-aware review-skill trigger, and compatibility tests that preserve the conditional reconciliation boundary and its phase-level regression test.
v2.5.63 (2026-07-22)
- Makes
BOOT//PULSEsignal-first and width-aware at common 80, 100, 120, and 160-column console sizes. Activity, elapsed time, and the selected view remain intact while the progress meter and verbose wording yield space first. - Suppresses zero-value CPU/process telemetry outside Debug, retains nonzero activity signals, and compacts duplicated provider wording such as
Installing Windows Updates :: Windows Update .... - Updates the standalone animation demo to preserve the right-edge view indicator instead of truncating the entire row.
- Runs the published-old-launcher adoption gate in a clean PowerShell process, preventing test-runner state from producing a false missing-breadcrumb failure after a successful replacement.
v2.5.62 (2026-07-22)
- Expands the animated
BOOT//PULSEforeground from four to seven color anchors and 48 to 112 interpolated frames. Two near-black theme-zero valleys create a legible long-distance pulse while the 100 ms transitions remain gradual rather than blink-like. - Keeps the splash artwork untouched and updates the standalone visual demo to use the exact production palette.
- Demotes routine non-blocking
ChocolateyPrototypeCleanupevidence from a Normal-view warning: Verbose shows a compact category/count, while Debug and the durable log retain sanitized fingerprints. - Preserves real replacements, protected Windows deletes, and provider-native restart evidence as prominent reboot barriers.
v2.5.61 (2026-07-22)
- Makes preflight visibly report its current check and elapsed time, while keeping Windows Update service recovery out of the global provider path.
- Gives Windows Update service start and component-reset recovery a strict 30-second process boundary. A stuck or indefinitely
StartPendingservice leaves only Windows Update retryable; safe independent providers continue. - Recognizes Winget's
Successfully installed. Restart the application...result as success and excludes packages already completed in user scope from the machine-scope pass, preventing duplicate attempts such as per-user applications encountered in both inventories. - Correctly parses hexadecimal Winget installer failures such as
0x80070005and reports their actual access-denied meaning instead of a zero exit code. - Gives completion, retry-without-reboot, user-context continuation, and restart-required notifications distinct plain-language titles and next steps.
- Adds synthetic regression coverage for hung services, provider isolation, Winget success parsing and scope de-duplication, and privacy-safe notification fixtures.
v2.5.60 (2026-07-22)
- Makes restart state unmistakable in the default Normal view: the splash says a confirmed check is underway, and both pre-update and post-update probes report
REQUIREDorNOT REQUIREDas dedicated status blocks. - Explains what happens next when a restart is required: the resume checkpoint is armed and the update run continues automatically after Windows restarts.
- Rewrites successful completion around the questions a new user actually has: whether the run finished, whether a restart is needed, whether anything was skipped, and whether any action is required.
- Replaces unexplained “converged with quarantine” console wording with plain language: repeatedly failing Winget packages were skipped and reversibly pinned to prevent another loop, were not counted as updated, and can be retried later with the displayed commands.
- Adds a smooth, very dark cyan-to-violet theme-0 under-glow behind the existing animated
BOOT//PULSEforeground fade, preserving the propeller cadence and bright palette while giving the status band more depth.
v2.5.59 (2026-07-22)
- Normalizes the modern
*1/*2prefixes used by Windows inPendingFileRenameOperationsinstead of treating the prefix as part of the path. - Separates delete-only housekeeping from update-critical file replacements using a vendor-independent risk boundary. Application, user-profile, cloud-storage, recovery, cache, temporary, and already-absent deletes are advisory; every replacement and delete beneath protected Windows runtime paths remains a reboot barrier.
- Records safe cleanup categories and short fingerprints before mutation and after updates, so sanitized diagnostics retain useful provenance without exposing local paths.
- Prevents third-party cleanup records from consuming the reboot budget or forcing every provider to run again.
- Preserves successful provider checkpoints across reboot. Only incomplete or interrupted phases resume; Windows Update alone uses its identity-aware post-boot convergence scan to reopen when additional applicable work appears.
- Reports optional third-party cleanup separately from blocking reboot evidence, keeping the final verification truthful without turning harmless housekeeping into another patch cycle.
- Recognizes Chocolatey's documented
350(pending reboot before mutation) and1604(install suspended/incomplete) results as durable reboot barriers while leaving the Chocolatey phase incomplete for a targeted post-boot retry. - Uses the Windows Update Agent
Microsoft.Update.SystemInfo.RebootRequiredAPI before mutation and immediately after installation, persisting that provider-native evidence instead of waiting for registry flags to appear.
v2.5.58 (2026-07-21)
- Makes the post-update service assessment read-only: it never starts, stops, or reconfigures a service unless a future explicit repair operation places that mutation in scope.
- Treats stopped trigger-start Windows Time, policy/AV-managed Defender, and intentionally unavailable printing separately from stopped core resolver/event services that need attention.
- Replaces the misleading “all critical services healthy” claim with a policy-aware assessment that reports expected, managed, and attention states.
- Counts only verified changed packages/extensions. Office Click-to-Run and other providers without an exact changed-item result are reported separately as updater actions triggered.
- Migrates state to schema v6 so action counts survive reboot/resume without being mixed into verified update totals.
v2.5.57 (2026-07-21)
- Serializes Winget user and machine scopes because both processes share App Installer state; independent providers remain parallel.
- Learns identical unclassified Winget execution failures, including
0x8A150001with no output, and stops automatic continuation after one verification retry. - Records a sanitized normalized launch contract on every initial and resumed pass: standard versus aggressive repair, origin, scope, output mode, enabled flags, skips, and filter counts.
- Keeps VS Code's Node
url.parse()deprecation warning in the provider transcript instead of presenting it as a boot-upd problem.
v2.5.56 (2026-07-21)
- Parses
PendingFileRenameOperationsas source/destination pairs and excludes only blank-destination deletions beneathWindows\SystemTemp\ChocolateyPrototype-*from hard reboot evidence. - Preserves genuine Chocolatey prototype renames, ordinary file replacements, and non-Chocolatey deletions as reboot barriers.
- Initializes the runtime install directory used by Winget repair-plan cleanup, preventing a secondary null-
Pathexception from masking provider HRESULTs such as0x8A150001.
v2.5.55 (2026-07-21)
Smarter Windows Update assessment reuse
- Reuses a successful online Windows Update assessment for up to six hours across reboot boundaries, after reconciling it against the local Windows Update Agent catalog.
- Invalidates the cache when update scope, Windows Update policy/source settings, or recent servicing history changes; failures fall back to an online assessment.
- Records only minimal diagnostic metadata:
UpdateID,RevisionNumber, timestamps, and non-sensitive fingerprints; sanitized diagnostic bundles include this breadcrumb. Update revisions are identities, not a global sequence counter. - Clears cached evidence before Windows Update, driver/firmware, or component-reset mutations and stores the sidecar atomically with NTFS compression.
README refresh
- Moves the copy-ready quick start, everyday commands, reboot warning, screenshots, navigation, status/recovery, and security model toward the top.
- Adds clearer phase coverage and read-only preview paths while preserving the default splash presentation.
v2.5.54 (2026-07-21)
- Makes explicit
upd -arquarantine an unchanged persistent Winget failure with a verified, reversible blocking pin after its bounded repair attempt is exhausted. - Reports quarantined packages as an amber degraded completion—not a fully-patched claim—and persists exact IDs, evidence, and
upd uq <id>recovery commands in status and sanitized diagnostics. - Adds
upd uq [id|all]to remove quarantine pins and atomically reconcile their durable records. - Reuses PSWindowsUpdate's explicit zero-result post-install scan only within the same boot and exact verification scope, avoiding a redundant exhaustive scan.
- Requires an explicit, count-matched completion marker for standalone Windows Update convergence scans and fixes
Installed [0]/Downloaded [0]package overcounting.
v2.5.53 (2026-07-21)
- Fixes false Windows Update work remaining when an empty scan result was serialized as
BOOTUPDATE_APPLICABLE||. - Records each aggressive Winget failure signature before repair and never repeats force repair/reinstall for the same package/error set; the next pass is verification-only.
- Makes the manual-attention repair plan and terminal banner resilient to unavailable or blocked clipboard services, with a bounded clipboard helper and truthful fallback messaging.
- Continues disarming automatic resume tasks and presenting the durable repair path even if checkpoint persistence or NTFS compression fails.
v2.5.52 (2026-07-21)
- Adds explicit
upd -ar/upd --aggressive-repairopt-in for package-specific Winget repair and force-reinstall attempts, preserved across elevation and reboot continuations. - Keeps default runs conservative and withholds command noise during the single automatic verification pass.
- Writes
BootUpdateCycle-repair-plan.txtonly when an identical failure becomes terminal; explanations are separate from a contiguous block containing only valid Command Prompt syntax. - Displays and copies the full plan path, includes the plan in sanitized
upd logsexports, and removes it after a verified clean Winget pass.
v2.5.51 (2026-07-21)
- Uses
winget repaironly for missing MSI-source error 1612; installers such as iCUE that do not support repair retain force-reinstall guidance. - Persists a normalized Winget package/error signature and treats its first occurrence as retryable.
- Stops and disarms automatic continuation after the identical non-transient signature repeats, preserving an
AttentionRequiredcheckpoint and withholding all fully-patched congratulations. - Clears the failure signature after a clean Winget pass so a later unrelated incident gets its own bounded retry opportunity.
v2.5.50 (2026-07-21)
- Makes
upd logsdisplay one absolute diagnostic ZIP path and copy that exact path to the Windows clipboard, while treating clipboard unavailability as a non-fatal warning.
v2.5.49 (2026-07-21)
Actionable diagnostics and explicit AWS modernization
- Adds
upd logs/upd l, which exports rotated core, provider, and AWS transcripts as a fail-closed sanitized ZIP and applies NTFS compression to runtime logs and archives. - Makes explicit
upd awsfully modernize verified AWS.Tools installations by default, with preservation switches for legacy modules and old modular versions. - Prints validated, paste-ready Winget remediation commands for failed package IDs plus concise pinned and unknown-version inspection commands.
- Keeps AWS audit mode non-destructive and expands privacy, rotation, launcher, AWS cleanup, and Winget command-injection regression tests.
v2.5.48 (2026-07-21)
PowerShellGet cleanup metadata compatibility
- Recognizes the fully anchored, AWS.Tools-specific “No match was found” cleanup message regardless of PowerShellGet's variable error ID and invocation metadata.
- Continues rejecting lookalike legacy-module messages, augmented messages, access failures, and all other cleanup errors.
- Captures every cleanup output stream so provider “Uninstalling…” chatter no longer leaks into the normal console.
- Retains the final exact path/version inventory as the authoritative report of any locked or independently installed older module copies.
v2.5.47 (2026-07-21)
AWS subprocess command-line overflow correction
- Executes the substantial AWS verification program from a random temporary script file instead of an oversized Base64
-EncodedCommand, eliminating Windows' process command-line length failure. - Writes the child file with a UTF-8 BOM for deterministic Windows PowerShell 5.1 parsing, passes only the short file path to the isolated subprocess, and removes the temporary file in
finallyon success or failure. - Adds a regression guard proving the child program exceeds the historical command-line ceiling and that the production launcher no longer uses
-EncodedCommand.
v2.5.46 (2026-07-21)
Deterministic, quieter AWS tooling maintenance
- Inventories every AWS PowerShell module by family, name, version, and exact installation path so user, machine, and cloud-synced module roots cannot be conflated.
- Keeps legacy
AWSPowerShell*installations isolated and untouched while modularAWS.Tools.*maintenance runs independently. - Separates install/update, Amazon-signature verification, and cleanup instead of using the noisy combined
Update-AWSToolsModule -CleanUppath. - Treats only exact PowerShellGet already-absent cleanup records as benign; unexpected cleanup failures still fail closed, while locked older copies are retained and reported precisely.
- Keeps the certificate-rollover bypass narrow: it is available only for an issuer-continuity mismatch between Amazon publishers after staged package signature, chain, synchronized-version, and byte-manifest verification.
- Suppresses raw AWS provider chatter in favor of a concise verified module/version/path summary.
- Makes
Repair-AwsTooling.ps1compatible with Windows PowerShell 5.1 as well as PowerShell 7 and exercises harmless audit startup under both engines.
v2.5.45 (2026-07-21)
Calmer provider diagnostics and correct BitLocker targeting
- Keeps verbose Winget and Chocolatey transcripts in
BootUpdateCycle.providers.logwhile the primary log reports concise attempted, updated, failed, pinned, deferred, and retry summaries. - Promotes individual Winget installer failures to warnings with package identity, decimal and hexadecimal exit codes, and a plain-language reason for common Windows Installer failures.
- Makes partial progress explicit: a provider can report successful updates while clearly stating that failed packages are queued for another convergence pass.
- Suspends BitLocker only on the Windows operating-system volume before reboot; protected data volumes are no longer probed or needlessly warned about.
- Adds regression coverage using the real noisy Winget failure transcript and OS-volume-only BitLocker assertions.
v2.5.44 (2026-07-21)
Cross-context exclusion and safe launcher activation
- Creates the global updater mutex with an explicit SYSTEM/Administrators ACL and fails closed if exclusion cannot be established, preventing concurrent user and SYSTEM continuation passes from racing the checkpoint.
- Staggers the user-primary and SYSTEM-fallback dated retries and gives every checkpoint write a process-unique temporary file.
- Applies the same-boot retry budget to repeated pending-reboot restart requests, so a canceled or ineffective restart cannot grow the pass counter indefinitely.
- Runs v2.5.44+ launchers from a verified temporary trampoline before activating
upd.cmd.next; a delayed compatibility worker safely bridges the one upgrade from pre-trampoline v2.5.43. - Condenses exact AWS.Tools already-absent cleanup records, then independently inventories and reports any genuinely retained older module copies.
v2.5.43 (2026-07-20)
Mapped-drive repair and batch launcher encoding
- Launcher source repair now ignores mapped or cloud-provider drives that are unavailable after reboot instead of emitting a misleading self-update warning; other reachable launcher locations are still repaired.
upd.cmdis stored byte-for-byte with CRLF endings, with a regression gate, because Windowscmd.execan misparse an LF-only batch file and repeatedly open the file-association dialog during launcher tests.
v2.5.42 (2026-07-20)
Resume-task verification and batch self-update fixes
- Resume-chain verification no longer throws a false "wrong principal" for user-context tasks: Task Scheduler reports
DOMAIN\userback as a bare user name, so the check now compares account SIDs (falling back to the leaf name) instead of raw strings. upd.cmdno longer misreads itself afteradopt-staged-batchreplaces it on disk: the adopt call and the final exit are now a single physical line, so cmd.exe buffers the whole command before the file swap and never resumes reading the new file at a stale byte offset (previously surfaced as a garbled'UPD_PWSHUPD_LAUNCHER" help' is not recognizederror).
v2.5.41 (2026-07-20)
Guarded AWS.Tools publisher-certificate rollover
- Handles AWS.Tools v4-to-v5 Authenticode publisher continuity failures without weakening the normal update path.
- Uses AWS's supported
-SkipPublisherCheckonly for the exact AWS.Tools issuer-mismatch error and only after staging every installed AWS.Tools module's current PSGallery candidate. - Requires the canonical PSGallery endpoint, synchronized candidate versions, valid Amazon Web Services Authenticode identities, code-signing EKUs, and trusted online certificate chains.
- Installs the verified target without cleanup, revalidates every installed module, and only then removes legacy versions; any unrelated, unsigned, untrusted, or non-Amazon result fails closed and retains the old modules.
- Never terminates unrelated PowerShell sessions to release module locks; locked legacy modules are retained and reported instead.
- Adds focused rollover security tests and a disposable Windows Server 2022 v4-to-v5 VM workflow with transcript artifacts.
v2.5.40 (2026-07-20)
Truthful reboot safety limit
- Counts completed Windows boot transitions instead of update passes, so the final allowed reboot always receives a settled pending-reboot probe and can converge cleanly.
- Counts immediate native
1641restart evidence even when Windows reboots before the normal post-phase checkpoint is written. - Stops only when confirmed reboot evidence remains after the reboot budget is exhausted; notifications name the exact sources instead of guessing that a stale signal is responsible.
- Separately bounds permanently failing same-boot recovery passes with
MaxRetryPasses, without misreporting them as reboot failures. - Persists a terminal checkpoint with timestamp, reason, and signal details for diagnosis, while disarming and verifying both resume tasks without deleting the evidence or firing the success-only
PostCyclehook. - Makes terminal launches idempotent: they do not re-arm tasks or repeat alerts unless an operator explicitly raises the applicable budget.
- Distinguishes update passes from completed reboots in the startup status, log, and Event Log.
v2.5.39 (2026-07-20)
Fresh-install PATH discovery under strict PowerShell 5.1
- Replaces
where.exe updwith a PowerShell-native, PATH-onlyupd.cmdresolver after fresh disposable VMs showed that the expected native “not found” stderr becomes terminating under strict error handling. - Treats no existing launcher as the normal Program Files fresh-install path while preserving the first PATH entry for transactional repairs.
- Covers absent PATH winners and paths containing spaces under actual Windows PowerShell 5.1.
v2.5.38 (2026-07-20)
Self-contained SHA-256 on minimal PowerShell 5.1 hosts
- Replaces the compatibility bridge's
Get-FileHashdependency with a built-in .NET SHA-256 implementation after the exact README command exposed a missing-cmdlet failure on a fresh Windows Server 2022 VM. - Keeps exclusive read sharing while hashing so cloud/local races cannot rewrite a file during verification.
- Adds a Windows PowerShell 5.1 test with module autoloading disabled and a two-image hosted-VM workflow for the exact live interactive bootstrap.
v2.5.37 (2026-07-20)
Choose the command after verified installation
- Adds an optional post-install prompt that appears only after the complete release bundle has passed checksum, version, syntax, transactional commit, and post-copy verification.
- Safely tokenizes quoted commands and options with Windows command-line rules instead of evaluating user input as PowerShell.
- Makes the short Chocolatey-style README bootstrap interactive by default while retaining explicit argument arrays for automation.
v2.5.36 (2026-07-20)
PS5-compatible transactional file replacement
- Supplies the concrete backup path required by Windows PowerShell 5.1's .NET Framework
File.Replaceimplementation instead of passing a null backup path. - Keeps the verified rollback snapshot and same-volume atomic replacement semantics, including safe cleanup of the redundant target-adjacent swap backup.
- Adds an actual Windows PowerShell 5.1 replacement test using an existing target in a path containing spaces.
v2.5.35 (2026-07-20)
Windows PowerShell 5.1 compatibility bridge restored
- Stops validating PowerShell 7-only release assets with the Windows PowerShell 5.1 parser, which incorrectly rejected valid modern syntax before a fresh install could bootstrap PowerShell 7.
- Keeps validation fail-closed: every asset still requires its release SHA-256; PS5-native bootstrap files are parsed by PS5; PS7 assets require an explicit runtime declaration and are parsed by
pwshwhenever it is already available. - Adds an actual Windows PowerShell 5.1 regression probe covering both PS7-present and fresh PS5-only paths, including install paths containing spaces.
v2.5.34 (2026-07-20)
Recovery queued without a false fatal exit
- Treats a successfully persisted and scheduled recovery pass as a clean process handoff while continuing to withhold the fully-patched claim.
- Prevents outer launch environments from turning the amber recovery banner into a red failure/pause prompt.
- Keeps actual terminal failures nonzero and continues treating Defender native exit code 2 as a retryable phase failure.
- Adds a Chocolatey-style README one-liner that can bootstrap a fresh Program Files installation or transactionally repair the existing
upd.cmdPATH winner before running.
v2.5.33 (2026-07-20)
Neon splash default restored across modern relaunches
- Centralizes terminal capability detection so a modern Windows ConsoleHost remains VT-capable when the host property under-reports support after a relaunch or UAC handoff.
- Restores neon gradient theme 0 as the no-override default on modern interactive consoles.
- Preserves explicit theme selection and the classic theme 2 fallback for redirected output and genuine legacy consoles.
- Leaves the splash artwork, animation palette, and layout unchanged.
v2.5.32 (2026-07-20)
Verbose without the heartbeat chatter
- Keeps informational duplicate-line compression summaries in the durable log while showing them on-screen only in Debug mode; repeated warnings and errors remain visible.
- Removes redundant timestamped phase start/finish narration from Verbose because the styled phase header and result already communicate the same state.
- Renders a planned machine-to-user-context continuation as an amber deferred result instead of a red failure.
- Preserves warnings, failures, useful preflight decisions, the animated live status row, and the splash screen unchanged.
v2.5.31 (2026-07-20)
Verified launcher handoff before operational dispatch
- Added a deliberately untyped stage-zero launcher that receives raw arguments, refreshes the complete checksummed release bundle, and only then invokes the current typed command implementation.
- With PowerShell 7 already present, operational and not-yet-known commands cross a single elevation boundary and are interpreted by the newly installed launcher; a current invocation no longer continues under stale in-memory dispatch code. A PS5.1-only machine may show a separate first-use consent while installing PowerShell 7.
- Help, version, plan, status, splash, demo, fun, and bootstrap remain local and non-mutating.
-nuremains the explicit offline/no-refresh escape hatch. - Added a PS5.1-compatible compatibility installer for pre-trampoline batches. It resolves the actual PATH winner, stages outside cloud storage, verifies every runtime asset, checks for sync races, snapshots exact targets, commits batch-last, rolls back on failure, and then forwards the requested arguments.
- Added checksummed recovery for a missing stage-zero asset and expanded release/deployer coverage and regression tests.
Historical batches still require the one-time external compatibility installer; newer code cannot intercept arguments that an already-running legacy batch rejected before handoff.
v2.5.30 (2026-07-20)
Windows PowerShell 5.1 can open the door; PowerShell 7 still runs the machine.
- Adds a Windows PowerShell 5.1-compatible bootstrap that installs PowerShell 7 side-by-side through WinGet or a Microsoft Authenticode-validated stable MSI fallback.
- Keeps help and version non-mutating on PS5-only systems and requires explicit
upd bootstrapbefore read-only preview, plan, or status commands. - Automatically bootstraps PowerShell 7 for operational update, repair, and AWS commands, then relaunches the typed launcher under
pwsh. - Preserves the PowerShell 7-only orchestrator,
Start-ThreadJob,ForEach-Object -Parallel, and absolute-pwshscheduled resume paths. - Adds the bootstrap to the checksummed transactional runtime bundle and release assets.
v2.5.29 (2026-07-20)
A friendly, compact launcher with safe previews and a checksummed self-updating handoff.
- Adds typed
updcommands for help, plan, status, version, explicit update, splash, demo, and fun, with compact aliases such asupd d,upd p,upd u, andupd v. - Adds short run flags (
-r,-o,-n,-t,-s,-drv,-fw,-w,-c,-m,-x, and-i) while retaining descriptive long forms. - Keeps help, planning, splash, demo, fun, version, and status non-elevated and non-mutating; operational execution still fails closed without administrator rights.
- Passes validated options across UAC as Base64-encoded structured JSON instead of rebuilding a free-form command line.
- Refreshes the full runtime bundle only from release assets with mandatory SHA256 sidecars, validates every asset before mutation, rolls back failed commits, and checksum/version-gates atomic
upd.cmd.nextadoption. - Preserves a compatibility bridge for older two-script installations, adds
upd repairrecovery, and publishes all six executable runtime assets plus matching checksums through a verified draft-release gate. - Adds
upd aws(upd a) for focused AWS CLI v2 and AWS.Tools repair/update work and rejects ambiguous dashed short commands before they can become a default update run. - Adds launcher behavior and forwarding tests while keeping every splash theme byte-identical.
v2.5.28 (2026-07-20)
A reboot chain that survives delayed evidence, canceled restarts, context changes, and honest provider failures.
- Persists native reboot requests in durable state and clears them only after Windows reports a different boot-session identity; reboot counts now represent observed completed boots.
- Uses the two-probe servicing-settle detector before mutation as well as at completion, preventing late CBS or Windows Update flags from racing the next install phase.
- Treats pending reboot evidence as a phase barrier and stops the remaining sequential/parallel work after a provider raises
3010or1641. - Adds dated watchdogs for cancelable shutdowns, maintenance-window deferrals, transient resumed preflight failures, and staged no-reboot continuations.
- Preserves a saved interactive identity across SYSTEM fallback runs and defers Winget user scope, Scoop, VS Code, WSL, and containers until a user-context continuation can run.
- Round-trips behavior-changing switches and structured include/exclude arrays through scheduled resumes, then reads tasks back to verify exact action arguments, principal, trigger types, startup delay, and retry policy.
- Stops treating provider exceptions, timeouts, failed thread jobs, or native nonzero exits as success across driver/firmware, WSL, containers, Defender, AWS, PowerShell modules, and parallel package adapters.
- Requires a final read-only Windows Update scan to report zero applicable updates in the configured category scope.
- Checks
shutdown.exeresults and queues recovery when restart initiation fails; unknown-user discovery retries no longer consume mutation iterations. - Moves the success notification and the personality-rich completion banner after hooks, task retirement, state cleanup, and terminal cleanup verification. Skipped health checks receive downgraded wording.
- Adds behavioral state-machine tests for boot identity, evidence retention, completion disposition, dated maintenance retries, convergence scans, watchdogs, cleanup ordering, and failed parallel jobs.
- Keeps every splash theme byte-identical.
Scope note
The verified claim is intentionally limited to the configured patch pass. Full zero-work convergence for asynchronous Office Click-to-Run and additional package providers is tracked as follow-up work.
v2.5.27 (2026-07-20)
Reboot-resilient checkpoints and a completion screen that earns its confidence.
- Arms and verifies the durable resume checkpoint before any mutating phase, so even an installer-initiated
1641surprise reboot has a continuation waiting after boot. - Captures native installer exit codes
3010and1641as explicit reboot requests instead of losing them at the PowerShell child-process boundary. - Requires two clean reboot-signal probes across a 20-second animated servicing-settle window before completion.
- Gives resume tasks three two-minute retries, rejects overlapping instances, and reads every registration back before permitting a reboot.
- Preserves the checkpoint and retry chain when a resumed run encounters a transient preflight failure; failed preflights no longer consume an iteration.
- Withholds success when any enabled phase is incomplete and queues a two-minute recovery pass.
- Tracks actual orchestrated reboot count in durable state.
- Replaces the optimistic
FULLY PATCHEDfooter with a warm, evidence-backedPATCH CYCLE VERIFIEDscreen: configured phases, double reboot check, service health, and queue state. - Keeps every splash theme byte-identical.
v2.5.26 (2026-07-20)
Smooth ConsoleHost repaint without blank-frame stagger.
- Removed the full
CSI 2Kerase from every steady-state VT animation tick; frames now overwrite the owned row directly with bounded tail padding. - Retained full-line erasure for console-width changes, logs, verbosity transitions, completion, and error cleanup.
- Preserved the v2.5.25
| / - \propeller, 100 ms cadence, and exact 48-step cyan/blue/magenta/acid-green glow. - Updated the demo and regression suite to enforce flicker-free steady-state writes and resize-safe clearing.
- Kept every splash theme byte-identical.
v2.5.25 (2026-07-20)
Turbo-era propeller status bar.
- Replaced the bidirectional chevron comet with the classic fixed-width ASCII
| / - \propeller sequence. - Preserved the existing smooth cyan, blue, magenta, and acid-green glow exactly; only the motion glyph changed.
- Retained the independent 48-step color cycle, 100 ms cadence, immutable status text, live
vmode switching, and safe non-VT fallback. - Updated the visual demo and regression suite to enforce the propeller order, fixed width, smooth loop seam, and production/demo parity.
- Kept every splash theme byte-identical.
v2.5.24 (2026-07-20)
Smoother BOOT//PULSE glow with a dependency-free console UI.
- Replaced the ten abrupt per-frame color jumps with a closed 48-step RGB interpolation through the splash palette's cyan, blue, magenta, and acid-green anchors.
- Decoupled the comet motion index from the color index so the ten-frame movement does not reset or strobe the longer color fade.
- Removed the
PwshSpectreConsolediscovery, installation, trust-validation, import, and rendering paths; its only remaining job was coloring three lines already covered by native output. - Phase headers and results now render directly through the existing native ANSI/console paths, eliminating a PSGallery/network dependency from elevated runs.
- Added regression coverage that bounds every adjacent RGB channel change, including the loop seam, while preserving the splash golden hash.
v2.5.23 (2026-07-20)
Splash-themed BOOT//PULSE animation with corruption-proof status text.
- Replaced PowerShell's host-owned yellow Minimal progress pane after ConsoleHost was observed shifting every status character down one code point.
- The updater now owns one live carriage-return row with a fixed-width ASCII comet and the splash palette's cyan, magenta, blue, and acid-green pulse.
- Activity and status text remain separate from the animated frame; unsafe controls are removed and the live row is normalized to single-cell ASCII before resize-safe truncation. Full Unicode remains unchanged in the log.
- Ordinary logs and Spectre phase/result lines clear the live row before printing; completion restores the cursor and removes residual text.
- Quiet mode hides the row while continuing to poll
v, and SYSTEM, redirected, detached, or non-VT consoles retain safe fallbacks. - The visual demo now exercises
BOOT//PULSE, the exact photographed Windows Update text, palette cycling, and live verbosity changes without running updates. - Added regression coverage for exact status preservation, ASCII-safe fixed-width frames, cadence, console cleanup, and width handling.
- The BBS splash implementation and all three themes remain byte-stable.
v2.5.22 (2026-07-19)
Continuously animated progress with extensive UI regression coverage.
- Spinner rendering now refreshes every 100 ms and polls
von every frame. - Long built-in commands and background jobs run behind progress-pumped, process-tree-aware adapters instead of freezing the parent UI thread.
- Sequential and staged paths now animate across Chocolatey, Windows Update and drivers, WSL, containers, package ecosystems, Defender, Office, AWS tooling, service checks, notification waits, and installer retry waits.
- Progress cleanup is idempotent and protected by a top-level
finally, including staged-rollout early returns. - Added behavioral tests for exact frame rotation, cadence bounds, live jobs, silent native processes, partial timeout output, descendant cleanup, failures, Quiet/noninteractive behavior, verbosity cycling, blocking-path coverage, and completion cleanup.
- Added
tools/Show-BootUpdateProgressDemo.ps1for a harmless human-visible animation smoke test. - The BBS splash implementation and all three themes remain unchanged.
Compatibility
- Trusted hooks retain their existing same-scope behavior and are not moved to background runspaces. Long-running hooks remain responsible for their own feedback.
v2.5.21 (2026-07-19)
Optional Spectre-enhanced phase rendering with automatic, safe bootstrap.
- Interactive PowerShell 7.4+ runs now use
PwshSpectreConsolefor richer phase and result lines. - When no protected all-users copy exists, stable version 2.6.3 is installed from PSGallery under Program Files; user-writable module copies are never imported by the elevated updater.
- SYSTEM, redirected, older-PowerShell, offline,
-WhatIf, and failed install/import paths retain the native renderer. - The key-responsive native
Write-Progressspinner and all themed splash functionality remain unchanged.
Compatibility
- PowerShell 7 remains the baseline. Spectre enhancement requires 7.4+, but it is optional and never blocks an update cycle.
v2.5.20 (2026-07-19)
Compact live progress, runtime verbosity controls, and preserved themed splash.
- Interactive runs now default to a compact phase/progress view while retaining the complete timestamped log file.
- The existing themed startup splash and preview/theme controls remain enabled in the default view; only explicit Quiet mode suppresses the splash.
- Pressing
vcycles live through Quiet, Normal, Verbose, and Debug console modes without restarting the updater. - Native minimal
Write-Progressrendering adds phase progress and spinner feedback during monitored processes and parallel cohorts, with safe automatic disablement under SYSTEM or redirected hosts. -OutputModeand the deploymentOutputModesetting select the initial view and persist across scheduled reboot resumes.
Compatibility
- No state-schema changes and no mandatory UI dependency. Normal remains the default, while full diagnostic output remains available in the log and through Verbose/Debug modes.
v2.5.19 (2026-07-19)
Fail-closed self-update integrity, protected webhook storage, and trusted elevated hooks.
- Self-update now fails closed unless every downloaded PowerShell asset has a valid, matching SHA-256 value.
- Notification webhook URLs persist only in an ACL-protected ProgramData file and are no longer forwarded through Task Scheduler or self-update process arguments.
- Elevated extension hooks must remain under the orchestrator directory, be owned by Administrators or SYSTEM, and pass path, reparse-point, and broad-write ACL checks before execution.
- Deployment now hardens the ProgramData installation directory, and a no-echo webhook initializer supports secure setup and removal.
Compatibility
- No state-schema changes. Existing webhook configuration can migrate through the one-time deployment setting; non-HTTPS webhook endpoints are now rejected.
v2.5.18 (2026-07-19)
Race-free self-update handoff, process-level regression coverage, and automated quality gates.
- The updater retains continuous ownership of the single-instance mutex while its replacement runs, eliminating the release/reacquire race.
- A consumed, process-only nonce capability identifies the replacement child while legacy updater handoffs remain supported.
- Mutex arbitration now has an injectable mutex-name seam, preserving fail-closed production behavior while enabling isolated real-process tests.
- Added focused unit and real-process regression coverage for accepted and rejected handoffs, capability consumption, continuous parent ownership, competing invocation rejection, and legacy compatibility.
- Added Windows GitHub Actions quality gates for PowerShell parsing, Pester 5, PSScriptAnalyzer error-severity findings, and Git diff integrity.
- Fixed invalid switch-return syntax in the update-history renderer that the new parser gate surfaced.
- Hardened release creation by staging immutable script copies before hashing and upload, cleaning temporary assets on every exit path, and supporting
-WhatIfvalidation without publication. - Added secure Windows Credential Manager onboarding for the centralized beads client and renamed its repository-local lookup key to
beads.credentialTarget.
Compatibility
- No user-facing updater parameter or state-schema changes. Drop-in replacement for v2.5.17.
v2.5.17 (2026-07-18)
Self-update mutex handoff and persistent source healing.
- The running version now releases the named mutex before launching its downloaded replacement.
- A replacement downloaded by v2.5.16 or older recognizes the legacy synchronous parent handoff, allowing existing broken installations to heal from GitHub without a manual file copy.
- After GitHub confirms the live script is current, it repairs an older launcher-side
Invoke-BootUpdateCycle.ps1so the nextupdrun cannot redeploy the stale version. - Deployment preserves a newer ProgramData copy if source update is unavailable, preventing a network failure from downgrading a healed installation.
- No parameter or state-schema changes. Drop-in replacement for v2.5.16.
v2.5.16 (2026-07-06)
ARSO user-context resume + wildcard/allowlist filters + notification levels.
ARSO user-context resume (2ql)
Where Windows ARSO (Automatic Restart Sign-On) is available — not SYSTEM, DisableAutomaticRestartSignOn policy unset, user not opted out — the post-reboot task is now registered as the user at logon instead of SYSTEM at startup. Combined with v2.5.15's shutdown /g, the user is signed back in automatically and the cycle resumes in user context, so user-scoped phases (winget user scope, Scoop, VS Code extensions, WSL, containers) run on every iteration, not just the first. No password is ever stored — winlogon handles the resume.
- Fallback: a
BootUpdateCycleFallbackSYSTEM task (startup + 3 min) covers the case where ARSO doesn't sign the user in; the named mutex arbitrates if both fire and phase flags prevent duplicate work. - Without ARSO, the classic single SYSTEM-at-startup task is registered as before.
Uninstall.ps1, re-deploys, and self-destruct remove both tasks.
Package filters (6sh, from Winget-AutoUpdate)
ExcludePatternsnow supports wildcards (Mozilla.Firefox*,*.Beta) alongside legacy substrings.- New
-IncludePatternsallowlist mode: when non-empty, ONLY matching packages update (winget/choco/pip filtered paths; exclude wins over include). - Both flow through remote config (
ConfigUrl) and the post-reboot task arguments.
Notification levels (6sh)
New -NotificationLevel Full|SuccessOnly|ErrorsOnly|None gates toast/webhook/email/msg.exe noise. Event log entries and the native shutdown countdown are never gated. Max-iterations exit now sends an Error-kind notification (visible under ErrorsOnly).
Compatibility
- New optional parameters only. Drop-in replacement for v2.5.15.
v2.5.15 (2026-07-06)
Reboot-loop diagnosability, WU self-healing, WU prefetch, ARSO restart.
Changes
- Per-signal pending-reboot detail (juw):
Test-PendingRebootnow reports WHY each signal is pending (FileRename count + sample paths, active→pending computer name, CCM hard/soft flags) and adds two signals: CBSPackagesPendingand WUPostRebootReporting. If a reboot is driven by the exact same signal set as the previous reboot, the log calls out a likely stale/perpetually-repopulated signal (the classicPendingFileRenameOperationsloop). - WU remediation escalation (gxo): after 2+ consecutive Windows Update phase failures (streak survives reboots via a sidecar file), the standard component reset runs once per streak — stop wuauserv/cryptsvc/bits/msiserver, rename SoftwareDistribution + catroot2, restart. DISM /RestoreHealth is deliberately left manual.
- WU download prefetch (2uj): Windows Update scan+download starts as a background child process right after the pending-reboot check and runs while Winget/Chocolatey execute (BITS downloads — no msiexec/CBS contention). The install step stays sequential and collects the prefetch first. Skipped in staged rollout/WhatIf/module-missing cases.
- ARSO restart: reboots now use
shutdown /ginstead of/r— Windows Automatic Restart Sign-On signs the last interactive user back in and restarts registered apps, with no stored password. Degrades gracefully to a plain restart where ARSO is unavailable.shutdown /astill aborts. - State gains
LastRebootSignals(add-if-missing migration; no schema version bump).
Compatibility
- No parameter changes. Drop-in replacement for v2.5.14.
v2.5.14 (2026-07-06)
Wider parallel cohort — faster cycles. Defender, Office 365, and PowerShell modules move from the sequential chain into the ThreadJob parallel cohort (now 8 phases wide), overlapping with pip/npm/Scoop/.NET tools/VS Code. None of the three touch msiexec or CBS, so they cannot conflict with the sequential installers. Typical saving: the full serial time of those three phases per iteration (often 5–15 min).
Details
- Defender in the cohort uses process-based
MpCmdRun.exe -SignatureUpdate -MMPCinstead ofUpdate-MpSignature(the Defender module's WinPS-compat remoting is not safe to share across ThreadJob runspaces). - Sequential chain is now: Winget → Chocolatey → Windows Update → Driver/Firmware → AWS tooling → WSL → Containers (msiexec/CBS contention, or opt-in caution).
- Staged rollout (
-StagedRollout) is unaffected — it still runs one phase per boot via the original functions. - Crash recovery, per-phase hooks, state flags, and summary counts unchanged.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.13.
v2.5.13 (2026-07-06)
Self-update hardening.
Changes
- Releases now ship
.sha256sidecar assets for both scripts (via newtools/New-Release.ps1helper), activating the SHA256 integrity checks that already existed in both self-update paths but had never fired. Deploy-BootUpdateCycle.ps1now also self-updates its own source copy from the latest release (previously only Invoke's source was refreshed). Same parse + SHA256 validation, atomic replace with.bak,BOOT_UPDATE_NO_SELF_UPDATEopt-out.upd.cmdis intentionally not auto-updated (replacing a running batch file is unsafe).- CLAUDE.md documentation caught up: splash themes/preview, log-filter and
--no-progressconventions, dual source self-update, release procedure.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.12.
v2.5.12 (2026-07-06)
Splash defaults to neon gradient. No more per-run rotation — theme 0 (neon gradient) is the default on VT consoles. BOOT_UPDATE_SPLASH_THEME=0|1|2 still switches themes, upd splash still previews all three, and non-VT consoles still get the classic blocks.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.11.
v2.5.11 (2026-07-06)
Splash art in README. Pixel-true SVG renders of all three splash themes (docs/img/splash-theme{0,1,2}.svg), generated from the actual Show-StartupArt ANSI output, embedded in the README — neon gradient as the hero image, the other two collapsible.
Compatibility
- Docs/assets only; no functional changes. Drop-in replacement for v2.5.10.
v2.5.10 (2026-07-06)
Splash preview mode. Invoke-BootUpdateCycle.ps1 -PreviewSplash renders all three splash themes (labeled, with the BOOT_UPDATE_SPLASH_THEME pin hint) and exits — no mutex, no state, no updates. upd splash reaches it from cmd/Run dialog (self-elevates, pauses so the window stays open).
Compatibility
- New optional switch only. No schema changes. Drop-in replacement for v2.5.9.
v2.5.9 (2026-07-06)
Rotating splash themes. Each run cycles through three wordmark variants: (0) neon gradient with scanlines/dither/bevel, (1) bright-rim outline with checkerboard-dithered fill and denser glitch confetti, (2) classic 16-color blocks. Pin one with BOOT_UPDATE_SPLASH_THEME=0|1|2.
Additions
- Glitch-confetti gutters flanking the wordmark (deterministic, sparse colored cells in the letter palette).
- Bevel on the neon theme: bright lip on top edges, dark shadow on bottom edges.
- BBS-style metadata footer:
[board] nanoDBA/boot-upd,[motd], and[log](live log path) lines under the sysop/carrier tagline.
Compatibility
- Non-VT consoles always get the classic block theme. Still spaces + background color only. No parameter or schema changes.
v2.5.8 (2026-07-06)
Neon gradient splash. The BOOT wordmark now renders as 24-bit ANSI/VT gradient cells — per-letter demoscene gradients (cyan B, magenta O, blue/violet O, acid-green T), CRT scanlines (odd rows dimmed), deterministic dither, and a phosphor reflection row under the letters. The BBS frame, sysop/carrier tagline, and metadata header are unchanged.
Compatibility
- Still spaces + background color only — no Unicode glyphs — so the pre-2.5.6 cmd.exe glyph-drop failure mode cannot recur.
- Consoles without VT truecolor (Server 2016, pre-Win10 1703) automatically fall back to the v2.5.6 16-color block wordmark.
- No parameter or schema changes. Drop-in replacement for v2.5.7.
v2.5.7 (2026-07-06)
Log spam elimination and upd.cmd hardening.
Fixes
- Chocolatey download progress no longer floods the log:
choco upgradenow runs with--no-progress, and theWrite-Logfilter drops anyProgress:line (previously onlyProgress: ...% - Savingwas filtered). A single git.install download had produced hundreds of identicalProgress: Downloading git.install ... 1%entries. Write-Lognow collapses consecutive duplicate lines from any phase: the first occurrence logs normally, repeats are counted, and one(previous line repeated N more times)summary is emitted when the message changes.Deploy-BootUpdateCycle.ps1now self-updates the SOURCE copy ofInvoke-BootUpdateCycle.ps1from the latest GitHub release before deploying (parse + SHA256 validation, atomic replace with.bak,BOOT_UPDATE_NO_SELF_UPDATEopt-out). Previously Invoke's self-update only patched the live ProgramData copy, which Deploy overwrote with the stale source on every run.
upd.cmd improvements
upd /?(also-h,--help) prints usage.- The delay argument is validated as a whole number before elevating; bad input exits with code 1 and a clear message.
- Verifies
pwshis on PATH andDeploy-BootUpdateCycle.ps1exists next to the launcher before doing anything, with clear errors instead of a silently vanishing window. - Startup banner now echoes the effective reboot delay.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.6.
v2.5.6 (2026-05-02)
Win11 cmd and Server 2016 splash visibility fix. Replaced glyph-dependent BOOT art with native PowerShell background-color cells made from ordinary spaces.
Fixes
- Main BOOT wordmark now renders as colored background blocks via
Write-Host -BackgroundColor, avoiding cmd.exe/font paths that drop Unicode block glyphs to blank space. - Keeps the BBS/NFO frame and compact startup status flow from v2.5.5.
- Removes the fragile UTF-8 glyph capability branch that looked valid by codepage but failed visually in Windows 11 cmd.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.5.
v2.5.5 (2026-05-02)
Splash and startup flow refinement. Restored real BBS gradient block styling when UTF-8 console output is active, while keeping an ASCII fallback for legacy consoles.
Fixes
- Added a gradient block splash path using
░▒▓█framing and heavier BOOT lettering for consoles running UTF-8. - Kept the ASCII-only splash fallback for constrained legacy output.
- Replaced the immediate second startup banner with a compact cycle status strip so the splash is not undermined by duplicate framing.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.4.
v2.5.4 (2026-05-02)
Splash redesign. Replaced the plain block-letter splash with a more distinctive static BBS/NFO-style BOOT screen.
Fixes
- Uses a custom framed composition instead of generic hash-block lettering.
- Keeps the startup splash ASCII-only, ANSI-colored, dependency-free, and below 80 visible columns.
- Preserves the no-animation startup behavior.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.3.
v2.5.3 (2026-05-02)
Splash compatibility cleanup. Applied the practical constraints from OmniJeff's ascii-art skill guidance: ASCII-only art, simple retro characters, and an 80-column-safe banner.
Fixes
- Removed the now-unnecessary
Show-StartupArtUnicode codepage P/Invoke path; the splash no longer depends on box-drawing or block glyph support. - Documented the banner's 80-column constraint in the splash comment.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.2.
v2.5.2 (2026-05-02)
Splash compatibility fix. Replaced the fragile Unicode BBS splash with a static ASCII-only BOOT banner.
Fixes
- Startup art now renders cleanly in legacy
cmd.execonsoles even when Unicode block and box-drawing glyphs fail. - Keeps the BBS-style neon ANSI look, but removes animation and palette rotation.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.1.
v2.5.1 (2026-05-02)
Splash render fix. The BBS startup splash was rendering as blank space on legacy cmd.exe consoles because chcp.com 65001 > $null 2>&1 at script start was silently no-opping when stdout was redirected, leaving the console at CP437/CP1252 — which strips Unicode box-drawing/block-element chars (U+2500–U+259F) to nothing.
Fixes
Show-StartupArtnow callskernel32!SetConsoleOutputCP(65001)andSetConsoleCP(65001)directly via P/Invoke right before drawing, plus re-asserts[Console]::OutputEncoding = UTF-8. Idempotent and reliable regardless of how the parent process was launched.- Reverted the v2.5.1-rc per-row palette rotation. Each splash invocation again picks one random palette from the constrained six-theme set and uses it across all 6 BBS rows.
Compatibility
- No parameter or schema changes. Drop-in replacement for v2.5.0.
v2.5.0 (2026-05-02)
Major feature release. Concurrency safety, BitLocker support, parallelized cohort, four new update phases, extension-hook system, self-update, and remote configuration. All 25 open issues from the 2026-05 code review closed across seven coordinated phases. State schema v2 → v3 with automatic migration; all changes backwards-compatible.
New features
- Named-mutex concurrency guard (
Global\BootUpdateCycle). A duplicate orchestrator instance now logs and exits cleanly instead of racing on$state.Iterationandshutdown.exe.AbandonedMutexExceptionfrom a crashed prior owner is recovered. - BitLocker suspend across reboot. New
Suspend-BitLockerForRebootrunsSuspend-BitLocker -RebootCount 1(withmanage-bde.exefallback) immediately beforeshutdown.exe /r. Eliminates the recovery-prompt stall on protected machines. New-SkipBitLockerswitch. - Parallel cohort. Pip, Npm, Scoop, DotnetTools, and Vscode now run concurrently via
Start-ThreadJob. ~30-40% wall-clock savings on the user-package phase. - Parallel Winget scopes.
--scope userand--scope machinerun concurrently in user context (sequential fallback under SYSTEM and whenExcludePatternsis active). - Defender signature update phase (default ON,
-SkipDefenderto disable). Runs after Windows Update. - Driver/firmware update phase (opt-in,
-IncludeDriverUpdates/-IncludeFirmwareUpdates). Honors regex-escapedExcludePatterns. - WSL kernel + distro phase (opt-in,
-UpdateWsl). Runswsl --updateplus per-distro apt/dnf/pacman. SYSTEM-context skipped. - Container image refresh + prune (opt-in,
-UpdateContainers). Detects Docker or Podman, pulls all non-<none>images unique-deduped, thensystem prune -f. SYSTEM-context skipped. - Metered connection detection. WinRT
GetConnectionCostwith CIM fallback. Aborts cleanly viaexit 0(not the error path) unless-AllowMeteredis set. - Pre-flight network cache. DNS + TCP probes cached in state for 5 minutes. Saves ~5-10s per iteration on slow networks. Cleared on reboot.
- Cycle-level hooks. New
-PreCycleScript/-PostCycleScriptparameters dot-source user .ps1 files at cycle entry and at successful-completion / max-iterations paths. - Per-phase hooks via
hooks.psd1. Sidecar file with 30 named scriptblocks (Before/After x 15 phases). Loaded at script start; failures are logged and never crash the cycle. - Self-update from GitHub releases (default ON,
-DisableSelfUpdateto disable). User-context only. Checks thelatestrelease, validates the downloaded asset parses, optionally verifies SHA256 from a sibling asset or release body, atomically replaces the live script, and re-execs with the original parameters. - Remote configuration URL. New
-ConfigUrlparameter pulls a JSON config; supported keys override$script:*defaults only when the user did not pass them on the command line. Successful fetches are cached atProgramData\BootUpdateCycle\remote-config.cache.json.
Bug fixes
$SkipDotnetToolsnow defaults to$true(matches documented OFF default; was running by accident).shutdown.exe /ccomment is quoted (PS7.0-7.2 Legacy native-arg passing).- pip per-package upgrade quotes the package name and applies
ExcludePatterns. - Windows Update
NotTitleregex-escapes user-suppliedExcludePatterns(no more silent over-exclusion or parse errors). Set-BootUpdateStateclears stale.tmpfrom a prior failed write and surfacesMove-Itemfailures via the logger.Save-CycleHistorywrites atomically and tolerates a corrupted/empty history file (try/catch aroundConvertFrom-Json).$state.Iteration++and the state write now happen AFTER the maintenance-window gate — narrow windows no longer burn iteration slots on misses.Register-BootUpdateTaskForRebootno longer early-returns when the task already exists;Register-ScheduledTask -Forcealways rewrites the action with the current arguments.Update-BootUpdateStateSchemawarns and backs up state files written by a future schema version (<path>.future-vN.bak).Repair-AwsTooling.ps1passes its multi-line scriptblock topwsh.exevia-EncodedCommand(newlines no longer drop acrossCreateProcess).Send-MailMessage -AsJobis awaited with a 30-second timeout, errors logged, and the job removed (no more job-object leak / silent SMTP failures).
State schema
- Bumped v2 → v3. Adds
DefenderDone,DriverFirmwareDone,WslDone,ContainersDone,LastPreflightNetworkOk,LastPreflightNetworkAt. Migration is automatic and idempotent. - Forward-compat guard added: a state file at
v > $script:BootUpdateStateSchemaVersionis backed up to<path>.future-vN.bakbefore the script proceeds.
Compatibility
- New optional parameters; no removals or renames.
$SkipDotnetToolsdefault flipped from running → skipped, restoring documented behavior.- All existing call sites and scheduled-task arg propagations updated.
v2.4.0 (2026-04-25)
Performance: PowerShell module updates now run in parallel via ForEach-Object -Parallel.
- PSResourceGet path (PS 7.4+ / PSResourceGet installed): bulk
Update-PSResourceruns N modules concurrently inside the existing child job. - Legacy path (PS 7.0-7.3): per-module
Update-Modulecalls also run in parallel inside one child job (was sequential). - Throttle limit:
min(8, max(2, ProcessorCount))— caps concurrency to avoid repository contention and resource exhaustion. - Same structured output format (
UPDATED|name|old|new,ERROR|name|msg); same hard timeout viaPackageTimeoutMinutes.
Expected: 3-5× faster module phase on machines with many installed modules.
v2.3.4 (2026-04-25)
Fix: BBS splash rendered as blank when launched via upd.cmd — Unicode block-drawing chars stripped by inherited CP437/CP1252 console encoding.
- Forces UTF-8 console I/O on script start (
[Console]::OutputEncoding+chcp 65001) so block/box-drawing chars (U+2588, U+2557, U+2550, etc.) survive the cmd.exe → pwsh handoff
v2.3.3 (2026-04-25)
UX: BBS-style startup splash (Show-StartupArt) now renders on every iteration instead of only the first. Visible on every upd.cmd invocation and on post-reboot SYSTEM task runs.
v2.3.2 (2026-04-25)
Fix: Banner version was hardcoded as v2.1 in three places. Extracted to $script:BootUpdateCycleVersion variable — single source of truth for all version displays.
v2.3.1 (2026-04-25)
Enhancement: Comprehensive pending reboot detection based on Boxstarter/Brian Wilhite's Get-PendingReboot.
| Check | Before | After |
|---|---|---|
| CBS RebootPending | Property lookup | Subkey existence (Test-Path) |
| WU RebootRequired | Property lookup | Subkey existence (Test-Path) |
| PendingFileRenameOperations | Property exists | Verify entries count > 0 |
| Netlogon JoinDomain | Property only | JoinDomain OR AvoidSpnSet |
| SCCM CCM_ClientUtilities | Not checked | Added (WMI, graceful skip if no SCCM client) |
v2.3.0 (2026-04-25)
Major: Migrate PowerShell module updates from sequential Update-Module to bulk Update-PSResource (PSResourceGet).
- Primary path (PS 7.4+ / PSResourceGet installed): single
Start-JobrunsUpdate-PSResourcefor all modules in one child process. ~2x faster, C#-native, no PackageManagement dependency conflicts. - Legacy fallback (PS 7.0-7.3): existing per-module
Update-ModuleviaStart-Jobpreserved. - Child process avoids module-in-use file locks.
- Structured output parsing (
UPDATED|name|old|new,ERROR|name|msg).
v2.2.1 (2026-04-25)
Fixes:
- AWS.Tools. stale repository* — all AWS.Tools modules failed with
Unable to find repositoryerror. Now usesUpdate-AWSToolsModule -CleanUpinstead of genericUpdate-Module. - Az meta-module timeout —
Azwrapper (80+ sub-modules) exceeded 5-minute timeout. Excluded from generic loop; sub-modules update individually. - PackageManagement noise — filtered
module is currently in usewarning from logs.
v2.2.0 (2026-04-25)
Major: Resolves all remaining open issues (7 bugs + 4 enhancements) via 4 parallel agents.
Bugs Fixed
| Issue | Description |
|---|---|
| #2 | pip JSON parsing breaks on single outdated package (wrapped in @()) |
| #3 | Crash recovery treats unknown phase names as crashes (now warns and ignores) |
| #4 | $LASTEXITCODE stale value — webhook uses -ErrorAction Stop |
| #5 | Module update job failures not detected (State checked before Remove-Job) |
| #6 | Repair-AwsTooling cmd.exe injection — uses msiexec.exe directly, non-MSI skipped |
| #16 | ExcludePatterns with special chars break task args (single quotes escaped) |
| #19 | Stop-Job leaves orphan pwsh.exe (child process killed via ProcessId) |
Enhancements
| Issue | Description |
|---|---|
| #17 | WebhookUrl validated with [ValidateScript] (must be http/https or empty) |
| #18 | SMTP auth via [pscredential]$SmtpCredential parameter |
| #20 | Webhook retry with exponential backoff (3 attempts, 2s/4s delays) |
| #21 | ASCII art splash picks random neon palette from 6 curated schemes |
v2.1.4 (2026-04-25)
Fixes from full codebase review:
- Deploy:
SkipHealthCheck,MaintenanceWindowStart,MaintenanceWindowEndnow forwarded to scheduled task args (were silently dropped after reboot) - ExcludePatterns uses
.IndexOf()instead of-like(no wildcard bugs with[],?,*) Show-BootUpdateHistory: empty JSON array[]handled gracefully[ValidateRange(-1, 23)]added toMaintenanceWindowStart/MaintenanceWindowEnd
v2.1.3 (2026-04-25)
Fix: Filter System.__ComObject noise from Windows Update log output. PSWindowsUpdate emits COM objects whose .ToString() renders as the type name.
v2.1.2 (2026-04-25)
Fix: Banner version strings updated from v2.0 to v2.1 (ASCII splash, normal banner, WhatIf banner).
v2.1.1 (2026-04-25)
Fix: Windows Update -NotTitle parameter type error. Parameter is [String], not [String[]] — joined ExcludePatterns array with | to produce regex alternation string.
v2.1 (2026-04-25)
Major release adding 8 features across three capability areas:
Observability
- Webhook & Email Notifications — Teams/Slack/Discord auto-detection, dual notifications (completion + reboot warning), proxy support, async email
- Trend Visualization (
Show-BootUpdateHistory.ps1) — Table/Graph/JSON output, ASCII bar charts with ANSI colors, read-only (no elevation) - Post-Update Health Check — validates W32Time, WinDefend, Dnscache, Spooler, EventLog; service recovery; state tracking
Safety & Control
- Exclude Patterns — skip packages by substring match across Winget, Chocolatey, Windows Update
- Maintenance Window — hour-based scheduling with midnight-crossing support; defers (doesn't fail)
- Staged Rollout — one package manager per boot; state persistence; isolated failure domains
Quality of Life
- WhatIf/Dry-Run Mode —
ShouldProcessguards on all external calls; zero side effects - System Restore Point — opt-in snapshot before first iteration; SYSTEM/Server SKU tolerant
Defaults: All features disabled by default except health check. 100% backward compatible with v2.0.
v2.0 (2026-04-25)
Initial release. Full-featured boot-time update orchestrator:
- 11 package manager phases (Winget, Chocolatey, Windows Update, pip, npm, Office 365, PowerShell modules, Scoop, dotnet tools, VS Code extensions, AWS tooling)
- Pre-flight checks (disk, network, battery, conflicts, WU service)
- Smart idle-aware timeouts with process tree monitoring
- Crash recovery with atomic state writes
- State schema versioning with auto-migration
- Log rotation, history tracking, toast notifications, event logging
- DirectFirstRun mode for user-scope Winget access
- Self-destructing scheduled task on completion
Configuration
$Config = @{
# Safety & Control
SkipRestorePoint = $true # Set $false to enable restore point
SkipHealthCheck = $false # Health check on by default
StagedRollout = $false # One manager per boot
ExcludePatterns = @() # Skip packages by substring
MaintenanceWindowStart = -1 # Hour (0-23), -1 = no restriction
MaintenanceWindowEnd = -1 # Hour (0-23), -1 = no restriction
# Notifications
WebhookUrl = '' # Teams/Slack/Discord webhook
NotifyEmail = '' # Email recipient
SmtpServer = '' # SMTP relay
# SmtpCredential = (Get-Credential) # Optional SMTP auth
# Core
RebootDelaySec = 0 # Immediate forced reboot
MaxIterations = 5 # Safety valve
PackageTimeoutMin = 30 # Hard timeout per manager
}Getting Help
# Monitor running cycle
Get-Content "$env:ProgramData\BootUpdateCycle\BootUpdateCycle.log" -Tail 50 -Wait
# View cycle history
Get-Content "$env:ProgramData\BootUpdateCycle\BootUpdateCycle.history.json" | ConvertFrom-Json
# Event log
Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName='BootUpdateCycle'}
# Trend visualization
.\Show-BootUpdateHistory.ps1 -Format Graph
# Preview without changes
.\Invoke-BootUpdateCycle.ps1 -WhatIf -Force
# Uninstall
& "$env:ProgramData\BootUpdateCycle\Uninstall.ps1"License
MIT - See LICENSE file