diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-12 15:26:22 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-12 15:26:22 -0500 |
| commit | 21ab10ef9e2fff9b4726695036e95e33937e1fa9 (patch) | |
| tree | 1d994b7a4228e70c7ad7b0980eede70eec875de2 | |
| parent | f2f5f571b5269a012f8c84de60d69b62658b1e9e (diff) | |
| download | rulesets-21ab10ef9e2fff9b4726695036e95e33937e1fa9.tar.gz rulesets-21ab10ef9e2fff9b4726695036e95e33937e1fa9.zip | |
fix(todo-cleanup): keep --archive-done silent on a real-mode no-op
The wrap runs --archive-done twice (wrap-it-up, then open-tasks.org Phase A). The first pass archives and reports. The second finds nothing and used to print "0 subtree(s) moved", which reads as alarming next to the first pass's diff. Now a real-mode run that moves nothing and skips nothing says nothing. Check mode still previews "0 would move", and a missing-section skip still reports, since those are conditions the caller needs.
| -rw-r--r-- | .ai/scripts/tests/test-todo-cleanup.el | 56 | ||||
| -rw-r--r-- | .ai/scripts/todo-cleanup.el | 38 | ||||
| -rw-r--r-- | claude-templates/.ai/scripts/tests/test-todo-cleanup.el | 56 | ||||
| -rw-r--r-- | claude-templates/.ai/scripts/todo-cleanup.el | 38 |
4 files changed, 160 insertions, 28 deletions
diff --git a/.ai/scripts/tests/test-todo-cleanup.el b/.ai/scripts/tests/test-todo-cleanup.el index 5d43f97..ad9260b 100644 --- a/.ai/scripts/tests/test-todo-cleanup.el +++ b/.ai/scripts/tests/test-todo-cleanup.el @@ -68,6 +68,28 @@ Return a plist: :result final file contents, :archived count from the last run, (tc-test--drop-buffer file) (delete-file file)))) +(defun tc-test--archive-report (content &optional runs check) + "Like `tc-test--archive' but also returns :report — the captured stdout of +`tc--emit-archive-report' from the last run. After the run loop the globals +still hold the last run's `tc-archived'/`tc-issues'/`tc-check-only', so the +captured report is the one that run would have printed." + (let ((file (make-temp-file "tc-test-" nil ".org")) + last-archived last-issues report) + (unwind-protect + (progn + (with-temp-file file (insert content)) + (dotimes (_ (or runs 1)) + (tc-test--reset check) + (tc-process-file file) + (setq last-archived tc-archived last-issues tc-issues) + (tc-test--drop-buffer file)) + (setq report (with-output-to-string (tc--emit-archive-report))) + (list :report report + :archived last-archived + :issues last-issues)) + (tc-test--drop-buffer file) + (delete-file file)))) + (defun tc-test--section (content needle) "Text of the level-1 section in CONTENT whose heading line contains NEEDLE — from the heading line through (not including) the next level-1 heading or EOF." @@ -299,6 +321,40 @@ from the heading line through (not including) the next level-1 heading or EOF." (should (= 3 (plist-get twice :archived))))) ;;; --------------------------------------------------------------------------- +;;; Report suppression: a real-mode no-op stays silent so a double-run wrap +;;; (wrap-it-up then open-tasks.org Phase A) doesn't print an alarming +;;; "0 subtree(s) moved" next to the first run's diff. + +(ert-deftest tc-archive-real-mode-zero-moves-is-silent () + (let ((out (tc-test--archive-report tc-test--nothing))) + (should (= 0 (plist-get out :archived))) + (should (equal "" (plist-get out :report))))) + +(ert-deftest tc-archive-double-run-second-pass-is-silent () + ;; First run archives, second run finds nothing — the second prints nothing. + (let ((out (tc-test--archive-report tc-test--basic 2))) + (should (= 0 (plist-get out :archived))) + (should (equal "" (plist-get out :report))))) + +(ert-deftest tc-archive-check-mode-zero-moves-still-reports () + ;; A preview the caller explicitly asked for still says "0 would move". + (let ((out (tc-test--archive-report tc-test--nothing nil t))) + (should (= 0 (plist-get out :archived))) + (should (tc-test--has (plist-get out :report) "0 subtree(s) would move")))) + +(ert-deftest tc-archive-real-mode-moves-are-reported () + (let ((out (tc-test--archive-report tc-test--basic))) + (should (= 1 (plist-get out :archived))) + (should (tc-test--has (plist-get out :report) "1 subtree(s) moved")))) + +(ert-deftest tc-archive-real-mode-skip-is-reported () + ;; 0 moved but a section is missing — the skip is a real condition and must + ;; not be swallowed by the silence rule. + (let ((out (tc-test--archive-report tc-test--no-resolved))) + (should (= 0 (plist-get out :archived))) + (should (tc-test--has (plist-get out :report) "skipped")))) + +;;; --------------------------------------------------------------------------- ;;; Realistic synthetic sample (committed under fixtures/) (defun tc-test--sample-file () diff --git a/.ai/scripts/todo-cleanup.el b/.ai/scripts/todo-cleanup.el index 569e7c7..6b3081a 100644 --- a/.ai/scripts/todo-cleanup.el +++ b/.ai/scripts/todo-cleanup.el @@ -397,20 +397,30 @@ before their descendants — a [#A] → [#B] → [#D] chain collapses in one pas (save-buffer)))) (defun tc--emit-archive-report () - (princ (format "todo-cleanup --archive-done: %d subtree(s) %s%s\n" - tc-archived - (if tc-check-only "would move" "moved") - (if tc-check-only " — CHECK MODE (no writes)" ""))) - (dolist (i (reverse tc-issues)) - (pcase (plist-get i :kind) - ('archive-skip - (princ (format " skipped %s: %s\n" (plist-get i :file) (plist-get i :detail)))) - ((or 'archive-moved 'archive-would) - (princ (format " %s:%d: %s %s\n" - (plist-get i :file) - (plist-get i :line) - (if tc-check-only "would move" "moved") - (plist-get i :heading))))))) + ;; A real-mode no-op stays silent. When nothing moved and nothing was + ;; skipped, there's nothing to report — and the wrap runs this twice + ;; (wrap-it-up, then open-tasks.org Phase A), so a vocal "0 subtree(s) moved" + ;; on the second pass reads as alarming next to the first pass's diff. Check + ;; mode always reports (a "0 would move" preview is information the caller + ;; asked for), and a skip always reports (a missing section is a real + ;; condition, not a no-op). + (let ((has-skip (cl-some (lambda (i) (eq (plist-get i :kind) 'archive-skip)) + tc-issues))) + (when (or tc-check-only (> tc-archived 0) has-skip) + (princ (format "todo-cleanup --archive-done: %d subtree(s) %s%s\n" + tc-archived + (if tc-check-only "would move" "moved") + (if tc-check-only " — CHECK MODE (no writes)" ""))) + (dolist (i (reverse tc-issues)) + (pcase (plist-get i :kind) + ('archive-skip + (princ (format " skipped %s: %s\n" (plist-get i :file) (plist-get i :detail)))) + ((or 'archive-moved 'archive-would) + (princ (format " %s:%d: %s %s\n" + (plist-get i :file) + (plist-get i :line) + (if tc-check-only "would move" "moved") + (plist-get i :heading))))))))) (defun tc--emit-hygiene-report () (princ (format "todo-cleanup: %d fix(es) applied%s\n" diff --git a/claude-templates/.ai/scripts/tests/test-todo-cleanup.el b/claude-templates/.ai/scripts/tests/test-todo-cleanup.el index 5d43f97..ad9260b 100644 --- a/claude-templates/.ai/scripts/tests/test-todo-cleanup.el +++ b/claude-templates/.ai/scripts/tests/test-todo-cleanup.el @@ -68,6 +68,28 @@ Return a plist: :result final file contents, :archived count from the last run, (tc-test--drop-buffer file) (delete-file file)))) +(defun tc-test--archive-report (content &optional runs check) + "Like `tc-test--archive' but also returns :report — the captured stdout of +`tc--emit-archive-report' from the last run. After the run loop the globals +still hold the last run's `tc-archived'/`tc-issues'/`tc-check-only', so the +captured report is the one that run would have printed." + (let ((file (make-temp-file "tc-test-" nil ".org")) + last-archived last-issues report) + (unwind-protect + (progn + (with-temp-file file (insert content)) + (dotimes (_ (or runs 1)) + (tc-test--reset check) + (tc-process-file file) + (setq last-archived tc-archived last-issues tc-issues) + (tc-test--drop-buffer file)) + (setq report (with-output-to-string (tc--emit-archive-report))) + (list :report report + :archived last-archived + :issues last-issues)) + (tc-test--drop-buffer file) + (delete-file file)))) + (defun tc-test--section (content needle) "Text of the level-1 section in CONTENT whose heading line contains NEEDLE — from the heading line through (not including) the next level-1 heading or EOF." @@ -299,6 +321,40 @@ from the heading line through (not including) the next level-1 heading or EOF." (should (= 3 (plist-get twice :archived))))) ;;; --------------------------------------------------------------------------- +;;; Report suppression: a real-mode no-op stays silent so a double-run wrap +;;; (wrap-it-up then open-tasks.org Phase A) doesn't print an alarming +;;; "0 subtree(s) moved" next to the first run's diff. + +(ert-deftest tc-archive-real-mode-zero-moves-is-silent () + (let ((out (tc-test--archive-report tc-test--nothing))) + (should (= 0 (plist-get out :archived))) + (should (equal "" (plist-get out :report))))) + +(ert-deftest tc-archive-double-run-second-pass-is-silent () + ;; First run archives, second run finds nothing — the second prints nothing. + (let ((out (tc-test--archive-report tc-test--basic 2))) + (should (= 0 (plist-get out :archived))) + (should (equal "" (plist-get out :report))))) + +(ert-deftest tc-archive-check-mode-zero-moves-still-reports () + ;; A preview the caller explicitly asked for still says "0 would move". + (let ((out (tc-test--archive-report tc-test--nothing nil t))) + (should (= 0 (plist-get out :archived))) + (should (tc-test--has (plist-get out :report) "0 subtree(s) would move")))) + +(ert-deftest tc-archive-real-mode-moves-are-reported () + (let ((out (tc-test--archive-report tc-test--basic))) + (should (= 1 (plist-get out :archived))) + (should (tc-test--has (plist-get out :report) "1 subtree(s) moved")))) + +(ert-deftest tc-archive-real-mode-skip-is-reported () + ;; 0 moved but a section is missing — the skip is a real condition and must + ;; not be swallowed by the silence rule. + (let ((out (tc-test--archive-report tc-test--no-resolved))) + (should (= 0 (plist-get out :archived))) + (should (tc-test--has (plist-get out :report) "skipped")))) + +;;; --------------------------------------------------------------------------- ;;; Realistic synthetic sample (committed under fixtures/) (defun tc-test--sample-file () diff --git a/claude-templates/.ai/scripts/todo-cleanup.el b/claude-templates/.ai/scripts/todo-cleanup.el index 569e7c7..6b3081a 100644 --- a/claude-templates/.ai/scripts/todo-cleanup.el +++ b/claude-templates/.ai/scripts/todo-cleanup.el @@ -397,20 +397,30 @@ before their descendants — a [#A] → [#B] → [#D] chain collapses in one pas (save-buffer)))) (defun tc--emit-archive-report () - (princ (format "todo-cleanup --archive-done: %d subtree(s) %s%s\n" - tc-archived - (if tc-check-only "would move" "moved") - (if tc-check-only " — CHECK MODE (no writes)" ""))) - (dolist (i (reverse tc-issues)) - (pcase (plist-get i :kind) - ('archive-skip - (princ (format " skipped %s: %s\n" (plist-get i :file) (plist-get i :detail)))) - ((or 'archive-moved 'archive-would) - (princ (format " %s:%d: %s %s\n" - (plist-get i :file) - (plist-get i :line) - (if tc-check-only "would move" "moved") - (plist-get i :heading))))))) + ;; A real-mode no-op stays silent. When nothing moved and nothing was + ;; skipped, there's nothing to report — and the wrap runs this twice + ;; (wrap-it-up, then open-tasks.org Phase A), so a vocal "0 subtree(s) moved" + ;; on the second pass reads as alarming next to the first pass's diff. Check + ;; mode always reports (a "0 would move" preview is information the caller + ;; asked for), and a skip always reports (a missing section is a real + ;; condition, not a no-op). + (let ((has-skip (cl-some (lambda (i) (eq (plist-get i :kind) 'archive-skip)) + tc-issues))) + (when (or tc-check-only (> tc-archived 0) has-skip) + (princ (format "todo-cleanup --archive-done: %d subtree(s) %s%s\n" + tc-archived + (if tc-check-only "would move" "moved") + (if tc-check-only " — CHECK MODE (no writes)" ""))) + (dolist (i (reverse tc-issues)) + (pcase (plist-get i :kind) + ('archive-skip + (princ (format " skipped %s: %s\n" (plist-get i :file) (plist-get i :detail)))) + ((or 'archive-moved 'archive-would) + (princ (format " %s:%d: %s %s\n" + (plist-get i :file) + (plist-get i :line) + (if tc-check-only "would move" "moved") + (plist-get i :heading))))))))) (defun tc--emit-hygiene-report () (princ (format "todo-cleanup: %d fix(es) applied%s\n" |
