<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/Makefile, 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-08-25T12:30:04+00:00</updated>
<entry>
<title>fix(telega): build the server image locally to meet tdlib 1.8.66</title>
<updated>2026-08-25T12:30:04+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-25T12:30:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=91fbac722e83cd108a295542a3c88de66d209fe8'/>
<id>urn:sha1:91fbac722e83cd108a295542a3c88de66d209fe8</id>
<content type='text'>
MELPA's 2026-08-18 telega raised telega-tdlib-min-version to 1.8.66. The pinned upstream image ships 1.8.64, so telega killed its own server on every launch. Upstream's only 1.8.66 image won't start: it's missing libglycin (zevlg/telega.el#596).

docker/telega-server/Dockerfile derives from that upstream image, pinned by digest, and adds the one missing package. make telega-image builds it as cj/telega-server:1.8.66-glycin, cj/telega-docker-image defaults to that tag, and a test holds the two equal. cj/telega now refuses to launch with a make telega-image hint when the image isn't built, since docker would otherwise try to pull a local-only tag from the registry. setup-telega.sh points at the make target instead of M-x telega-server-build.

I chose the local build over pinning the telega package back to 20260706.2147. The derived image satisfies both machines' floors. package.el can't pin a version and MELPA serves only its latest build, so nothing would enforce the package pin. When #596 is fixed upstream the pin returns to a registry digest and the Dockerfile goes.
</content>
</entry>
<entry>
<title>fix(packages): survive a failed install instead of aborting startup</title>
<updated>2026-08-14T09:12:55+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-14T09:12:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=b7f6984983ea947dd969fa2be9200b53bbf447fe'/>
<id>urn:sha1:b7f6984983ea947dd969fa2be9200b53bbf447fe</id>
<content type='text'>
A fresh install pulls around 190 packages over the network. One transient download error left the config two thirds loaded, with hooks registered for packages that never installed.

use-package already warns and continues when an install fails, but it guards with condition-case-unless-debug, which does nothing while debug-on-error is set. early-init sets that for all of startup so my own errors stay loud, and it's what disarms the guard. I inhibited the debugger for the install alone, so the rest of init keeps it. Failures are recorded and reported when startup finishes, and cj/retry-failed-package-installs picks them up.

Editing hooks are silenced during an install. Generating autoloads visits .el files, which is how one missing package breaks the install of unrelated ones. A session-wide retry budget bounds the retrying. Installs stop after five failures in a row, since a run that long means the network is gone rather than one package being unlucky.

:vc packages get the same treatment through advice. use-package drops :ensure whenever :vc is present, and its clone path carries no error handling. A machine without credentials for the git host aborted init the same way.

make bootstrap installs everything headlessly, so a fresh machine never meets the debugger. It refuses to run against byte-compiled modules, where use-package consumes :ensure at compile time and a pass would report success having installed nothing.
</content>
</entry>
<entry>
<title>fix(test): stop silently skipping every integration test</title>
<updated>2026-07-16T20:59:50+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-16T20:59:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=f30a96edd320337ea9a35d2f0fc0cf21f94deb05'/>
<id>urn:sha1:f30a96edd320337ea9a35d2f0fc0cf21f94deb05</id>
<content type='text'>
INTEGRATION_TESTS globbed test-integration-%.el through $(wildcard ...), which
takes a shell glob where % is a literal character, not a pattern. It expanded to
nothing, so test-all skipped the integration phase and still printed "All tests
complete". Fourteen files never ran, for as long as the variable has existed.
The % is right one line up, because filter-out does take make patterns.

The glob is now test-integration-*.el, and the counts add up: 597 unit + 14
integration = the 611 test files on disk.

Turning the gate on surfaced five failures, none of them in production code.

Four were rotting fixtures. parse-ics drops events outside a rolling window of
today minus calendar-sync-past-months to plus future-months, and four tests fed
it dates pinned to November 2025 or February 2026. They passed when written and
began failing once the window slid past them. Their neighbours survived for two
reasons: some hand their fixture to parse-event, which applies no window, and
the weekly ones use unbounded RRULEs that keep generating into the window
however old the DTSTART is. The fixtures now build dates relative to now, which
is what the timezone file's own helper already did.

The fifth was a real regression, caught five months late. The recording toggle
test asserted on a fixture device and got whatever hardware is plugged into the
developer's machine. cj/recording-get-devices runs --validate-system-audio,
which shells to pactl, finds the fixture device isn't a real source, and
auto-fixes the configured device to the default sink's monitor. The test mocked
start-process-shell-command but not shell-command-to-string, so validation
reached the real machine. It passes at 5bdd3420~1 and fails at 5bdd3420, the
commit that added that validation in February.

I faked pactl at the shell boundary rather than stubbing --validate-system-audio
out, so the validation logic still runs, against a fixture machine.
</content>
</entry>
<entry>
<title>chore: archive resolved tasks older than a week</title>
<updated>2026-06-29T20:17:53+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-29T20:17:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=b46e1f02d9d5124aaccc927f4391c850626438df'/>
<id>urn:sha1:b46e1f02d9d5124aaccc927f4391c850626438df</id>
<content type='text'>
make task-sorted now ages the Resolved section. Tasks closed more than a
week ago, and any with no CLOSED date, move out to archive/task-archive.org,
keeping only the last week of closed tasks in todo.org. The target then runs
org-lint on todo.org to catch structural problems from the move. This pass
moved 207 tasks to the archive and pulled 4 newly-closed tasks into Resolved,
dropping todo.org from 9,600 to 5,600 lines.
</content>
</entry>
<entry>
<title>chore(ai): archive gptel and remove it from the live config</title>
<updated>2026-06-24T00:12:58+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-24T00:12:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=10fa6f4e2e7150ad99827721ada1ae4badcc5e90'/>
<id>urn:sha1:10fa6f4e2e7150ad99827721ada1ae4badcc5e90</id>
<content type='text'>
I archived gptel to archive/gptel/ since I rarely use it. Moved there: the six gptel modules (ai-config, ai-conversations, ai-conversations-browser, ai-mcp, ai-quick-ask, ai-rewrite), the gptel-tools/ directory, custom/gptel-prompts.el, their test files and utilities, and the four gptel-only specs.

Scrubbed from the live config: the ai-config require in init.el, which also drops the whole C-; a keymap; the gptel-mode emojify hook in font-config.el; the gptel-tools entries in the Makefile clean target and the coverage runner; and the gptel feature notes in README. Cancelled the open gptel tasks in todo.org (the AI Open Work issues, the feature-extension brainstorm, the velox gptel-magit bug).

ai-term stays. It is the ghostel Claude launcher, independent of gptel.

Verified: every module loads, a batch init launch reaches completion clean, and the full test suite shows only pre-existing coverage failures unrelated to this change.
</content>
</entry>
<entry>
<title>build: add task-sorted target to archive resolved todo tasks</title>
<updated>2026-06-16T04:46:33+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-16T04:46:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=549808155cc45ca12a66915c6a195b1c00d4618b'/>
<id>urn:sha1:549808155cc45ca12a66915c6a195b1c00d4618b</id>
<content type='text'>
make task-sorted wraps todo-cleanup.el --archive-done, moving DONE/CANCELLED level-2 subtrees from Open Work into Resolved. Ran it: archived this session's closed tasks.
</content>
</entry>
<entry>
<title>build: add deploy-wip target for live WIP theme reload</title>
<updated>2026-06-15T13:22:35+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-15T13:22:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=9b46e603c8c4efff773f71e1ecd1de793fd2c96a'/>
<id>urn:sha1:9b46e603c8c4efff773f71e1ecd1de793fd2c96a</id>
<content type='text'>
Build scripts/theme-studio/WIP.json into themes/WIP-theme.el, load it into the running daemon via the existing theme-reload target, and fire a silent desktop notification on success. The notify runs after the reload, so a build or load failure aborts before claiming the theme deployed.
</content>
</entry>
<entry>
<title>feat(theme-studio): make targets for the build-theme converter</title>
<updated>2026-06-14T23:20:04+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-14T23:20:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=fe75ac13b4082644b4ce9eeba7f49d3eea2cc716'/>
<id>urn:sha1:fe75ac13b4082644b4ce9eeba7f49d3eea2cc716</id>
<content type='text'>
theme-studio-theme converts a Theme Studio JSON export to themes/&lt;name&gt;-theme.el. theme-studio-theme-load disables the custom themes and loads one in the running Emacs. theme-studio-theme-reload chains the two. Each delegates to the scripts/theme-studio/Makefile and errors clearly when its required JSON or THEME argument is missing.
</content>
</entry>
<entry>
<title>build(theme-studio): expose every theme-studio target from the root</title>
<updated>2026-06-09T12:55:56+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-09T12:55:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=99977ae7cf961f30e3be09178ee652e744c846c3'/>
<id>urn:sha1:99977ae7cf961f30e3be09178ee652e744c846c3</id>
<content type='text'>
Only test and coverage delegated from the root; check, gen, and open were local-only, so `make theme-studio-open` didn't exist. Added the missing delegations so the whole family is reachable from the root with the theme-studio- prefix, matching the convention. gen and open forward SEED through to the sub-make for viewing a specific palette. Grouped them under their own heading in `make help`.
</content>
</entry>
<entry>
<title>build(theme-studio): add a local Makefile; root delegates test + coverage</title>
<updated>2026-06-09T12:53:12+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-09T12:53:12+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=3d7cc92a1d845caa845c5af0ef586694bdc40556'/>
<id>urn:sha1:3d7cc92a1d845caa845c5af0ef586694bdc40556</id>
<content type='text'>
theme-studio is a self-contained Python + JS subproject with its own toolchain (python3, node, uvx, headless Chrome), unrelated to the root Makefile's Elisp/ERT world. Gave it a local Makefile that owns that toolchain — test, check (fast, no browser), coverage, gen, open — so the build logic lives with the code and the short target names don't collide with the root's Elisp-flavored test/coverage.

The root keeps the discoverable entry points: theme-studio-test and a new theme-studio-coverage now delegate via make -C. run-tests.sh grows a --no-browser flag so `make check` can skip the headless-Chrome gates for a fast inner loop. gen/open take an optional SEED to view a specific palette.

coverage reports both halves: node --experimental-test-coverage for the three JS modules (all 100% line, ~96% branch) and uvx coverage for generate.py (89% lines; the rest is the __main__ writer and the optional seed-env branch).
</content>
</entry>
</feed>
