aboutsummaryrefslogtreecommitdiff
path: root/.ai/scripts/tests/test-lint-org.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-08-05 17:49:17 -0500
committerCraig Jennings <c@cjennings.net>2026-08-05 17:49:17 -0500
commitfc1a519e6891769733f593b4fd4286bfa00e5cb7 (patch)
treec15cdb06406d223ec7a4b538e8e3ee4f907c835a /.ai/scripts/tests/test-lint-org.el
parent8b5d34c3a504e39b7a0e0e678acb803f71aa9317 (diff)
downloadrulesets-fc1a519e6891769733f593b4fd4286bfa00e5cb7.tar.gz
rulesets-fc1a519e6891769733f593b4fd4286bfa00e5cb7.zip
fix(lint-org): stop flagging session anchors with todo.org conventions
The todo-format checkers encode todo.org's completion rules, so they misfired on a session anchor. A Session Log's dated level-2 headings are the documented correct form, and every one came back as a defect telling the author to convert it to DONE plus CLOSED. One 427-line anchor produced six. lo--spec-file-p becomes lo--todo-format-exempt-p. It now covers the live anchor, the per-agent anchors, and the archives alongside docs/specs/. The archives belong there because wrap-up renames the anchor unchanged, so it keeps the same shape later in its life. All five checkers in the family fire on an anchor, not only the dated-header one. Link, table and structural checks still run.
Diffstat (limited to '.ai/scripts/tests/test-lint-org.el')
-rw-r--r--.ai/scripts/tests/test-lint-org.el69
1 files changed, 69 insertions, 0 deletions
diff --git a/.ai/scripts/tests/test-lint-org.el b/.ai/scripts/tests/test-lint-org.el
index ceee209..10a4fa4 100644
--- a/.ai/scripts/tests/test-lint-org.el
+++ b/.ai/scripts/tests/test-lint-org.el
@@ -1098,3 +1098,72 @@ phases section may carry ** TODO [#x] items that aren't backlog tasks."
(out (lo-test--run-at "todo.org" c))
(cs (lo-test--checkers (lo-test--judgments (plist-get out :issues)))))
(should (memq 'task-missing-last-reviewed cs))))
+
+;;; todo-format checkers skip session anchors too (protocols.org)
+;;
+;; A session anchor carries level-2 dated headings BY INSTRUCTION, not by
+;; accident: protocols.org prescribes "** Topic section headers at natural
+;; seams ... Timestamps optional — use when genuinely useful" for the Session
+;; Log. So level-2-dated-header reads every log entry as a completion defect
+;; and tells the author to convert it to DONE + CLOSED:, which would be wrong.
+;; Reported from work 2026-08-03: six judgment items on one 427-line anchor,
+;; and sentry pass 8 surfaces them nightly in every project.
+;;
+;; Three anchor paths, all the same shape: the live anchor, the per-agent
+;; anchors under AI_AGENT_ID, and the archives wrap-up renames them into.
+
+(defconst lo-test--anchor-log
+ "* Session Log\n** 2026-08-03 Sun @ 14:02:11 -0500 Diagnosed the sync guard\nNarrative.\n"
+ "A Session Log entry: a level-2 dated header, the documented correct form.")
+
+(ert-deftest lo-level2-dated-header-skips-the-live-anchor ()
+ (let* ((out (lo-test--run-at ".ai/session-context.org" lo-test--anchor-log))
+ (cs (lo-test--checkers (lo-test--judgments (plist-get out :issues)))))
+ (should-not (memq 'level-2-dated-header cs))))
+
+(ert-deftest lo-level2-dated-header-skips-per-agent-anchors ()
+ "AI_AGENT_ID resolves the anchor into .ai/session-context.d/<id>.org."
+ (let* ((out (lo-test--run-at ".ai/session-context.d/velox.rulesets.claude.1718400000.org"
+ lo-test--anchor-log))
+ (cs (lo-test--checkers (lo-test--judgments (plist-get out :issues)))))
+ (should-not (memq 'level-2-dated-header cs))))
+
+(ert-deftest lo-level2-dated-header-skips-archived-anchors ()
+ "Wrap-up renames the anchor into .ai/sessions/ unchanged, so the archive has
+the same shape as the live file and lints the same way."
+ (let* ((out (lo-test--run-at ".ai/sessions/2026-08-03-14-02-some-work.org"
+ lo-test--anchor-log))
+ (cs (lo-test--checkers (lo-test--judgments (plist-get out :issues)))))
+ (should-not (memq 'level-2-dated-header cs))))
+
+(ert-deftest lo-whole-todo-format-family-skips-anchors ()
+ "The five are scoped together, as they are for specs — a Session Log is free
+to carry any of these shapes while narrating what happened."
+ (let* ((c (concat "* Session Log\n"
+ "** DONE Shipped the guard\n"
+ "** 2026-08-03 Sun @ 14:02:11 -0500 Did a thing\n"
+ "SCHEDULED: <2026-08-10 Mon>\n"
+ "** TODO [#B] A note to self\n"
+ "*** DONE A sub-step\n"))
+ (out (lo-test--run-at ".ai/session-context.org" c))
+ (cs (lo-test--checkers (lo-test--judgments (plist-get out :issues)))))
+ (should-not (memq 'level2-done-without-closed cs))
+ (should-not (memq 'level-2-dated-header cs))
+ (should-not (memq 'dated-log-heading-active-timestamp cs))
+ (should-not (memq 'task-missing-last-reviewed cs))
+ (should-not (memq 'subtask-done-not-dated cs))))
+
+(ert-deftest lo-link-checks-still-fire-on-anchors ()
+ "Only the todo-format family is scoped out. An anchor's links are worth
+checking — it is where a session records where its artifacts landed."
+ (let* ((c "* Session Log\n** Topic\n[[file:does-not-exist-xyz.org][link]]\n")
+ (out (lo-test--run-at ".ai/session-context.org" c))
+ (cs (lo-test--checkers (lo-test--judgments (plist-get out :issues)))))
+ (should (memq 'link-to-local-file cs))))
+
+(ert-deftest lo-a-plain-ai-file-is-not-exempt ()
+ "The exemption is the three anchor paths, not all of .ai/ — notes.org lives
+there and follows todo.org's conventions."
+ (let* ((out (lo-test--run-at ".ai/notes.org" lo-test--anchor-log))
+ (cs (lo-test--checkers (lo-test--judgments (plist-get out :issues)))))
+ (should (memq 'level-2-dated-header cs))))