mirror of
https://github.com/felixrieseberg/windows95.git
synced 2026-05-09 00:24:09 +00:00
* Rewrite update-v86.js for the current build pipeline Both v86 fixes we've been carrying are now real branches on the fork (PR #1540 electron-renderer-fs-loader, PR #1541 ide-shared-registers) combined as felixrieseberg/v86:windows95-base. update-v86.js no longer needs to patch sources at build time — it just builds whatever's checked out and copies the result. Gone: the fallback-to-copy.sh path, the skew-day check, the structural regex patches for load_file/exportSymbol/fetch-bind, the phantom-slave guard (both are in the branch), the --js-only flag. If you don't have cargo/clang/java/closure, the script fails loudly — no silent fallbacks. Added: sanity checks against the installed libv86.js for the invariants our SMB integration and parcel-build shim depend on, so if upstream changes something load-bearing we see it as a WARN at update time instead of a runtime failure. Tested end-to-end: 5/5 sanity checks, fresh boot SUCCESS in 32s. * docs and skills: capture SMB/v86/testing knowledge from the session - docs/smb-share.md: user-facing SMB integration overview (how to mount in Win95, what's implemented, what's not). Points at the protocol-level README inside src/renderer/smb/ for wire-level gotchas. - .claude/skills/probe-win95: how to boot and test the VM without a human. Env vars, file locations, failure modes, the XT scancode keyboard trick, bisect rules of thumb. - .claude/skills/update-v86: how to pull upstream v86 changes, what the five sanity-check WARNs mean, how to retire the fork branches when the PRs merge upstream. .gitignore narrowed to exclude only the runtime dirs (scheduled_tasks.lock, worktrees) instead of the whole .claude/ tree, so skills can be committed.
5.1 KiB
5.1 KiB
name, description
| name | description |
|---|---|
| probe-win95 | Boot Windows 95 in Electron under Claude's control, without a human clicking anything. Use when testing v86 updates, SMB changes, keyboard input, boot stability, or bisecting regressions. |
Probing Windows 95 autonomously
You can run and test the Win95 VM yourself. The harness is already wired up — three pieces:
| File | Role |
|---|---|
src/renderer/debug-harness.ts |
Activated by WIN95_PROBE=1. Boots fresh automatically, samples CPU + VGA + text screen every 5s, writes /tmp/win95-probe.json + /tmp/win95-screen.png, detects SUCCESS vs FAIL modes, optionally drives keyboard input. |
src/renderer/smb/index.ts |
Wraps console.log so [smb] and [nbns] lines tee to $TMPDIR/windows95-smb.log (outside Electron, readable by any polling script — no CDP needed). |
tools/probe-boot.sh |
One-shot: kill leftovers → parcel build → launch Electron → poll /tmp/win95-probe.done → report → kill. |
One-shot boot test
tools/probe-boot.sh
Prints SUCCESS or a FAIL verdict. ~40s on a clean run.
Boot + type into Run
pkill -9 -f "windows95.*electron"; sleep 2
rm -f "$HOME/Library/Application Support/windows95/state-v4.bin"
rm -f /tmp/win95-probe.json /tmp/win95-probe.done \
"$TMPDIR/windows95-smb.log"
WIN95_PROBE=1 \
WIN95_PROBE_SCRIPT='HOST/HOST' \
WIN95_SMB_SHARE="$HOME/Downloads" \
./node_modules/.bin/electron . > /tmp/win95-electron.log 2>&1 &
WIN95_PROBE_SCRIPT='HOST/HOST' types \\HOST\HOST into Start → Run on
desktop. / → \ substitution (env var / shell quoting, pragmatism). The
harness drives it via XT scancodes — Win95 doesn't have Win+R (Win98+
only), so the sequence is Esc, Esc, Ctrl+Esc, R, backslashes + text,
Enter.
Reading results
| File | What |
|---|---|
/tmp/win95-probe.json |
Live status: phase (init/text-mode/splash/desktop), gfxW/H, textScreen, instructionDelta, verdict |
/tmp/win95-probe.done |
Written once when verdict is decided |
/tmp/win95-screen.png |
Canvas screenshot, refreshed each tick |
$TMPDIR/windows95-smb.log |
SMB/NBNS protocol trace |
/tmp/win95-electron.log |
Electron stderr |
Verdicts
| Verdict | Meaning | Action |
|---|---|---|
SUCCESS |
Canvas ≥640×480, CPU active, uptime >30s | desktop reached |
FAIL_VXDLINK |
"Invalid VxD dynamic link call" | flaky — retry |
FAIL_IOS / FAIL_PROTECTION |
IOS subsystem protection error | usually driver/BIOS mismatch |
FAIL_KRNL386 |
"Cannot find KRNL386.EXE" in safe mode | disk reads returning garbage — wasm/BIOS drift |
FAIL_SPLASH_HANG |
Canvas stuck 320×400 for >70s | IRQ starvation — if you're on v86 master, check the IDE register fix |
FAIL_HUNG |
CPU stopped advancing or text screen frozen 40s | hard hang |
Rules of the road
- Sporadic bluescreens are normal on all v86 versions. One FAIL_VXDLINK or FAIL_HUNG doesn't prove anything — retry up to 3×.
- Always clean state (
state-v4.bin) before a probe.pkillon a wedged Electron triggersonbeforeunload, saving the corrupted state. Deleting it forces fallback toimages/default-state.bin. - Don't trust the text buffer in graphics mode. After desktop (≥640×480)
the stale BIOS text lingers in the buffer. The harness's
phasefield accounts for this; don't re-readtextScreenin adesktopphase and think you hit a BSOD. - Kill Electron when done. Background processes pile up, each holding
the disk image lock.
pkill -f "windows95.*electron"on every path out.
Bisecting v86
tools/bisect-v86.sh <commit> handles one step. The harness retries 3×
per commit. Hard-won lessons:
- Validate bounds against a known-good binary. Source-built wasm can drift from prod due to cargo/rustc version differences. We hit this: the "GOOD" bound produced a wasm that couldn't read the disk at all.
- JS-only when toolchain drifts. Keep the prod wasm, rebuild only libv86.js at each commit. Closure is deterministic enough; cargo isn't always. Works until you cross a commit that changes the JS↔wasm ABI (for v86, the APIC→Rust port in Aug 2025).
- Retry on FAIL, never on SUCCESS. One SUCCESS = commit is good. Three different FAILs at the same commit = commit is bad.
- State cleanup between runs (see above). Skipping this is the #1 cause of spurious "bad" verdicts during bisect.
Extending the harness
- New verdicts: add to the chain in
collectStatusindebug-harness.ts - New keyboard actions: extend
runScript(current types:keys,chord,text,wait) - New probe signals: add to
ProbeStatusinterface
Gate everything new on process.env.WIN95_PROBE === "1" so it stays out
of the normal app.
Common failure diagnostics
| Symptom | Check |
|---|---|
| No SMB traffic at all | $TMPDIR/windows95-smb.log should have hooked adapter line. If absent, v86 API changed — see src/renderer/smb/README.md |
| SMB hooks fire, no connection | Win95's "NetBIOS over TCP/IP" checkbox — bake into default-state.bin |
Boot hangs on 2996c087 or older v86 |
You probably have a ABI-mismatched wasm/JS pair. Prod wasm is the ground truth; rebuild JS against it. |