<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/org-refile-config.el, branch load-graph-classify-end</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-end</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-end'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-05-24T21:34:16+00:00</updated>
<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>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>refactor(cj-cache): rename to cj-cache-lib for naming consistency</title>
<updated>2026-05-10T20:23:23+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T20:23:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a0e5edfb3d77f34d0f71bdc9bb8bc3a563ee6436'/>
<id>urn:sha1:a0e5edfb3d77f34d0f71bdc9bb8bc3a563ee6436</id>
<content type='text'>
Library files in this codebase are suffixed `-lib' (system-lib.el is
the established precedent).  The Phase 5 cache helper landed as
cj-cache.el; the spec's table proposed names without the suffix and
I followed it without checking against convention.  Fix the
inconsistency now while there are only two consumers and one test.

Rename modules/cj-cache.el -&gt; modules/cj-cache-lib.el; update
provide form, file header, and the three (require 'cj-cache) call
sites in org-agenda-config, org-refile-config, and test-cj-cache.
No behavior change.
</content>
</entry>
<entry>
<title>refactor(org-refile): migrate to cj-cache helper</title>
<updated>2026-05-10T19:51:53+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T19:51:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=7833f4ff97edd46d62cea1eeb0405923ec2806cb'/>
<id>urn:sha1:7833f4ff97edd46d62cea1eeb0405923ec2806cb</id>
<content type='text'>
Phase 5 step 3 of utility-consolidation, second of two cache migrations.  Same shape as the agenda migration: drop four state vars, replace the build-with-cache function with a thin wrapper around `cj/cache-value-or-rebuild', extract the slow scan into a pure-ish helper.

Add `cj/--org-refile-scan-targets' as the slow filesystem walk (org-roam node enumeration plus 30,000+ todo.org files across code-dir and projects-dir).  `cj/build-org-refile-targets' now reads as: detect background-build state, ask the cache helper for the value with the scan helper as BUILD-FN, route the original log lines through :on-hit / :on-build-success.

Drop four module-level state vars:
- `cj/org-refile-targets-cache'
- `cj/org-refile-targets-cache-time'
- `cj/org-refile-targets-cache-ttl'
- `cj/org-refile-targets-building'

Rewrite the existing test file to test wrapper behavior at the contract level (stub the scan helper, verify wrapper outcomes).  8 tests parallel the agenda test set: first-call builds, second-call uses cache, force-rebuild bypass, TTL expiration, empty scan, building-flag cleanup on success and error, and error propagation.
</content>
</entry>
<entry>
<title>fix(org-refile): skip airootfs directories to avoid permission errors</title>
<updated>2026-01-24T18:25:38+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-01-24T18:25:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=36fb98d848c65cdaadcec08c128adf82b2b0323e'/>
<id>urn:sha1:36fb98d848c65cdaadcec08c128adf82b2b0323e</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor: Use cj/log-silently for debug messages</title>
<updated>2025-11-17T04:10:58+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2025-11-17T04:10:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=6f57d93f9fa09ccbd97a767ba995a5755dedc103'/>
<id>urn:sha1:6f57d93f9fa09ccbd97a767ba995a5755dedc103</id>
<content type='text'>
Converted debug/informational messages to use cj/log-silently instead of
message across multiple modules. These are automatic initialization or
background task messages that don't need minibuffer display but should
still be logged to *Messages* buffer.

Changes:
- org-agenda-config.el: Cache build/hit messages (4 messages)
- org-refile-config.el: Cache build/hit + mode switching (5 messages)
- org-export-config.el: reveal.js download message (1 message)
- auth-config.el: oauth2-auto cache fix message (1 message)
- quick-video-capture.el: initialization message (1 message)

All modules now require system-lib for cj/log-silently function.
Keeps UI clean while maintaining debuggability.
</content>
</entry>
<entry>
<title>perf: Optimize org-refile with caching to eliminate 15-20s delay</title>
<updated>2025-11-12T00:34:08+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2025-11-12T00:34:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=22e359cc511e4a3ee8a93164e299d62a40cd52f7'/>
<id>urn:sha1:22e359cc511e4a3ee8a93164e299d62a40cd52f7</id>
<content type='text'>
Implemented comprehensive caching solution for org-refile targets that
eliminates repeated filesystem scans (34,649 files) on every refile operation.

Performance Impact:
- Before: 15-20 seconds per refile × 12+/day = 3-4 minutes daily
- After: Instant (&lt;50ms) via cache, async build in background
- Daily time saved: ~3-4 minutes + eliminated 12+ context switches

Root Cause:
- cj/build-org-refile-targets scanned all files in 3 directories:
  * ~/.emacs.d (11,995 files)
  * ~/code (18,695 files)
  * ~/projects (3,959 files)
- Called on EVERY refile via cj/org-refile
- directory-files-recursively is expensive with deep hierarchies

Solution Implemented:
1. Cache layer with 1-hour TTL
   - First call: builds and caches targets (one-time cost)
   - Subsequent calls: use cache (instant)
   - Auto-refresh after 1 hour or Emacs restart

2. Async cache building
   - Runs 5 seconds after Emacs idle (non-blocking)
   - Zero startup impact
   - Cache ready before first use in typical workflow

3. Manual refresh available
   - M-x cj/org-refile-refresh-targets
   - Use after adding new projects/todo.org files
   - Force rebuild bypasses cache

4. Robust error handling
   - Building flag prevents concurrent builds
   - unwind-protect ensures flag always clears
   - Graceful handling if user refiles before async build completes

Changes:
- modules/org-refile-config.el:
  * Added cache variables with TTL support
  * Modified cj/build-org-refile-targets for caching
  * Added cj/org-refile-refresh-targets for manual refresh
  * Async build via run-with-idle-timer
  * Enhanced commentary documenting performance

- tests/test-org-refile-build-targets.el (NEW):
  * 9 comprehensive ERT tests
  * Coverage: normal, boundary, error cases
  * Tests cache logic, TTL, force rebuild, async flag
  * All tests pass, zero regressions

Test Results:
- 9/9 new tests passing
- 1,814 existing tests still passing
- Zero regressions introduced
</content>
</entry>
<entry>
<title>changing repositories</title>
<updated>2025-10-12T16:47:26+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2025-10-12T16:47:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=092304d9e0ccc37cc0ddaa9b136457e56a1cac20'/>
<id>urn:sha1:092304d9e0ccc37cc0ddaa9b136457e56a1cac20</id>
<content type='text'>
</content>
</entry>
</feed>
