From ad42670a92d5563f803613848d17cb9419b322df Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 12 Jul 2026 09:02:44 -0500 Subject: chore(todo): record privmodel silent-auto decision, maint reconciliation, and spec outline --- todo.org | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/todo.org b/todo.org index 035f0e6..1b6234b 100644 --- a/todo.org +++ b/todo.org @@ -22,7 +22,9 @@ The vocabulary is open — topic tags are coined as needed — so these are conv - *Topic / area* (open): the subsystem a task touches — e.g. =:hyprland:= =:waybar:= =:mpd:= =:music:= =:network:= =:tooling:= =:llm:= =:eask:= =:pocketbook:= =:cmail:=. Coin a new one when it aids filtering. * Archsetup Open Work ** DOING [#B] Retro widget catalogue :feature:design: -The panel widget gallery ([[file:docs/prototypes/panel-widget-gallery.html][docs/prototypes/panel-widget-gallery.html]]) grows into a retro-instrument component catalogue: reference photos of period hardware → gallery cards (the visual + behavioral spec) → reusable components for three targets (emacs svg.el, web/React, waybar). Tokens single-sourced in [[file:docs/prototypes/tokens.json][tokens.json]] (gen_tokens.py emits web/waybar/elisp); svg.el proof widget shipped (gallery-widget.el, needle gauge). Reference photos live in [[file:working/retro-stereo-widgets/][working/retro-stereo-widgets/]] (Berna 3 / Sancristoforo faceplates, 2026-07-11 batch). R-series cards are the reference-derived widgets. +The panel widget gallery ([[file:docs/prototypes/panel-widget-gallery.html][docs/prototypes/panel-widget-gallery.html]]) grows into a retro-instrument component catalogue: reference photos of period hardware → gallery cards (the visual + behavioral spec) → reusable components for three targets (emacs svg.el, web/React, waybar). Tokens single-sourced in [[file:docs/prototypes/tokens.json][tokens.json]] (gen_tokens.py emits web/waybar/elisp); svg.el proof widget shipped (gallery-widget.el, needle gauge). Reference photos live in [[file:working/retro-stereo-widgets/][working/retro-stereo-widgets/]]. R-series cards (R01-R31) are the reference-derived widgets — collection phase COMPLETE 2026-07-12 (84 cards, all behaviorally verified). + +Next: write the component-generation spec (spec-create, fresh session). Outline agreed with Craig 2026-07-12: Phase 1 demand inventory (widget-to-target matrix from real consumers — waybar panels, emacs games, React UI; port to demand, not all 84). Phase 2 web library extraction (lift card builders into parameterized widgets.js; gallery becomes the demo of the library; CDP behavioral tests carry over). Phase 3 emacs ports (extend gallery-widget.el pattern + gallery-tokens.el; per-widget ERT + rsvg-convert side-by-side visual harness; keymap/click-region interaction per widget). Phase 4 waybar pilot (one real panel — audio — onto tokens-waybar.css + banked composition idioms; lives in ~/.dotfiles, archsetup owns end-to-end; manual-testing checklist). Phase 5 generator decision point (revisit Level-2 codegen after ~5 hand ports, per the recorded architecture decision). Baked decisions: SVG-first substrate, single token source, per-target interaction layers, demand-driven porting, gallery-as-spec. Banked variant/composition ledger lives in the 2026-07-11/12 session archive. ** TODO [#C] Net panel: Enterprise error never dismisses :bug:dotfiles:network: The enterprise-auth error banner in the network panel stays no matter what; selecting another action should clear it (from roam inbox, 2026-07-11). Repro screenshot: =~/pictures/screenshots/2026-07-10_195911.png=. Minor severity × some users, sometimes (only enterprise-network users who hit the error) = P3 = [#C]. Distinct from the net doctor's enterprise auth verdict shipped this session — that's the doctor's terminal message; this is the panel's stuck error banner. ** TODO [#C] Notification/capture popup grows too large :bug:hyprland: @@ -114,9 +116,13 @@ The model: a doctor resolves its privilege at run time from three signals — pa The shared helper is built (see the dated entry below). What remains is per-panel adoption: wire each doctor's remedies through =panelkit.privmodel.resolve()= and audit them against the Confirm/Arm floor, and reconcile maint's =priv.py= build/fire table with the model rather than leaving its implicit always-passwordless assumption. That wiring lives in the per-panel fix phases (net Phase 1, bt Phase 2, audio input/output), each needing a real privileged host to verify =--fix= end to end, so none is agent-solo. +Craig's decision, 2026-07-12: maint's harmless-reclaim privileged remedies (the silent CLEAN UP set — paccache keep3, journal vacuum, coredump clean) STAY silent-auto. The reconciliation gives that class a sanctioned, documented exception to the confirm floor rather than forcing Confirm/Arm; the value of the floor holds for everything else. Where sudo is not passwordless, maint should degrade per the model (prompt on a tty, guide in a GUI) instead of hard-failing. + *** 2026-07-11 Sat @ 03:48:57 -0500 Built the shared privilege model (panelkit) On dotfiles main (=b987820=, pushed). Craig chose to share a library, not per-panel copies. New =panelkit= package (=panelkit/src/panelkit/=): pure library code in the dotfiles tree, no CLI, no stow package — a consumer reaches it by adding =panelkit/src= to =sys.path= alongside its own =/src= and =from panelkit import privmodel=. Self-contained (its own =cmd.py=) so a panel plus panelkit stays a coherent unit (keeps the pluggable-panel option open). =privmodel=: four classes (=auto=/=privileged=/=reboot-tail=/=guide=), =resolve(remedy_class, ctx)= → a =Resolution= (=RUN=/=PROMPT=/=GUIDE_ONLY=, =confirm=, =reboot_after=, =reason=) over a =PrivContext= (passwordless via =sudo -n true=, tty, is-GUI). Safety floor enforced and property-tested across all 8 context combos: every privileged/reboot-tail remedy that runs requires a deliberate confirmation, never silent auto. =PANELKIT_SUDO= test seam (="true"=/="false"=), =detect_context()= + =plan()= convenience. 19 tests, full =make test= green (65 suites), review-code clean. Inbox note sent to dotfiles. NOT wired to a consumer — that's the per-panel adoption above. +*** 2026-07-12 Sun @ 09:01:25 -0500 Reconciled maint onto the shared privilege model (dotfiles 7937a9e) +maint's doctor now resolves every privileged step through =panelkit.privmodel= instead of the old always-=sudo -n= hard-fail: RUN where passwordless (unchanged), PROMPT on a CLI tty (plain sudo, preceded by a wall note), GUIDE events in a GUI with neither — the typable command on the wall, nothing executed. User-scope steps never resolve; a macro's user steps still run around guided privileged ones. Craig's silent-auto decision (above) is implemented as the documented exception: recorded in =maint/remedies.py= (tier semantics) and =panelkit/privmodel.py= (the floor's own docstring), waiving only the confirm gesture, only for the auto-tier reclaim set. TDD (15 new tests red→green incl. both wall renderers), full suite 65/65, live-verified RUN + GUIDE end-to-end on this host via the real launcher shim. Bonus root-cause fix caught by the live run: =probes/logs.py= crashed on journalctl MESSAGE=null entries (key present, so the =.get= default never applied), which broke every real fix's re-probe — normalized at =_journal_lines= with a regression test. Remaining under this task: net Phase 1 / bt Phase 2 / audio adoption (queue items 2-3), and the PROMPT-path + GUI-wall manual checks (see Manual testing and validation). ** TODO [#B] Scrolling/Carousel layout: frame fit + wrap-around :hyprland: :PROPERTIES: @@ -681,6 +687,22 @@ Craig's standing checklist of everything that isn't agent-verifiable. Each child Priority and type tag added by that audit: the task carried neither, which kept the project's largest live container out of the agenda entirely. +*** maint privilege degrade: PROMPT path on a real tty +What we're verifying: with sudo not passwordless, a maint fix on a terminal prompts for the password (after the wall note) instead of hard-failing. Safe on ratio/velox — run from a real terminal; PANELKIT_SUDO=false makes the model treat the box as non-passwordless without touching sudoers, while the fix still fires through real (prompting) sudo. +#+begin_src sh :results output +PANELKIT_SUDO=false maint fix cache_clean +#+end_src +- Type your password if sudo asks. +Expected: a dim note line "no passwordless sudo — sudo will ask for your password on this terminal", then the RUN line shows plain "sudo paccache -r" (no -n) and the step lands OK with re-probe notes after. On ratio/velox the NOPASSWD grant means sudo won't actually prompt (only the seam is faked); the real password prompt is only observable on a box without the grant — a VM or a fresh install pre-sudoers. + +*** maint privilege degrade: GUIDE events on the GUI wall +What we're verifying: the maint panel's CLEAN UP degrades to guide instructions on the results wall (nothing executes) when the box can't elevate silently. +#+begin_src sh :results output +PANELKIT_SUDO=false setsid -f maint panel >/dev/null 2>&1 +#+end_src +- In the panel, press CLEAN UP (needs an off-nominal reclaim metric; if the board is quiet, expect the "nothing to clean" note instead). +Expected: each privileged reclaim lands on the wall as a dim instruction line — "cannot elevate here (...) — run yourself: $ sudo ..." — with no RUN/OK pair for it, and nothing actually reclaimed. Close the panel afterward (it inherited the fake PANELKIT_SUDO). + *** Net doctor privileged fixes (net Phase 1) — run in a disposable VM/container What we're verifying: the three control-plane fixes actually repair a real broken state under real sudo. These states are dangerous on a daily driver (masking NM kills the network), so run them in a throwaway VM or booted nspawn with NetworkManager installed and passwordless sudo, NOT on ratio/velox. Each: break the state, run =net doctor --fix=, confirm the repair. **** nm-masked → unmask-nm -- cgit v1.2.3