<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/org-refile-config.el, branch load-graph-classify-start</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-05-24T12:21:44+00:00</updated>
<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>
