Testing: oracles and the evidence ledger
The oracles behind the terminal specification's requirements, and the one evidence ledger for its TCF, TSP, TKM, TPR, TPG, TSE, TSS and TDV requirements. The Android page keeps its own verification table for NOD.
Oracles
| Class | Oracle (independent of the implementation) | Covers |
|---|---|---|
| Configuration | hand-written fixtures per layer with the expected resolved value; a malformed file with its expected location | TCF |
| Key table | bindingsAt vs resolve agreement (the toolkit's KEY test); a static scan for KBD3 keys; a recording pty swept over the encoder's key set | TKM |
| Protocol bytes | input and reply bytes transcribed from each authority (protocols), never produced by our own encoder | TPR |
| Hostile input | injection fixtures: controls in titles, a closing bracket inside a paste, oversized OSC payloads, a javascript: OSC 8 URI | TPR2, TPR6, TPR8, TPR18, TPR20 |
| Secrets stay put | a marker typed, pasted, autofilled (fake service) and copied; then searched for in the log ring, the log file, keys.txt and the clipboard | TPG6, TSE9 |
| Rendering | RecordingCanvas / --render of each surface: slot declarations, the monochrome profile, a theme swap compared with a cold render | every surface (design) |
| Placement | property tests over the menu placement: flip at the top, slide at the sides, never inside the keyboard inset | TSE6 |
| Device | the screen and key oracles (NOD14), screenshots, dumpsys notification, on the Xiaomi 11T Pro (arm64) | Android rows |
| Desktop | --debug-take-screenshot-and-exit under xvfb; a real session for D-Bus notifications and the portal's scheme | desktop rows |
| Inclusion | markdown fixtures with hand-written expected expansions for each VitePress form, plus hostile ones (a path escaping the repository, a cycle, a missing region) | hue VIW5–VIW7, TPG13 |
| Credits | the artifact manifests (dub locks, the APK builders' library and font lists) against the parts present | TPG14, TPG16 |
Skipped or unavailable checks are not passes; a row stays partial naming the missing configuration.
Protocol authorities, pinned
The editions the TPR byte fixtures were transcribed from (libs/terminal-view/src/sparkles/terminal_view/protocol_oracle.d and the osc_scan.d tests):
| Authority | Edition |
|---|---|
| XTerm Control Sequences | ctlseqs.txt updated for XTerm Patch #411 (2026/08/23); OSC 52 reply shape read from that patch's misc.c (ManipulateSelectionData) |
| kitty keyboard protocol | docs/keyboard-protocol.rst; the key-0 text event's shape from kitty/key_encoding.c |
| kitty desktop notifications (OSC 99) | docs/desktop-notifications.rst |
| OSC 777 / OSC 9 as Ghostty accepts them | rxvt_extension.zig, osc9.zig |
| Contour colour-palette updates (mode 2031) | color-palette-update-notifications.md |
One deliberate divergence: OSC 9 whose first field is a number is ConEmu's family and never a notification (protocols), where Ghostty falls back to a notification for a malformed ConEmu form (9;1).
Evidence ledger
| Date | Rows | Revision | Command / scenario | Configuration | Result | Remaining gap | | ---------- | ------------------------------------------------------ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | | 2026-10-02 | TCF6 | feat/terminal/workspace | dub test :wired; dub test :hue | Linux, LDC 1.42 | 205 / 435 passed; hue's settings_io tests unchanged over the shared reader and renderers | — | | 2026-10-02 | TCF1–TCF5, TCF7, TCF8 | feat/terminal/workspace | dub test :terminal (settings, settings_load, settings_io, extra_keys, cli); terminal config show/write against a hand-written file with a typo | Linux, LDC 1.42 | 37 passed; the typo is dropped with its $-path, the rest applies | TCF4 line/column; TCF8 font | | 2026-10-02 | TCF7, TCF8 | feat/terminal/workspace | phone: config.json written with run-as, then termux-reload-settings; visible: never; the file deleted and reloaded; input swipe down on the row and up from the bottom edge | Xiaomi 11T Pro, terminal-nix-apk | live: background and one-row layout applied; row hidden; defaults restored; swipe hides and restores | — | | 2026-10-02 | TCF1, TCF2 | feat/terminal/workspace | desktop --debug-take-screenshot-and-exit under xvfb with no config file | Linux, xvfb | the built-in dark scheme (Catppuccin Mocha) renders | — | | 2026-10-02 | TKM1–TKM5, TKM7–TKM9 | feat/terminal/workspace | dub test :terminal (keymap, key_router: the table, the reserved keys, the leader, the overlay merge, the routing sweep, the reference page) | Linux, LDC 1.42 | 49 passed | TKM2 recording pty; TKM4 overlays | | 2026-10-02 | TKM5 | feat/terminal/workspace | desktop under Xvfb: xdotool key ctrl+shift+space, screenshot after the delay, then Escape | Linux, Xvfb | the guide lists ? all keys and k toggle extra keys in the derived chrome colours; Escape closes it | — | | 2026-10-02 | TKM7 | feat/terminal/workspace | phone: a tap on the MENU extra key | Xiaomi 11T Pro, terminal-nix-apk | the guide opens at the root over the pane | tappable rows (TKM6, M8) | | 2026-10-02 | TSS1, TSS3, TSS6–TSS8, TSS14, TSS15 | feat/terminal/workspace | dub test :terminal (workspace, workspace_host), dub test :terminal-view (respawnRunsTheProgramAgainInPlace, pool) | Linux, LDC 1.42 | 54 and 99 passed | — | | 2026-10-02 | TSS1–TSS3, TSS7–TSS9 | feat/terminal/workspace | desktop under Xvfb with xdotool: leader p v, leader p s, typing in each pane, exit 3, then Escape | Linux, Xvfb | three panes; the exited one shows status 3 and the keys; Escape starts a shell below a separator rule | E1 banner (M8) | | 2026-10-02 | TSS14 | feat/terminal/workspace | desktop: split, quit, start again | Linux, Xvfb | the split comes back with fresh shells | Android not yet seen | | 2026-10-02 | TSS10 | feat/terminal/workspace | dub test :terminal -- -i resizeSplit; desktop: leader p v, a drag from the divider to x=400, then far past the left edge | Linux, Xvfb, xdotool | a guide line follows the drag; on release stty size reads 68 columns; past the edge the divider stops a few columns in | touch: a drag scrolls the pane under it | | 2026-10-02 | TSS8 (resize) | feat/terminal/workspace | dub test :terminal -- -i "resizeToward\|shiftSeparates"; desktop: leader p v, then leader p Shift+H three times, stty size after each | Linux, Xvfb, xdotool | 49, 51, 53 columns | renaming a tab | | 2026-10-02 | TPR5–TPR7 | feat/terminal/workspace | dub test :terminal -- -i links, dub test :terminal-view -- -i linkAt; desktop: a printed https://example.org/docs and an OSC 8 link whose text is https://a and URI javascript:alert(1), each Ctrl+clicked, with a logging xdg-open first on PATH; phone (the selection agent's run): a tap on a printed URL | Linux, Xvfb, xdotool; Xiaomi 11T Pro | the log holds only https://example.org/docs; on the phone the L1 card shows above the row with Copy, Share and Open | links.tap = open \| off and links.longPress on a device | | 2026-10-02 | TCF4 | feat/terminal/workspace | dub test :wired -- -i Tolerant; dub test :terminal -- -i "settings_load\|reportConfigWarnings"; desktop: a config.json whose line 3 sets links.tap to "sometimes" | Linux, Xvfb | the log line and a wrapped toast both say config.json, $.links.tap (line 3, column 21), the value and the allowed ones; the app starts with the default | — | | 2026-10-02 | TSS2 (long command) | feat/terminal/workspace | dub test :terminal -- -i exit_banner; desktop: terminal -- false argument-001 … argument-200, a click on the status line, three wheel notches over the banner | Linux, Xvfb, xdotool | the command wraps (no word cut off), 10 of 30 lines show with ↓ 19 lines; after the wheel ↑ 9 lines and ↓ 10 lines; the status mark stays whole | the touch drag on a device | | 2026-10-02 | TKM6 | feat/terminal/workspace | dub test :terminal -- -i touch_guide; phone: MENU, a tap on settings, Back; MENU, the search field, sprt, a tap on the first result | Xiaomi 11T Pro, the Nix APK | the guide shows the leader's rows with icons; settings opens and Back closes it; sprt ranks split right first, and the tap splits the pane (the new shell's prompt shows) | — | | 2026-10-02 | TPR4, TSS14 | feat/terminal/workspace | desktop: cd /usr, leader p v, pwd; a pane prints OSC 7 file://localhost/var, leader p v, pwd; phone: a split, cd /tmp, HOME, force-stop, launch, pwd | Linux, Xvfb; Xiaomi 11T Pro, the Nix APK | /usr, then /var (OSC 7 wins over /proc); on the phone the split comes back and HOME saves the workspace (its mtime moves), but both shells start in the home directory | the phone's directories: Nix-on-Droid's bash sends no OSC 7 and proot emulates chdir | | 2026-10-02 | TPG7 | feat/terminal/workspace | desktop: a pane prints OSC 2 build watcher, OSC 9 Build finished, OSC 52 with a base64 secret and OSC 7 /var; then the log file and stderr are read | Linux, Xvfb | four TRC lines (title, directory, notification with its route, a 15-byte clipboard write); the secret is in neither the file nor stderr, and stderr has no TRC line | — | | 2026-10-02 | TCF7, TKM4, TPR1 | feat/terminal/workspace | phone: MENU, toggle extra keys, a tap on a pane; MENU, settings, Back, typing; desktop: OSC 2 build watcher, leader t t | Xiaomi 11T Pro, the Nix APK; Linux, Xvfb | the row goes and the panes take its space, and stays gone with the soft keyboard up; Back returns the keys to the pane that had them; the tree names the tab and the pane build watcher | — | | 2026-10-02 | TCF9 | feat/terminal/workspace | desktop: config.json with ui.buttonLabels: "icon", then terminal -- false | Linux, Xvfb | the exit prompt's Re-run, Shell and Close show their icons alone | tooltips and accessible names for icon-only buttons | | 2026-10-02 | TPG11 | feat/terminal/workspace | dub test :terminal-view -- -i unseenFrom; desktop: a pane prints OSC 9 Build finished | Linux, Xvfb | the rail's tab button carries the unseen dot (the pill shows ●n; the tree marks the pane) | — | | 2026-10-02 | TPG8 | feat/terminal/workspace | phone: MENU, logs, the Share button, Cancel | Xiaomi 11T Pro, the Nix APK | the system share sheet opens with the log; Cancel returns to the page | — | | 2026-10-02 | TPR5 (off, open) | feat/terminal/workspace | phone: config.json with links.tap off, then open; a tap on a printed https://example.org/docs each time | Xiaomi 11T Pro, the Nix APK | off: no card, the keyboard comes up; open: Chrome is the resumed activity at once | — | | 2026-10-02 | TSE3 (reduced motion) | feat/terminal/workspace | phone: settings put global animator_duration_scale 0 while the app is in the background, then back to it (and the setting restored) | Xiaomi 11T Pro, the Nix APK | logcat: terminal: animations removed; the selection's edge scroll then steps a row at a time (edgeScroll, host-tested) | — | | 2026-10-02 | TSS10 (touch) | feat/terminal/workspace | phone: a split; input swipe from the divider (x 107) to x 540 over 1.2 s, then stty size in the right pane | Xiaomi 11T Pro, the Nix APK | the divider lands where the finger lifted (the right pane 22 columns); neither pane scrolls or takes the focus during the drag | — | | 2026-10-02 | TPR12, TSS15 (Android) | feat/terminal/workspace | phone, each time with the app in the background: a pane notifies (OSC 9) while another has the focus, then the notification is tapped; a pane notifies and its shell exits, then the notification is tapped | Xiaomi 11T Pro, the Nix APK | deep link to pane 1 and that pane takes the focus; for the closed pane, the notification log opens with the entry on top, marked "pane closed" | — | | 2026-10-02 | TSS2 | feat/terminal/workspace | desktop under Xvfb: terminal -- '…; exit 1'; a click on the status line, then on Re-run | Linux, Xvfb | the E1 banner shows ✗ exited with status 1 · command; the click expands it to the command, directory and times; Re-run runs it again below a rule, the old output intact | scrolling a long command | | 2026-10-02 | TPR9, TPR19–TPR21, TCF10 | feat/terminal/workspace | desktop under Xvfb: a three-line paste into cat (Ctrl+Shift+V); printf '\e]52;c;?\a'; printf '\e]9;Build finished\a' | Linux, Xvfb | the P1 card below the cursor line (no room above), with the preview and Cancel / As one line / Paste; the P2 sheet naming the program, tab and pane; the toast | — | | 2026-10-02 | TSS11–TSS13, TCF12, TCF13 | feat/terminal/workspace | desktop under Xvfb: a split and a second tab under reveal, header and framed; Ctrl+Shift+P; phone: a tap on the pill | Linux, Xvfb; Xiaomi 11T Pro | the rail with the current tab barred; the tree beside it (search on top); headers and rounded frames, the focused one accented; on the phone the centred pill opens the tree below it, search at the bottom | divider drags | | 2026-10-02 | TPG4 | 8165c245b | dub test :base -- -i log_sinks: ring wrap with the drop count and seq gap, truncation at a code point, text-arena eviction, a @nogc write, forwarding to the replaced sink at its level, initLogger levelling the chain | Linux x86_64; LDC 1.42 and DMD 2.112 | pass (8 tests; :base 613 pass) | — | | 2026-10-02 | TPG5 | 8165c245b, 8344cec04 | log_sinks.RotatingFileCoreLogger.appendsAndRotates (rotation at the threshold, one older file, the previous run moved aside on open); …failureDisablesWithOneWarning (/dev/full: disabled, both entries forwarded, one warning); the Nix-built desktop binary run once writes $XDG_STATE_HOME/sparkles-terminal/terminal.log | Linux x86_64 | pass | the Android file (files/state/…) not yet inspected on a device | | 2026-10-02 | TPG2 | 2f270ab71, 8344cec04 | build_stamp.* tests; dub build :terminal logs sparkles:terminal dev (unknown commit); nix build .#terminal from a dirty tree logs 0.1.0 (f187d25 + uncommitted changes); nix build .#libterminal-android carries the same string in the arm64 .so | Linux x86_64; Android arm64/x86_64 cross build | pass | the stamp in logcat on a device | | 2026-10-02 | TPG6 | 24566bd2b, 8344cec04 | terminal_view.log.typedAndPastedTextNeverReachesTheLog (markers typed and pasted into cat reach the screen, not the ring or the file; making sendPaste log its text fails it); installer.runInstaller.retriesAFailedDownloadThenTakesTheDefault (a typed URL never reaches the ring) | Linux x86_64, a real pty | pass | autofill (TSE9), copying and OSC 52 do not exist yet | | 2026-10-02 | TPG7 | 24566bd2b, 8344cec04 | the marker test also finds raylib: probe 42 and the ghostty-vt build line in the ring and the file; the Nix-built desktop binary's terminal.log holds its build line and raylib's initialisation | Linux x86_64 | pass | protocol events and notifications at debug (M3) | | 2026-10-02 | TPR2, TPR4, TPR8, TPR20, TPR21 (parsing) | 73f59af62 | dub test :terminal-view -- -i osc_scan — hostile titles (C0/C1/DEL, ill-formed UTF-8, 1 MiB), OSC 7 forms, OSC 9/777/99 incl. chunking, base64, eviction; OSC 52 forms | Linux x86_64, LDC 1.42, libghostty-vt 0.1.0-dev+4749c4e | 17/17 pass | — | | 2026-10-02 | TPR1–TPR4, TPR8, TPR9, TPR14–TPR21, TPG9 | 73f59af62 | dub test :terminal-view -- -i protocol_oracle — a raw recording pty plays the program; a DSR barrier proves silence; the paste-injection fixture \e[201~rm -rf ~\n (TPR18) | as above; adopted pty, no window | 15/15 pass, ×4 runs stable | Android (TPR16, TPR17 on a device); the visual surfaces (M8); system notification posts (TPR10, TPR11) | | 2026-10-02 | open question 2 (mode 2031 on enable) | 73f59af62 | protocol_oracle.TPR14.schemeQueryAndMode2031Reports: CSI ? 2031 h followed by the barrier | as above | nothing sent | — | | 2026-10-02 | whole package | 73f59af62 | dub test :terminal-view, dub test :terminal, dub test :ghostty; dub build :ui-gallery, dub build :terminal | as above | 95 / 22 / 0 pass; builds | :ghostty has no tests of its own | | 2026-10-02 | TPG12–TPG14, TPG16 | 7af76d33 | ci --check-credits passes (23 parts, 36 components); with parts/zlib.md removed it fails, naming libz.a uncredited and the three pages that include it; dub test :ci -- -i credits (12 tests: removed part, part nothing ships, page composition); nix build .#credits stages 24 licence files and fails on a named file a source lacks; yarn docs:build renders every licence (24/17/23 licence blocks on the index, terminal and hue pages, no unexpanded include); nix build .#terminal-apk carries assets/credits/ and the generated NOTICE; .#hue-android-assets lists credits/ in its manifest | x86_64-linux, NixOS | pass | TPG14: transitive desktop libraries (glfw, libGL, X11/Wayland under raylib) are not read; TPG15/TPG17 (in-app page) are M11 | | 2026-10-02 | TPR11, TPR12, TPR13 (codec and protocol) | 85aabb7da | dub test :terminal -- -i "dbus\|desktop" (LDC and DMD): the wire format against the specification's Hello bytes and a hand-built big-endian signal, truncated and lying lengths rejected, ill-formed UTF-8 scrubbed; a private dbus-daemon with a fake notification server and portal — Notify carries the default action and the escaped body, a second post replaces the first, ActionInvoked names the pane and a forged one from another client does not, NotificationClosed forgets it; ReadOne, the version-1 Read fallback, SettingChanged with a duplicate and a foreign key, no portal at all | Linux x86_64; LDC 1.42, DMD 2.112; nixpkgs dbus 1.16.2 | 21/21 pass | — | | 2026-10-02 | TPR11 | 85aabb7da | notifications.when = always, a program printing OSC 777;notify;Build;done <ok> \o/, dbus-monitor on the session bus | GNOME on Wayland, the real session bus | Notify: summary Build, body done <ok> \o/, actions default, Show; GNOME Shell takes it | a click on a live desktop (ActionInvoked) is covered only by the fake server | | 2026-10-02 | TPR13, TPR14 | 85aabb7da | a program sets mode 2031 and records its input while gsettings set org.gnome.desktop.interface color-scheme prefer-light, then back | GNOME on Wayland, xdg-desktop-portal-gnome | CSI ? 997 ; 2 n then CSI ? 997 ; 1 n reach the pane, once each; the log shows both switches | Android uiMode (M5), macOS | | 2026-10-02 | UIA14, TDV11 | caacfa304, 15bebc650 | dub test :doc-view (146), dub test :hue (300, 3 skipped); apps/hue/tools/gui-ab.d on README.md, libs/ui/src/sparkles/ui/state.d, docs/specs/ui/containers.md, libs/doc-view/test/fixtures/dsv/ragged-synthetic.csv against the pre-move binary; apps/hue/tools/tui-ab.d on the same D source and README | LDC 1.42, Xvfb display 91, WAYLAND_DISPLAY/XDG_RUNTIME_DIR unset | all GUI captures and TUI streams byte-identical, before and after emitVisibleOps | hue's window does not mount DocViewPane | | 2026-10-02 | TDV1–TDV4, TDV7, TDV10, TPG15 (desktop) | 86421bb68 | under Xvfb, open.target = splitRight: a pane runs xdg-open on README.md, a semicolon CSV, a .d source, a PNG and docs/credits/terminal.md, then on a missing file; dub test :terminal (open_request.*, workspace.openDocument.*) | dub build :terminal and nix build .#terminal | each opens a split beside the shell, status 0; the missing file prints xdg-open: … no such file, status 1; the Nix build's credits show every licence text | OSC 8 and selection-menu opens | | 2026-10-02 | TDV1, TDV2, TDV5, TDV6, TPG15 (Android) | 86421bb68 | Xiaomi 11T Pro (bd123586), nix build .#terminal-nix-apk: termux-open of a markdown part, a CSV, a .d source and a PNG from the nix-on-droid shell; a swipe over the source; q; Leader c and a search for the MIT text | the APK's grammar subset | each opens a tab (markdown preview, the grid, highlighted D, the image); the swipe scrolls; q closes; the credits render from the APK with their licence texts | long-press selection and copy | | 2026-10-02 | TDV8, VIW5, VIW7 | 43860509f, 15bebc650 | dub test :doc-view -- -i "include | pane": ranges, regions, @/, the confinement, cycle, missing and depth cases, asset paths; reload keeping the top line, a deleted file flagged | host | pass | the raw view shows expanded includes | | 2026-10-02 | TPG17 | c30ebdaa8 | hue credits --ansi from nix build .#hue | | every licence text rendered | hue on Android | | 2026-10-02 | TCF6 | feat/terminal/workspace | dub test :wired; dub test :hue | Linux, LDC 1.42 | 205 / 435 passed; hue's settings_io tests unchanged over the shared reader and renderers | — | | 2026-10-02 | TCF1–TCF5, TCF7, TCF8 | feat/terminal/workspace | dub test :terminal (settings, settings_load, settings_io, extra_keys, cli); terminal config show/write against a hand-written file with a typo | Linux, LDC 1.42 | 37 passed; the typo is dropped with its $-path, the rest applies | TCF4 line/column; TCF8 font | | 2026-10-02 | TCF7, TCF8 | feat/terminal/workspace | phone: config.json written with run-as, then termux-reload-settings; visible: never; the file deleted and reloaded; input swipe down on the row and up from the bottom edge | Xiaomi 11T Pro, terminal-nix-apk | live: background and one-row layout applied; row hidden; defaults restored; swipe hides and restores | — | | 2026-10-02 | TCF1, TCF2 | feat/terminal/workspace | desktop --debug-take-screenshot-and-exit under xvfb with no config file | Linux, xvfb | the built-in dark scheme (Catppuccin Mocha) renders | — | | 2026-10-02 | TKM1–TKM5, TKM7–TKM9 | feat/terminal/workspace | dub test :terminal (keymap, key_router: the table, the reserved keys, the leader, the overlay merge, the routing sweep, the reference page) | Linux, LDC 1.42 | 49 passed | TKM2 recording pty; TKM4 overlays | | 2026-10-02 | TKM5 | feat/terminal/workspace | desktop under Xvfb: xdotool key ctrl+shift+space, screenshot after the delay, then Escape | Linux, Xvfb | the guide lists ? all keys and k toggle extra keys in the derived chrome colours; Escape closes it | — | | 2026-10-02 | TKM7 | feat/terminal/workspace | phone: a tap on the MENU extra key | Xiaomi 11T Pro, terminal-nix-apk | the guide opens at the root over the pane | tappable rows (TKM6, M8) | | 2026-10-02 | TPG4 | 8165c245b | dub test :base -- -i log_sinks: ring wrap with the drop count and seq gap, truncation at a code point, text-arena eviction, a @nogc write, forwarding to the replaced sink at its level, initLogger levelling the chain | Linux x86_64; LDC 1.42 and DMD 2.112 | pass (8 tests; :base 613 pass) | — | | 2026-10-02 | TPG5 | 8165c245b, 8344cec04 | log_sinks.RotatingFileCoreLogger.appendsAndRotates (rotation at the threshold, one older file, the previous run moved aside on open); …failureDisablesWithOneWarning (/dev/full: disabled, both entries forwarded, one warning); the Nix-built desktop binary run once writes $XDG_STATE_HOME/sparkles-terminal/terminal.log | Linux x86_64 | pass | the Android file (files/state/…) not yet inspected on a device | | 2026-10-02 | TPG2 | 2f270ab71, 8344cec04 | build_stamp.* tests; dub build :terminal logs sparkles:terminal dev (unknown commit); nix build .#terminal from a dirty tree logs 0.1.0 (f187d25 + uncommitted changes); nix build .#libterminal-android carries the same string in the arm64 .so | Linux x86_64; Android arm64/x86_64 cross build | pass | the stamp in logcat on a device | | 2026-10-02 | TPG6 | 24566bd2b, 8344cec04 | terminal_view.log.typedAndPastedTextNeverReachesTheLog (markers typed and pasted into cat reach the screen, not the ring or the file; making sendPaste log its text fails it); installer.runInstaller.retriesAFailedDownloadThenTakesTheDefault (a typed URL never reaches the ring) | Linux x86_64, a real pty | pass | autofill (TSE9), copying and OSC 52 do not exist yet | | 2026-10-02 | TPG7 | 24566bd2b, 8344cec04 | the marker test also finds raylib: probe 42 and the ghostty-vt build line in the ring and the file; the Nix-built desktop binary's terminal.log holds its build line and raylib's initialisation | Linux x86_64 | pass | protocol events and notifications at debug (M3) | | 2026-10-02 | TPR2, TPR4, TPR8, TPR20, TPR21 (parsing) | 73f59af62 | dub test :terminal-view -- -i osc_scan — hostile titles (C0/C1/DEL, ill-formed UTF-8, 1 MiB), OSC 7 forms, OSC 9/777/99 incl. chunking, base64, eviction; OSC 52 forms | Linux x86_64, LDC 1.42, libghostty-vt 0.1.0-dev+4749c4e | 17/17 pass | — | | 2026-10-02 | TPR1–TPR4, TPR8, TPR9, TPR14–TPR21, TPG9 | 73f59af62 | dub test :terminal-view -- -i protocol_oracle — a raw recording pty plays the program; a DSR barrier proves silence; the paste-injection fixture \e[201~rm -rf ~\n (TPR18) | as above; adopted pty, no window | 15/15 pass, ×4 runs stable | Android (TPR16, TPR17 on a device); the visual surfaces (M8); system notification posts (TPR10, TPR11) | | 2026-10-02 | open question 2 (mode 2031 on enable) | 73f59af62 | protocol_oracle.TPR14.schemeQueryAndMode2031Reports: CSI ? 2031 h followed by the barrier | as above | nothing sent | — | | 2026-10-02 | whole package | 73f59af62 | dub test :terminal-view, dub test :terminal, dub test :ghostty; dub build :ui-gallery, dub build :terminal | as above | 95 / 22 / 0 pass; builds | :ghostty has no tests of its own | | 2026-10-02 | TPG12–TPG14, TPG16 | 7af76d33 | ci --check-credits passes (23 parts, 36 components); with parts/zlib.md removed it fails, naming libz.a uncredited and the three pages that include it; dub test :ci -- -i credits (12 tests: removed part, part nothing ships, page composition); nix build .#credits stages 24 licence files and fails on a named file a source lacks; yarn docs:build renders every licence (24/17/23 licence blocks on the index, terminal and hue pages, no unexpanded include); nix build .#terminal-apk carries assets/credits/ and the generated NOTICE; .#hue-android-assets lists credits/ in its manifest | x86_64-linux, NixOS | pass | TPG14: transitive desktop libraries (glfw, libGL, X11/Wayland under raylib) are not read; TPG15/TPG17 (in-app page) are M11 | | 2026-10-02 | TPR10 | f2226593f | phone: sh ~/n.sh (sleep, then OSC 777) and Home; dumpsys notification shows tag=pane-1, channel terminal, a contentIntent; the shade shows "Build / finished in pane one"; a second post replaced it (one record); pm revoke … POST_NOTIFICATIONS, then a post: the warning "notifications are not allowed for this app" | Xiaomi 11T Pro, Android 14 (API 34), the nix-on-droid APK (targetSdk 28) | pass; the first channel creation made the system ask for the permission (the targetSdk ≤ 32 path), no requestPermissions needed | the toast a refused post falls back to (M8); the log records the route given, not whether the post succeeded (TPG9) | | 2026-10-02 | TPR12 (spike, D15) | f2226593f | phone: a tap on the notification while away; on resume Activity.getIntent() and ActivityManager.getAppTasks()[0].getTaskInfo().baseIntent read for the pane extra (the spike's two direct reads, since removed); then deepLinkOnResume over getActiveNotifications: tapped → "deep link to pane 1"; opened from the launcher with the notification still shown → nothing; dub test :terminal -- -i droid_platform | as above | the direct reads fail (both -1: a single-task NativeActivity gets the tap as onNewIntent, which it does not override); the inference works | focusing the pane (TSS15) and the log page (TPG10); Linux D-Bus | | 2026-10-02 | TPR13 (Android) | f2226593f | phone: Settings → Display → Light / Dark with the terminal in the background, back to it: the pane recolours both ways, and with printf '\e[?2031h'; cat -v running it receives ^[[?997;2n then ^[[?997;1n; at start the scheme in effect is the system's | as above; no ~/.termux, so appearance.followSystem | pass — but native_app_glue's AConfiguration_getUiModeNight stayed light after the switch to dark while the activity's resources read dark, so the source is the resources over JNI (sparkles.android.system_scheme); cmd uimode night does not switch this MIUI build | a switch while the terminal stays in the foreground (the about-once-a-second poll) was not exercised; the extra-keys row keeps its fixed colours | | 2026-10-02 | TSE10 (probe) | 0c37c433f, f2226593f | dub test :terminal-view -- -i process_info (ptyReading sees the slave's modes through the master: echoing, password, raw); phone: the probe's log at a bash prompt (raw), under sleep/cat (echoing) and read -s (password) | Linux x86_64, a real pty; the phone as above | pass; Bionic needs the TCGETS ioctl (druntime declares no termios functions there), and SELinux allows it on the master | the chip (M8) | | 2026-10-02 | TSE8, TSE9 (spike, OQ3) | f2226593f | phone: a read -s prompt, then the autofill-request trigger: the field turns into a password input, AutofillManager.isEnabled() is true and Gboard's strip offers "Suggest strong password" / "Pick a saved password"; then autofill-fake fills a marker through View.autofill(AutofillValue): 14 bytes to the pty, got 14 chars: <marker> after Enter, the marker in neither terminal.log*, keys.txt nor logcat (only adb's own command lines), and typing (with a backspace) works after the field is restored | as above; Google's autofill service (the device default) | pass | no real service fill was completed (it would use the owner's passwords); the ring, the clipboard and the notification log not searched; no menu item or chip (M8) | | 2026-10-02 | Share (TSE5) | f2226593f | phone: am start -a android.intent.action.SEND -t text/plain --es android.intent.extra.TEXT shared-from-the-terminal in the shell (through the in-app am server) opens the system share sheet; dub test :terminal -- -i am_command | as above | pass | the menu item (M8) | | 2026-10-02 | TCF6 | feat/terminal/workspace | dub test :wired; dub test :hue | Linux, LDC 1.42 | 205 / 435 passed; hue's settings_io tests unchanged over the shared reader and renderers | — | | 2026-10-02 | TCF1–TCF5, TCF7, TCF8 | feat/terminal/workspace | dub test :terminal (settings, settings_load, settings_io, extra_keys, cli); terminal config show/write against a hand-written file with a typo | Linux, LDC 1.42 | 37 passed; the typo is dropped with its $-path, the rest applies | TCF4 line/column; TCF8 font | | 2026-10-02 | TCF7, TCF8 | feat/terminal/workspace | phone: config.json written with run-as, then termux-reload-settings; visible: never; the file deleted and reloaded; input swipe down on the row and up from the bottom edge | Xiaomi 11T Pro, terminal-nix-apk | live: background and one-row layout applied; row hidden; defaults restored; swipe hides and restores | — | | 2026-10-02 | TCF1, TCF2 | feat/terminal/workspace | desktop --debug-take-screenshot-and-exit under xvfb with no config file | Linux, xvfb | the built-in dark scheme (Catppuccin Mocha) renders | — | | 2026-10-02 | TKM1–TKM5, TKM7–TKM9 | feat/terminal/workspace | dub test :terminal (keymap, key_router: the table, the reserved keys, the leader, the overlay merge, the routing sweep, the reference page) | Linux, LDC 1.42 | 49 passed | TKM2 recording pty; TKM4 overlays | | 2026-10-02 | TKM5 | feat/terminal/workspace | desktop under Xvfb: xdotool key ctrl+shift+space, screenshot after the delay, then Escape | Linux, Xvfb | the guide lists ? all keys and k toggle extra keys in the derived chrome colours; Escape closes it | — | | 2026-10-02 | TKM7 | feat/terminal/workspace | phone: a tap on the MENU extra key | Xiaomi 11T Pro, terminal-nix-apk | the guide opens at the root over the pane | tappable rows (TKM6, M8) | | 2026-10-02 | TPG4 | 8165c245b | dub test :base -- -i log_sinks: ring wrap with the drop count and seq gap, truncation at a code point, text-arena eviction, a @nogc write, forwarding to the replaced sink at its level, initLogger levelling the chain | Linux x86_64; LDC 1.42 and DMD 2.112 | pass (8 tests; :base 613 pass) | — | | 2026-10-02 | TPG5 | 8165c245b, 8344cec04 | log_sinks.RotatingFileCoreLogger.appendsAndRotates (rotation at the threshold, one older file, the previous run moved aside on open); …failureDisablesWithOneWarning (/dev/full: disabled, both entries forwarded, one warning); the Nix-built desktop binary run once writes $XDG_STATE_HOME/sparkles-terminal/terminal.log | Linux x86_64 | pass | the Android file (files/state/…) not yet inspected on a device | | 2026-10-02 | TPG2 | 2f270ab71, 8344cec04 | build_stamp.* tests; dub build :terminal logs sparkles:terminal dev (unknown commit); nix build .#terminal from a dirty tree logs 0.1.0 (f187d25 + uncommitted changes); nix build .#libterminal-android carries the same string in the arm64 .so | Linux x86_64; Android arm64/x86_64 cross build | pass | the stamp in logcat on a device | | 2026-10-02 | TPG6 | 24566bd2b, 8344cec04 | terminal_view.log.typedAndPastedTextNeverReachesTheLog (markers typed and pasted into cat reach the screen, not the ring or the file; making sendPaste log its text fails it); installer.runInstaller.retriesAFailedDownloadThenTakesTheDefault (a typed URL never reaches the ring) | Linux x86_64, a real pty | pass | autofill (TSE9), copying and OSC 52 do not exist yet | | 2026-10-02 | TPG7 | 24566bd2b, 8344cec04 | the marker test also finds raylib: probe 42 and the ghostty-vt build line in the ring and the file; the Nix-built desktop binary's terminal.log holds its build line and raylib's initialisation | Linux x86_64 | pass | protocol events and notifications at debug (M3) | | 2026-10-02 | TPR2, TPR4, TPR8, TPR20, TPR21 (parsing) | 73f59af62 | dub test :terminal-view -- -i osc_scan — hostile titles (C0/C1/DEL, ill-formed UTF-8, 1 MiB), OSC 7 forms, OSC 9/777/99 incl. chunking, base64, eviction; OSC 52 forms | Linux x86_64, LDC 1.42, libghostty-vt 0.1.0-dev+4749c4e | 17/17 pass | — | | 2026-10-02 | TPR1–TPR4, TPR8, TPR9, TPR14–TPR21, TPG9 | 73f59af62 | dub test :terminal-view -- -i protocol_oracle — a raw recording pty plays the program; a DSR barrier proves silence; the paste-injection fixture \e[201~rm -rf ~\n (TPR18) | as above; adopted pty, no window | 15/15 pass, ×4 runs stable | Android (TPR16, TPR17 on a device); the visual surfaces (M8); system notification posts (TPR10, TPR11) | | 2026-10-02 | open question 2 (mode 2031 on enable) | 73f59af62 | protocol_oracle.TPR14.schemeQueryAndMode2031Reports: CSI ? 2031 h followed by the barrier | as above | nothing sent | — | | 2026-10-02 | whole package | 73f59af62 | dub test :terminal-view, dub test :terminal, dub test :ghostty; dub build :ui-gallery, dub build :terminal | as above | 95 / 22 / 0 pass; builds | :ghostty has no tests of its own | | 2026-10-02 | TPG12–TPG14, TPG16 | 7af76d33 | ci --check-credits passes (23 parts, 36 components); with parts/zlib.md removed it fails, naming libz.a uncredited and the three pages that include it; dub test :ci -- -i credits (12 tests: removed part, part nothing ships, page composition); nix build .#credits stages 24 licence files and fails on a named file a source lacks; yarn docs:build renders every licence (24/17/23 licence blocks on the index, terminal and hue pages, no unexpanded include); nix build .#terminal-apk carries assets/credits/ and the generated NOTICE; .#hue-android-assets lists credits/ in its manifest | x86_64-linux, NixOS | pass | TPG14: transitive desktop libraries (glfw, libGL, X11/Wayland under raylib) are not read; TPG15/TPG17 (in-app page) are M11 | | 2026-10-02 | TSP1, TSP2 (the lift; M7's gate) | 418707f2f | dub test :ui -- -i settings_pane (9); dub test :hue -- -i settings_ (20, hue's SET tests unchanged over the lifted component); hue GUI A/B against 681e49e06: HUE_GUI_SCREENSHOT under xvfb-run -n 91 (no Wayland), four scenarios — the plain view, the pane open, navigated (jjl), filtered (/them) — twice per build; arrayElementEditsStayInTheirOwner fails with ownedCopy removed from open | Linux x86_64, LDC 1.42, xvfb | all eight captures byte-identical between the builds (and between runs) | — | | 2026-10-02 | TSP3 | 1b301a572 | dub test :ui -- -i settings_pane (autosave.*: written at once, only changed paths, a flag's value never baked in, the toast's Undo writes the file back, a refusal keeps the edit live, a drag settled at close is saved); hue workspace.settingsPaneOpensEditsSaves (browsing writes no file; an edit writes only its path; Undo restores {}) and settings_store.autosaveRewritesFromTheSessionBase; the same A/B at 171cc0a87 | Linux x86_64, LDC 1.42, xvfb | pass; the A/B differs only in a 179×15 px box at (502, 77) — the hint line losing · s save | the toast surface (M8) | | 2026-10-02 | TSP4 | 2f87966fa | ui.settings_pane.provenance.followsTheEditAndNamesWhatItOverrides; wired.overlay.originAt.readsTheLeafFieldsOrigin | Linux x86_64, LDC 1.42 | pass | the per-row chip (TSP5, M8) | | 2026-10-02 | TSP1–TSP4 (the terminal's model) | 171cc0a87 | dub test :terminal -- -i settings_store: the pane over the whole TerminalConfig; colors.properties → followSystem edited → config.json holds only that, the leaf says "overrides colors.properties", Undo writes {} back; --font-size never baked in and shadows its leaf; a @Range refusal writes nothing; then dub test of :wired, :ui, :terminal, :hue | Linux x86_64, LDC 1.42 | 4 pass; 208 / 598 / 53 / 436 pass (hue: 3 skipped) | the page on screen, live application in a running host, the toast (M8) | | 2026-10-02 | TSP1–TSP8, PRT36–PRT41, TCF8 (the page) | feat/terminal/settings-page | dub test :ui (property_tree.sectionsColoursAndWireChoices, property_sections.*, chord_capture.*, settings_pane.editsByPathCommitThroughTheDispatch); dub test :terminal (settings_page.*: sections in declaration order and expanded, a stepper/segment/reset/dropdown commit that applies and saves, Undo from the toast, drill-in and Back, a capture that refuses Ctrl+C, rebinds ␣ p s → ␣ p d, swaps on a conflict, cancels on Esc, and undoes; key_router.openGuideAtLeader.menuThenSOpensSettings); then dub test of :ui, :terminal, :hue | Linux x86_64, LDC 1.42 | all pass | — | | 2026-10-02 | TSP5, TSP6, TSP8, TCF8 | feat/terminal/settings-page | desktop under Xvfb (temporary XDG_CONFIG_HOME/XDG_STATE_HOME, no Wayland): xdotool Ctrl+Shift+Space s opens the modal panel; Down×3, Right toggles follow-system and config.json gets "followSystem": false; /zoom, End, Enter captures; Ctrl+Shift+W is a conflict ("close pane"); Enter swaps | Linux x86_64, LDC 1.42, xvfb | the panel is drawn over the panes, the toast says "Zoom → Ctrl+Shift+W · saved", and the file holds "ctrl+shift+w": "zoomPane", "space p z": "closePane" | — | | 2026-10-02 | TSP5, TSP6, TSP8, TCF8, TKM7 | feat/terminal/settings-page | phone: MENU then s opens the full-screen page; extra keys auto ▾ → never (the row disappears live, config.json holds "visible": "never", the toast offers Undo); the row's ↺ writes {} back; drags scroll to the keys; Zoom's ✎, then the extra-keys CTRL latched and e typed, writes "ctrl+e": "zoomPane", "space p z": null; drilling into Colors, Back pops the level and Back again closes the page | Xiaomi 11T Pro, terminal-nix-apk | as described; Back reaches the app only after fix(ui-raylib.events) added Back and Menu to the full keyboard's key set | the toast's Undo expires after 6 s | | 2026-10-02 | TSP1 (hue's half) | feat/terminal/settings-page | hue GUI A/B against feat/terminal/workspace: apps/hue/tools/gui-ab.d under xvfb-run -n 91 (no Wayland), the plain view and HUE_GUI_SETTINGS = "", jjl, /them, twice per build | Linux x86_64, LDC 1.42, xvfb | all eight captures byte-identical between the builds (and between runs) | — | | 2026-10-02 | TPG1, TPG2, TPG3 | ef56674e8 | dub test :terminal -- -i about_page (facts, summary, links through the service); dub test :base -- -i build_stamp (component. lines); desktop: leader a under Xvfb (dub build: dev, unknown commit, debug, unknown version, ReleaseFast, raylib 6.0 · OpenGL 3.3); phone: the open-page debug trigger with about | Linux x86_64, LDC 1.42, Xvfb; Xiaomi 11T Pro (arm64, API 34), terminal-nix-apk | pass; the phone shows 0.1.0, checked, libghostty-vt 0.1.0-dev+4749c4e-nix, ReleaseFast SIMD off, OpenGL ES 2.0, the package, versionCode 20261002 (0.0.0+20261002), API 34; logcat has sparkles:terminal 0.1.0 (unknown commit) | a release build's commit on a device; the in-app credits (TPG15) | | 2026-10-02 | TPG8 | ef56674e8 | dub test :terminal -- -i "log_page\|page_kit" (tail following; a reader scrolled up is not moved by a new entry; chips, source:, /regex/, a broken regex reported; free text ranked by sparkles:fuzzy with a typo; Copy; the previous run's file with a continuation line); desktop under Xvfb: Up×5 pauses, / then source:desk filters, a click on the debug chip toggles it, a click on Back closes; phone: the page by trigger, a drag scrolls it (paused) | as above | pass | Share not tapped on a device | | 2026-10-02 | TPG9, TPG10, TPG11, TPG18 | ef56674e8 | dub test :terminal -- -i notification_page (every grouping, rules first-match, Unknown, git root, persisted grouping, a closed pane's entry inert, unseen dots, Mark all read); dub test :terminal-view -- -i "notification_log\|TPR8" (source recorded, unseen); desktop under Xvfb: OSC 9/777/99 from a shell, then leader (the guide's row reads notifications · 3 new), leader n (grouped by tab, dots), g×5 (project), Down (the selection shows), Enter (the pane focused, the page closed); phone: the same notifications, the page by trigger (chips in two rows), Project chip tapped, an entry tapped → its pane | as above | pass | the tab strip's count (TPG11); a real notification tap reaching the fallback (TPG10); whether a system post succeeded (TPR10) | | 2026-10-02 | TSE1, TSE2, TSE4 | 55f91ac12, 69f162755 | dub test :terminal-view -- -i selection (word, URL, line and wrap-following spans; ends crossing; a block's rows by \n, a stream's soft wraps joined; the selection kept on its text as output scrolls it into the scrollback; ED 2 and ED 3 clearing it; find wrapping; one model behind the touch calls and the copy chord) | Linux, LDC | pass | — | | 2026-10-02 | TSE5, TSE6, TSE7, TCF11 | afe4e15ce | dub test :terminal -- -i selection_menu (the hidden-not-disabled action sets; the card above, flipped below, slid inside, clear of the handles, the keyboard inset, the sheet fallback; the sheet's lift held across frames, one note; the sheet row cut, swiped, ending in More; X1's groups, shortcut hints, arrows and Enter) | Linux, LDC | pass | — | | 2026-10-02 | TSE2, TSE5, TSE7 | afe4e15ce | desktop under Xvfb: a double-click on https://ex.org/a?b=1 selects the URL whole; a right-click opens X1 below the selection's row (Copy with Ctrl+Shift+C, Select all, Find in scrollback, Run in a new pane; no Paste with an empty clipboard); Find selects the previous make and toasts "Match 3 of 4"; a right-click on a link with nothing selected selects it and More holds Open URL; Run opens a split running the selection | Xvfb 1100×700, XDG_* in a scratch dir | as described | — | | 2026-10-02 | TSE1, TSE3–TSE6, TSE8, TSE10 | f91ec0326 | phone: a long-press on https://example.org/docs selects it whole, handles and the S2 sheet (Copy, All, Open, Share, Find cut off; Autofill password below); on a path broken across rows; on blank cells only Paste and All; a selection near the bottom with the keyboard up: the content lifts 5 lines above the sheet with one note; the row swipes to Share, Find, Run, More, More lists Copy and Select all; Copy toasts and clears, Paste types it; a start handle dragged to the top edge and held scrolls into the scrollback (34 lines); Share opens the system sheet; Esc closes the menu, the selection stays; a tap elsewhere clears it. read -s x with the keyboard up: the A1 chip; its tap opens the service's suggestions (none picked); Back, then Enter: the request is cancelled, nothing sent, the keyboard types normally | Xiaomi 11T Pro, Gboard, Google autofill | as described | the card and pill presentations not run on the device; reduced motion (TSE3) has no source; one Back with the keyboard hidden did not close the menu (Esc did) | | 2026-10-03 | TPG19, TKM6 (a tall level) | feat/terminal/workspace | dub test :terminal -- -i "aTallLevel\|aWideScreen"; tablet: ⋯, the guide, +pane; phone in landscape with the soft keyboard up: MENU, then a drag on the guide | Xiaomi Pad 8 Pro (3200×2136, 440 dpi) and Xiaomi 11T Pro, the Nix APK | the guide is 100 columns wide and centred; the pane group fits; on the phone the keyboard steps aside, two rows show with ↓ 7 more, and the drag scrolls | — | | 2026-10-03 | TCF14, TSE6 | feat/terminal/workspace | dub test :terminal -- -i menuStyle; tablet: rotate to portrait; long-press a word on both devices | Xiaomi Pad 8 Pro; Xiaomi 11T Pro | the tablet keeps the rail in portrait and shows the anchored card above the selection; the phone shows the sheet | — | | 2026-10-03 | TSS16 | feat/terminal/workspace | dub test :terminal -- -i opener.guide; tablet with its keyboard cover's driver present (the extra-keys row hidden): a tap on the rail's ⋯; phone in portrait: the pill band | Xiaomi Pad 8 Pro; Xiaomi 11T Pro | the touch guide opens; the pill band carries the ⋯ beside the pill | — | | 2026-10-03 | TKM10 | feat/terminal/workspace | dub test :terminal -- -i eachPlatformsLeader; the settings page on the tablet | Linux; Xiaomi Pad 8 Pro | both leaders parse and bind; the tablet's settings show ctrl+alt+space | a hardware keyboard sending the chord on a device | | 2026-10-03 | TSP6, TSS11, TSS12, TSE3, TPG7 (tablet) | feat/terminal/workspace | tablet: settings (portrait and landscape), the reveal toolbar, the tree, a selection with the guide opened over it, the log page | Xiaomi Pad 8 Pro | Font reads FiraCodeNerdFontMono · 13 · 5 settings, a wrapped description keeps a blank row below it; the toolbar keeps bash whole; the tree fills its panel beside the rail; the guide covers the handles; the log has one line per font load, not hundreds; the status bar holds HyperOS's ••• handle (D48) | — |