PLN, 2026-08-21: "i dont use the webui most of the time, tray indicator is the
only ui i use for parvagues gear bro". The gearbox shipped with an engine, a CLI
and a web panel — and its one everyday surface still said Silent/Cool/Standard/
Extreme/Normal, still wrote governor/EPP/platform_profile itself through
`sudo perf-audio`, and was DISABLED at login. So the surface he uses was the one
surface that had not moved.
What this does
* tools/bridge/gearbox.py — the client both faces speak. Names the three gears
and the three trims once, reads the persisted state unprivileged, and builds
the argv for a switch. rig.py's gear() now delegates to it, so the tray and
the web panel cannot drift on what a gear is called.
* perf-tray.py — the mode list is gone. In its place: gear (off/standard/
aggressive) and trim (quiet/auto/cool) as two INLINE radio blocks under their
own headers, because the separation is the design. A reader who sees one flat
list keeps believing there is a single "how fast" dial and that quiet and cool
are two words for it; two headers teach the model every time the menu opens.
* It no longer writes any thermal knob itself. Switching goes `sudo -n` to the
arbiter, which is the point — a tray reaching around it would rebuild the
four-writer mess GEARBOX.md removed, in one click.
* The desired-mode bookkeeping is gone with it. The gearbox persists the gear and
re-asserts it from a udev hook on power-source changes and a system-sleep hook
on resume; a second bookkeeper in the tray could only ever disagree.
* The checked gear is read from the FILE, never inferred from sysfs. Inference
(perf.detect_mode) cannot tell a deliberate gear from power-profiles-daemon
having moved the same knobs, which it does by design since the gearbox
cooperates with ppd rather than masking it.
* "Gear ▸" (the apps and services) is now "Rig ▸": gear is the thermal lever
now, and the web panel already calls that collection the rig.
* perf-tray.service was never tracked — it lived only in ~/.config. Now in the
repo, so the unit and the script it runs can no longer drift apart.
The icon carries the lever, so it reads with the menu shut
Width = gear, colour = trim, drawn as the badge's border. One element for two
axes because the panel renders this at ~22 px and any design with two separate
marks turns to mush there. Width is the cue that has to survive a dark room and
a peripheral glance ("am I in the gig gear?" is the mid-set question), so gear
gets shape and trim, which is set-and-forget, gets colour. Off draws no ring: a
bare badge is the honest picture of nothing steering the machine.
First attempt used 2 px / 5 px, which looked right in a mockup and VANISHED on
the panel — 64→22 px scaling turns a 2 px stroke into 0.7 px of grey. Rendering
every combination at 20/24/32 px before believing it gave 6 px / 11 px, and then
forced the temperature numeral and the sparkline to shrink with the ring, since
an 11 px border over a 30 px numeral clips the digits at exactly the size where
aggressive is the gear whose temperature you most want to read.
Verified on hardware, through the real menu over its D-Bus interface (Plasma's
own protocol), not by calling the Python directly:
* live tooltip reads "gear: Standard · Cool · cap 15/35W"
* the menu exports two radio groups, correctly checked, headers live
* clicking Aggressive -> GEAR=aggressive, RAPL 45 W / 115 W
* clicking Standard -> GEAR=standard, back to 15/35 W
* clicking Cool -> TRIM=cool, fans 0 -> ~2900 rpm
* a CLI-side gear change is picked up by the tray within one refresh
* enabled and running under graphical-session.target, so it survives logout
Harness caveat worth writing down: the very FIRST dbusmenu Event sent to a
never-opened menu landed on the wrong item (asked for Aggressive, got trim Auto).
Every subsequent one mapped exactly, from both dbus-send and gdbus. Reading it as
provisional ids on a menu Qt has not yet had to show — a human cannot click an
item without opening the menu first, which is what the later probes did.
18 tests for gearbox.py (79 in the bridge suite, all green). They defend two
things, neither arithmetic: the sudoers contract (the argv IS a security
boundary — `--trim cool` must stay two words, and `performance`/`--boot`, both
real helper verbs, must never be reachable from a face that only knows gears),
and the honest-unset rule (never-engaged is not the same state as off, which is
why off had to become an explicit gear).
| Name |
Last commit
|
Last update |
|---|---|---|
| .gitea/workflows | Loading commit data... | |
| armada | Loading commit data... | |
| blocks | Loading commit data... | |
| blog | Loading commit data... | |
| config/wireplumber | Loading commit data... | |
| copycat | Loading commit data... | |
| docs | Loading commit data... | |
| gifts | Loading commit data... | |
| lib-parvagues | Loading commit data... | |
| live | Loading commit data... | |
| output | Loading commit data... | |
| releases | Loading commit data... | |
| sandbox | Loading commit data... | |
| study | Loading commit data... | |
| test | Loading commit data... | |
| tools | Loading commit data... | |
| utils | Loading commit data... | |
| visuals/slop | Loading commit data... | |
| viz | Loading commit data... | |
| .gitignore | Loading commit data... | |
| BootTidal.hs | Loading commit data... | |
| BootTidal.hs.broken | Loading commit data... | |
| BootTidal.visuals.broken.hs | Loading commit data... | |
| CLAUDE.md | Loading commit data... | |
| EVENING.md | Loading commit data... | |
| FOH_MASTER.md | Loading commit data... | |
| LAST_THIRD.md | Loading commit data... | |
| LICENSE | Loading commit data... | |
| MORNING.md | Loading commit data... | |
| PatchBay_MultiChannel.xml | Loading commit data... | |
| PatchBay_Perf.xml | Loading commit data... | |
| PatchBay_Perf5.1.xml | Loading commit data... | |
| README.md | Loading commit data... | |
| RUNBOOK.md | Loading commit data... | |
| SHOPPING_LIST.md | Loading commit data... | |
| TASKS_DUMP.md | Loading commit data... | |
| backlog.md | Loading commit data... | |
| bullet_train.tidal | Loading commit data... | |
| collide.sh | Loading commit data... | |
| debug.tidal | Loading commit data... | |
| didacticpatternvisualizer.pde | Loading commit data... | |
| gig-up.sh | Loading commit data... | |
| gpu-mode.sh | Loading commit data... | |
| hello.sc | Loading commit data... | |
| init_midi.sh | Loading commit data... | |
| intro.md | Loading commit data... | |
| library.txt | Loading commit data... | |
| link_jack.sh | Loading commit data... | |
| link_samples.sh | Loading commit data... | |
| link_samples_all.txt | Loading commit data... | |
| main_fairbanks.scd | Loading commit data... | |
| notes.md | Loading commit data... | |
| parvagues-sc.service | Loading commit data... | |
| perf-audio.sudoers | Loading commit data... | |
| perf-tray.py | Loading commit data... | |
| perf-tray.service | Loading commit data... | |
| perf.sh | Loading commit data... | |
| sample_watch.scd | Loading commit data... | |
| samples.txt | Loading commit data... | |
| setlist_opal2026.txt | Loading commit data... | |
| start_and_midi.scd | Loading commit data... | |
| test.tidal | Loading commit data... |