<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rulesets/.ai/scripts/tests/sync-templates.bats, branch main</title>
<subtitle>Claude Code skills, rules, and language bundles
</subtitle>
<id>https://git.cjennings.net/rulesets/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/rulesets/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/'/>
<updated>2026-07-31T18:36:21+00:00</updated>
<entry>
<title>fix(sync): narrow the dirty-rulesets guard to per-file excludes</title>
<updated>2026-07-31T18:36:21+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-31T18:36:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=f69dc22c80156f92c6e3519e87bc014558d77dbf'/>
<id>urn:sha1:f69dc22c80156f92c6e3519e87bc014558d77dbf</id>
<content type='text'>
One uncommitted file under the synced template paths used to skip all three rsyncs for every project. On 2026-07-30 that froze every template everywhere for a full day, and five workflow files went stale in one project alone with nothing reporting it. The blast radius had no relation to what I was editing.

Each dirty path now becomes an --exclude on its own rsync. rsync honors an exclude on both sides, so a withheld file is neither overwritten nor deleted downstream. Every clean file still propagates. A dirty protocols.org skips only its own single-file transfer. A rename withholds both names, since sweeping the old copy would delete a file the project still runs mid-rename.

The run now names what it held back, so a project can see it's one file behind.

The behind-upstream guard stays all-or-nothing. That staleness lives in the destination, so there's no single source file to narrow to.

I verified it against the real checkout mid-change: 48 workflows propagated while the two files dirty at the time were withheld and named. The same run under the old guard would have synced nothing.
</content>
</entry>
<entry>
<title>refactor(startup): extract the template sync into a tested script</title>
<updated>2026-07-31T11:07:34+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-31T11:07:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=f57105773366aebdceeafdb51dc3584c42b0e4e4'/>
<id>urn:sha1:f57105773366aebdceeafdb51dc3584c42b0e4e4</id>
<content type='text'>
The .ai/ sync is how every workflow, protocol and script change reaches every project, and until now it was untested inline bash in startup.org. Yesterday it failed in two ways at once and nothing anywhere reported either.

An uncommitted edit of mine under the synced paths skipped all three rsyncs for a full day, so no project got anything. Five workflow files went stale in .emacs.d alone. One of them was a telegram plugin whose staleness crashed telega-server on every triage run, which is the only reason anyone noticed.

Work found the second failure. The --delete rsync silently reverts a local patch to a rulesets-owned file, so they hit a bug, fixed it, restarted, and came back running the broken version. Their own log still said it was patched.

I want both guards changed. Neither change is safe to make against inline bash that runs in every session, so this commit only moves the logic and pins what it does.

sync-templates is a faithful extraction, rough edges included. I verified it differentially rather than by reading: the old block and the new script over the same fixtures produce identical stdout, exit status and resulting tree.

Two of the fifteen characterization tests pin the failures above. "ONE dirty file blocks ALL THREE rsyncs" is the blast radius in one assertion, and the narrowing lands by turning it red on purpose. "a locally-edited template is silently overwritten, with no record kept" pins work's regression, asserting the output is indistinguishable from an ordinary sync and that no warning exists anywhere.

A third test pins a false-success path I found but deliberately did not fix: the success line prints unconditionally, so a run whose rsyncs all failed still reports a clean sync. That matters next rather than now, because a last-synced manifest written from that branch would stamp success onto a sync that did nothing. The script carries the warning at the line itself.

startup.org keeps a fallback for the case where it holds this file but the script is missing. It announces the skip and names the recovery command, because that state cannot heal itself: the fallback runs instead of the sync, so no later sync can deliver what is missing.
</content>
</entry>
</feed>
