Commit Graph
385 Commits
Author SHA1 Message Date
Simone 6a57c1d815 fix(deploy-win): don't re-patch an already-patched ISO
deploy-win patched its input into vm_dir/install-noprompt.iso and only its
own sidecar cache could skip the repack — so feeding an already-patched ISO
(e.g. from `template patch-win-iso`, or via --win-iso) triggered a wasteful
second extract+repack that double-injected the answer files.

deploy-win now detects a patched input (autounattend.xml present at the ISO
root via `iso_patch.iso_has_root_file`) and uses it as-is, skipping Step 4.
Raw ISOs are still patched once and cached as before.
2026-06-09 20:15:30 +02:00
Simone 3680f07ee3 feat(template): check-win-iso (massgrave resolver) + patch-win-iso
Add `ci template check-win-iso`: parse the massgrave windows-server-links
markdown source on GitHub for the newest Windows Server 2025 build, file
name and link, and report whether it is already in <CI_ROOT>/iso/. The
download itself stays manual — the massgrave link is behind a Cloudflare
Turnstile file host, not scriptable.

Add `ci template patch-win-iso --in ISO [--out ISO]`: standalone equivalent
of deploy-win Step 4 — inject autounattend.xml + post-install.ps1 and a
no-prompt boot image into a manually downloaded ISO, producing a
ready-to-deploy `.patched.iso`.

winimage/massgrave.py does the parse (no auto-download). RUNBOOK §5
documents the check → download → patch → deploy workflow. Coverage 93.6%.
2026-06-09 18:53:04 +02:00
Simone c257c931c3 refactor(deploy-win): drop UUP dump, take ISO via --iso-url / --win-iso
On a Linux host the UUP converter only produces the RTM install.wim (build
26100.1), so Windows Update had to install the entire cumulative anyway —
the UUP download/convert machinery added a slow ~5 GB step and several host
tools (aria2/wimtools/cabextract/chntpw) for no benefit.

Replace it: deploy-win now takes the install ISO directly via `--iso-url`
(urllib download + cache by file name under <CI_ROOT>/iso/, optional
--iso-sha256) or a local `--win-iso` (exactly one required). Patch + deploy
flow is unchanged. Supply an already-updated ISO (e.g. a massgrave link) to
skip the WU step entirely.

- Remove winimage/uup.py and its tests.
- Trim setup-host-linux.sh deps to p7zip-full + xorriso + genisoimage.
- Update RUNBOOK §5 and the Windows-host port plan. Coverage 93.6%.
2026-06-09 18:42:22 +02:00
Simone cd88dec15d feat(prepare-win): add --gui/--nogui flag, default headless
Lets `template prepare-win` start the template VM in the Workstation
window (--gui) for interactive debugging; defaults to headless --nogui.
2026-06-09 00:20:49 +02:00
Simone a0497ffa4e feat(deploy-win): cache the patched ISO, skip repack when inputs unchanged
The ISO repack (extract + xorriso, ~minutes) ran on every deploy. Cache it
per VM dir: store an inputs key (base ISO size+mtime + rendered
autounattend.xml + post-install.ps1) in a `.iso.inputs` sidecar next to
install-noprompt.iso. Step 4 skips the repack when the patched ISO and a
matching sidecar already exist, and re-patches automatically when the base
ISO or either answer file changes.
2026-06-08 23:53:18 +02:00
Simone 6626b25a52 fix(deploy-win): post-install picks VMware Tools CD, not the install ISO
The patched install ISO is mounted as a CD and has setup.exe at its root
(Windows Server Setup). The first-logon CD scan matched it before the
VMware Tools CD and ran `setup.exe /s /v...`, which Windows Setup rejects
("unknown command-line option [/s]"), and copied the multi-GB install
media instead of the Tools payload.

Skip any CD that carries sources\install.wim / install.esd (the OS
installer) and prefer setup64.exe (VMware Tools x64 has it; Windows media
does not) when resolving the Tools setup.
2026-06-08 23:42:24 +02:00
Simone 32d753df3e feat(deploy-win): build the VMX without USB controllers
A headless CI build VM has no USB devices — input is the VMware PS/2
keyboard/mouse + SVGA console. Drop the usb/ehci/usb_xhci controllers from
the generated VMX (one explicit `usb.present = "FALSE"`), trimming device
enumeration at boot. Step 9's usb* line stripping becomes a harmless no-op.
2026-06-08 23:36:29 +02:00
Simone 0df7305841 fix(deploy-win): extract ISO with 7z so no-prompt boot patch works
xorriso -extract reads the ISO9660 name tree, which on a Windows ISO has
no Rock Ridge — names come back upper-cased/truncated, so the
`efi/microsoft/boot/efisys_noprompt.bin` lookup failed ("missing from
ISO") and a repack from that tree would corrupt Windows' long file names.

Extract with 7z instead (reads the UDF/Joliet tree, preserving the real
lower-case paths), excluding 7z's synthetic `[BOOT]` dump. Verified
end-to-end on the cached 26100.32860 ISO: 7z extract → xorriso repack
yields a 5 GB ISO with autounattend.xml + post-install.ps1 at the root and
efisys_noprompt.bin as the UEFI El Torito image (no boot prompt).

Also: cap the Joliet volume id at 16 chars (silence xorriso warning), add
a 7z preflight check, and add p7zip-full to setup-host-linux.sh.
2026-06-08 23:31:18 +02:00
Simone c757e7bec2 docs: document deploy-win + Windows-host port plan
RUNBOOK §1/§5 gain `ci template deploy-win` (UUP determinism, build pin,
--win-iso, tooling + scratch-space notes). Add plans/deploy-win-windows-host.md
describing the deferred cross-platform port (os.name dispatch to oscdimg /
IMAPI2FS shim; deploy-linux seed ISO via oscdimg on Windows).
2026-06-08 23:21:02 +02:00
Simone b83a7fa624 feat(template): add deploy-win — UUP download + ISO patch + deploy WS2025
New `ci template deploy-win` builds the Windows Server 2025 template VM on
the Linux host, mirroring the legacy Deploy-WinBuild2025.ps1 ten-step flow
in Python:

- winimage/uup.py: resolve the newest (or pinned) WS2025 build via the
  uupdump API and build a cached, MS-signed ISO via the uup converter.
- winimage/autounattend.py + assets/: render autounattend.xml and the
  guest post-install.ps1 (ported from the PS heredoc; VMware Tools now
  mounted as a 2nd CD, scanned at first logon).
- winimage/iso_patch.py: xorriso repack injecting the answer files at the
  ISO root and swapping the EFI boot image to efisys_noprompt.bin
  (no "press any key" prompt — essential for an unattended headless install).
- commands/template.py: the deploy-win command + _winbuild_vmx_lines
  (the 82-key VMX), _remove_vmx_lines, _wait_install_flag, _vmrun_soft_stop.
  Acquire → patch → VMDK → VMX → install → flag wait → strip media +
  NIC e1000e→vmxnet3 → verify IP → cold snapshot.

Deterministic by build (--build), with --win-iso to bypass UUP. Tests
mirror the prepare-win mocking style; total coverage 93%.
2026-06-08 23:21:02 +02:00
Simone 976c4b1cae chore(setup): install Windows-image tooling for deploy-win
Add aria2 + wimtools (wimlib-imagex) + xorriso + genisoimage + cabextract
+ chntpw to setup-host-linux.sh (Step 3) — the UUP dump → ISO conversion
and the no-prompt ISO repack that `ci template deploy-win` needs. Also
create the <CI_ROOT>/iso cache dir in the layout step.
2026-06-08 23:21:02 +02:00
Simone 11daad8a91 docs(runbook): make §4 manual lifecycle copy-paste-correct
Verified the whole §4 chain end-to-end on the live host and fixed every
break:

- Capture the clone VMX from `vm new` stdout into $VMX and the guest IP
  via `vmrun getGuestIPAddress` into $IP, then reuse both downstream.
  Removes the fragile `Clone_dbg-1_*` globs that broke when more than one
  clone shared a job-id ("unexpected extra argument").
- §4.3: `build run` does not inject the Gitea PAT (only `job` does), so the
  private burnin-dummy repo can't be cloned in-guest. Use --host-source-dir
  against the local copy instead.
- §4.4: collect from /opt/ci/output (where build run stages the artifact),
  not the `dist` source dir — the old path failed with "tar: dist: Cannot
  open".
- §4.1 now boots with --gui (manual debugging); §4.7 reuses $VMX.

Confirmed green: vm new → wait-ready → build → collect (build-info.txt +
manifest.json) → vm remove, and the §3 `job` pipeline (SUCCESS in 66s).
2026-06-08 22:10:18 +02:00
Simone d10973c467 feat(vm): add --gui/--nogui to vm new --start, default headless
Mirror the `job` flag on the manual lifecycle: `vm new --start` was
hardcoded headless; add --gui/--nogui (default --nogui) so a clone can be
booted into the Workstation GUI window for interactive debugging. The
start banner reflects the mode.

Also update the runbook: §4.1 shows the --gui variant, and §3 notes that
the burnin-dummy build.sh is a ~30s fake build writing dist/build-info.txt
so the examples exercise the full pipeline.
2026-06-08 21:54:47 +02:00
Simone 0a8398aebf docs(runbook): use burnin-dummy repo in job/build examples
Switch the §3 and §4.3 examples to Simone/burnin-dummy (the canonical
burn-in test repo): `bash build.sh` (fake ~30s build) producing a `dist/`
artifact, so the examples exercise a real build + artifact collection end
to end.
2026-06-08 21:48:06 +02:00
Simone bfc63906a1 docs(runbook): show --gui variant in §3 job example 2026-06-08 21:46:38 +02:00
Simone b317a8bf4c feat(job): add --gui/--nogui flag, default headless
The Phase-2 VM start was hardcoded to headless. Expose a --gui/--nogui
toggle (default --nogui, preserving current behaviour); --gui starts the
clone with the Workstation GUI window (needs an X display, see §4.7). The
phase banner now reflects the chosen mode.
2026-06-08 21:45:49 +02:00
Simone cfce307c5b docs(runbook): use a real repo in job/build examples
Replace the non-existent myrepo.git placeholder (which fails with
"repository not found") with this repo's URL and a harmless
`echo build-ok` build command, so §3 and §4.3 run as pasted.
2026-06-08 21:43:34 +02:00
Simone 9ecb767b18 docs(runbook): fix §3 job example — required template flags
The `job` command enforces --template-path (job.py:447) and defaults
--snapshot-name to BaseClean, which is wrong for Linux. The §3 example
omitted both and failed with "--template-path is required". Add both
flags (BaseClean-Linux) and note them as required.
2026-06-08 21:37:24 +02:00
Simone 027e2ff4b6 docs(runbook): rewrite Phase C runbook for clarity
Replace the terse, abbreviation-heavy style with clean prose and
consistent formatting. Make command blocks copy-paste-ready on this host:
capture the guest IP into a shell variable for `validate guest` / `build
run`, expand globbed VMX paths, and group the `job` flags into readable
lists. Add intra-doc anchor links throughout. Point the pwsh-rollback note
at scripts/archived/. No commands or flags changed.
2026-06-08 21:31:25 +02:00
Simone c274d334d3 docs(agents): point PS→Python map at scripts/archived/
The shim mapping table now notes the .ps1 live in scripts/archived/
(frozen, lint-exempt, no live caller) and gains the Phase C host tools
(bench/smoke/validate host/creds set). Fix the "stays in PowerShell"
list: drop Test-CapacityBurnIn (archived) and the non-existent
Measure-CIBenchmark; keep retention/backup/template/e2e/Windows-side.
2026-06-08 21:26:07 +02:00
Simone 7f615333b6 docs(runbook): add guest IP discovery to §2
Document `vmrun getGuestIPAddress` (run as ci-runner) for templates and
clones as the prerequisite for `validate guest`, with the AGENTS.md #1
"Error: on stdout" gotcha. Update the validate-guest Linux example to the
live template IP.
2026-06-08 21:26:07 +02:00
Simone 0b0d5486f0 chore(scripts): archive PowerShell scripts superseded by the Python CLI
Move 16 .ps1 files to scripts/archived/ — they have no live caller:

- 10 pure shims (New-BuildVM, Remove-BuildVM, Cleanup-OrphanedBuildVMs,
  Wait-VMReady, Invoke-RemoteBuild, Get-BuildArtifacts, Watch-DiskSpace,
  Watch-RunnerHealth, Get-CIJobSummary, Invoke-CIJob) that only forwarded
  to `ci_orchestrator`; the live Gitea composite action now calls
  `python -m ci_orchestrator job` directly.
- 6 Phase-C host tools reimplemented natively in Python (Start-BurnInTest
  [+ -Linux], Test-CapacityBurnIn → bench; Test-Smoke → smoke run;
  Validate-HostState → validate host; Set-CIGuestCredential → creds set).

Add scripts/archived/README.md mapping each file to its `ci` replacement,
and exempt scripts/archived/ from the PSScriptAnalyzer lint job.

Kept (still used / not yet ported): Register-CIScheduledTasks,
Backup-CITemplate, Invoke-RetentionPolicy, Set-TemplateSharedFolders,
Test-CIGuestWinRM, the e2e build harnesses, and all template/ guest
provisioning scripts.
2026-06-08 21:15:05 +02:00
Simone cda4276d9e docs(runbook): document persistent xhost grant for vmware GUI
§4.7 now explains the grant is per-session and points to setup Step 8 /
the standalone install-vmware-gui-access.sh, keeping the manual one-off
xhost command as a fallback.
2026-06-08 21:11:07 +02:00
Simone 3f43b1ca12 feat(setup): persist ci-runner X grant for ci vmware GUI
`ci vmware` runs as ci-runner and relies on host-based X auth (xhost),
but the grant is per-session and wiped on logout / X restart, so the GUI
launch fails with "cannot open X display" after every desktop relogin.

Add scripts/install-vmware-gui-access.sh: installs an XDG autostart entry
in the desktop user's home that re-applies `xhost +SI:localuser:ci-runner`
at each graphical login, and applies it immediately when a display is
reachable. Desktop user resolves from --desktop-user / $CI_DESKTOP_USER /
$SUDO_USER (never root); service user from $CI_RUN_USER. --uninstall
removes the autostart entry and revokes the live grant.

Wire it into setup-host-linux.sh as Step 8, with --desktop-user (default
$SUDO_USER) and --skip-gui-access for headless hosts.
2026-06-08 21:11:07 +02:00
Simone de5348c36c refactor(cli): rename vmgui command to vmware
Rename the GUI launcher command from `vmgui` to `vmware` (`ci vmware ...`).
Updates the click command name, function, log-file prefix, __main__
registration, tests and runbook references. Behaviour unchanged.
2026-06-08 00:32:13 +02:00
Simone b74e854d48 docs(vmgui): clarify it works like sudo -u ci-runner vmware
The GUI connects via the X host ACL (xhost), not the inherited XAUTHORITY
cookie (unreadable by ci-runner). On a normal session the grant is already
present and `ci vmgui` works with no --display/xhost dance — sudo forwards
DISPLAY. xhost is only needed if you hit "cannot open X display". Drop the
overstated "--display :0 required" framing from §4.7.
2026-06-08 00:30:21 +02:00
Simone 23b5858802 Merge branch 'fix/vmgui-x-display' (vmgui: X preflight, no silent failure) 2026-06-08 00:26:14 +02:00
Simone 41d646577d fix(vmgui): pre-flight X display, stop failing silently
`vmgui` sent the child's stderr to /dev/null, so when the X display was
unreachable (the common case: sudo -u ci-runner loses the desktop user's
XAUTHORITY and xhost wasn't granted) the GUI died with "cannot open display"
and the command still printed success — "nothing opens".

Now it:
- pre-flights the display with xdpyinfo and aborts with the exact
  `xhost +SI:localuser:ci-runner` hint instead of spawning a doomed process;
- drops an inherited XAUTHORITY that this user can't read (falls back to
  host-based xhost auth);
- logs the GUI's stdio to /tmp/vmgui-*.log and grace-polls 1.5s, surfacing the
  log if the GUI exits immediately;
- errors (non-zero) when no DISPLAY is resolvable.

Runbook §4.7 updated with the "if nothing opens" guidance. 13 tests; green ≥90%.
2026-06-08 00:25:37 +02:00
Simone b612ea9d2c Merge branch 'feat/vm-open-no-vmx' (vmgui: GUI launcher, optional VMX) 2026-06-08 00:16:54 +02:00
Simone 41d64fc212 feat(vmgui): GUI launcher command, VMX optional
Add top-level `vmgui` to open the VMware Workstation GUI (renamed from the
earlier `vm open`). --vmx is optional: with it the GUI opens that VM, without
it the GUI starts bare. Power-on/fullscreen flags ignored (with a notice) when
no VMX is given. Needs an X display — sudo -u ci-runner strips $DISPLAY, so
--display / xhost; see runbook §4.7. 9 tests; suite green ≥90%.
2026-06-08 00:16:50 +02:00
Simone dc06a560d8 Merge branch 'feat/phase-c-runbook-tooling' (vm open + ci alias + manual runbook) 2026-06-08 00:12:01 +02:00
Simone 60c829887c docs: add complete manual CLI runbook (all commands + ci alias + vm open)
Rewrite docs/RUNBOOK-PhaseC.md as a full manual-command reference: every
ci_orchestrator command with a working example as the ci-runner user, the `ci`
alias setup, quick-reference table, manual VM lifecycle (incl. vm open GUI
launch with the xhost/--display procedure), templating, maintenance, Phase C
testing, cutover checklist and a troubleshooting map.
2026-06-08 00:11:36 +02:00
Simone 22b1b797d0 feat(setup): add ci shell alias helper + install it from setup-host
scripts/install-ci-alias.sh installs `ci` (runs the orchestrator as ci-runner
via the prod venv) and `ci-me` (current user). Idempotent, marker-bounded;
supports --system (/etc/profile.d), --uninstall. setup-host-linux.sh gains a
step [7/7] that installs it system-wide, passing CI_PROD_PYTHON/CI_RUN_USER.
2026-06-08 00:11:36 +02:00
Simone cac38f7c0c feat(vm): add vm open to launch the VMware Workstation GUI
Open a VMX in the interactive Workstation GUI (not the headless vmrun path) for
hands-on debugging of a clone. Spawns `vmware` detached (own session, stdio
detached) and returns the child PID.

Flags: --vmx (required), --power-on (-x), --fullscreen (-X), --new-window (-n),
--display (sudo -u ci-runner strips $DISPLAY, so allow forcing it),
--vmware-path. Warns when no X display is set. 7 tests; vm.py 96%.
2026-06-08 00:11:36 +02:00
Simone 07053c993f Merge branch 'feat/phase-c-powershell-removal' (Phase C: pwsh-free Linux host) 2026-06-07 20:16:41 +02:00
Simone 10e7240a70 docs: record Phase C cutover; close $IsWindows shim bug (Phase C9)
- CLAUDE.md: Linux host no longer runs pwsh; PS 5.1 constraints scoped to
  Windows guests + Windows runner.
- RUNBOOK: add "Phase C — Python equivalents" table; §6-§13 benchmark records
  kept as historical provenance.
- TODO §3.7: close $IsWindows shim bug (resolved-by-replacement — bench run
  bypasses the shim).
- plans: mark C1-C8 done + docs C9; flag operational cutover/uninstall pending.
2026-06-07 20:15:10 +02:00
Simone af1960bbf3 feat(setup): make pwsh opt-in on the Linux host (Phase C8)
Invert step 6 default: pwsh is no longer installed. Add --with-pwsh to opt in;
keep --skip-pwsh as a deprecated no-op alias. Update usage/help.
2026-06-07 20:15:10 +02:00
Simone a697491d4f ci(lint): move PSScriptAnalyzer off the Linux runner (Phase C7)
Apply analysis §4 option 1: pssa job runs on windows-build with
shell: powershell, gated to workflow_dispatch so push/PR don't queue it when
no Windows runner is registered. The python job stays on linux-build. No job
on a Linux runner uses pwsh anymore.
2026-06-07 20:15:10 +02:00
Simone 799e8a755e chore(scripts): retire PS benchmark modules superseded by bench (Phase C3)
Remove _Common.psm1, _Transport.psm1 and their Pester test, plus their sole
consumer Measure-CIBenchmark.ps1 — all replaced by `bench measure`. Leaving
the script would dangle an Import-Module on a deleted .psm1.
2026-06-07 20:15:10 +02:00
Simone 575cc81b8f feat(cli): port burn-in/smoke/validate/creds to Python (Phase C1-C6)
Add four native command groups so the Linux host no longer needs pwsh for
manual ops. __main__ registers all four at once, so they ship together.

- bench run     (C2): N concurrent jobs in-process via concurrent.futures,
                      per-round orphan-clone + stale-lock assertions. Replaces
                      Test-CapacityBurnIn.ps1 + Start-BurnInTest*.ps1. No
                      Start-Job/pwsh/$IsWindows.
- bench measure (C3): clone/start/IP/transport/destroy timings appended to
                      benchmark.jsonl (legacy field names kept). Replaces
                      Measure-CIBenchmark.ps1.
- smoke run     (C4): one E2E job; asserts exit 0 + artifact dir + job/success
                      event. ns7zip/nsinnounp presets. Replaces Test-Smoke.ps1
                      + Test-*Build-Linux.ps1.
- validate host (C5): vmrun/snapshot/keyring/permissions/systemd checks.
- validate guest(C6): transport probe with explicit failure cause.
- creds set     (C6): keyring writer matching credentials.py read scheme;
                      password via stdin/prompt only. Replaces
                      Set-CIGuestCredential.ps1.

All groups import backends.load_backend only (Phase D ESXi path stays open).
Suite green, coverage 95.10% (gate 90%); new modules at 100%.
2026-06-07 20:15:10 +02:00
Simone 0bc88c66b7 chore(plans): archive completed Phase B docs
Phase B is closed (checklist Passi 1–9 [x], benchmark matrix §6–§14
recorded). Move the two finished working docs into the dated archive:

  plans/PhaseB-user-checklist.md   → plans/archived/2026-06-07/
  plans/benchmark-windows-host.md  → plans/archived/2026-06-07/

plans/ now holds only the forward-looking plans (idea-3 Phase C pwsh
removal, idea-4 Phase D ESXi, ideas-overview). Fixed the live links that
pointed at the moved/relocated files: idea-3 §4, idea-2 §8 (relative path),
and ideas-overview (idea-1/idea-2 now under archived/, Phase A+B marked ✅).
2026-06-07 19:41:24 +02:00
Simone fce03be201 docs: close Phase B Passo 9 — dual-boot procedure (RUNBOOK §15)
RUNBOOK §15: dual-boot operation — Linux⇄Windows switch procedure, per-OS
CI-stack table (roots/runner/vmrun), current GRUB behaviour (DEFAULT=0,
TIMEOUT=0 hidden → boots straight to Linux), post-boot verification commands
for both OSes, and an optional GRUB tweak (left unapplied — boot-to-Linux is
intentional so the box returns as the Linux CI host after any unattended
reboot).

Checklist: Passo 9 done; fixed the stale global tracking table (Passi 6–9
were still [ ] despite being complete). Phase B is now fully closed (1–9 [x]).
2026-06-07 19:38:32 +02:00
Simone 5dd151fdf8 docs(plans): rename idea-3-esxi-support → idea-4 (fix name collision)
idea-3- prefix was shared with idea-3-powershell-removal.md; rename the ESXi
idea to idea-4-esxi-support.md and update the ideas-overview link. Pure rename,
content unchanged.
2026-06-07 14:06:30 +02:00
Simone b31d6b61b8 docs(todo): track WinRM 4× concurrency instability + shim $IsWindows bug
§3.6: Windows-host WinRM loses jobs under sustained 4× concurrency (burn-in
§13 Win 36/40, rounds 6–8); mitigations noted (vCPU/parallelism, pypsrp
timeout+retry). §3.7: Invoke-CIJob.ps1:37 derefs $IsWindows, undefined on
Windows PowerShell 5.1 + StrictMode — throws unless CI_VENV_PYTHON is set.
2026-06-07 14:06:21 +02:00
Simone 34635a3996 docs(benchmark): record Windows-host §11–§14 + plan closeout
§11 Win-guest static (boot 29.75s, +24% vs Linux-host §8; static-IP floor
~22s confirmed host-independent), §12 Lin-guest DHCP (13.51s, +53%), §13
burn-in 4×10 (Win 36/40 — transient WinRM faults under 4× concurrency,
self-recovered; Lin 40/40). §14 adds the full host×guest×IP-mode matrix.
Plan checkboxes filled with results and the template-parity pre-req note.
2026-06-07 14:06:13 +02:00
Simone 85d1158ba4 docs(baseline): add raw benchmark output for Windows host baseline
Raw Measure-CIBenchmark.ps1 output captured 2026-05-18; supports
the B7 ±20% comparison criterion documented in RUNBOOK.md.
2026-06-07 11:30:20 +02:00
Simone 752600ef5a docs(bridge): Phase A→B bridge checklist completed
All sections done: SSH keys, BuildVMGuest password, Gitea PAT,
OpenSSH Server, template powered-off verification, CI backup.
Fixed errata: .vmsn always present (not error indicator), backup
switched from Git tar to 7z LZMA2, removed scheduled-task section
(no CI-* tasks exist on this host).
2026-06-07 11:30:20 +02:00
Simone f0361df0a5 docs(runbook): record Windows host pre-migration baseline
Phase A benchmark data (2026-05-17): VM lifecycle avg 60.6s boot,
smoke job avg 27s Win / 49s Linux, 100% success rate (12/12 burn-in).
B7 reference thresholds: Win ≤32s, Linux ≤59s.
2026-06-07 11:30:20 +02:00
Simone 3c0470351b docs: Linux-guest benchmark (RUNBOOK §10) + Windows-host benchmark plan
§10: single-job Measure-CIBenchmark on LinuxBuild2404 (DHCP, 10 iter) on the
Linux host — boot total 8.82s avg, near-deterministic even on DHCP (IP-acquire
7.45s, σ≈0.01). Guest-vs-guest table: Linux guest ~63% faster boot total than
the Windows static-IP guest (§8) on the same host.

plans/benchmark-windows-host.md: dual-boot plan to collect the symmetric
Windows-host numbers (§11 Win static, §12 Linux DHCP, §13 concurrent burn-in)
so the host×guest×IP-mode matrix is complete and Linux-vs-Windows is a
column-for-column comparison. Includes Windows paths, Credential Manager
prereqs, and the BaseClean-Linux snapshot caveat.
2026-06-07 01:57:16 +02:00
Simone 8db927f843 docs: close Phase B (B7 concurrent burn-in PASS + B8 stability)
Concurrent capacity burn-in run on the Linux host as ci-runner with the
static-IP pool: WinBuild2025 40/40 PASS (~78.6s/round) and LinuxBuild2404
40/40 PASS (~70.2s/round) — 80/80 jobs, 20/20 rounds, near-deterministic
(static IP eliminates the DHCP IP-acquire variance of the §6/§7 baselines).

- RUNBOOK §9: concurrent burn-in result + ip-pool reset/recovery note.
- PhaseB-user-checklist Passo 7/8 marked done; fixed two checklist bugs:
  run as ci-runner (the simone path needs g+w on the /var/lib/ci root for
  ip-pool.tmp, not just the sub-dirs), and the Linux command was missing
  -SnapshotName BaseClean-Linux (default BaseClean is Windows-only).
- idea-2-linux-host §8 DoD: Phase B complete (B1–B7 + >2 weeks stability).
- TODO §2.8 [P2]: ip-pool is not reconciled against live clones; a killed
  job leaks its lease permanently and exhausts the 4-IP pool. Proposed fix.
2026-06-07 01:44:56 +02:00