docs truth pass
Every checkable claim in the user-facing docs, walked against the build and
marked β or β (#233). This file is a dated record of a pass, not a live
status page: it says what was true on a given commit and what was done about
what wasn't. The live enforcement is tests/unit/docs-truth.bats, which turns
each β found here into a test so the same drift fails CI instead of a reader.
Pass 1 β 2026-09-02, against 94025c5β
Scope: README.md, docs/getting-started.md, docs/user-guide.md,
docs/manual-testing.md, docs/branded-walkthroughs.md, docs/branding.md,
docs/branding-and-distribution.md, docs/RELEASING.md.
Method: static β every claim checked against the shipping source (Go,
frontend JS, workflows, images.json, brand.json), with the two
channel-dependent behaviours confirmed by running the real resolvers
(effectiveBranding(), GetSupportPolicy(), GetImages()) rather than
reading them. Not a VM walk; see Still open below for what that leaves.
β Found and fixed (9)β
| # | Where | Claimed | Actually |
|---|---|---|---|
| 1 | getting-started.md Β§4 | first screen reads "Try Linux alongside Windows β no repartitioning, nothing deleted, and fully undoable" | reads "Bring Windows to Linux β keep everything." The quoted string is the JS fallback in launchpad.js, and defaultBranding() always sets a tagline β so the fallback is unreachable in every build |
| 2 | manual-testing.md bug-report table | installer state at C:\wootc\install\state.json | C:\wootc\state.json (app/state.go). C:\wootc\install\ does exist (wifi/, slurp/), which is why the wrong path read as plausible |
| 3 | manual-testing.md Β§Before you start | "The app refuses to start on battery" | the app opens; it disables Install with "Plug in the power adapter first" β and only when a battery is actually detected (onBattery && batteryKnown), so a desktop is never blocked |
| 4 | user-guide.md footer | loop "verified end-to-end on real hardware (UEFI + Secure Boot + TPM 2.0)" | evidence is the KVM VM rig (status.md). Real-hardware evidence is the unmet v0.2.0-alpha gate in ROADMAP.md |
| 5 | RELEASING.md Β§User instructions | instructions shipped in "the release notes / INSTALL.md" | no INSTALL.md exists anywhere in the tree |
| 6 | RELEASING.md | "The published artifact is wootc.exe" | release.yml publishes one exe per brand plus deployer-vmlinuz, deployer-initramfs.img, shimx64.efi, grubx64.efi, mmx64.efi, best-effort wubildr.efi, and SHA256SUMS |
| 7 | README.md "What you get", user-guide.md Β§1 and Β§7 | "BitLocker-safe", "BitLocker is fine too", "wootc offers to put Linux on an unencrypted partition" | BitLockerSupported: false on alpha and beta; gateScenario() hard-refuses and the Install button is disabled. manual-testing.md and RELEASING.md already said so β the user guide contradicted them, and a BitLocker reader would have downloaded and hit a wall the guide said was not there |
| 8 | user-guide.md Β§2 | "The default (Yellowfin GNOME)" | main.js pre-selects images[0]; in alpha GetImages() returns green images in file order, so the default is Bluefin LTS β which RELEASING.md Β§Alpha already named |
| 9 | user-guide.md Β§4 | the "Bring your setup over" dashboard | the app calls it "Bring Over From Windows" (wootc-manifest.desktop, wootc-manifest-gui). That label existed nowhere in the product |
Also aligned, having found the docs disagreeing with each other and with the
code: the free-space figure. The launchpad gates on maxDiskSizeGB() < 20
with DISK_HEADROOM_GB = 15, i.e. 35 GB; user-guide.md and
RELEASING.md both said "~40 GB" while manual-testing.md said 35.
β Checked and correct (spot-check, not exhaustive)β
Paths β C:\wootc, C:\wootc\disks\root.disk, C:\wootc\logs\,
C:\wootc\logs\deployer.log, C:\wootc\logs\deployer-last-journal.log,
C:\wootc\channel.txt, C:\wootc\brand.json, C:\wootc\brand.css,
C:\wootc\bundle\oci.
Registry β the Add/Remove entry is TunaOS (wootc) for the generic build
(displayName = b.Name + " (wootc)"), as getting-started.md,
user-guide.md Β§9 and manual-testing.md all say.
Commands and env β wootc.exe uninstall, winget install TunaOS.wootc,
WOOTC_PRELOAD=1, WOOTC_CHANNEL, wootc.debug, just test, just build,
npx playwright test.
Channel behaviour β default channel alpha; alpha offers green images
only, no custom OCI refs, no BitLocker; the alpha image is
ghcr.io/projectbluefin/bluefin:lts; images.json carries
"status": "green" | "experimental" as RELEASING.md describes.
On-screen strings β "Restart into <distro> β", "Also delete my Linux data", "Make it feel like Windows", the disabled-Install reasons.
Exe names β Bazzite-Installer, Bluefin-Installer, Aurora-Installer,
TunaOS-Installer all match their brand.json exeName, and the docs
advertise no exe that no brand builds.
Links and images β every relative .md/.png link in the scoped docs
resolves; all 20 branded walkthrough screenshots and all 12 GUI walkthrough
screenshots are present.
Catalog β GNOME / KDE Plasma / Niri / XFCE on el10 / fedora / arch / debian, as README and the user guide describe.
Still open β needs the RC build and a VMβ
These are not β and were not claimed as such. They cannot be settled from a checkout, and the issue's done-when depends on them:
- Walk each doc against an actual RC build in a Windows VM.
- Timings: "5β15 minutes on a fast line", "30β60 minutes on a slow connection", "a few minutes". Measured, not asserted.
- SmartScreen behaviour post-signing. Every SmartScreen and "unknown
publisher" paragraph is written for unsigned binaries. Signing is a 1.0
criterion in
ROADMAP.md; when it lands,getting-started.mdΒ§2β3,README.mdandRELEASING.mdΒ§1 all change together. - Add/Remove rendering β that
TunaOS (wootc)is what Settings shows, not just what the installer writes. - Regenerate every screenshot from the RC SHA. Deliberately not done
here: the GUI and branded sets regenerate from the Playwright suites and
the timelapse comes from the nightly, so regenerating them from
mainwould date them to the wrong build. They must be dated from the RC.
Code observation, left aloneβ
launchpad.js renders state.brand?.tagline || '<long fallback>'. No build
can reach that fallback β defaultBranding() sets a tagline and every
brand.json overrides it β and finding β1 means it has already misled a
reader once, via a doc that quoted it. Removing it is a frontend change and
was out of scope for a docs pass; docs-truth.bats now pins the doc to the
real brand.json tagline instead, so the two cannot drift again.