aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-16 11:59:40 -0500
committerCraig Jennings <c@cjennings.net>2026-05-16 11:59:40 -0500
commit70af2a019e7592089d33a0dde4a1af699175f7ef (patch)
treeccaae88fa1bc222192c92e50cd86181df08b6240
parentc5846df088a47a6f77a298bc0431dcff66e672d2 (diff)
downloadrulesets-70af2a019e7592089d33a0dde4a1af699175f7ef.tar.gz
rulesets-70af2a019e7592089d33a0dde4a1af699175f7ef.zip
chore(ai): sync lint-org and wrap-it-up from claude-templates
Project .ai/ mirror catches up to two canonical updates already in claude-templates/: - lint-org cj-comment block suppression (3fb4c80). The =#+begin_src cj: ...= annotation pattern triggered three lint categories (suspicious-language, empty-header-argument, wrong-header-argument) as false positives at todo.org:16 and todo.org:1291. lint-org.el now recognizes the opener and skips all three on those lines. - LINT_ORG_FOLLOWUPS default flipped to =./inbox/lint-followups.org= (684891d). The previous hardcoded default routed every project's wrap-up findings into the work project's inbox. Phase A startup rsync brought both into the project mirror this morning; bundled into one chore commit since neither delta is project-specific work.
-rw-r--r--.ai/scripts/lint-org.el18
-rw-r--r--.ai/scripts/tests/test-lint-org.el56
-rw-r--r--.ai/workflows/wrap-it-up.org32
3 files changed, 98 insertions, 8 deletions
diff --git a/.ai/scripts/lint-org.el b/.ai/scripts/lint-org.el
index 3e643d4..64b78d0 100644
--- a/.ai/scripts/lint-org.el
+++ b/.ai/scripts/lint-org.el
@@ -221,11 +221,29 @@ org-lint reports the blank line after the heading-like text."
;; Fixer declined — emit as judgment so nothing is silently swallowed.
(lo--emit-judgment name line msg))))
+(defun lo--cj-comment-block-opener-p (line)
+ "Non-nil when LINE in the current buffer is a `#+begin_src cj: ...' opener.
+The cj-comment annotation convention puts `cj:' as the src-block language and
+`comment' as the apparent header arg. org-lint reads that shape three ways
+(unknown language, empty header-arg value, missing colon in header arg) and
+flags each — all three are false positives, since cj-comment is a
+Craig-specific annotation marker rather than Babel src-block syntax."
+ (save-excursion
+ (lo--goto-line line)
+ (looking-at-p "^[ \t]*#\\+begin_src[ \t]+cj:")))
+
(defun lo--handle-item (item)
(let ((name (lo--checker-name item))
(line (lo--line item))
(msg (lo--message item)))
(cond
+ ;; Silent suppression of cj-comment false positives — see
+ ;; `lo--cj-comment-block-opener-p'. No fix counted, no judgment emitted.
+ ((and (memq name '(suspicious-language-in-src-block
+ empty-header-argument
+ wrong-header-argument))
+ (lo--cj-comment-block-opener-p line))
+ nil)
((eq name 'item-number)
(lo--apply-or-preview name line msg #'lo-fix-item-number))
((eq name 'missing-language-in-src-block)
diff --git a/.ai/scripts/tests/test-lint-org.el b/.ai/scripts/tests/test-lint-org.el
index 8e1ebc4..9328064 100644
--- a/.ai/scripts/tests/test-lint-org.el
+++ b/.ai/scripts/tests/test-lint-org.el
@@ -168,6 +168,31 @@ content
#+end_src
")
+;; cj-comment annotation block — Craig's convention #+begin_src cj: comment.
+;; org-lint flags the language (cj:) as unknown and the comment header arg as
+;; both missing-colon and empty-value. All three are false positives.
+(defconst lo-test--cj-comment-block "\
+* Heading
+
+#+begin_src cj: comment
+my annotation text
+#+end_src
+")
+
+;; cj-comment block alongside a real suspicious-language warning — verifies
+;; the cj suppression doesn't leak into other src blocks in the same file.
+(defconst lo-test--cj-comment-with-real-warning "\
+* Heading
+
+#+begin_src cj: comment
+my annotation
+#+end_src
+
+#+begin_src markdown
+real suspicious-language warning here
+#+end_src
+")
+
;; Mixed fixture — each category once.
(defconst lo-test--mixed "\
* Mixed
@@ -317,6 +342,37 @@ content
(lo-test--checkers judgments)))))
;;; ---------------------------------------------------------------------------
+;;; cj-comment block — Craig's annotation convention is silently suppressed
+
+(ert-deftest lo-cj-comment-block-emits-no-judgments ()
+ "Normal: a `#+begin_src cj: comment ...' block must not trigger the three
+false-positive warnings org-lint emits for it (unknown language, empty
+header-arg value, missing colon in header arg)."
+ (let* ((out (lo-test--run lo-test--cj-comment-block))
+ (res (plist-get out :result))
+ (judgments (lo-test--judgments (plist-get out :issues)))
+ (checkers (lo-test--checkers judgments)))
+ ;; File untouched, no fixes applied.
+ (should (equal lo-test--cj-comment-block res))
+ (should (= 0 (plist-get out :fixes)))
+ ;; None of the three false-positive checkers fired.
+ (should-not (member 'suspicious-language-in-src-block checkers))
+ (should-not (member 'empty-header-argument checkers))
+ (should-not (member 'wrong-header-argument checkers))))
+
+(ert-deftest lo-cj-comment-suppression-does-not-mask-real-warnings ()
+ "Boundary: the cj-comment suppression is scoped to cj-comment block openers
+only — a regular `#+begin_src markdown' in the same file still emits its
+suspicious-language judgment."
+ (let* ((out (lo-test--run lo-test--cj-comment-with-real-warning))
+ (judgments (lo-test--judgments (plist-get out :issues)))
+ (suspicious (cl-count 'suspicious-language-in-src-block
+ (lo-test--checkers judgments))))
+ ;; Exactly one suspicious-language judgment — from the markdown block,
+ ;; not the cj-comment block.
+ (should (= 1 suspicious))))
+
+;;; ---------------------------------------------------------------------------
;;; --check mode
(ert-deftest lo-check-mode-does-not-modify-file ()
diff --git a/.ai/workflows/wrap-it-up.org b/.ai/workflows/wrap-it-up.org
index 496bebe..e2a535b 100644
--- a/.ai/workflows/wrap-it-up.org
+++ b/.ai/workflows/wrap-it-up.org
@@ -134,8 +134,13 @@ emacs --batch -q -l .ai/scripts/todo-cleanup.el --check-child-priority todo.org
*** Lint org files (mechanical sweep, judgments deferred)
#+begin_src bash
-followups="${LINT_ORG_FOLLOWUPS:-$HOME/projects/work/inbox/lint-followups.org}"
-[ ! -d "$(dirname "$followups")" ] && followups=".ai/lint-followups.org"
+if [ -n "$LINT_ORG_FOLLOWUPS" ]; then
+ followups="$LINT_ORG_FOLLOWUPS"
+elif [ -d "./inbox" ]; then
+ followups="./inbox/lint-followups.org"
+else
+ followups=".ai/lint-followups.org"
+fi
[ -f todo.org ] && emacs --batch -q -l .ai/scripts/lint-org.el \
--followups-file="$followups" todo.org
#+end_src
@@ -148,11 +153,17 @@ links, verbatim-asterisk inside body prose, suspicious src-block languages)
to the follow-ups file as a dated org section. Mechanical fixes show up in
the wrap-up commit's diff for review before push.
-The follow-up path defaults to =~/projects/work/inbox/lint-followups.org=
-(where the next morning's daily-prep merges it in). If that directory
-doesn't exist on the machine, the script falls back to
+The follow-up path defaults to =./inbox/lint-followups.org= in the current
+project (where the next morning's daily-prep merges it in). If the project
+doesn't have an =inbox/= directory, the script falls back to
=.ai/lint-followups.org= inside the current project. Override with
-=LINT_ORG_FOLLOWUPS=<path>= in the environment if needed.
+=LINT_ORG_FOLLOWUPS=<path>= in the environment if needed — useful for
+routing all wrap-up output to a single shared inbox across projects.
+
+Each project's own =inbox/= is the right default because daily-prep reads
+that project's inbox at startup. Hardcoding a single project's path
+(formerly =~/projects/work/inbox/=) routed every project's wrap-up findings
+into the wrong inbox.
Preview without writing — same flags as =--check= on the other scripts:
@@ -170,8 +181,13 @@ Scan =todo.org= for open =[#A]= and =[#B]= tasks that have neither a =DEADLINE:=
The two timestamps mean different things (=DEADLINE:= = external, consequence-bearing; =SCHEDULED:= = social, accountability-bearing — see the priority spec at the top of =todo.org=). High-priority work that carries neither is suspicious: either it has an implicit deadline that should be made explicit, or it has someone waiting that should surface in the agenda, or its priority is wrong. The scan flags candidates; the operator decides.
#+begin_src bash
-followups="${LINT_ORG_FOLLOWUPS:-$HOME/projects/work/inbox/lint-followups.org}"
-[ ! -d "$(dirname "$followups")" ] && followups=".ai/lint-followups.org"
+if [ -n "$LINT_ORG_FOLLOWUPS" ]; then
+ followups="$LINT_ORG_FOLLOWUPS"
+elif [ -d "./inbox" ]; then
+ followups="./inbox/lint-followups.org"
+else
+ followups=".ai/lint-followups.org"
+fi
[ -f todo.org ] && awk '
/^\*\* (TODO|DOING|VERIFY) \[#[AB]\]/ {
if (heading != "" && !has_date) print line ": " heading