diff options
Diffstat (limited to 'todo.org')
| -rw-r--r-- | todo.org | 77 |
1 files changed, 76 insertions, 1 deletions
@@ -21,6 +21,39 @@ The vocabulary is open — topic tags are coined as needed — so these are conv - *Effort / autonomy*: =:quick:= a spare-moment fix (minutes, not a sitting); =:solo:= Claude can carry it end to end — there's a build path, a test path, and no upfront decision needed (a leftover manual spot-check doesn't disqualify it). - *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 +** TODO [#C] Net diagnostics leak connection names + SSIDs into copyable report and --json :bug:dotfiles:network:solo: +The net doctor's copyable report (=report.py=, =scrub_text=) scrubs only MAC/IP, and =net diag/doctor --json= (=cli.py=) dumps the raw dict with no redaction. SSID redaction lives only in the event log (=redact_event=, gated on =redact_ssid=, default off). So a connection name (usually the SSID) appears in the clear in the link-step evidence and in every =--json= consumer — the copyable report is exactly the text a user pastes into a bug report. Secrets (PSK/password/token/portal URL) are already stripped, so this is names, not credentials: Minor severity, graded on severity alone per the privacy carve-out. + +Split out of the 2026-07-11 net-doctor-expansion spec review: that spec's new rival-manager/keyfile-perms verdicts keep parity with this pre-existing behavior rather than half-solve it. Fix shape: extend redaction to cover the connection name + keyfile basename across the copyable report and =--json= (one systemic pass, not per-verdict), with a redaction test. Engine-wide, so it wants one coherent change rather than being bolted onto the expansion work. + +** TODO [#B] Net doctor expansion v1 — build the READY spec :feature:dotfiles:network: +:PROPERTIES: +:SPEC_ID: ce29b103-ed9d-4f56-bf8c-9ed8fe680ff3 +:END: +Build the [[file:docs/specs/2026-07-11-net-doctor-expansion-spec.org][net doctor expansion]] (DOING). Adds the control-plane cluster (rival-manager / nm-masked / keyfile-perms) and a sharper auth verdict to the shipped net doctor (=~/.dotfiles/net/=). Archsetup owns the dotfiles work end to end — edit, test, commit, and push in =~/.dotfiles=, then drop an inbox note. Phases 1-2 are gated on the shared cross-panel run-time privilege model, which doesn't exist yet; Phase 0 builds now. +*** 2026-07-11 Sat @ 02:47:47 -0500 Built the read-only control-plane probe +New module =net/src/net/control_plane.py= plus =diag.py= wiring, on dotfiles main (=21ca3ff=, pushed). =net diagnose= now carries a =control_plane= key in its envelope with three read-only signals: NetworkManager state (masked/failed/stopped/active, finer than the plain =is-active= the ladder used), any rival manager active alongside NM (dhcpcd, systemd-networkd, iwd via =systemctl is-active=), and the active profile's keyfile permissions (=stat= under an env-overridable =NET_NM_CONNECTIONS= root, default =/etc/NetworkManager/system-connections=). Detection only: no classifier change, no new step, no bearing on =overall=. Surfaced via =net diag --json=. The masked/failed read also runs in the nmcli-down early-return path, or a masked NM would short-circuit before the probe. Every read bounded through =cmd.run='s timeout; degrades to unknown / no-rival / None on an unreadable tool or unstattable file, so a probe that can't see never invents a fault. As a normal user the real 0700 root:root dir is unstattable, so the keyfile signal reads unknown (readable only under root, e.g. the doctor's privileged path). 21 new tests, full =make test= green; =/review-code= approved (two Minor items, both Phase 1 concerns already tracked in the spec: link-scoping the rivals and guarding the keyfile path in the chmod fix). Inbox note sent to dotfiles. +*** TODO [#C] Phase 1 — control-plane verdicts + privilege model +Blocked on the shared cross-panel run-time privilege model. =classify= gains =rival-manager=/=nm-masked=/=keyfile-perms= (all =fixable=), ordered ahead of the generic not-running rule, with the masked check reachable in the NM-down early-return path. Fixes register as =VERBS= + =ACTIONS= (=disable-rival=/=unmask-nm=/=chmod-keyfile=), each narrowly scoped. Hard gate: must not land before the Confirm floor exists, or =net doctor --fix= runs root ops via passwordless sudo ungated. Live verification needs a real rival/masked/bad-keyfile state (a VM or a deliberately-broken host), so not solo. +*** TODO [#C] Phase 2 — sharpened auth verdict +Auth-reason classifier reading profile key-mgmt (=manage.py=) + scanned SECURITY (=nmcli.py=): SAE / hidden / enterprise / generic. SAE and hidden become =fixable= profile-modify (Confirm-tier); the rest stay =needs-user-action= with a cause-named message. Pairwise over (reason × profile-state). The classify logic is agent-buildable with fakes; the live profile-modify fix needs a real WPA3/hidden network to verify, so that part is manual. +*** TODO [#C] Phase 3 — flip the net spec to IMPLEMENTED +On v1 completion: flip the spec's status heading to IMPLEMENTED (dated history line + mirror) and log the vNext items (flaky/drops cluster, DoT/DNSSEC verdict, profile hygiene) to todo.org. + +** TODO [#B] Bt doctor expansion v1 — build the READY spec :feature:dotfiles:bluetooth: +:PROPERTIES: +:SPEC_ID: 3d4d61c4-e5df-44e9-b8e0-40b31452c3f7 +:END: +Build the [[file:docs/specs/2026-07-11-bt-doctor-expansion-spec.org][bt doctor expansion]] (DOING). Adds a dmesg firmware-hint probe (names the missing blob on a no-adapter fault) and a boot-enablement probe (catches an adapter disabled at boot) to the shipped bt doctor (=~/.dotfiles/bluetooth/=). Phase 2 is gated on the shared cross-panel privilege model; Phases 0-1 build now. Archsetup owns the dotfiles work end to end. +*** TODO [#B] Phase 0 — the two read-only probes :solo: +Pure engine, no repair change. The dmesg firmware-hint reader (no-adapter branch, bounded =cmd.run(journalctl -k)= reusing the =doctor.py:84= precedent, per-vendor signature match) and the boot-enablement reader (AutoEnable from main.conf [Policy], =systemctl is-enabled=, TLP list). Both report into =diagnose()='s dict feeding the human summary + =--json=. Fault fires only on explicit AutoEnable=false / disabled service / TLP entry — bluez's default is true, so absent config is auto-enable-on and never a fault. Tests: canned journal buffer per vendor + injected main.conf/is-enabled/tlp states. Verify: fakes + =make test=. Solo. +*** TODO [#B] Phase 1 — firmware-hint Guide verdict :solo: +=diagnose= emits =no-adapter-firmware= (blob name in evidence, Reboot-tail Guide) on a signature match; falls back to the generic no-adapter otherwise. No auto-fix — a Guide, so no privilege dependency; lands independently of the shared model. The distinction rides existing =evidence=/=next_action= (no formatter change); an additive =schema.step= =code= key only if a machine identifier is wanted (locked test-contract ripple). Verify: fake journal fixtures + =make test=. Solo. +*** TODO [#C] Phase 2 — persistent-power verdict + fix +Blocked on the shared cross-panel privilege model. =powered-off-persistent= distinct from =powered-off=; the fix sets AutoEnable / enables the service / edits tlp, Privileged/Confirm. Needs an idempotent INI setter for main.conf ([Policy], preserve comments) and a list-edit for tlp.conf's =DEVICES_TO_DISABLE_ON_STARTUP= — real work, not argv one-liners. Hard gate: no Privileged fix before the Confirm floor. Persistence only proves out across a real reboot, so verification is manual. +*** TODO [#C] Phase 3 — flip the bt spec to IMPLEMENTED +On v1 completion: flip the spec's status heading to IMPLEMENTED (dated history line + mirror) and log the vNext items (stale-bond signature, connection-parameter hints, bt-audio-profile expansion) to todo.org. + ** TODO [#D] Maintenance console vNext :feature: Deferred from the [[file:docs/specs/2026-07-07-maintenance-console-spec.org][spec]] (v1 ships determinate remedies only): AI/workflow assistance on read-only metrics (the vLater tier — failed-unit diagnosis, journal-error fix suggestions, OOM investigation); SIGKILL escalation for TERM-survivors on the KILL lever; live streaming meters on evidence rows where a count could be a level. @@ -62,6 +95,25 @@ Scope note (Craig, 2026-07-07): realtime lamp *behavior* only. The maintenance c Addendum (Craig, 2026-07-07): DO backport the 3.5-entry height convention — every panel's output well caps at 3.5 visible entries, the half-visible entry being the scroll cue, with the dark slate-on-black scrollbar. Layout stays compact per above; only the height cap + scroll affordance carries over. +** TODO [#B] One copy + close control pair on every output wall :feature:dotfiles:solo: +Converge all four instrument-console output walls on the net panel's well controls: a copy glyph and a ✕ close, as an overlay at the top right, hidden until content lands. Craig's call, 2026-07-10, while reviewing the audio doctor's wall: "network panels as standard across all others, make it consistent." + +Where they stand today, no two alike. net has copy + ✕ (=net/src/net/gui.py=, the =o-copy= / =o-clear= overlay). bluetooth has ✕ but no copy. maint has COPY + HIDE as keys in a header row, and no ✕. audio just gained copy + ✕ (dotfiles =bd33440=). + +Work: give bluetooth a copy key, give maint the overlay pair, and lift the four hand-rolled =_copy_output= implementations into one shared helper rather than a fifth copy. maint keeps HIDE alongside close, because its wall is a persistent session action log you collapse and keep, where net's, bt's, and audio's are per-run results you dismiss. + +Copy text is per panel but one rule: it pastes as that panel's CLI prints, so the paste lines up with the terminal a user is already looking at. audio's =viewmodel.wall_copy_text()= is the worked example. + +Consistent with the 2026-07-07 scope note on the sibling task above: net's compact glyph overlay is what standardizes, not maint's wide COPY-key header row. + +** TODO [#B] Run-time privilege model, standard across every panel doctor :feature:dotfiles: +The audio input/output doctor is gaining a run-time privilege model (see [[file:docs/specs/2026-07-10-audio-doctor-input-side-spec.org][docs/specs/2026-07-10-audio-doctor-input-side-spec.org]], decision "The doctor may use sudo, resolved by context at run time"). Craig's call, 2026-07-10: make it a standard, "revise the other panels to be consistent with these changes." + +The model: a doctor resolves its privilege at run time from three signals — passwordless sudo available (=sudo -n true=, which never hangs), a tty to prompt at, and whether it is the GUI panel. Four remedy classes: Auto (user-scope, reversible), Privileged (needs sudo — runs where passwordless, prompts on a CLI tty, degrades to Guide in a GUI with neither), Reboot-tail (run the applicable part, then instruct the reboot), and Guide (physical/BIOS/wait-for-upstream, nothing to run). Safety floor: every Privileged and Reboot-tail remedy defaults to Confirm or Arm tier, never silent Auto, because passwordless sudo is not consequence-free. + +Work: factor the privilege resolution and the remedy-class machinery into a shared helper the net, bluetooth, maint, and audio doctors all use, and audit each panel's existing remedies against the Confirm/Arm-default floor. maint already has a =priv.py= verb table and sudo handling — reconcile it with the shared model rather than leaving two privilege paths. Depends on the audio input/output doctor landing the model first (it is the reference implementation). + + ** TODO [#B] Scrolling/Carousel layout: frame fit + wrap-around :hyprland: :PROPERTIES: :LAST_REVIEWED: 2026-07-06 @@ -1125,7 +1177,8 @@ Rewrote the bare =if $var= boolean conditionals (=show_status_only=, =fresh_inst *** 2026-05-26 Tue @ 15:27:09 -0500 eval task moot — the line-434 eval is gone, the survivor is deliberate Verified: the only =eval= left in =archsetup= is line 578 in =retry_install=, and it's intentional and documented — it captures =$?= directly from =eval "$cmd"= to dodge the if-compound-swallows-exit-code trap. Replacing it with an array would reintroduce that bug. The line-434 eval this task pointed at no longer exists. Nothing to change. -** TODO [#B] Doctor button for the audio panel :feature:audio: +** DONE [#B] Doctor button for the audio panel :feature:audio: +CLOSED: [2026-07-10 Fri] :PROPERTIES: :LAST_REVIEWED: 2026-07-09 :END: @@ -1140,6 +1193,28 @@ The real bug, found by driving it: =build_status()= guarded its two device-list A server that hangs on the *first* call never exposes this — =list_sinks= raises inside the guard and masks the unguarded reads behind it — so the obvious regression test passes against broken code. =fake-pactl= grew =FAKE_PACTL_SLEEP_DEFAULTS= to express "answers the lists, hangs on the defaults". Verified end to end: =waybar-audio= now emits =class: degraded= / "Audio graph unavailable" and exits 0. dotfiles =4d42eb3=; full =make test= green. +*** 2026-07-10 Fri @ 06:41:00 -0500 Shipped: the audio doctor, phases 1 through 4 +=audio diag=, =audio doctor=, =audio doctor --fix=, and the panel's DOCTOR section header with DIAGNOSE / FIX keys streaming into a results wall (copy + close). Spec is IMPLEMENTED. dotfiles =01a1d80=, =76857e3=, =7223c51=, =1550ac8=, =4320255=, =bd33440=. + +Live verification on ratio replaced the planned VM run for remedies 1, 4 and 5, and found two bugs no fake could surface: =pactl get-default-sink= prints the literal =@DEFAULT_SINK@= placeholder when no default is set, and remedy 1 re-probed before WirePlumber had re-created the devices, calling a repaired stack broken. Both fixed. + +Left open, not a v1 gap: mpv played silently while the doctor read healthy. The stack was genuinely fine, and per-application stream routing is an explicit spec Non-Goal. Worth a task only if it recurs. + +Second sighting, 2026-07-10: Chrome stopped recognizing the microphone while the stack was healthy (Shure MV7+ default, unmuted, 82%, PTT off). Restarting Chrome fixed it; nothing on the machine was touched. Both sightings share a shape the doctor cannot see: the graph is fine and one client cannot use it. A third sighting turns this into a design question, namely whether the doctor should say "the stack is fine, the fault is in the application" rather than a bare healthy. + +** TODO [#B] The audio doctor never checks the microphone :bug:audio:solo: +The classifier is output-only. =diag.probe_semantic= already collects =default_source= and =default_source_present=, and =classify.py= reads neither: the word "source" appears once in the whole module, in the graph row that counts them. So a muted mic, a default source naming an unplugged device, or a mic at zero volume all classify as =healthy=, and the verdict prints "the default output is present and audible" while the input side goes unexamined. Found 2026-07-10 while asking whether the doctor would have caught Chrome losing the mic. It would not have. + +Not a scope decision. The spec's Non-Goals never say the doctor is output-only, and its Summary calls it a doctor for "a broken sound stack". + +Work: mirror the sink rules onto the source. =probe_semantic= gains =default_source_muted= / =default_source_volume=; the classifier gains the source cases; =classify.findings()= gains an input row beside its =defaults= row, so the CLI wall and the GUI wall both grow it for free. + +Two things not to get wrong. An absent microphone is legitimate on a desktop, so "no input devices" must never be a fault the way =no-output-devices= is. And a monitor source is a legitimate default source (recording desktop audio), which is why =probe_semantic= passes =include_monitors=True= — inheriting the panel's display filter here would call a working setup broken. + +Specced 2026-07-10 after discussion with Craig, and the design grew past the original gap: [[file:docs/specs/2026-07-10-audio-doctor-input-side-spec.org][docs/specs/2026-07-10-audio-doctor-input-side-spec.org]] (DRAFT, four decisions open). A doctor key per direction, a kernel-level capture probe below PipeWire, PTT-aware muting, and a direction-aware guard. The precedence question the build would have faced is gone: a doctor per direction means the user's press says which side they came to fix. + +Parent spec: [[file:docs/specs/2026-07-09-audio-doctor-spec.org][docs/specs/2026-07-09-audio-doctor-spec.org]] (IMPLEMENTED). This is a v1 gap found after the fact, not a phase of it. + ** TODO [#D] Telega coredump recurrence tell :bug:maint: :PROPERTIES: :LAST_REVIEWED: 2026-07-09 |
