diff options
Diffstat (limited to 'todo.org')
| -rw-r--r-- | todo.org | 225 |
1 files changed, 191 insertions, 34 deletions
@@ -55,34 +55,111 @@ 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 -** TODO [#C] todo.org org-lint follow-ups :refactor: -From the 2026-06-15 lint-org sweep. Each needs a human read — these are judgment items, not mechanical fixes, and the line numbers will drift as todo.org changes. -- obsolete-properties-drawer — incorrect PROPERTIES drawer contents (lines 8392, 4201, 4023, 65, 55). -- misplaced-heading — possibly misplaced heading (line 8116). - -** DONE [#C] Reproducible face-coverage generator + coverage diff :feature:solo: -CLOSED: [2026-06-18 Thu] -Built: =face-coverage-dump.el= + =face_coverage.py= + =make face-coverage= / =make face-coverage-diff=. Validated by regenerating and diffing against the hand-built worklist (headings identical; only an intro line and one sharper description differ). Compare mode reports newly-covered / newly-present / disappeared / per-tier deltas. Unrecognized faces route by defface source (elpa -> own package bucket, built-in -> emacs-general child), so a newly-loaded package self-buckets. - -Known edge: a new package whose face prefix collides with an existing family name (e.g. =org-modern= faces start with =org=) folds into that family's bucket instead of getting its own, because the family match wins before the source fallback. Fix when it bites: add the package's prefix to =EXTRA_FAMILIES= in =face_coverage.py=. - -=scripts/theme-studio/face-coverage.org= is hand-regenerated by a throwaway /tmp script each time. Commit a self-contained generator so the worklist regenerates with one command, plus a diff that names what coverage changed between runs. - -Generator — two pieces plus a Makefile target: -- =face-coverage-dump.el= — batch elisp run via =emacsclient= against the live daemon (captures actually-loaded packages), with an =emacs --batch -l init.el= fallback for a clean checkout. For every face in =(face-list)= emit name, first-line docstring, and =(symbol-file f 'defface)=. One JSON/TSV out. -- =face_coverage.py= — read that dump plus the studio's managed set (font-lock map from =build-theme.el=, =UI_FACES= from =generate.py=, =package-inventory.json=); classify each face core/general/package by where its defface lives (=/usr/share/emacs= = built-in, =elpa= = package); group; write =face-coverage.org= with the TODO/DONE tree, =[d/t]= cookies, per-face docstrings, and per-bucket descriptions (group-documentation / package summary). -- =make face-coverage= runs both and writes the file. - -Carry over the manual logic already worked out: the CORE_HINT core-face set; the subsystem/package family buckets (including abbrev, which-func, git-gutter, git-commit, twentyfortyeight, yas, edit-indirect); the erc-ansi and =bg:erc=/=fg:erc= routing; and the separator-aware prefix match (=-=, =:=, =/=). - -Compare mode (=make face-coverage-diff=): -- Parse the committed (HEAD) =face-coverage.org= and the freshly generated one into face→state maps via =^\*+ (TODO|DONE) name=. Report newly covered (TODO→DONE), newly present (new package or Emacs upgrade), disappeared (package removed), and net coverage with per-tier deltas. -- =git diff face-coverage.org= already gives the raw line delta; this is the friendlier summary. -- 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 [#B] F9 toggle collapses a 3-window layout to 2 :bug: +CLOSED: [2026-06-20 Sat] +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). + +*** DONE — browser-gates harness rewrite (with Craig's go-ahead, 2026-06-20) +- =gate(id, body)= helper (05697e83): the 38 standard gates' ok/notes/A + title + + result-div boilerplate, note format standardized to " fails=". Each call site keeps + its literal =location.hash==='#NAMEtest'=. 6 custom gates stay inline. First automated + attempt deleted gates (a closing-finder spanned boundaries) — caught by a gate-count + guard, reverted, redone anchored on each gate's unique =d.id=. Verified all 44 green + + a forced A(false) in a converted gate still FAILs. +- =withSavedState(keys, body)= (a473aa7c): wraps the 7 restore-nothing gates, scoped to + the globals each mutates; JSON-clone snapshot + finally-restore (structuredClone threw + on the studio objects — caught by the gate run as "no verdict", switched to JSON like + the gates' own local saves). The 14 self-restoring gates left as-is. Verified 44 green, + restore round-trip holds, broken assertion in a wrapped gate still FAILs. + +*** 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=). @@ -105,6 +182,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. @@ -112,18 +192,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: @@ -131,11 +216,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. @@ -353,6 +440,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. @@ -368,6 +481,26 @@ Config modules hardcode colors that should come from the theme (audit 2026-06-16 The view-assignment dropdown is a plain HTML menu. Make it a custom menu colored like the other custom menus, and have it indicate which assignment views have all their elements locked, so the user knows when a view's assignments are done. From the roam inbox 2026-06-16. *** TODO [#C] theme-studio: move the "clear palette" button :feature:studio:next: The clear-palette button is too easy to hit by accident (then re-import the JSON to recover). It currently rides with the update-color and palette-generation controls, not with the palette columns. Move it to be left-aligned at the same vertical level as the color-column names. Layout/CSS change in the palette area (app.js / styles.css); visual, so verify by eye. From the roam inbox 2026-06-16. +*** 2026-06-20 Sat @ 05:53:39 -0400 Tightened the elements-table horizontal layout +Reduced per-cell padding 12px to 8px across all three tables and shortened the redundant "mode-line-highlight (mode-line hover)" label to "(hover)". The weight/slant narrowing landed with the custom-widget task below. Commit 792e09b5. +*** 2026-06-20 Sat @ 05:53:39 -0400 Custom weight/slant dropdowns with previews +Replaced the native weight/slant selects with mkEnumDropdown, themed like the color dropdown. Values are spelled out (semibold not "semi"; unset reads "weight"/"slant"), each popup option previews its own weight or slant, and lock + popup behavior mirrors the color dropdown. Commit 055e0992. +*** 2026-06-20 Sat @ 05:53:39 -0400 Language dropdown sorted with nav arrows +Alphabetized the language list with Elisp pinned as the default, and added the ‹ › arrows that step the selection (clamped) reusing stepViewIndex. #langtest gate. Commit be62ae5b. +*** 2026-06-20 Sat @ 05:53:39 -0400 Moved the lock column to the leftmost position +Lock cell now sits first in all three tables, ahead of the element/face name; the name sort moved to column 1. From the roam inbox 2026-06-20. Commit 4f869aa1. +*** 2026-06-20 Sat @ 06:44:07 -0400 Explanatory hovers on the expander detail labels +Each label in the expander detail row carries a DETAIL_HOVERS tooltip, matching the table-header labels. From the roam inbox 2026-06-20. Commit 2caa4606. +*** 2026-06-20 Sat @ 06:44:07 -0400 View-dropdown lock indicator +The view dropdown prefixes a lock glyph on any view whose elements are all locked. Delivers the lock-indicator half of the custom-view-dropdown task; the custom-menu half is still open. From the roam inbox 2026-06-20. Commit 2caa4606. +*** 2026-06-20 Sat @ 06:44:07 -0400 Expand/collapse-all toggle with disclosure triangles +Per-row expander toggles show ▶/▼ disclosure triangles; a header-level expand-all/collapse-all button per table opens or closes every row at once. From the roam inbox 2026-06-20. Commit 2933a362. +*** 2026-06-20 Sat @ 06:44:07 -0400 Expander stays open across a table rebuild +A package edit rebuilds the table, which had collapsed an open expander mid-edit. An EXPANDED set keyed by element/face reopens the open rows on rebuild. From the roam inbox 2026-06-20. Commit 7382bf53. +*** 2026-06-20 Sat @ 06:44:07 -0400 Added 18 language previews +Tokenized samples.py previews for Racket, Scheme, Haskell, OCaml, Scala, Kotlin, Swift, Lua, Ruby, Perl, R, Erlang, SQL, PHP, Ada, Fortran, MATLAB, Assembly, wired into the language dropdown (28 languages total) with a guard test. From the roam inbox 2026-06-20. Commit 309b1e9a. +*** 2026-06-20 Sat @ 06:44:07 -0400 Moved the box column between style and contrast +Box now sits at column 5 in all three tables, after style and before contrast (reverses the earlier box-to-last). From the roam inbox 2026-06-20. Commit 2a34c3c7. *** VERIFY [#A] theme-studio: deploy-wip button on the browser page :feature:studio:next: Needs from Craig: a mechanism choice before I build it. The page is served from file://, so a button can't run make directly. Two options: (a) a tiny localhost helper the page POSTs to (it runs make deploy-wip), or (b) the page writes a watched trigger file that a small daemon/timer picks up. Pick (a) or (b) and I'll implement + test it. Add a button on the theme-studio page that runs the make deploy-wip target locally (build WIP.json into the theme, live-reload the daemon). The page is served from file://, so the browser can't run make directly. Needs a local bridge: a tiny localhost helper the button POSTs to, or a watched trigger file the page writes. Pick the mechanism before building. From the roam inbox 2026-06-15. @@ -8170,7 +8303,7 @@ CLOSED: [2026-06-12 Fri] :END: Parent task for the Emacs Signal client bring-up. Engine: signal-cli (linked secondary device). Front end: a fork of signel at =~/code/signel=, wired through =modules/signal-config.el=. Design: [[id:0cabd6ee-c458-47b5-a8af-3ee054b25821][docs/specs/signal-client-spec-doing.org]]. -Closed 2026-06-12: the bring-up shipped (dated history below). The signel project now has its own =.ai/= scope, so all open signel/signal-cli issues moved to [[file:~/code/signel/todo.org][the signel todo]] and are tracked there flat (the three open children here — handle-error leak, link-with-QR, groups in picker — moved in that pass). Work on =modules/signal-config.el= stays in this file. +Closed 2026-06-12: the bring-up shipped (dated history below). The open signel/signal-cli issues moved to [[file:~/code/smoke/todo.org][the smoke todo]] (smoke is the evolved Signal package) and are tracked there flat (the three open children here — handle-error leak, link-with-QR, groups in picker — moved in that pass). Work on =modules/signal-config.el= stays in this file. *** 2026-06-12 Fri @ 07:34:05 -0500 Signel notify-only-for-unviewed-conversation shipped Wire =cj/signal--should-notify-p= (done) into signel's =signel--handle-receive= notify block (signel.el:277), route through Craig's notify script instead of bare =notifications-notify=, and gate sound behind a defcustom that defaults off. Spec addendum (the four notify details + wiring architecture) accepted 2026-06-11 — see [[id:0cabd6ee-c458-47b5-a8af-3ee054b25821][signal-client-spec-doing.org]] "Notification slice". @@ -8206,7 +8339,7 @@ Verified: (1) new contract test =test-signal-config-prefix-map-registered-under- CLOSED: [2026-06-12 Fri] Relocated from the global capture inbox 2026-06-06. When inside a projectile project, C-c c t (Task) files into that project's root todo.org under the "<Project> Open Work" header. If the project has no todo.org, fall back to the global inbox-file and warn naming the project. -Implemented 2026-06-06 in =modules/org-capture-config.el=: a shared project-aware =function= capture target (=cj/--org-capture-project-location=) used by =C-c c t= (Task, =* TODO=) and a new =C-c c b= (Bug, =* TODO [#C]=). Matches an existing top-level "... Open Work" heading (so ~/.emacs.d hits "Emacs Open Work") and creates "<Capitalized project> Open Work" only when absent. Outside a project / no todo.org -> global inbox under "Inbox" (with a warning in the no-todo.org case). 15 ERT tests in =tests/test-org-capture-config-project-target.el=; daemon e2e confirmed a real capture lands "** TODO [#C] ..." prepended under Open Work. Manual verify filed under the Manual testing and validation parent. NOTE: the matching "<Project> Resolved Work" header for the wrap-up workflow is a separate concern, not handled here. +Implemented 2026-06-06 in =modules/org-capture-config.el=: a shared project-aware =function= capture target (=cj/--org-capture-project-location=) used by =C-c c t= (Task, files a top-level TODO) and a new =C-c c b= (Bug, files a top-level TODO [#C]). Matches an existing top-level "... Open Work" heading (so ~/.emacs.d hits "Emacs Open Work") and creates "<Capitalized project> Open Work" only when absent. Outside a project / no todo.org -> global inbox under "Inbox" (with a warning in the no-todo.org case). 15 ERT tests in =tests/test-org-capture-config-project-target.el=; daemon e2e confirmed a real capture lands a second-level TODO entry prepended under Open Work. Manual verify filed under the Manual testing and validation parent. NOTE: the matching "<Project> Resolved Work" header for the wrap-up workflow is a separate concern, not handled here. ** DONE [#A] theme-studio: 2D gallery color picker for assignment dropdowns :feature:studio: CLOSED: [2026-06-15 Mon] Replaced the per-face color dropdown (mkColorDropdown popup in app.js) with a 2D grid in the palette-panel shape: galleryModel(cur,palette,ground) in app-core.js (pure; reuses columnsFromPalette) returns a default chip, an optional (gone) cell, and rows = ground strip then one row per family (members dark->light, one selected). 5 node tests + #gallerytest browser gate. Trigger and ‹ › step buttons unchanged; applies to all three tiers. From the roam inbox 2026-06-15. @@ -8567,3 +8700,27 @@ Also done this session: =ghostel-module-auto-install= set to =download= (the ori *** 2026-06-18 Thu @ 16:33:56 -0500 ai-term confirmed working after the 0.33.0 pin Craig confirmed in normal use — opening/selecting ai-terms works with no whole-process crash ("everything seems to be working as normal now"). Headless reproduction (open a ghostel buffer in a PGTK GUI frame) had already survived; this is the live-hands confirmation. +** DONE [#C] Reproducible face-coverage generator + coverage diff :feature:solo: +CLOSED: [2026-06-18 Thu] +Built: =face-coverage-dump.el= + =face_coverage.py= + =make face-coverage= / =make face-coverage-diff=. Validated by regenerating and diffing against the hand-built worklist (headings identical; only an intro line and one sharper description differ). Compare mode reports newly-covered / newly-present / disappeared / per-tier deltas. Unrecognized faces route by defface source (elpa -> own package bucket, built-in -> emacs-general child), so a newly-loaded package self-buckets. + +Known edge: a new package whose face prefix collides with an existing family name (e.g. =org-modern= faces start with =org=) folds into that family's bucket instead of getting its own, because the family match wins before the source fallback. Fix when it bites: add the package's prefix to =EXTRA_FAMILIES= in =face_coverage.py=. + +=scripts/theme-studio/face-coverage.org= is hand-regenerated by a throwaway /tmp script each time. Commit a self-contained generator so the worklist regenerates with one command, plus a diff that names what coverage changed between runs. + +Generator — two pieces plus a Makefile target: +- =face-coverage-dump.el= — batch elisp run via =emacsclient= against the live daemon (captures actually-loaded packages), with an =emacs --batch -l init.el= fallback for a clean checkout. For every face in =(face-list)= emit name, first-line docstring, and =(symbol-file f 'defface)=. One JSON/TSV out. +- =face_coverage.py= — read that dump plus the studio's managed set (font-lock map from =build-theme.el=, =UI_FACES= from =generate.py=, =package-inventory.json=); classify each face core/general/package by where its defface lives (=/usr/share/emacs= = built-in, =elpa= = package); group; write =face-coverage.org= with the TODO/DONE tree, =[d/t]= cookies, per-face docstrings, and per-bucket descriptions (group-documentation / package summary). +- =make face-coverage= runs both and writes the file. + +Carry over the manual logic already worked out: the CORE_HINT core-face set; the subsystem/package family buckets (including abbrev, which-func, git-gutter, git-commit, twentyfortyeight, yas, edit-indirect); the erc-ansi and =bg:erc=/=fg:erc= routing; and the separator-aware prefix match (=-=, =:=, =/=). + +Compare mode (=make face-coverage-diff=): +- Parse the committed (HEAD) =face-coverage.org= and the freshly generated one into face→state maps via =^\*+ (TODO|DONE) name=. Report newly covered (TODO→DONE), newly present (new package or Emacs upgrade), disappeared (package removed), and net coverage with per-tier deltas. +- =git diff face-coverage.org= already gives the raw line delta; this is the friendlier summary. +- 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. |
