From f6dde4e0fe21022966196e19d535f2bb7abcfcdb Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sat, 20 Jun 2026 23:28:47 -0400 Subject: feat(lint-org): flag level-2 dated headers as a completion defect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A `** …` heading carries no keyword, so todo-cleanup's --archive-done can never archive it and task-review drops it from selection. The new level-2-dated-header check (custom, like org-table-standard) emits a judgment item per offending heading so the wrap-up sweep routes it to the next morning's review. Judgment-only, never auto-fixed: the repair needs a DONE-vs-CANCELLED call and the original heading text. Three ERT cases cover it (flagged at level 2, clean for DONE+CLOSED, clean for a level-3 dated entry). --- .ai/scripts/lint-org.el | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to '.ai/scripts/lint-org.el') diff --git a/.ai/scripts/lint-org.el b/.ai/scripts/lint-org.el index 8f55cc6..3633dba 100644 --- a/.ai/scripts/lint-org.el +++ b/.ai/scripts/lint-org.el @@ -367,6 +367,31 @@ Emits one judgment item per violating table." (format "table violates the org-table standard: %s — wrap-org-table.el reflows it" (string-join violations "; "))))))))) +;;; --------------------------------------------------------------------------- +;;; level-2 dated-header check (claude-rules/todo-format.md) +;; +;; A completed task or resolved VERIFY at level 2 must carry a terminal +;; keyword (DONE/CANCELLED + CLOSED:), never a dated heading. A `** ' +;; header has no keyword, so todo-cleanup's --archive-done can never archive +;; it (it accumulates in Open Work forever) and task-review drops it from +;; selection. Judgment-only, never auto-fixed: the repair needs a +;; DONE-vs-CANCELLED call and the original heading text, which is a judgment +;; the sweep can't make. Targets todo/task files; a dated-log-format org +;; file using `** ' headings intentionally will false-positive here, in +;; which case the human dismisses the judgment item. + +(defun lo--check-level2-dated-headers () + "Flag level-2 headings whose text begins with a YYYY-MM-DD date. +Emits one judgment item per offending heading (checker +`level-2-dated-header')." + (save-excursion + (goto-char (point-min)) + (while (re-search-forward + "^\\*\\* \\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)" nil t) + (lo--emit-judgment + 'level-2-dated-header (line-number-at-pos) + "level-2 dated header is a completion defect (todo-format.md): a ** task or VERIFY closes with DONE/CANCELLED + CLOSED:, not a dated heading — convert it so --archive-done can archive it")))) + ;;; --------------------------------------------------------------------------- ;;; File processing @@ -401,6 +426,8 @@ left unmodified and mechanical entries are recorded with :preview t." ;; After org-lint items: the custom table-standard scan. Runs on the ;; post-fix buffer; judgment-only, so order doesn't perturb fixes. (lo--check-tables) + ;; Same shape: flag level-2 dated headers (completion defects). + (lo--check-level2-dated-headers) (when (and (not lo-check-only) (buffer-modified-p)) (save-buffer))) (with-current-buffer buf (set-buffer-modified-p nil)) -- cgit v1.2.3