<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/tests, 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-24T20:31:07+00:00</updated>
<entry>
<title>test: cover markdown-html filter and media-player selector</title>
<updated>2026-05-24T20:31:07+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T20:31:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c6a81743f95638bc8275bea1b590f4ca9f7cbc39'/>
<id>urn:sha1:c6a81743f95638bc8275bea1b590f4ca9f7cbc39</id>
<content type='text'>
Two real-logic gaps from the refreshed coverage backlog. cj/markdown-html (markdown-config) is the impatient-mode filter that wraps a source buffer's text in the strapdown HTML shell — tested for normal content and an empty buffer. cj/select-media-player (media-utils) was the one untested function there — tested that choosing an available player updates cj/default-media-player and that a non-matching selection leaves it unchanged. Both mock at the boundary (completing-read, the source buffer).
</content>
</entry>
<entry>
<title>test(elfeed): cover extract-stream-url and process-entries helpers</title>
<updated>2026-05-24T20:03:39+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T20:03:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=35fa629759978cb123e4a1ccd6747a2d4cc9a17b'/>
<id>urn:sha1:35fa629759978cb123e4a1ccd6747a2d4cc9a17b</id>
<content type='text'>
elfeed-config had only the youtube-feed-format helper under test; cj/extract-stream-url and cj/elfeed-process-entries were untested despite having clear error/boundary paths. Added characterization + Normal/Boundary/Error coverage: extract-stream-url returns the trimmed URL on success, nil on non-URL output or nonzero exit, and signals when yt-dlp is absent; process-entries applies the action per selected entry and marks read, errors when nothing is selected, skips entries with no link, catches per-entry action errors by default, and propagates them under skip-error-handling. yt-dlp (call-process) and the elfeed-search API are stubbed at the boundary.
</content>
</entry>
<entry>
<title>test(org-capture): smoke-test template key uniqueness and file targets</title>
<updated>2026-05-24T19:42:58+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T19:42:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=2e3905c728bacb713ee7857091d1d69d2b0473f4'/>
<id>urn:sha1:2e3905c728bacb713ee7857091d1d69d2b0473f4</id>
<content type='text'>
Org capture templates are assembled across org-capture-config, quick-video-capture, org-contacts-config and other modules, so a duplicate dispatch key or a file target pointing at an unset path variable would be easy to miss. Added a smoke test that loads the cleanly-loadable capture modules, applies their lazy additions, and asserts no two templates share a key and that every symbol-valued file target resolves to a non-empty string path. Literal-string targets (the video template's no-save (file "")) and lambda targets (the drill file pickers) are intentionally excluded; webclipper templates need org-web-tools and are covered by their own test.
</content>
</entry>
<entry>
<title>fix(elfeed): bound and clean up the synchronous YouTube fetch</title>
<updated>2026-05-24T19:40:03+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T19:40:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c097b5b4540d51fd279a81c0834b008331e936c9'/>
<id>urn:sha1:c097b5b4540d51fd279a81c0834b008331e936c9</id>
<content type='text'>
cj/youtube-to-elfeed-feed-format called url-retrieve-synchronously with no timeout, so a hung YouTube request would block Emacs indefinitely, and it only killed the temporary URL buffer when an ID was successfully extracted — a page without the expected markers leaked the buffer.

Passed cj/elfeed-url-fetch-timeout (10s) to the synchronous fetch, and moved the fetch+parse into an unwind-protect that always kills the temp buffer (live-p guarded), including the parse-failure path. Tests mock the network boundary and cover a normal channel parse, that a timeout is passed, and that the buffer is not leaked when parsing fails.

Also added tests for the EWW user-agent advice (no code change): it already injects the desktop UA only from eww-mode buffers, so package.el and other non-EWW url callers pass through untouched — the tests pin that scoping and the replace-not-duplicate header behavior.
</content>
</entry>
<entry>
<title>fix(org-export): remove contradictory org-export-with-tasks default</title>
<updated>2026-05-24T19:36:43+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T19:36:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=94ef5242e72a39faa9eb14a705387ccad339be14'/>
<id>urn:sha1:94ef5242e72a39faa9eb14a705387ccad339be14</id>
<content type='text'>
org-export-config.el set org-export-with-tasks twice in a row — first to ("TODO"), then to nil. The final value won (export no tasks), but the stale first assignment and its "export with tasks by default" comment contradicted it, so the intended policy was ambiguous on a read.

Removed the leftover ("TODO") line. nil is the deliberate default: it is the value that was already winning, its comment matches, and it sits with the adjacent "export without tags / section numbers by default" settings. Added a smoke test that fires the deferred ox :config and pins org-export-with-tasks to nil so a future flip is caught.
</content>
</entry>
<entry>
<title>fix(org-roam): guard move-branch-to-roam against data loss</title>
<updated>2026-05-24T19:33:21+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T19:33:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=5c0fa15d1d5bbe48f85f21e98bb6e91e9b9bcd85'/>
<id>urn:sha1:5c0fa15d1d5bbe48f85f21e98bb6e91e9b9bcd85</id>
<content type='text'>
cj/move-org-branch-to-roam cut the subtree from the source buffer before writing the new roam file, so a failure in the demote/format/write/db-sync steps left the subtree gone from the source and not persisted anywhere — a destructive operation with no rollback.

Reordered so the node file is written and verified on disk before org-cut-subtree runs; a failed write now aborts with the source untouched. Added a no-clobber guard (refuse an existing target file) and a confirmation prompt for large subtrees (&gt;= cj/move-org-branch-confirm-lines, 30) or buffers with unsaved changes. The source buffer is deliberately left modified and undoable rather than auto-saved, so the move stays reversible. New test drives the write-failure-preserves-source invariant via an unwritable roam dir; the existing creates-roam-file test gained the confirm mock.
</content>
</entry>
<entry>
<title>refactor(linear): point config at the renamed pearl package</title>
<updated>2026-05-24T12:45:14+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T12:45:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c858c74aa09667fbf899f587be816e8ad5e20d55'/>
<id>urn:sha1:c858c74aa09667fbf899f587be816e8ad5e20d55</id>
<content type='text'>
The linear-emacs package was renamed to pearl (~/code/pearl, feature pearl, all symbols pearl-*). Swapped every linear-emacs-* reference to pearl-* across linear-config.el (the use-package form, :load-path, the 26 :commands, the api-key/default-team-id/org-file-path vars, and the lazy-key advice targets pearl--graphql-request-async and pearl-check-setup), the dashboard launcher, and the two test files.

Kept the Linear-domain naming intact, since pearl is just a client for the Linear service: the C-; L prefix, the cj/linear-* wrapper helpers, the "Linear" dashboard label, the api.linear.app authinfo host, and the data/linear.org synced file are unchanged. Verified the wiring in a live daemon — pearl loads, the team id and org-file path apply, and the key advice installs on both entry points.
</content>
</entry>
<entry>
<title>refactor(text-enclose): extract shared region-or-buffer bounds helper</title>
<updated>2026-05-24T12:26:20+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T12:26:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a7cc89482cc931f60d4b43d5c7b875542cbe2538'/>
<id>urn:sha1:a7cc89482cc931f60d4b43d5c7b875542cbe2538</id>
<content type='text'>
The append/prepend/indent/dedent *-in-region-or-buffer commands each inlined the same (if (use-region-p) (region-beginning) (point-min)) / (region-end)/(point-max) block — four copies of the "operate on the region, else the whole buffer" contract. Extracted cj/--region-or-buffer-bounds as the single source of that decision and routed all four through it. Behavior is unchanged; the public-wrapper tests still pass.

This was the "extract a shared helper that decides the target range" option from the reconcile task. The sibling custom-ordering.el helpers (cj/--arrayify, cj/--unarrayify) already document an explicit (start end) contract accurately and are region-required by design, so they needed no docstring change — each pair now has one clear, consistent contract. Tests cover the helper for the region case, the no-region whole-buffer case, and an empty buffer.
</content>
</entry>
<entry>
<title>fix(modeline): key VC cache on resolved truename for symlink moves</title>
<updated>2026-05-24T12:22:56+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T12:22:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=9135298c45f2f03ab92903edb242c8f5f94396d5'/>
<id>urn:sha1:9135298c45f2f03ab92903edb242c8f5f94396d5</id>
<content type='text'>
The VC modeline cache keyed on (list file cj/modeline-vc-show-remote). If file was a symlink whose target moved to a different VC tree (shared drives, CI workspaces), the key was unchanged and the cache kept serving the old branch/state.

Added the resolved file-truename to the key, so a symlink re-pointed at a new target produces a different key and the cache refreshes. The extra file-truename is one stat per modeline refresh, cheap next to the VC calls the cache exists to avoid. Tests cover truename inclusion, key stability for an unchanged file, and a symlink whose target moves.
</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>
</feed>
