aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ai/scripts/tests/test-todo-cleanup.el56
-rw-r--r--.ai/scripts/todo-cleanup.el38
-rw-r--r--claude-templates/.ai/scripts/tests/test-todo-cleanup.el56
-rw-r--r--claude-templates/.ai/scripts/todo-cleanup.el38
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"