Skip to content

fix(win): Program Files boot - compiled engine, CI boot gate, installer clamp relax - #338

Merged
mlcyclops merged 8 commits into
masterfrom
test/win-startup-fix
Aug 25, 2026
Merged

fix(win): Program Files boot - compiled engine, CI boot gate, installer clamp relax#338
mlcyclops merged 8 commits into
masterfrom
test/win-startup-fix

Conversation

@mlcyclops

Copy link
Copy Markdown
Owner

Payload (the full ADR-0250 -> 0262 arc)

  • P-WINBOOT.1/.2 (ADR-0250/0251): the v1.12.0 Program Files brick, fixed permanently. The engine ships as bin/lucid-engine, a bun build --compile binary (dev.ts + all JS embedded; native .node addons the only externals; renderer prebuilt). Fast, actionable failure dialogs for stale installs.
  • P-WINBOOT.2C (ADR-0261): the regression gate that would have caught the brick. desktop/build/pf-boot-smoke.ts stages the packaged repo into C:\Program Files\..., denies the runner user the specific write/delete rights (never generic W - it includes SYNCHRONIZE and EPERMs CreateProcess), proves the denial, then requires bin/lucid-engine to answer /api/health and serve the prebuilt renderer from the protected tree. Wired STRICT into build-desktop.yml's Windows job.
  • P-WINBOOT.3 (ADR-0262): the ADR-0250 installer clamp relaxed - assisted installer, per-user DEFAULT, per-machine (Program Files) allowed again. Coupled: demo-P-WINBOOT.1 asserts the posture AND the gate's presence, so removing the gate turns the demo red.
  • fix(build): bin/ kept tracked via .gitkeep - a fresh CI checkout had no bin/ and current Bun no longer creates the --outfile parent (dist died ENOENT at compile-lucid).

Proof

  • CI run 32796994917: all 3 OSes green, publish-latest skipped. The Windows job ran the gate strict on the max-fidelity path - packaged bytes staged to real C:\Program Files, write-denial proven, engine booted, health ok, 7.1MB bundle served.
  • Local: demos P-WINBOOT.1/.2/.2C green; 37 engine unit tests + 14 pf-smoke tests; root+desktop tsc clean; license clean; bun test harness at the documented baseline (3 pre-existing lucid_acp.test.ts path-separator fails only).

Merge instructions

SQUASH-merge required. The branch deliberately keeps its history (no force-push), which includes the Aug-1 "test-only ... DO NOT MERGE" titled commit whose content ADR-0262 has since made intended. Squashing keeps that stale title out of master. See DECISIONS.md ADR-0262.

Fixes the v1.12.0 Windows brick where an install under C:\Program Files showed a 30s blank window: main.ts ran `bun run desktop/dev.ts` and Bun EPERMs loading a .ts from the ACL-protected tree.

P-WINBOOT.1 (ADR-0250): installer clamp (nsis allowElevation + allowToChangeInstallationDirectory = false), early engine-exit detection, and an actionable engine_boot.ts classifier (protected-location | engine-exited | timeout) instead of a silent 30s wait.

P-WINBOOT.2 (ADR-0251): ship the engine as a `bun build --compile` binary (bin/lucid-engine, --external '*.node'): dev.ts is embedded so Bun never module-loads a .ts off the install disk; native addons load via the OS loader (Program Files-safe); execPath-derived base dir; prebuilt renderer bundle; resolveEngineSpawn cutover in main.ts. airgap-smoke guards both shipped artifacts.

Verified: demo-P-WINBOOT.1/.2 (the latter builds+boots the real binary), 23 unit tests, packaged_boot green, desktop tsc clean. The Program Files end-to-end boot is Increment C, which this branch's test installer is for.
Reverts the P-WINBOOT.1 installer clamp ON THIS TEST BRANCH ONLY so LucidAgent-Setup.exe offers C:\Program Files again, letting the smoke test reproduce the friend's exact original install path and confirm the P-WINBOOT.2 compiled engine now boots from a protected dir.

master keeps allowElevation:false + allowToChangeInstallationDirectory:false until Increment C proves a protected-root boot in CI (see ADR-0251). Drop this commit before any merge. Note: demo-P-WINBOOT.1's nsis assertions intentionally do not hold on this branch.
Stages the packaged repo (or a source-built skeleton) into a Program
Files-ACL location, denies the current user the specific write/delete
rights (never generic W - it includes SYNCHRONIZE and EPERMs
CreateProcess itself), proves the denial with a failed probe write,
then requires bin/lucid-engine to answer /api/health and serve the
prebuilt renderer bundle from the protected tree. Wired STRICT into
build-desktop.yml's Windows runner - the regression class that shipped
the v1.12.0 brick now fails the build, never a user.

Verified: demo-P-WINBOOT.2C end to end on Windows (engine boots from
the write-denied tree, health ok, 7.1MB bundle served); 14 unit tests;
demo-P-WINBOOT.2 still green; root+desktop tsc clean; license clean;
bun test harness at the documented baseline.
…eir output dir

A fresh CI checkout had no bin/ (fully gitignored, zero tracked files)
and the runner's floating bun latest no longer creates the --outfile
parent dir, so dist:win died ENOENT at compile-lucid before packaging.
Same .gitkeep pattern as desktop/whisper/.
…ot gate (ADR-0262)

demo-P-WINBOOT.1 section [5] now asserts the assisted-installer,
per-user-default, per-machine-allowed posture AND that build-desktop.yml
still runs the strict Program Files boot gate - removing the gate turns
the demo red, so the clamp relax can never outlive its justification
silently. engine_boot.ts keeps its protected-location classifier (stale
pre-engine packages must still fail fast + actionably); comment and
Makefile help text updated; ADR-0262 + PROGRESS entry.
Conflict resolutions:
- desktop/main.ts: UNION of ADR-0259's engine tail + exit watcher and
  ADR-0246's spawn-error tee; the error handler now also feeds the tail
  and the exit flag so waitForServer bails at once with a named cause.
- DECISIONS.md / PROGRESS.md: both sides kept, chronological order.
- ADR renumber: the branch's parallel P-WINBOOT ADR-0250/0251 collided
  with master's shipped 0250 (P-MODEL.1) / 0251 (P-AVATAR); renumbered
  to ADR-0259/0260 across code comments, demos, Makefile, and both logs
  (master-meaning citations untouched, e.g. trainer_model.ts, dev.ts
  P-AVATAR line).

Verified post-merge: demos P-WINBOOT.1/.2C green, 37 engine tests, root
+ desktop tsc clean, license clean, bun test harness 1833 pass / 3
documented pre-existing fails, bun test desktop 4268 pass / 15
documented pre-existing (fs_browse Windows, symbol_graph TS7, stale
desktop/release copies).
for (const cmd of hardenPlan(STAGE, user, PLAT)) run(cmd);
hardened = true;
let denied = false;
try { writeFileSync(join(STAGE, "deny-probe.txt"), "x"); } catch { denied = true; }
The 10-minute silence kill murdered legitimately long turns (subagent
fan-outs outlive any fixed clock). User call: the cutoff is removed - a
turn ends when the work ends, Stop, or transport death. The failure the
clock actually guarded against is now event-driven: ACPClient rejects
every in-flight request when the omp child exits (proven with a real
child process). Visibility replaces the clock: turn_pending.ts tracks
the open tool calls (spawned subagent tasks labeled as such), every
slow notice carries them, and the HUD/toast name what the turn is
waiting on and for how long. Chat turns only; util completions keep
their deliberate background clocks until P-KG-INGEST.5 lands.

20 unit tests; demos P-STALL.1 (evolved) + P-STALL.2 green; root +
desktop tsc clean; desktop suite at the documented baseline.
@mlcyclops
mlcyclops merged commit 19dd169 into master Aug 25, 2026
5 checks passed
@mlcyclops
mlcyclops deleted the test/win-startup-fix branch August 25, 2026 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants