Conversation
The MSI preflight matched the ASCII spelling of winunitd.exe against raw task-file bytes. Task Scheduler stores registered definitions as UTF-16LE with a byte order mark, so a direct machine task launcher was never detected on a real task store. Decode UTF-8 and UTF-16 definitions (with or without a byte order mark) before the case-insensitive match. Refuse malformed encodings with the existing launcher-inspection conflict. Registry Run values keep their separate string match. Add regressions for every accepted encoding, malformed input, a mixed store, a wrapper-only task and the install/repair/upgrade conflict with the uninstall exemption. Document the detection contract: explicit references in task definitions and machine Run/RunOnce values only; wrapper, script and per-user launchers stay with explicit migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe the BOM-less UTF-16 detection as the scanner's own two-byte heuristic, broader than the XML Appendix F signatures and not an XML parser. Say that a wrapper task is still reported when its definition names winunitd.exe. Match each test fixture's XML declaration to the bytes it emits. No runtime change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tracks #259.
Symptom
The MSI preflight's launcher check matched the ASCII spelling of
winunitd.exeagainst raw task-file bytes. Task Scheduler stores registered definitions as UTF-16LE with a byte order mark, so a scheduled task that nameswinunitd.exedirectly was never detected on a real task store. Install, repair and upgrade therefore did not raise the incompatible-pilot conflict for it.Fix
tools/msi-check/preflight.godecodes each task definition before the unchanged case-insensitive match:could not inspect machine launchersconflict: invalid UTF-8, an odd UTF-16 length, unpaired surrogates, NUL characters. NUL bytes are never stripped to force a match.Run/RunOncestring match, the count, depth and size bounds, reparse refusal, and the conflict text.preflight_test.goruncountTaskLauncherson complete task definitions:docs/INSTALLATION.md,docs/MSI-INSTALLER-PLAN.mdanddocs/R6-EVIDENCE.mdnow state the detection contract:winunitd.exereferences in task-definition text and in 64-bit machineRun/RunOncevalues, whatever the task's principal.The fix changes availability: one task-store file that isn't valid UTF-8 or UTF-16 now blocks install, repair and upgrade. This is intentional, because silently skipping such a file would reopen the false-negative path. It is covered by the whole-store native lane below.
Verification
417ee80bc59353438b7f82a44c5b7b79ca520c00) succeeded: windows, test (linux) and compile (linux, GOOS=windows). Artifacts: windows-amd6410863167915, cross-windows-amd64-manifest10862497977.go test ./tools/msi-check -race -count=1: every new test passes. The two existing symlink tests (TestTaskScanDoesNotFollowReparse,TestServicingDoesNotFollowMutableReparse) fail at symlink creation for lack of privilege, the same as on unmodified main.go vetfor Windows and Linux, staticcheck 2026.2.1 and gofmt are clean.Native qualification — pending
This must pass before merge, on a disposable Windows guest from a fresh snapshot and fixture namespace. No fixture task is ever started.
winunitd.exeaction. Record the actual registered file bytes and byte order mark. The corrected scanner, running as SYSTEM, must count both. The previous scanner must return zero on the same UTF-16 bytes.preflight conflict: incompatible pilot launches winunitd; explicit migration is requiredbefore quiesce. SCM, payload, data, registration and the task must be unchanged. Uninstall's exemption is verified in a package-owned layout.🤖 Generated with Claude Code