aboutsummaryrefslogtreecommitdiff
path: root/todo.org
diff options
context:
space:
mode:
Diffstat (limited to 'todo.org')
-rw-r--r--todo.org159
1 files changed, 151 insertions, 8 deletions
diff --git a/todo.org b/todo.org
index f883eb190..575102256 100644
--- a/todo.org
+++ b/todo.org
@@ -55,11 +55,115 @@ Tags are additive. For example, a small wrong-behavior fix can be
=:bug:quick:=, and a feature that requires internal restructuring can be
=:feature:refactor:=.
* Emacs Open Work
-** DONE [#C] todo.org org-lint follow-ups :refactor:
+** DONE [#B] F9 toggle collapses a 3-window layout to 2 :bug:
CLOSED: [2026-06-20 Sat]
-From the lint-org sweeps (2026-06-15, refreshed 2026-06-20). Resolved 2026-06-20: the misplaced-heading false positive was reworded (the bug-capture task's prose quoted heading-like "* TODO" strings), and the broken link was repointed from the missing =~/code/signel/todo.org= to =~/code/smoke/todo.org= (smoke is the evolved Signal package). The obsolete-properties-drawer entries no longer reproduce under a full org-lint pass. Both lint-org --check and the built-in org-lint now report zero.
+Fixed 2026-06-20 (option 1 — reversible toggle, Craig's call). In a 3+ window layout where
+the agent had its own split, toggle-on reused the working window at the bottom edge,
+displacing its buffer and collapsing three windows to two. Added a flag
+(=cj/--ai-term-last-toggle-deleted-split=) set when toggle-off delete-windows the agent's own
+window; =cj/--ai-term-reuse-edge-window= consumes it and falls through to a fresh re-split, so
+the agent returns to its own window and the others are untouched. The flag only changes the 3+
+window case (2-window slot-reuse unchanged). TDD regression
+=test-ai-term--reuse-edge-window-3win-toggle-restores-own-window=; full =make test= green;
+live-reloaded. Commit 64916462. GUI sign-off is a VERIFY under Manual testing and validation.
+
+** TODO [#B] Codebase refactoring program — remaining batch :refactor:solo:
+Resumes the full-codebase refactoring scan run of 2026-06-20 (8-agent fan-out over
+modules/ + scripts/theme-studio/). The goal: apply every scan finding except the
+won't-do items, one focused refactor per commit. 25 done and pushed across the
+2026-06-20 sessions (see =.ai/sessions/= for the logs); 8 remain, listed below.
+The 5 medium extractions are done (calibredb-epub nov helpers fccf29b0, ai-term
+toggle-off 62fee96b, calendar-sync exception parser 23f405b4, dirvish playlist-target
+a1ca2fb0, custom-case title-case-word 4cc9ca0b); the 2 big single-file and 6
+theme-studio items below remain.
+
+*** Working protocol (apply to every item)
+- TDD: write/keep a failing-then-green test; harvest new test seams the refactor opens.
+- Behavior-preserving only. If a "dedup" would delete a real test seam or couple
+ dissimilar code, SKIP it and record why (see skips below).
+- Per refactor, verify in this order, then commit + push (no-approvals mode):
+ 1. =make test-file FILE=<basename.el>= for touched + new tests.
+ 2. =make validate-modules= (loads all 123 modules; catches load/paren errors).
+ 3. Init-launch smoke on a throwaway daemon: =emacs --daemon=cj-sNN=, then
+ =emacsclient -s cj-sNN -e '(emacs-pid)'= to capture the PID, check
+ =(length features)= = 807 and no init errors in the log, then kill by that
+ PID (the emacsclient kill-emacs is flaky; pkill -f 'daemon=cj-sNN'
+ self-matches its own shell — kill the captured PID).
+ 4. Live-reload the edited module into Craig's running daemon
+ (=emacsclient -e '(load "/home/cjennings/.emacs.d/modules/<m>.el")'=); skip
+ the live reload for big use-package modules whose :config restacks (verify via
+ the fresh smoke daemon instead, as with mail-config).
+- Tab-heavy files: =sed -n 'A,Bp' FILE | cat -A= to get exact bytes before an Edit;
+ write NEW code in the documented 2-space style.
+- Shared asset already created: =cj/format-region-with-program= in system-lib.el
+ (the run-a-formatter-over-the-buffer helper). Reuse it for any further
+ format-region duplicates.
+
+*** DONE — medium extractions (2026-06-20 afternoon)
+All five shipped: calibredb-epub nov re-render/centering helpers (fccf29b0);
+ai-term toggle-off teardown + working-buffer swap (62fee96b); calendar-sync
+per-event exception parser (23f405b4); dirvish playlist-target resolution
+(a1ca2fb0); custom-case per-word title-case decision (4cc9ca0b).
+
+*** DONE — big single-file + theme-studio (2026-06-20 afternoon, no-approvals run)
+Both big single-file items shipped: dwim-shell branching command builders
+(f93b4615); custom-comments divider/box generator dedup (42f0c88a). Five of the
+six theme-studio items shipped: face_coverage path_kind (9a52370b),
+capture-default-faces condition_matches unify (28b4d1cf), dropdownRowTextColor
+delete (10a56789), test-file inline-integrity dedup — subTest loop + shared
+inline-strip.mjs (13969c70), generate.py lazy _build()/__getattr__ (6df4ebdc),
+browser-gates assertPreviewFaces for the 3 preview gates (5627f137).
+
+*** Remaining — browser-gates harness rewrite (HIGHEST RISK, deferred for review)
+Two parts of the browser-gates.js item are intentionally NOT done in the
+autonomous no-approvals run — they rewrite the harness that verifies everything,
+so a subtle helper bug manufactures silent false-greens across all 44 gates:
+- =gate(name, body)= helper for the ~39 gates' =let ok;notes;A=...; title; result-div=
+ boilerplate. LOW value (pure boilerplate; note format drifted 17 " | " vs 24
+ " fails="). CRITICAL CONSTRAINT on any attempt: each gate keeps its literal
+ =location.hash==='#NAMEtest'= (run-tests.sh greps it to discover gates) — wrap only
+ the body, e.g. =if(location.hash==='#x')gate('X','x',A=>{...})=. Verify: all 44 gates
+ green AND a deliberately-broken assertion still FAILS (proved feasible — chrome is
+ available; the assertPreviewFaces commit ran exactly that check).
+- =withSavedState(keys, body)= for the ~13 mutating gates' inconsistent
+ PALETTE/MAP/UIMAP/SYNTAX snapshot-restore (7 mutating gates currently restore
+ NOTHING — a real state-pollution bug, not just dedup). Needs per-gate key analysis.
+Both warrant Craig's eye before/after given the harness-rewrite risk. The
+=assertPreviewFaces= part of this item is already done (5627f137).
+
+*** Remaining — item-8 plan() factory (deferred, low value)
+The =plan(overrides)= factory for the ~30 planPaletteGenerator calls (test-app-core.mjs
++ test-palette-generator-core.mjs) was deferred. The calls pass heterogeneous options
+(scheme/accentCount/sourceMode/vibe/intent vary per call); a factory only dedups the
+constant spanCount:0/rng and would hide which options each test actually exercises —
+premature abstraction over varying calls. The other two item-8 parts (subTest loop +
+shared stripExports) shipped in 13969c70.
+
+*** WON'T-DO (do not re-attempt — assessed and rejected)
+- theme-studio buildTable/buildUITable/buildPkgTable merge: genuine per-tier divergence
+ (column order, syntax dual fg/bg dropdowns, ui preview cell, pkg nd markers) + the
+ =.cells[N]= positional sort coupling make a unified builder MORE complex than the
+ three explicit ones. Close as won't-do.
+- Cross-language test overlap (browser-gates preview gate vs test_generate.py
+ PackageFaceCoverage): don't merge — would couple a fast Python test to a headless
+ browser run. A one-line comment in each noting the split is the most that's worth it.
+
+*** Skipped this run (with reasons — don't redo)
+- eshell-config ssh-alias "merge the two helpers": =cj/--eshell-ssh-alias-commands= is
+ a deliberate pure/effectful split with 3 dedicated tests; merging deletes the seam.
+- prog-*-setup boilerplate: only python+webdev share the full pattern; shell/c/elisp/
+ common-lisp differ materially. A keyword-arg helper would be less readable. No
+ premature abstraction.
+- erc join-command =cj/erc--ensure-active-connection= extraction: nesting-only on
+ untestable UI (call-interactively/switch-to-buffer), no test seam, risky tab-rewrite.
+- coverage-core =simplecov-executable-lines= vs =parse-simplecov= clone: borderline
+ MEDIUM, differs only by a =(> hits 0)= predicate; parameterize with a keep-line-p
+ only if revisiting. Low priority.
** TODO [#B] Un-pin ghostel from 0.33.0 once upstream fixes #422/#423 :bug:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-20
+:END:
ghostel is held at 0.33.0 (=ghostel-20260604.2049=, commit 5779a2adceb2) in =modules/term-config.el= to dodge the 0.35.x native-PTY crash. When dakra/ghostel ships a fix for #422 (Linux malloc/signal reentrancy) and #423 (macOS recursive lock), restore =:ensure t= (drop the pin comment) and =package-upgrade ghostel=, then re-run the open-ghostel-in-a-GUI-frame survival check. Watch the two issues for the fixing commit.
archsetup automated the zig 0.15.2 pin (managed =install_zig_pin= step, sha-verified, unit-tested). If the un-pinned ghostel bumps its ghostty dependency to a newer zig, send archsetup the new version + sha256 so it bumps its =ZIG_VERSION= / =ZIG_SHA256= constants (=inbox-send archsetup=).
@@ -82,6 +186,9 @@ Needs from Craig: re-enabling native-comp config-wide is a stability/perf judgme
From the 2026-06 config audit (verified against the live daemon). =early-init.el:69= =(setq native-comp-deferred-compilation nil)= — the obsolete alias of =native-comp-jit-compilation= — turns JIT native compilation OFF entirely, not "synchronous" as the comment claims: 19 .eln files exist for 184 packages, ~100 of 121 modules run interpreted for the daemon's lifetime, and system-defaults.el:42-44's speed-3/8-jobs/always-compile settings are dead. Plus =early-init.el:113-116= restores =gc-cons-threshold= to the captured STOCK default (800000, verified) post-startup — frequent small GC pauses forever. Together these plausibly feed the filed org-capture 15-20s task more than anything in the capture path itself. Actions: retest the old "Selecting deleted buffer" race on 30.2 and re-enable JIT (or AOT sweep); set a deliberate 16-64MB threshold (or gcmh). Check both before burning time on the capture-perf debug task.
** VERIFY [#B] calendar-sync robustness: atomic writes, curl --fail, zero-event false errors :bug:solo:next:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-20
+:END:
Deferred, pairs with the calendar-sync recurrence VERIFY above. The mechanical parts (write to a temp file + rename, add curl --fail, guard the zero-event case) are doable, but any calendar-sync change needs verification against a real .ics feed to avoid masking a genuine empty/failed sync. Do this together with the recurrence fix once you provide a fixture / confirm the live feed.
From the 2026-06 config audit, =modules/calendar-sync.el=:
- =:1309= — agenda file written via =with-temp-file= directly on the target (truncate-in-place); org-agenda/chime reading mid-write sees a partial calendar, hourly. Write temp + =rename-file= (atomic same-fs). Same for =--save-state= :258.
@@ -89,18 +196,23 @@ From the 2026-06 config audit, =modules/calendar-sync.el=:
- =:1229-1233= — =--parse-ics= returns nil for both garbage and a valid calendar with zero in-window events, so healthy near-empty calendars report "parse failed" in =calendar-sync-status=. Distinguish the cases.
** VERIFY [#B] org-roam :config triggers the 15-20s refile scan synchronously at first idle :bug:solo:next:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-20
+:END:
Needs from Craig: this is measurement-first (perf), not a blind fix — it's the same bottleneck as the "optimize org-capture target building" debug task. Run /debug with debug-profiling to measure what actually costs the 15-20s (file count? regex? agenda rebuild?), then fix from the data. I won't restructure the refile/agenda scan without a profile. Say "let's debug it" and I'll profile + fix.
=modules/org-roam-config.el:78-79= — org-roam is =:defer 1=, so its :config calls =cj/build-org-refile-targets= at 1s idle, BEFORE the 5s background timer (=org-refile-config.el:144-151=); on a cold cache the 30k-file scan runs inline and freezes Emacs at first idle. Drop the call — org-roam is loaded long before the 5s timer fires. Likely a player in the filed org-capture 15-20s perf task (=[#B] Optimize org-capture target building performance=) — check both together. From the 2026-06 config audit.
** VERIFY [#B] transcription: stderr never reaches the log, video transcripts stranded in /tmp :bug:solo:next:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-20
+:END:
Deferred from the batch (no blocker; needs a focused pass with live verification). Plan: (1) transcription-config.el:210 — make-process :stderr with a file path creates a buffer, not a file; route stderr into the process buffer and write the captured text out in the sentinel, then drop the leaked buffer. (2) :370-374 — derive the txt/log base from the VIDEO path, not the temp mp3's /tmp path, so transcripts land alongside the source. The path-derivation half is cleanly unit-testable; the stderr half needs a real transcription run to verify, which is why I held it for a focused session rather than the batch.
From the 2026-06 config audit, =modules/transcription-config.el=:
- =:210= — =make-process :stderr= with a file PATH creates a BUFFER named like the path (verified by probe); the "Errored. Logs in <file>" notification points at a log without the error text, and the hidden stderr buffer leaks per transcription. Route stderr into the process buffer or write it out in the sentinel.
- =:370-374= — video path derives txt/log from the temp mp3's /tmp path; the transcript lands in /tmp and dies on reboot, contradicting the "alongside the source" docstring. Pass the video's path as the output base.
-** VERIFY [#C] Dirvish: free D for hard-delete, move duplicate :feature:quick:next:
-Needs from Craig: two confirmations before I wire this. (1) Which key for the moved duplicate command (your note said "duplicate on 2" — confirm 2)? (2) Binding D to sudo rm -rf is genuinely dangerous; confirm you want a forced hard-delete on a single capital key, and whether it should prompt (yes-or-no-p naming the target) before running. I won't bind an unguarded sudo rm -rf autonomously.
-In dirvish, keep =d= = delete (=dired-do-delete=), move duplicate (=cj/dirvish-duplicate-file=, currently =D=) to another key, and bind =D= = =sudo rm -rf= for a forced hard delete — capital for the more destructive op. Craig's note says "duplicate on 2"; confirm that's the intended key, and guard the sudo path carefully before wiring. From the roam inbox.
+** 2026-06-20 Sat @ 10:29:42 -0400 Dirvish: d duplicates, D force-deletes (guarded)
+Decided with Craig 2026-06-20: remove delete-to-trash entirely, bind =d= = =cj/dirvish-duplicate-file= and =D= = =cj/dirvish-hard-delete= (sudo rm -rf after a =yes-or-no-p= naming the exact targets). Built in =modules/dirvish-config.el= (=cj/--dirvish-hard-delete-command= pure builder + =cj/dirvish-hard-delete= command; keymap =d=/=D= swap). 4 ERT tests for the command builder; full suite green; live-reloaded into the daemon (=dirvish-mode-map= =d=/=D= rebinding confirmed). Manual keypress + sudo-flow check filed under Manual testing and validation.
** VERIFY [#C] page-signal pager account deregistered — re-registration needs your hands
:PROPERTIES:
@@ -108,11 +220,13 @@ In dirvish, keep =d= = delete (=dired-do-delete=), move duplicate (=cj/dirvish-d
:END:
Reported by .emacs.d 2026-06-12 01:01: the dedicated pager number (+15045173983, the Claude Pager Google Voice number on signal-cli) returns "User ... is not registered" on every send — Signal appears to have deregistered it (GV numbers get periodically re-verified). Re-registration requires captcha/SMS, which only you can do. Until then every page-signal call fails; .emacs.d's config-audit page fell back to email. Wrapper lives at claude-templates/bin/page-signal.
-** VERIFY [#C] Pull a fullscreen terminal window away with C-; b + arrow :feature:next:
-Needs from Craig: confirm the intended behavior. When a terminal fills the frame, C-; b + arrow should "pull a window away" — split off a new window in the arrow's direction and move focus there? Or pop the terminal out and restore the prior layout? The C-; b window family exists (resize lives there); I need the exact gesture + target before wiring it.
-When a terminal fills the frame, =C-; b= then a right or down arrow should shrink the window from that edge, reducing its width or height so another buffer can share the screen without leaving the terminal. Relates to the ai-term adaptive placement and unified-popup tasks. From the roam inbox.
+** 2026-06-20 Sat @ 10:29:42 -0400 C-; b + arrow pulls a window away from a sole window
+Decided with Craig 2026-06-20: when the selected window is the sole window, =C-; b= + arrow keeps that window on the arrow's edge and slivers =other-buffer= in on the opposite side (=minimize-window=, so the current window keeps almost the whole frame), focus staying put; each further arrow then shrinks it step by step via =windsize=, reading the same as resizing an existing split. Generalizes to any sole window, not just terminals — resize was a no-op there before. Built in =modules/ui-navigation.el= (=cj/window-pull-side= pure mapping + =cj/window--pull-away= + a =one-window-p= branch in =cj/window-resize-sticky=). ERT tests for the mapping and both sticky paths; geometry verified in a headless frame (down -> terminal 37/40 at the bottom, reveal 2 lines slivered on top via window-min-height=1, windsize-down then steps it down); full suite green; live-reloaded into the daemon. Refined from a first cut that split toward the arrow and jumped to 50%, per Craig's feedback. Manual gesture check filed under Manual testing and validation.
** VERIFY [#C] Remove unused system-power keybindings :refactor:quick:next:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-20
+:END:
Needs from Craig: the task says "confirm the exact set to keep before unbinding." Under C-; ! the bindings are shutdown (s), reboot (r), restart-Emacs (e), and friends. Tell me which to keep bound and which to drop (the completing-read menu still reaches the rare ones), and I'll unbind the rest.
=modules/system-commands.el= binds shutdown (=C-; ! s=), reboot (=C-; ! r=), restart-Emacs (=C-; ! e=) and friends under the =C-; != prefix. Craig rarely uses them and wants the key real-estate back. Drop the bindings he doesn't use; the completing-read menu can still reach the rare ones. Confirm the exact set to keep before unbinding. From the roam inbox.
@@ -330,6 +444,32 @@ What we're verifying: C-c c t and C-c c b file into the current projectile proje
- Run C-c c b (Bug) similarly and confirm it lands as "* TODO [#C] ..." under the same header.
- Run a capture from outside any project (or a project with no todo.org) and confirm the global-inbox fallback with a warning.
Expected: in-project captures land in that project's Open Work; out-of-project captures fall back to the global inbox with a warning.
+*** VERIFY Dirvish d duplicates, D force-deletes with a confirm
+What we're verifying: in dirvish, d now duplicates the file at point (delete-to-trash removed), and D force-deletes the marked files via sudo rm -rf after a yes-or-no-p naming the targets. The pure command builder is unit-tested; this is the live keypress plus the guarded destructive path.
+- Open dirvish on a scratch directory holding a couple of throwaway files
+- Put point on a file and press d — confirm a "<name>-copy.<ext>" appears (a duplicate, nothing deleted)
+- Mark one or two throwaway files, press D, and read the "Force-delete (sudo rm -rf, NO undo): <names>?" prompt
+- Answer no first (confirm nothing happens), then press D again and answer yes
+- Note whether sudo prompts for a password and whether the file actually disappears
+Expected: d duplicates; D names the exact targets and only deletes on yes; the files are gone with no trash copy. If sudo needs a password that shell-command can't supply, flag it — the delete may need to route through a tty instead.
+*** VERIFY F9 agent toggle no longer shrinks the window after a C-; b pull-away
+What we're verifying: the f9 split-shrink bug is fixed. The toggle now captures the agent window's total-height (not body-height), so the capture/replay round-trip is immune to the mode line's pixel height — the agent should keep the same height across repeated toggles even with the WIP theme's near-zero =mode-line-inactive= (=:height 2=). The batch harness can't reproduce this (a TTY mode line is always a full line), so this needs a real GUI frame.
+- Open the agent (F9) and maximize it so it fills the frame (=C-x 1= inside it)
+- Pull it down with =C-; b <down>= (the reveal slivers in above; the agent becomes the bottom window) and press =<escape>= to end the sticky resize
+- Note the agent window's height (eyeball it, or =M-:= the form below)
+#+begin_src emacs-lisp
+(window-total-height (get-buffer-window (current-buffer)))
+#+end_src
+- Press F9 to toggle the agent off, then F9 again to toggle it back on. Repeat 5–6 times.
+- Re-check the height after each on-toggle
+Expected: the agent window stays the same height every cycle (no one-line-per-toggle shrink). Before the fix it lost ~1 line each toggle. If it still shrinks, capture the height sequence and reopen this as a TODO — the remaining drift would point at a different rounding source than the mode-line pixel height.
+*** VERIFY F9 toggle preserves all windows in a 3-window layout
+What we're verifying: toggling the agent off then on in a 3-window layout no longer eats a working window. The fix re-splits the agent into its own window on toggle-on instead of reusing the working window at the edge, so the layout is preserved across the toggle (off then on returns the same three windows). Batch tests already assert the window count; this is the visual read in a real frame.
+- Set up three windows: a code/file window on top, a second working window (e.g. todo.org) in the middle, and the agent (F9) as a full-width strip at the bottom
+- Note the three windows and which buffers they show
+- Press F9 to toggle the agent off (the bottom strip closes, two windows remain)
+- Press F9 again to toggle it back on
+Expected: you are back to three windows — the agent returns as its own bottom strip, and both working windows (code + middle) are still showing their buffers. Before the fix, toggle-on replaced the middle/bottom working window with the agent, leaving two windows.
** PROJECT [#A] Theme-Studio Open Work
Parent grouping the open theme-studio / theming issues; close each child independently.
@@ -8585,3 +8725,6 @@ Compare mode (=make face-coverage-diff=):
- Optional: append a dated =covered/total= line to a small coverage-log for progress over time.
Dump from the live daemon by default (reflects the packages actually run); the batch fallback won't see lazily-loaded packages until required.
+** DONE [#C] todo.org org-lint follow-ups :refactor:
+CLOSED: [2026-06-20 Sat]
+From the lint-org sweeps (2026-06-15, refreshed 2026-06-20). Resolved 2026-06-20: the misplaced-heading false positive was reworded (the bug-capture task's prose quoted heading-like "* TODO" strings), and the broken link was repointed from the missing =~/code/signel/todo.org= to =~/code/smoke/todo.org= (smoke is the evolved Signal package). The obsolete-properties-drawer entries no longer reproduce under a full org-lint pass. Both lint-org --check and the built-in org-lint now report zero.