<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/org-agenda-config.el, branch main</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-06-03T01:38:06+00:00</updated>
<entry>
<title>feat(ui): name the operation in completing-read prompts</title>
<updated>2026-06-03T01:38:06+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-03T01:38:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=13b053c2a99d30c1131d920a62febde6ee9a628b'/>
<id>urn:sha1:13b053c2a99d30c1131d920a62febde6ee9a628b</id>
<content type='text'>
A picker prompt is the last thing shown before a command commits, so a bare noun leaves a mis-keyed command ambiguous. Hitting C-f8 (project agenda) instead of C-f9 (AI-vterm picker) gave the same "Project:" prompt with no signal which one was about to run.

Reworded 17 prompts across 8 modules so each names the operation rather than just the thing being chosen: "Project:" becomes "Show agenda for project:", "F6:" becomes "Run tests:", the dwim-shell sub-prompts gain their context (checksum algorithm, PDF compression quality, text-to-speech voice, run dwim-shell command), the two contact pickers split into "Find contact:" and "Insert contact email:", and the dirvish ediff, org finalize, and custom-comments length/box-style prompts get the same treatment.

I audited all ~124 completing-read / read-* call sites; the rest already named their operation and were left alone. These are prompt-string changes only, no logic touched.
</content>
</entry>
<entry>
<title>docs(load-graph): classify Org modules</title>
<updated>2026-05-24T21:34:16+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T21:34:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=02baa68063f02cc571789c03b1101c28d139200d'/>
<id>urn:sha1:02baa68063f02cc571789c03b1101c28d139200d</id>
<content type='text'>
Seventh classification batch: the thirteen Org modules — config, agenda, babel, capture, contacts, drill, export, noter, refile, reveal, roam, webclipper, hugo. I annotated each header, added a Batch 7 table to the inventory, and extended the validation allowlist. 65 of 102 modules are now classified.

The daily workflows (config, agenda, capture, refile, roam) keep their eager reason per the spec's Phase 6 target. Babel and contacts move to after-load; export, reveal, drill, noter, webclipper, and hugo become command-loaded. The agenda and refile idle-timer caches are recorded as the side effects the spec already tracks for cache-lifecycle work. No new hidden dependencies.
</content>
</entry>
<entry>
<title>fix(org): surface directory-scan failures instead of crashing or hiding them</title>
<updated>2026-05-24T12:21:44+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T12:21:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=12fb0108ba217f06fb9d40da8431d49540650402'/>
<id>urn:sha1:12fb0108ba217f06fb9d40da8431d49540650402</id>
<content type='text'>
The refile target scan caught permission-denied and silently dropped the directory, and would crash outright on a missing root (only permission-denied was caught, so a missing code-dir/projects-dir raised file-missing and aborted the whole build). The agenda build had the same crash: cj/add-files-to-org-agenda-files-list called directory-files on projects-dir with no existence check.

Extracted cj/--org-refile-scan-dir, which warns (display-warning) and returns nil for a missing, unreadable, or permission-denied root so the rest of the scan continues. Guarded the agenda scan the same way. Both now log a concise warning naming the skipped directory rather than failing silently or fatally.

Also fixed a latent bug surfaced here: org-refile-targets was never declared special, so under make compile cj/org-refile-in-file let-bound it lexically and the scoped targets never reached org-refile. Added (defvar org-refile-targets) so the binding stays dynamic when byte-compiled. Tests cover the helper (missing/permission-denied/normal) and the agenda missing-dir guard.
</content>
</entry>
<entry>
<title>feat(chime): limit the event tooltip to the next 3 days</title>
<updated>2026-05-24T05:12:03+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T05:12:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=85eb9bfa42bb8d36fef6d05211a266da06894d17'/>
<id>urn:sha1:85eb9bfa42bb8d36fef6d05211a266da06894d17</id>
<content type='text'>
The tooltip looked ahead a full week (chime-tooltip-lookahead-hours was 7 * 24), which crowded it with events I don't need at a glance. I dropped it to 3 * 24, so it shows today, tomorrow, and the next day only. I also fixed the comment above it, which still claimed 10 events within 6 days when the code already said 20 within 7.
</content>
</entry>
<entry>
<title>test(architecture): guard top-level timers + add startup-contract smoke test</title>
<updated>2026-05-15T07:13:37+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-15T07:13:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c3420106b57b999db6526c62c1ce0e33c28ef121'/>
<id>urn:sha1:c3420106b57b999db6526c62c1ce0e33c28ef121</id>
<content type='text'>
Add a tiny source-level architecture suite at
tests/test-architecture-startup-contracts.el with two checks:

- Only keybindings.el may globally own the exact C-; prefix.  Catches
  accidental cross-module rebinding before it ships.
- Top-level timer scheduling (run-with-timer / run-at-time /
  run-with-idle-timer) must be guarded by (unless noninteractive ...)
  so requiring a module in batch / test mode does not schedule
  startup timers.  Timer calls inside defuns are exempt -- the test
  only rejects forms that execute their body when the module loads.

Four modules had unguarded top-level timer scheduling and would have
tripped the new test.  Wrap their startup hooks/timers in
(unless noninteractive ...):

- modules/org-agenda-config.el: 10s idle cache build
- modules/org-refile-config.el: 5s idle cache build
- modules/quick-video-capture.el: after-init-hook + 2s fallback
- modules/wrap-up.el: emacs-startup-hook bury-buffers delay

The contract being protected is "requiring a module in batch should
not start a clock running."  Test failures will now point straight at
the offending file/form.
</content>
</entry>
<entry>
<title>feat(org-agenda): add VERIFICATION and IN-PROGRESS blocks around SCHEDULE</title>
<updated>2026-05-14T01:14:41+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-14T01:14:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=9a8a2096303c702f86f5175cb332e0938dd420d0'/>
<id>urn:sha1:9a8a2096303c702f86f5175cb332e0938dd420d0</id>
<content type='text'>
The main "d" agenda view grows two new blocks. A VERIFICATION block lists tasks in the VERIFY TODO state, placed just above the day's SCHEDULE. An IN-PROGRESS block lists tasks in the DOING TODO state, placed just under SCHEDULE. The full block order is now: OVERDUE -&gt; HIGH PRIORITY -&gt; VERIFICATION -&gt; SCHEDULE -&gt; IN-PROGRESS -&gt; PRIORITY B.

Scope matches the other blocks (every entry in `org-agenda-files`). Scheduled and deadlined entries are included -- a VERIFY task with a date appears in both VERIFICATION and SCHEDULE, mirroring how HIGH PRIORITY behaves. Habits are skipped via `cj/org-skip-subtree-if-habit`; PROJECT-keyword parents wouldn't match `(todo "VERIFY")` exact-state filters anyway, so no extra skip there.

Two new header defvars (`cj/main-agenda-verify-title`, `cj/main-agenda-doing-title`) for symmetry with the existing four. Both blocks reference the shared `cj/--main-agenda-prefix-format` so a format tweak still lands in one place.

Five new tests in `test-org-agenda-config-skip-functions.el` lock the block order, each new block's header / prefix-format / skip-function, and the include-scheduled-entries contract.
</content>
</entry>
<entry>
<title>refactor(org-agenda): extract main-agenda prefix format into a defvar</title>
<updated>2026-05-13T21:14:50+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-13T21:14:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=e58f58b656cff9d9dc0e4b9fa59e236f0431e1b4'/>
<id>urn:sha1:e58f58b656cff9d9dc0e4b9fa59e236f0431e1b4</id>
<content type='text'>
`org-agenda-custom-commands` inlined `  %i %-15:c%?-15t% s` four times across the "d" command's overdue / high-priority / schedule / priority-B blocks. New `cj/--main-agenda-prefix-format` defvar holds the literal once; every block now references the symbol so a format tweak lands in one place.

Regression test walks the "d" command's blocks and asserts each `org-agenda-prefix-format` cell resolves to the shared symbol -- a block that silently diverges fails the check.
</content>
</entry>
<entry>
<title>feat(org-agenda): use project name as todo.org category</title>
<updated>2026-05-13T20:25:52+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-13T20:25:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c3514440eb3de3101576baa5c3c592c0d908f70b'/>
<id>urn:sha1:c3514440eb3de3101576baa5c3c592c0d908f70b</id>
<content type='text'>
The %c column on agenda blocks rendered every project's todo.org as "todo:" -- org defaults the buffer category to the filename without extension, so every entry looked alike. An org-mode-hook now overrides org-category with the parent directory's basename (stripping a single leading dot, so ~/.emacs.d/todo.org reads as "emacs.d") whenever a todo.org file opens and its category is still the filename default. Explicit #+CATEGORY: keywords still win.

14 tests in test-org-agenda-config-category.el cover the helper's normal/boundary/error paths and the hook's override + explicit-category-preserved cases.
</content>
</entry>
<entry>
<title>fix(org-agenda): skip CANCELLED entries from main agenda SCHEDULE</title>
<updated>2026-05-13T18:04:50+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-13T18:04:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=8e579508a1e23e66513d2e8f97844d0eab2156d7'/>
<id>urn:sha1:8e579508a1e23e66513d2e8f97844d0eab2156d7</id>
<content type='text'>
The "d" command's (agenda ...) block had no org-agenda-skip-function. The global org-agenda-skip-scheduled-if-done is nil. CANCELLED tasks with a SCHEDULED date rendered in the forward-looking schedule unfiltered.

The fix adds an org-agenda-skip-function to the SCHEDULE block: (org-agenda-skip-entry-if 'todo '("CANCELLED")). The scope is deliberate. Only CANCELLED is filtered, not DONE or FAILED. A scheduled DONE task is a record of when something happened and stays visible.

Tests cover the configuration: the form must appear on the agenda block and must not appear on the overdue, hi-pri, or priority-B blocks.
</content>
</entry>
<entry>
<title>fix(org): give the F8 agenda window 75% of the frame</title>
<updated>2026-05-12T11:07:20+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-12T11:07:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=fb39fe85378b58b77d2c5a7a6464b1b4aec0b85d'/>
<id>urn:sha1:fb39fe85378b58b77d2c5a7a6464b1b4aec0b85d</id>
<content type='text'>
The agenda buffer's `display-buffer-alist' rule used `(window-height . fit-window-to-buffer)', so a sparse agenda opened as a sliver a few lines tall. The rule now takes `(window-height . cj/org-agenda-window-height)', a defcustom defaulting to 0.75 (the fraction of the frame the agenda window gets), and the rule itself moved into `cj/--org-agenda-display-rule' so it's testable. New `test-org-agenda-config-display.el' checks that the configured fraction flows through, that it's no longer `fit-window-to-buffer', and (integration) that `display-buffer' produces a window near that size.

`(use-package alert)' gained an `:if (or (not noninteractive) (require 'alert nil t))' guard: the batch test runner loads this module without `package-initialize', so the optional notification package may be installed but not yet on the load path, and the unconditional `:config' setq's would error.
</content>
</entry>
</feed>
