aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-15 23:12:14 -0500
committerCraig Jennings <c@cjennings.net>2026-05-15 23:12:14 -0500
commitcd8b6e9e9c40e2fcd83104457afae1b286924a0e (patch)
treef02f0baabbcbad324315ca1bf8deb3cc2713773a
parentea5e55da714e13ba64bb34ae7603f2c8ed6fc129 (diff)
downloadrulesets-cd8b6e9e9c40e2fcd83104457afae1b286924a0e.tar.gz
rulesets-cd8b6e9e9c40e2fcd83104457afae1b286924a0e.zip
chore(ai): wrap stale-cleanup + bats harness for audit/install-ai
Two arcs this session: closed two stale todo entries (/lint-org retroactively, pull-ordering doc proactively after writing the missing protocols.org paragraph), then built scripts/tests/audit.bats and scripts/tests/install-ai.bats covering the three deferred destructive edges from yesterday's fold-epic test plan. A dotemacs cross-project handoff for a cj-scan nested-fence bug landed during commit staging and shipped as its own commit, separate from the test-harness work. archive-done moved three DONE level-2 entries to Rulesets Resolved.
-rw-r--r--.ai/sessions/2026-05-15-23-10-stale-cleanup-and-audit-install-ai-bats.org87
-rw-r--r--todo.org91
2 files changed, 131 insertions, 47 deletions
diff --git a/.ai/sessions/2026-05-15-23-10-stale-cleanup-and-audit-install-ai-bats.org b/.ai/sessions/2026-05-15-23-10-stale-cleanup-and-audit-install-ai-bats.org
new file mode 100644
index 0000000..0e485f9
--- /dev/null
+++ b/.ai/sessions/2026-05-15-23-10-stale-cleanup-and-audit-install-ai-bats.org
@@ -0,0 +1,87 @@
+#+TITLE: Session Context — stale todo cleanup + protocols pull-ordering doc
+#+AUTHOR: Craig Jennings & Claude
+#+DATE: 2026-05-15
+
+* Summary
+
+** Active Goal
+
+Started as stale-entry cleanup (=/lint-org= at =todo.org:1292= was shipped 2026-05-14 but never flipped). Surfaced one partially-stale entry at =todo.org:36= during the audit; chose to actually do the remaining protocols.org pull-ordering documentation work rather than defer it. Then took the =[#C]= sibling at =todo.org:1766= (bats test harness for =make audit= + =make install-ai= edge cases) as the evening task. A cross-project handoff from a parallel dotemacs session landed during commit staging and got absorbed as its own commit.
+
+** Decisions
+
+- =/lint-org= and the pull-ordering doc task were both genuinely stale → flipped to =DONE= with retroactive =CLOSED:= dates.
+- Pull-ordering entry at =todo.org:36= was partially stale (step 1 shipped, step 2 hadn't). Option 1: rewrite the body to reflect post-fold framing (no separate claude-templates pull anymore) and do the protocols.org documentation work in this session.
+- Test harness location =scripts/tests/= (colocate with the scripts being tested), not =.ai/scripts/tests/= as the TODO body said — the TODO body was carried forward from the wrong mental model. Audit and install-ai are rulesets-only utilities, not =.ai/= templates.
+- Test framework: bats 1.13.0 (parallels the elisp ERT pattern for =todo-cleanup= and =lint-org=).
+- Test isolation: redirect =HOME= per test, scaffold synthetic project trees under =HOME/code/=, leave canonical pointing at the real one (resolved relative to each script's =$0=). PATH stubs for =fzf= and =find= cover the interactive and race-condition edges.
+- The =.ai/-missing= FAIL branch in =audit.sh:161= is a defensive race-condition guard that can't be timed by black-box test. Exercised via a PATH-stubbed =find= that injects a fabricated path; the loop hits the FAIL branch on the ghost and continues to the real project.
+- Cross-project handoff disposition (cj-scan nested-fence fix from dotemacs): three-commit split — dotemacs fix first (separate concern), test harness, then todo updates. Handoff file deleted after processing (the work is captured in git + the =DONE [#C]= entry in =Rulesets Resolved=).
+
+** Data Collected / Findings
+
+- bats 1.13.0 is installed at =/usr/bin/bats=.
+- =make test= now totals 352 green: 296 pytest + 1 skipped + 22 lint-org ERT + 23 todo-cleanup ERT + 6 audit bats + 5 install-ai bats. Up from 341.
+- Phase A inbox scan only looks at =./inbox/= at the project root. Post-fold the canonical's inbox lives at =claude-templates/inbox/=, which Phase A doesn't see. The dotemacs handoff dropped there earlier today; my 18:25 startup missed it. Surfaced only when staging commits at 22:50. Filed as a =[#B]= bug.
+- Auto-push observed: =origin/main= advanced from =8577a88= → =7ef200a= at 23:04:39, 26 seconds after committing 7ef200a. No =PostCommit= hook in =~/.claude/= or =.git/hooks/=. No =git push= in this session's command history between the early-session push and the pre-push reconcile. Source unknown — likely a Magit =after-save-hook= or a parallel Claude session.
+- Canonical pytest with the cj-scan fix: 302 passed, 1 skipped (matches the handoff's verification).
+
+** Files Modified
+
+Rulesets (5 commits pushed to =origin/main=):
+- =cdf3909 docs(protocols): add startup pull-ordering rule= — new =** Startup Pull Ordering — Rulesets Before Project= subsection under =IMPORTANT - MUST DO= in both canonical (=claude-templates/.ai/protocols.org=) and project copy (=.ai/protocols.org=).
+- =8577a88 docs(todo): close /lint-org and pull-ordering doc tasks= — todo flips on =/lint-org= (retroactive =CLOSED: [2026-05-14 Thu]=) and the pull-ordering doc task.
+- =dc1661c fix(cj-scan): suppress detection inside nested non-cj begin_* blocks= — dotemacs handoff absorbed. =claude-templates/.ai/scripts/cj-scan.py= gains a =wrapper_type= state machine; =test_cj_scan.py= gains =TestCjScanNestedFencesIgnored= (6 tests); =todo.org= =Rulesets Resolved= gets a new DONE entry.
+- =7ef200a test(scripts): add bats harness for audit + install-ai edge cases= — =scripts/tests/audit.bats= (140 lines, 6 tests), =scripts/tests/install-ai.bats= (103 lines, 5 tests), Makefile =test:= target extended with a bats stanza.
+- =ea5e55d docs(todo): close test harness; file Phase A inbox-scan bug= — test-harness task flipped to DONE; new =[#B]= filed at line ~1792 for the Phase A inbox-scan blind spot.
+
+Working-tree artifacts:
+- =claude-templates/inbox/2026-05-15-handoff-from-dotemacs-cj-scan-nested-fence-fix.org= — deleted (one-time signal absorbed).
+- =claude-templates/inbox/= directory removed (was empty).
+
+** Next Steps
+
+- =[#B]= open at =todo.org:~1792= (post-archive): extend Phase A inbox discovery to also scan =claude-templates/inbox/= when the canonical is in-repo. Also settle whether cross-project handoffs file into =./inbox/= or stay in =claude-templates/inbox/= — the =inbox-send= script's target-project logic is where to decide.
+- Investigate the auto-push source. The pre-push reconcile caught it cleanly tonight, but a non-trivial divergence at the wrong moment could surface as a non-fast-forward push abort. Could be Magit, =git config push.autoSetupRemote=, a parallel Claude session, or something else.
+- Carryover still open: =[#C]= Consolidate =claude-templates/Makefile= after fold; =DOING [#A]= memory-sync (pending VERIFY on stow approach); =[#A]= =/update-skills=, =create-documentation=, 2026-05-04 audit review pass.
+
+* Session Log
+
+** Startup (18:25 CDT)
+
+Clean startup — previous session wrapped cleanly (no =session-context.org=), inbox absent, no cross-agent traffic, no reminders, no pending decisions. Read the 5 most recent session Summaries. Last session (today, 15:13–18:19) closed the /Consolidate .ai/ template infrastructure/ epic. Surfaced one stale entry at =todo.org:1292= (=/lint-org=, shipped 2026-05-14 but never flipped) and offered top open A items.
+
+** Stale entry cleanup
+
+Craig asked to fix the stale entry and then check for others. Flipped =/lint-org= at =todo.org:1292= → =DONE [#A]= with =CLOSED: [2026-05-14 Thu]= per the depth-based completion rule (level-2 → keyword flip + CLOSED line + body retained).
+
+Audit of remaining open level-2 entries against recent commits surfaced one partially-stale entry at =todo.org:36= (=Document rulesets + claude-templates pull-before-project ordering in protocols.org=). Body listed two action items: step 1 (rulesets pull in =startup.org= Phase A.0) had shipped 2026-05-15 as part of the claude-templates fold; step 2 (state the rule in =protocols.org=) had not. Also the framing was outdated — post-fold there's no separate claude-templates pull anymore.
+
+Craig picked option 1 (rewrite the body to reflect step 1 done + drop the claude-templates framing). Rewrote the heading to =Document startup pull-ordering rule in protocols.org= and trimmed the body to isolate the remaining work.
+
+** Did the remaining work — protocols.org paragraph
+
+Edited canonical =claude-templates/.ai/protocols.org= first (per canonical-source rule), then rsynced into =.ai/protocols.org=. Added new =** Startup Pull Ordering — Rulesets Before Project= subsection under =IMPORTANT - MUST DO=, placed between "Always Check the Time" and "Session Context File" (chronologically lining up with Phase A.0 firing first at session start). Three paragraphs: the ordering + what each pull lands, the dirty/merge resolution rule with the no-auto-stash/merge/rebase guardrail, pointer back to =startup.org= Phase A.0 for the mechanics.
+
+Flipped =todo.org:36= → =DONE [#B]= with =CLOSED: [2026-05-15 Fri]= and a one-line resolution note pointing at the new subsection.
+
+** Commit + push
+
+Step 0 reconcile clean (0/0). Voice-mode check showed =.ai/notes.org= tracked → general-voice mode, no approval gate. Two commits:
+
+- =cdf3909 docs(protocols): add startup pull-ordering rule= — both =.ai/protocols.org= copies, +16 lines total. =/voice= fired #3 (-ing analysis) and #27 (passive → active).
+- =8577a88 docs(todo): close /lint-org and pull-ordering doc tasks= — todo flips. =/voice= fired #30 (fragment in prose) and #31 (noun-ified verb).
+
+Pre-push reconcile 0 behind / 2 ahead; pushed cleanly to =origin/main=.
+
+** Test harness for audit + install-ai (option 4)
+
+Craig picked the =[#C]= sibling at =todo.org:1766= for the bats test harness. Flipped to =DOING=. Phase 0 walk: bats 1.13.0 available, no existing harness in tree, scripts under =scripts/= (not =.ai/scripts/=). Proposed Phase 2 design with five points: location =scripts/tests/= (corrects the TODO body which said =.ai/scripts/tests/= — those scripts are rulesets-only, not template content), bats as the tool, HOME-redirect per test for isolation, fzf stub for the interactive case, ~8 tests covering the three deferred edges plus happy-path sanity. Craig: "proceed."
+
+Built two bats files. =scripts/tests/audit.bats= — 6 tests covering clean-sweep, drift detection, =--apply= convergence, dirty-skip, =--apply --force= clobber, and the .ai/-missing loop-continuation edge. The .ai/-missing race-condition guard at line 161 of audit.sh can't be timed by black-box test, so the test stubs =find= via PATH override to inject a fabricated =.ai/= path and confirms the loop hits the FAIL branch and continues to the real project. =scripts/tests/install-ai.bats= — 5 tests covering happy path with explicit PROJECT, =--track= gitkeep stubs, refusal on existing =.ai/=, notes.org placeholder substitution, and the fzf-pick form with a stubbed fzf (=head -n 1=).
+
+Extended =Makefile= =test:= target with a third stanza globbing =scripts/tests/*.bats=. Description updated from "Run the .ai/scripts/ test suites (pytest + ERT)" to "Run all test suites (pytest + ERT + bats)".
+
+Verification: =make test= runs clean — 296 pytest + 1 skipped + 22 lint-org ERT + 23 todo-cleanup ERT + 6 audit bats + 5 install-ai bats = 352 green, no regressions. Each new bats file ran independently first before the full suite run, so failures wouldn't get masked by upstream noise.
+
+Flipped =todo.org:1766= → =DONE [#C]= with =CLOSED: [2026-05-15 Fri]=.
diff --git a/todo.org b/todo.org
index 98d1723..343176f 100644
--- a/todo.org
+++ b/todo.org
@@ -33,16 +33,6 @@ commit + push archsetup. After that, every machine running =stow=
picks up the same memory tree.
*** VERIFY Approve stow-based sync of ~/.claude/projects via archsetup/dotfiles/common/
-** DONE [#B] Document startup pull-ordering rule in protocols.org
-CLOSED: [2026-05-15 Fri]
-
-Phase A.0 of =startup.org= now pulls rulesets ff-only before the project repo
-(shipped 2026-05-15 as part of the claude-templates fold — after the subtree
-merge, there's no separate claude-templates pull, just rulesets-then-project).
-The protocols.org paragraph stating the ordering and "resolve any issues
-before proceeding" rule shipped 2026-05-15 in the =** Startup Pull Ordering=
-subsection under =IMPORTANT - MUST DO=.
-
** TODO [#A] Build =create-documentation= skill for high-quality project/product docs
Create a Claude skill named =create-documentation= that can plan, write,
@@ -1280,28 +1270,6 @@ See also the DoD-specific notations section under the later TODO
starting point across the DoD notation landscape (SysML, DoDAF/UAF,
IDEF1X). This entry is the execution plan for that starting point.
-** DONE [#A] Build =/lint-org= skill + wrap-up integration
-CLOSED: [2026-05-14 Thu]
-
-Spec: [[file:.ai/specs/lint-org-skill-spec.md]]
-
-A two-mode skill (=interactive=, =mechanical-only=) that runs =org-lint=,
-auto-fixes safe categories (item-number, missing-language-in-src-block,
-misplaced-planning-info, markdown-bold → single-asterisk), and walks judgment
-items (broken local-file links, invalid fuzzy links, verbatim-asterisk false
-positives, suspicious-language blocks) inline.
-
-Wrap-up integration: =wrap-it-up.org= invokes
-=/lint-org todo.org --mode=mechanical-only= after the existing
-=todo-cleanup.el --archive-done= pass. Judgment items defer to a
-carry-forward file that the next morning's daily-prep merges in, so
-wrap-up never blocks on a judgment call.
-
-Baseline that motivated this: the 2026-05-14 manual pass took =todo.org=
-from 55 → 1 lint warnings across two commits (=0d10458= signal,
-=9ad5b30= cosmetic). A nightly mechanical sweep keeps the count near
-zero forever — each day's drift is small.
-
** TODO [#A] Build =/update-skills= skill for keeping forks in sync with upstream
The rulesets repo has a growing set of forks (=arch-decide= from
@@ -1763,21 +1731,6 @@ The four canonical rules (=commits=, =testing=, =verification=, =subagents=) are
The Elisp pair is the most suspicious — three repos using essentially the same rules. Audit: diff these across the projects, check for drift, then decide whether to canonicalize them under =~/code/rulesets/claude-rules/languages/<lang>/= and symlink, or leave them as project-local.
-** DONE [#C] Test harness for =make audit= + =make install-ai= edge cases :test:
-CLOSED: [2026-05-15 Fri]
-
-Three edge cases from the fold-epic test plan were not exercised because they're destructive on real projects:
-
-- =audit --force= clobbers uncommitted =.ai/= work — needs a project with intentionally dirty =.ai/= to verify the override path.
-- =audit= reports =FAIL= when =.ai/= is missing — needs a project where the directory was deleted to verify the loop continues past the failure.
-- =install-ai= fzf-pick form (no =PROJECT= arg) — needs interactive testing.
-
-Build a self-contained test harness under =.ai/scripts/tests/= that spins up =/tmp/audit-test-projects/= with a known matrix of project states (clean, dirty, missing =.ai/=, pristine, etc.), runs the audit + install-ai targets against it, and asserts expected outputs. The harness should clean up after itself.
-
-Pattern reference: bats or shell-based assertions (similar to the elisp ERT suites for =todo-cleanup= and =lint-org=, but for shell scripts).
-
-Triggered by: 2026-05-15 fold-epic, child 4 test plan; commits =94782ee= (audit) + =d364cf2= (install-ai).
-
** TODO [#C] Consolidate =claude-templates/Makefile= after fold :chore:
Sibling follow-up from the fold child (2026-05-15). After the subtree merge, =rulesets/claude-templates/Makefile= still has its standalone =install= / =uninstall= / =list= / =test-scripts= targets. The =install= target's =bin/ai= logic is now duplicated in =rulesets/Makefile=. Both work; the redundancy is harmless but worth cleaning up.
@@ -2162,3 +2115,47 @@ After local fold + audit + install-ai are working, propagate to ratio.
**** Adjacent: cross-machine memory sync
The =[#A] DOING= memory-sync investigation (todo.org:10) is adjacent. Both involve "make my Claude setup portable across machines." Coordinate so the memory-sync stow approach (if approved) doesn't conflict with this fold's symlink mechanics.
+** DONE [#B] Document startup pull-ordering rule in protocols.org
+CLOSED: [2026-05-15 Fri]
+
+Phase A.0 of =startup.org= now pulls rulesets ff-only before the project repo
+(shipped 2026-05-15 as part of the claude-templates fold — after the subtree
+merge, there's no separate claude-templates pull, just rulesets-then-project).
+The protocols.org paragraph stating the ordering and "resolve any issues
+before proceeding" rule shipped 2026-05-15 in the =** Startup Pull Ordering=
+subsection under =IMPORTANT - MUST DO=.
+** DONE [#A] Build =/lint-org= skill + wrap-up integration
+CLOSED: [2026-05-14 Thu]
+
+Spec: [[file:.ai/specs/lint-org-skill-spec.md]]
+
+A two-mode skill (=interactive=, =mechanical-only=) that runs =org-lint=,
+auto-fixes safe categories (item-number, missing-language-in-src-block,
+misplaced-planning-info, markdown-bold → single-asterisk), and walks judgment
+items (broken local-file links, invalid fuzzy links, verbatim-asterisk false
+positives, suspicious-language blocks) inline.
+
+Wrap-up integration: =wrap-it-up.org= invokes
+=/lint-org todo.org --mode=mechanical-only= after the existing
+=todo-cleanup.el --archive-done= pass. Judgment items defer to a
+carry-forward file that the next morning's daily-prep merges in, so
+wrap-up never blocks on a judgment call.
+
+Baseline that motivated this: the 2026-05-14 manual pass took =todo.org=
+from 55 → 1 lint warnings across two commits (=0d10458= signal,
+=9ad5b30= cosmetic). A nightly mechanical sweep keeps the count near
+zero forever — each day's drift is small.
+** DONE [#C] Test harness for =make audit= + =make install-ai= edge cases :test:
+CLOSED: [2026-05-15 Fri]
+
+Three edge cases from the fold-epic test plan were not exercised because they're destructive on real projects:
+
+- =audit --force= clobbers uncommitted =.ai/= work — needs a project with intentionally dirty =.ai/= to verify the override path.
+- =audit= reports =FAIL= when =.ai/= is missing — needs a project where the directory was deleted to verify the loop continues past the failure.
+- =install-ai= fzf-pick form (no =PROJECT= arg) — needs interactive testing.
+
+Build a self-contained test harness under =.ai/scripts/tests/= that spins up =/tmp/audit-test-projects/= with a known matrix of project states (clean, dirty, missing =.ai/=, pristine, etc.), runs the audit + install-ai targets against it, and asserts expected outputs. The harness should clean up after itself.
+
+Pattern reference: bats or shell-based assertions (similar to the elisp ERT suites for =todo-cleanup= and =lint-org=, but for shell scripts).
+
+Triggered by: 2026-05-15 fold-epic, child 4 test plan; commits =94782ee= (audit) + =d364cf2= (install-ai).