Wiki · Evidence & Verdicts
Receipt — HUD widget launch: compiled service + native Task Scheduler (no script, no fragility)
How to read this page
Three ways to read this page. Precise is the document itself, exactly as it is written in the repository. Plain and Clear were written for this website to help you meet that document — they are about it. They are not it, and they are not evidence.
Eighty-seven dated pages: receipts, pre-registrations, handoffs, validation records and review verdicts. A receipt is written at the moment a piece of work was checked. It names what was claimed, the commit and the seed, what was actually run, and the outcome in one of a small set of controlled words. Then it names what the work did not achieve. That last part is what makes it a receipt rather than an announcement. A pre-registration is the same discipline run in advance: the conditions that would count as a pass and the conditions that would falsify the claim are written down before the run, so neither can be adjusted once the numbers arrive.
That is why so many small dated stubs are an audit trail rather than noise. No one of them is meant to be a good read. The value is in the sequence and in the dates, because you can watch a prediction be registered, then the run happen, then the verdict land — sometimes against the prediction. Pages here record a falsified result, a rejected fix, a retracted overclaim, and a green receipt that turned out not to be reproducible from the commit that carried it. A record that carried only successes would be worth a good deal less than this one.
A gentle way in is to read a pre-registration first, so the shape becomes familiar, then a result page, then one of the corrections. This section sits off the main navigation on purpose: it is the record you check the rest of the site against, not the place to begin.
What it is not: documentation, and not a summary. Nothing here has been tidied in hindsight. Every entry reads as of its date, a later entry may overturn an earlier one, and the presence of a page is not a claim that its result stood.
Your browser cannot switch reading levels, so the document itself is shown.
Precise — the source document
This is the document. Rendered from the repository at the commit above, with nothing rewritten for the web. A gate re-renders it on every deploy and fails the build if a single byte differs.
Date: 2026-07-18 · Track: studio · Surface: THINKER (studio box) · Class: B (observed-with-artifact)
Gates: hud-widget-launcher-supervises = PASS · hud-boot-persistent = PENDING (auto-confirms on next power-cycle)
The problem (why the HUD was missing on screen after reboot)
The UNI-HUD-WidgetLauncher Windows service (added 2026-07-18) hand-rolled the spawn of the WPF
widget into the operator's session: WTSQueryUserToken → DuplicateTokenEx → CreateProcessAsUser(lpDesktop "winsta0\\default"). CreateProcessAsUser returned a valid PID, but the child died within ~2 s —
the textbook 0xC0000142 (STATUS_DLL_INIT_FAILED): a Session-0 service spawning a UI process into the
interactive desktop must first grant the interactive window-station and desktop DACLs to the
duplicated token (AddAceToWindowStation/AddAceToDesktop). That hand-rolled DACL surgery is the
brittle path — it breaks on RDP reconnect, fast-user-switching, and Windows updates.
Captured live one last time in logs/widget_launcher_service.log during this cutover:
[...17:59:17...] attempting CreateProcessAsUser in session 1...
[...17:59:17...] CreateProcessAsUser returned PID=13492 TID=19568
[...17:59:19...] child EXITED before +2s (PID 13492 not found). CreateProcessAsUser returned true
but the process did not survive - most likely a manifest/dependency issue, or a
WPF init failure.
The fix — keep a compiled Windows service; delegate the spawn to Task Scheduler
Session 0 isolation is an OS law, not our code: a Windows service runs in Session 0 and cannot
draw a window in the operator's session (Session 1). So UNI.Hud.Widget.exe (WPF) must be a
user-session process. The only question is how a service launches it. The non-fragile, professional
answer (what Docker Desktop, Steam, GPU control panels do) is to let the Windows Task Scheduler
service — which already owns the session/window-station/desktop plumbing correctly — perform the
spawn. That is why launching through it cannot produce 0xC0000142.
Architecture (all compiled/native, no .vbs, no .ps1 in the boot or run path):
Windows SCM ──auto──► UNI-HUD (UNI.Hud.Service.exe, NetworkService, :8100 JSON) [backend, unchanged]
└─ crash recovery: sc.exe failure restart/5000 x3
Windows SCM ──auto──► UNI-HUD-WidgetLauncher (UNI.Hud.WidgetLauncher.exe, LocalSystem) [compiled supervisor]
├─ on start: EnsureTask() registers "UNI\HUD Widget" (idempotent)
└─ 5s tick: widget absent in the active session → task.Run()
└─ Task Scheduler service ──► UNI.Hud.Widget.exe (WPF, operator session)
Scheduled Task "UNI\HUD Widget" (native OS object):
trigger : At log on (the operator) ← reboot / logon survival, even if the service is down
restart : on failure, every 1 min ← OS-native fallback supervision
principal : interactive user, InteractiveToken (NO password), RunLevel = Limited
action : UNI.Hud.Widget.exe ← direct, no wrapper
dedup : the widget's named mutex "UNI-HUD-Widget" makes any double-fire a safe no-op
Two supervision legs: fast active (the compiled service re-triggers the task within 5 s of the widget going missing — the air-alarm surface lives in the widget) and OS-native fallback (the task's own at-logon trigger + restart-on-failure bring it up even if the service is stopped).
Service-account discipline honored: the launcher service runs as LocalSystem (a machine identity — needed only to register/trigger a task for the logged-on user); the task runs as the operator via an interactive token — no password is ever stored. No service is tied to a person's account.
Files
viewer/hud/native/UNI.Hud.WidgetLauncher/LauncherWorker.cs— rewritten:CreateProcessAsUserand all its token/desktop P/Invoke deleted;EnsureTask()+task.Run()viaMicrosoft.Win32.TaskScheduler; session user resolved read-only viaWTSQuerySessionInformation.viewer/hud/native/UNI.Hud.WidgetLauncher/UNI.Hud.WidgetLauncher.csproj—+ TaskScheduler 2.11.0.viewer/hud/native/UNI.Hud.WidgetLauncher/Program.cs— header updated to the Task Scheduler chain.viewer/hud/native/_install_widget_launcher_elevated.ps1— verifies service Running AND task registered before the.donemarker; refreshes the native-config reboot marker on install.viewer/hud/native/hud_native_boot_proof.ps1— clause 5 now = launcher service Running + task with at-logon trigger + widget action (was:UNI-HUD-Widget.vbspresent).viewer/hud/native/hud_widget_boot_install.ps1— retired (refuse-to-run guard);hud_widget_open.vbskept only as the manual cold-open (never copied to Startup again).viewer/door_lifecycle.cjs— thehuddoor's supervision text corrected (was "per-user Startup .vbs on logon", which is what rendered stale in the widget's supervision card).
Empirical proof (live, 2026-07-18)
- Install:
_install_widget_launcher_elevated.ps1(one UAC) → markerok. Service:State=Running, StartMode=Auto, StartName=LocalSystem. TaskUNI\HUD Widget:Logon Mode: Interactive only. - LocalSystem registers + runs an InteractiveToken task without a password (the plan's one flagged
empirical unknown — now proven):
Widget PID 8132, SessionId 1, survived (no "child exited" — contrast theSTART pid=14960 user=THINKER$ widget_target=...\publish\widget\UNI.Hud.Widget.exe exists=True EnsureTask: registered/updated UNI\HUD Widget for user=THINKER\mpolz action=...\UNI.Hud.Widget.exe tick: widget absent in session 1 -> task.Run() task.Run() issued (Task Scheduler will spawn the widget in-session)0xC0000142line above). - Supervision (
hud-widget-launcher-supervisesPASS): killed PID 8132 → respawned as PID 25788 in 2.6 s (the 5 s service tick, not the 1-min task fallback), log showed a freshtask.Run(). - Visible + healthy:
MainWindowHandle=1509666(non-zero top-level window),Responding=True, single instance (mutex). Screenshot of the docked widget rendering live content:docs/receipts/hud_widget_visible_2026-07-18.png.
Honest residual (reboot-survival is PENDING, not PROVEN)
The launcher + task were installed at 12:59 today, after the last boot (11:30). Installing the
launcher changed the native HUD config, so its reboot-survival has not been observed across a real
power-cycle yet. The installer refreshes the native-config marker, so hud_native_boot_proof.ps1 now
reports rebooted_since_config: False and exits 1 (NOT YET) — the honest state. hud-boot-persistent
is therefore PENDING; it auto-confirms PASS on the operator's next real power-cycle (the WS-F reboot),
and cannot be false-passed by a manual restart. Clauses 1, 3, 4, 5 all PASS immediately.
sha256 38aff0db2bdc00bd — of the original file, so what was ingested stays checkable.
Plain — written for this website, not the source document
A record of why an on-screen panel kept vanishing after a restart, and the fix. A background service was trying to launch a window into the logged-in operator's session by hand, which needs fragile permission surgery, and the child process died within seconds every time. The fix stops doing that by hand and asks the part of the operating system that already owns that plumbing to launch it instead. Two layers of supervision now exist, one fast and one native. Surviving a restart is honestly still pending, because the install happened after the last one.
Plain · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 38aff0db2bdc00bd
Clear — written for this website, not the source document
A receipt — the file recording what was run — for replacing a fragile mechanism with a native one. The symptom was a panel missing from the screen after a restart. The cause was a background service spawning a window process into the operator's session itself, which requires granting rights on the window station and desktop to a duplicated token, and that surgery breaks on remote reconnects, user switching and updates. The log line from the last time it failed is quoted: the launch reports a valid process, which is then gone within two seconds.
The fix is framed as accepting a rule of the operating system rather than working around it. A service runs in an isolated session and cannot draw a window in the operator's session, so the window process has to run in the user session, and the only real question is who launches it. The answer is to let the scheduler service, which already owns that plumbing correctly, perform the spawn. That is why launching this way cannot produce the old failure, and the page names other products that work the same way.
The architecture is drawn out: two services registered with the system, one of which registers a scheduled task and re-triggers it whenever the panel is missing, and the task itself triggered at logon with its own restart-on-failure. That gives two supervision legs, one fast and one native, and either alone brings the panel back. A named lock makes a double fire a harmless no-op. One discipline point is called out: the supervising service runs as a machine identity, and the task runs as the operator through an interactive token, so no password is stored anywhere and no service is tied to a person's account.
The files section reads as much as a deletion list as an addition list, and one script is retired behind a refuse-to-run guard rather than left lying around. A stale sentence describing the old mechanism on another surface was corrected at the same time.
The proof is live. The install is checked by state rather than by its own log. The previously open question, whether a machine identity can register and run a task as the interactive user with no password, is answered by doing it. The panel survives where it used to die. And a supervision test kills the process and watches it return within a few seconds through the fast leg rather than the slow one.
The closing residual is honest. The install happened after the last restart, so restart survival has not been observed. The relevant check reports not yet and exits non-zero, that gate stays pending, and the page notes it cannot be passed by a manual restart.
Clear · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 38aff0db2bdc00bd