Files
Classroom_Desktop/docs/testing.md
T
ekklesiaandClaude Opus 5 52301084a5 feat: an external-only display mode, chosen rather than inferred
The women's Bible study laptop is a fixed appliance: AC power, battery
out, lid shut, one television on HDMI. Its own panel should be off.

DISPLAY_MODE=external-only says so, and it is a setting rather than
something inferred from having a lid, because another laptop may want its
own screen or both. Nothing reads DEVICE_TYPE to decide it.

The built-in panel is identified by kscreen's output TYPE — 7 is Panel —
rather than by connector name. Matching "eDP-1" would be matching one
machine's spelling: eDP, LVDS and DSI are all internal, numbered
differently per driver and renamed between kernel versions. The names are
kept only as a fallback for a driver that reports no type, which some
virtual devices do.

One rule overrides the setting: never leave the machine with no screen. A
laptop asked for external-only whose television is off keeps its own
panel and says so in the journal. A machine nobody can see is one nobody
can fix standing in front of it, and it corrects itself the next time
this runs with the set on. Only the outputs that are not already right
are touched, so a television power cycle is not a stream of mode sets.

Applied at login from an autostart entry named to sort before the scale
one, so the scale lands on the displays this leaves enabled.

The lid itself needed no new code — logind ignores every lid event,
PowerDevil's lidAction is 0 in all three profiles with
triggerLidActionWhenExternalMonitorPresent=false, the profiles are
immutable and the classroom account cannot reach suspend through polkit.
That was all already true for towers. What was missing was a test saying
so, and there is one now, because it is the property the laptop depends
on and nothing would have noticed it regressing.

KNOWN LIMITATION, and it is written into docs/testing.md rather than left
to be discovered: the mode is applied at login, not continuously. If KWin
re-enables the internal panel when the television is power cycled, it
stays enabled until the next login. The lab has no lid and no HDMI
hotplug, so this cannot be settled here; the physical procedure says to
check it specifically, because the answer decides whether the follow-up
needs an event-driven applier like the audio policy's.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 21:17:06 -05:00

404 lines
18 KiB
Markdown

# Classroom test checklist
Run against the exact artifact published to canary, on the real endpoint,
before promoting to stable with `./update_stable.sh`.
## Boot
- [ ] Cold boot reaches the classroom shell with no terminal or window junk
- [ ] Reboot does the same
- [ ] Wallpaper appears
- [ ] Dock appears, centred
- [ ] Clock appears, bottom right
## Provisioning
- [ ] `journalctl -u ekklesia-classroom-provision` shows a clean run
- [ ] Google Chrome is installed on a machine that never had it
- [ ] A second boot does not reinstall anything
- [ ] A machine with no network still boots to a working shell, and
provisioning succeeds at a later boot once it is online
## Networking
- [ ] `nmtui` is installed and `NetworkManager.service` is enabled
- [ ] An Ethernet interface declared in `/etc/network/interfaces` remains
managed by ifupdown and keeps its existing address
- [ ] `sudo nmtui` can save and activate a Wi-Fi connection
- [ ] The saved Wi-Fi connection reconnects after reboot
- [ ] A machine with no Wi-Fi adapter reaches the classroom normally without
an online-wait delay or NetworkManager failure
- [ ] Ethernet-only operation is unchanged
## Printing
- [ ] `cups.service` is enabled and `lpstat -r` reports that the scheduler runs
- [ ] `lpinfo -m` contains the generic color PCL 6/PCL XL driver documented in
[printing.md](printing.md)
- [ ] `sudo classroom-printer-setup` creates only `Elmer`, enables it, and
makes it the system default
- [ ] Provisioning creates Elmer automatically at
`socket://10.10.0.155:9100` with description `Elmer`
- [ ] `lpoptions -p Elmer -l` shows `*Normal` for `PrintoutMode` and `*Color`
for `ColorModel`
- [ ] An upgrade removes the old `Classroom_Color` queue
- [ ] Repeating provisioning reports Elmer already configured and does not
rewrite the queue
- [ ] Chrome opens the system print dialog and shows only Elmer
- [ ] `lpstat -e` prints only `Elmer`; neither the Brother label printer nor a
discovered duplicate Ricoh appears
- [ ] `avahi-daemon.service` and `avahi-daemon.socket` are masked
- [ ] The CUPS test page prints in color on the Ricoh MP C3502
- [ ] With the Ricoh powered off, the classroom still boots normally and a job
simply remains queued
## Secondary Chrome windows
- [ ] The first Chrome top-level remains maximised, tiled and borderless
- [ ] A second `google-chrome` top-level floats instead of splitting the main
browser
- [ ] It is centred at roughly three quarters of the logical display
- [ ] Its red Close button is visible and mouse-accessible
- [ ] Close removes only the secondary and reveals the untouched main browser
- [ ] Changing either page title does not change the main/secondary roles
- [ ] A third Chrome top-level also floats and Close targets the newest one
- [ ] Chrome minimise/restore and the dock Browser button still behave normally
## UI scale
UI_SCALE sets sway's output scale, so it scales the whole session.
Change it, then `sudo systemctl restart getty@tty1`.
- [ ] `UI_SCALE=1.0` is identical to a session with no scaling
- [ ] `swaymsg -t get_outputs` shows the mode still 1920x1080 at every
scale, with only the logical size changing
- [ ] At 1.25 and 1.5, **Chrome** grows: tabs, omnibox, toolbar icons,
menus and page content
- [ ] Chrome's buttons are still easy to hit with the mouse
- [ ] Dock, clock, notifications and the DVD bar grow by the same
amount — once, not twice
- [ ] Dock icons stay crisp at 1.25 and 1.5 on a normal-density monitor,
not just from across the room: compare an icon against the clock
text beside it
- [ ] DVD control bar icons are crisp at the same scales
- [ ] `UI_SCALE=0.8` shrinks everything together
- [ ] A nonsense value (`UI_SCALE=banana`) still gives a working shell
- [ ] An extreme value (`UI_SCALE=9`) is clamped, not obeyed
- [ ] `journalctl` or the sway log shows `classroom-scale: session scale N`
## Reserved bottom shell (regression)
The bottom strip is one full-width layer-shell surface with a 76px
exclusive zone. Dock and clock live inside it. Do not split them back
into separate layer-shell windows.
- [ ] A maximised Chrome window stops above the bottom strip
- [ ] The clock does not float over Chrome
- [ ] Dock stays centred, clock stays bottom right
- [ ] Wallpaper shows through the unused parts of the strip
- [ ] Every dock button still responds to clicks
- [ ] A fullscreen application covers the whole display, dock included
## Browser
- [ ] First Browser click launches Chrome
- [ ] Chrome opens on Wonder Ink (https://app.wonderink.org/)
- [ ] Clicking Browser while Chrome is focused minimises it
- [ ] Clicking Browser again restores it **maximised, not floating or draggable**
- [ ] Clicking Browser while Chrome is running but unfocused focuses it
- [ ] `Super+M` minimises the focused window
- [ ] `Super+Shift+M` restores the most recently minimised window
- [ ] Normal navigation to any other site works
- [ ] The Home button returns to Wonder Ink
- [ ] Fullscreen YouTube video uses the whole display
- [ ] Leaving fullscreen restores the correct geometry above the dock
- [ ] The main Chrome window has **no sway title bar** — it starts at Chrome's
own tab strip, and Chrome's tabs and address bar are still there
- [ ] Chrome still maximises and minimises as before
- [ ] After a reboot, no "Restore pages? Chrome didn't shut down
correctly" bubble
- [ ] Chrome does not offer to save passwords
- [ ] Chrome shows no way to sign into the browser itself
- [ ] No "Add profile" and no Guest entry in the profile menu
- [ ] No profile picker at startup
- [ ] Wonder Ink signs in normally during a session
- [ ] After closing Chrome fully and reopening, Wonder Ink is signed out
(see browser.md — this is the unverified one)
- [ ] YouTube is still signed into the church account after that
- [ ] `chrome://policy` lists PasswordManagerEnabled as an applied
managed policy
- [ ] Website logins still persist across a reboot
- [ ] Clicking Browser when Chrome is closed shows a throbber on the
dock button until the window appears
- [ ] Clicking Browser when Chrome is already open feels immediate,
with no throbber
- [ ] The pointer shows a busy cursor while it is over the dock
- [ ] No first-run, default-browser or sign-in nag appears
- [ ] `chrome://policy` lists the Ekklesia policies as applied, with no
"unknown policy" entries
- [ ] Chrome does not start by itself at boot
- [ ] After a reboot, cookies and site logins are still there
- [ ] After an OTA update, cookies and site logins are still there
Known limitation: Chrome's own minimise button in its title bar does
nothing. Sway ignores the Wayland minimise request and gives no event to
hook. Minimising is the dock's Browser button or `Super+M`.
## Notifications
- [ ] `classroom-notify-test` renders with the classroom styling:
dark translucent, rounded, white text, top right
- [ ] `classroom-notify-test --critical "Parent Call" "Room 3 needs a parent."`
renders in the critical style and does not time out
- [ ] Notifications appear over a fullscreen video
Over SSH from an administrator account, run it with sudo:
```
sudo classroom-notify-test --dry-run # show the session it resolved
sudo classroom-notify-test # send into the classroom desktop
```
The classroom desktop belongs to the classroom user, and mako sits on
that user's D-Bus session. A plain notify-send from an SSH session lands
in the administrator's own session, where nothing owns
org.freedesktop.Notifications, so D-Bus tries to start a second mako with
no display and the call times out with NoReply. The script finds the
running sway process for the classroom user and delivers into its
session instead. It never starts mako.
- [ ] `sudo classroom-notify-test` from an SSH session displays on the
classroom screen
- [ ] `sudo classroom-notify-test --dry-run` reports the resolved
XDG_RUNTIME_DIR, bus address and Wayland display
- [ ] Running it as an unprivileged admin account explains it needs sudo
- [ ] `tests/test-classroom-notify-test.sh` passes (also run by the build)
## Audio
The room prefers the television. `AUDIO_OUTPUT` in device.conf decides:
`auto` (prefer a connected HDMI or DisplayPort set, fall back to the
jack), `hdmi`, or `analog`. A machine with no digital output at all — a
laptop, when one arrives — is correct on `auto` without any change here.
Two test suites cover this, and both run in the build:
- [ ] `tests/test-classroom-audio.sh` — the decision itself, against the
shapes real pactl emits
- [ ] `tests/test-classroom-audio-daemon.sh` — the real daemon driven
through every situation a room gets into, against a pactl that
answers the way PipeWire does
On a machine:
- [ ] `classroom-audio show` lists the outputs, what it chose, the
profile it would set and whether it is `settled`
- [ ] `journalctl --user -u ekklesia-classroom-audio` shows one
`output is ...` line per real change and nothing in between
- [ ] Leaving the room alone for an hour adds no further lines and no
measurable CPU time
### The television switched on after the computer
This is the scenario that silenced River Kids on 0.2.2 and the one no lab
can produce: ALSA reports a television through the HDMI port's
availability, and no loopback or dummy sound driver has such a port. The
suites above play it through a mock, and the mock is faithful to the real
server as far as it was measured — but a mock cannot prove the real
ALSA jack change arrives. **Do not take a passing build as evidence that
this works.** It has to be done at a machine, once, per release:
1. Switch the television **off** at the set, not the remote.
2. Reboot the computer and let it reach the classroom desktop.
3. Leave it at least two minutes, so any startup settling is over.
4. `journalctl --user -u ekklesia-classroom-audio` — expect one
`output is ...` line. In a room with nothing in the analog jack it
names the HDMI port even now, which is right: there is nowhere
better for the sound to go, and the set is then already correct
when it comes on.
5. Open Wonder Ink and Chrome and start something playing.
6. Switch the television **on**.
7. Sound should arrive within about a minute, in both applications,
**without closing or reopening either one**.
8. `wpctl status` should show the HDMI sink as default, and
`classroom-audio show` should say `settled=True`.
9. Switch the television off and on again. Sound should come back.
10. Check the volume is where the teacher left it, and that an output
muted on purpose is still muted.
If step 7 fails, the jack change is not reaching PipeWire at all; capture
`pactl subscribe` and `classroom-audio show` with the set off and then on,
which is what distinguishes that from a policy fault.
## Device features
Every optional application is its own setting in device.conf, and
`DEVICE_TYPE` decides none of them. A laptop can take children's church
and a tower can be a Bible study.
```
DEVICE_TYPE=desktop|laptop what the hardware IS
WONDERINK_ENABLED=true|false
DVD_ENABLED=true|false a drive is still required as well
PARENT_CALL_ENABLED=true|false
NETWORK_PREFERENCE=wired|wifi
DISPLAY_MODE=all|external-only
```
All default to the classroom's existing behaviour, so an upgrade changes
nothing until somebody edits the file. `classroom-desktop-layout` writes
the answers into the packaged layout; the bar is rebuilt from it at the
next login.
- [ ] `tests/test-classroom-desktop-layout.sh` passes (also run by the build)
- [ ] After changing a setting, `classroom-desktop-layout` then a
logout/login shows the new bar
- [ ] A disabled application leaves no gap: the remaining launchers close up
- [ ] The launcher order is the same on two machines with the same
features enabled
- [ ] Dragging a launcher does not move it
- [ ] Right-clicking a launcher offers no Pin, Unpin, Configure or panel
edit entry
- [ ] The order survives launching and closing applications, logout/login
and a reboot
- [ ] The bar is right at 1080p/100% and 4K/200%
## The Bible study laptop
A laptop installed as a fixed appliance: AC power, battery out, lid shut,
one television on HDMI, Wi-Fi.
```
DEVICE_TYPE=laptop
DISPLAY_MODE=external-only
NETWORK_PREFERENCE=wifi
WONDERINK_ENABLED=false
PARENT_CALL_ENABLED=false
DVD_ENABLED=false
```
Nothing about `DEVICE_TYPE=laptop` turns those applications off; they are
off because those lines say so.
### Physical verification — a real lid and a real television
The lab has no lid and no HDMI hotplug, so none of this is proven by a
passing build. Do it once at the machine:
1. With the lid **open** and the television on, check
`classroom-display-mode` reports the panel switched off and the
television on, and that only the television is lit.
2. Close the lid. The machine must keep running: the television stays on,
audio keeps playing, SSH stays up. `systemctl is-system-running`
still answers, and `loginctl` shows the session active.
3. Leave it closed for ten minutes. It must not suspend, hibernate, log
out or lock. `journalctl -b | grep -i -E "suspend|hibernate|lid"`
should show nothing acting.
4. With the lid still closed, switch the television **off** and on again.
The picture must come back. **Known limitation of 0.2.4:** the display
mode is applied at login, not continuously, so if KWin re-enables the
internal panel on that power cycle it stays enabled until the next
login. Check whether it does, and report it — that decides whether the
follow-up needs an event-driven applier like the audio policy's.
5. Unplug and replug HDMI, lid closed. Same check.
6. Reboot with the lid closed and the television on. It must come back to
the classroom desktop on the television.
7. Confirm Wi-Fi reconnects on its own, with nobody typing a password.
8. Confirm the HDMI audio policy still works (see Audio, above).
## Messaging
- [ ] With `MQTT_ENABLED=false`, `journalctl -u ekklesia-classroom-mqtt`
shows one line and the service is inactive — and the room is
completely normal
- [ ] With a broker configured, the service connects and
`mosquitto_sub -t 'classroom/status/#' -v` shows the room online
- [ ] A published notification appears on the classroom screen in the
classroom styling
- [ ] `urgency: critical` renders in the critical style
- [ ] Killing the broker leaves the room entirely usable
- [ ] The service reconnects on its own when the broker returns
- [ ] Rebooting with the broker **down** boots normally to the dock
- [ ] A retained notification left on the broker does not appear at boot
## DVD
With `DVD_ENABLED=false`:
- [ ] No DVD button in the dock
With `DVD_ENABLED=true`:
- [ ] Drive unplugged: button present, icon held back, friendly notification on click
- [ ] Drive present, no disc: friendly notification on click, nothing crashes
- [ ] Inserting a disc produces one **DVD Ready** notification
- [ ] The DVD icon comes up to full strength while a disc is in
- [ ] Nothing plays until the button is pressed
- [ ] Clicking plays the disc
- [ ] Menus work
- [ ] Audio works
- [ ] Chapter navigation works
- [ ] Fullscreen works
- [ ] `Super+M` minimises the player, the DVD button restores it
- [ ] Closing the player works
- [ ] Ejecting is detected, the icon goes back
- [ ] Reinserting is detected again
- [ ] Commercial CSS disc plays without anyone having run codec setup
by hand
## Sanctuary LIVE capability
With `LIVE_ENABLED=false`:
- [ ] No LIVE button or spacing hole appears in the dock
- [ ] No live-specific service or process starts
With `LIVE_ENABLED=true`:
- [ ] LIVE appears after DVD when DVD is enabled, and after Browser otherwise
- [ ] Clicking it shows the existing placeholder notification
- [ ] No live playback is attempted
### DVD mode
- [ ] Pressing DVD covers the **whole** display immediately, dock and
clock included — no wallpaper visible anywhere, at any point
- [ ] A spinner and "Loading DVD…" show while the disc spins up
- [ ] No partial VLC window is ever visible against the wallpaper
- [ ] The loading surface stays up until the disc menu is actually
showing — VLC's tiled black startup window is never visible
- [ ] Video or the disc menu replaces the loading surface when ready
- [ ] A disc that never opens still gives the desktop back (20s)
- [ ] No VLC chrome anywhere: no menu bar, no fullscreen controller,
no cone, no sway title bar
- [ ] Wallpaper is never visible around VLC
- [ ] Moving the mouse to the bottom slides the classroom bar up
- [ ] It hides again shortly after the mouse leaves it
- [ ] While hidden, clicking a disc menu item near the bottom still
reaches the menu
- [ ] Play/pause toggles and the icon follows the actual state
- [ ] Previous and next chapter work
- [ ] The menu button returns to the disc menu
- [ ] Space pauses; arrow keys and Enter navigate the disc menu
- [ ] Arrow keys do **not** change volume, and no key reaches crop,
aspect ratio, subtitles, audio tracks or deinterlacing
- [ ] Esc leaves DVD mode cleanly, with no black window left behind
- [ ] Close leaves DVD mode cleanly
- [ ] Eject leaves DVD mode and opens the tray
- [ ] Killing VLC by hand also returns to the classroom desktop
- [ ] Pressing DVD twice quickly does not start two sessions
- [ ] The bar is sized by UI_SCALE like the dock
## OTA
- [ ] `./update_canary.sh` publishes package first, manifest last
- [ ] The endpoint on the canary channel picks the update up
- [ ] SHA-256 verification passes
- [ ] Install succeeds and the endpoint reboots
- [ ] Everything above still works after the update
- [ ] Upgrade from 0.1.36 preserves every existing `device.conf` value
- [ ] `LIVE_ENABLED=false` is appended exactly once on upgrade and remains
single after reinstall
- [ ] `tools/validate-trixie-release.sh` passes against the 0.1.37 package and
the 0.1.36 package