From ca4bd5349f03f5517cf3d359179bfbba30a73233 Mon Sep 17 00:00:00 2001 From: Michal Czyz Date: Thu, 26 Mar 2026 01:23:03 +0000 Subject: [PATCH 1/7] fix(ace-task): keep the stats footer for empty lists Route empty and non-empty task output through the same formatter path so the footer is always emitted. Add coverage for the empty-state summary and zero-total filtered output. --- ace-task/CHANGELOG.md | 21 +++++++++++++++++++ .../task/molecules/task_display_formatter.rb | 15 ++++++++++--- ace-task/lib/ace/task/version.rb | 2 +- ace-task/test/commands/list_test.rb | 1 + .../molecules/task_display_formatter_test.rb | 19 +++++++++++++++-- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/ace-task/CHANGELOG.md b/ace-task/CHANGELOG.md index d4d678b844..4fc663e5c7 100644 --- a/ace-task/CHANGELOG.md +++ b/ace-task/CHANGELOG.md @@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.31.3] - 2026-03-26 + +### Fixed +- Simplified `TaskDisplayFormatter.format_list` by consolidating the shared stats footer return path for empty and non-empty output. + +### Technical +- Strengthened `ace-task list` command coverage to assert empty-state stats footer output includes the zero-total summary. + +## [0.31.2] - 2026-03-26 + +### Fixed +- Tightened empty-list stats rendering to match the corrected support formatter output (`Tasks: • 0 total`) for fully empty roots. + +### Technical +- Strengthened task display formatter regression coverage with an exact empty-output assertion. + +## [0.31.1] - 2026-03-26 + +### Fixed +- Updated `ace-task list` empty-result rendering to always append the stats footer, matching non-empty output and `ace-idea` behavior. + ## [0.31.0] - 2026-03-24 ### Fixed diff --git a/ace-task/lib/ace/task/molecules/task_display_formatter.rb b/ace-task/lib/ace/task/molecules/task_display_formatter.rb index 46f1063525..da99aa0e1d 100644 --- a/ace-task/lib/ace/task/molecules/task_display_formatter.rb +++ b/ace-task/lib/ace/task/molecules/task_display_formatter.rb @@ -115,10 +115,19 @@ def self.format(task, show_content: false) # @param global_folder_stats [Hash, nil] Folder name → count hash from full scan # @return [String] Formatted list output def self.format_list(tasks, total_count: nil, global_folder_stats: nil) - return "No tasks found." if tasks.empty? + stats_line = format_stats_line( + tasks, + total_count: total_count, + global_folder_stats: global_folder_stats + ) + + body = if tasks.empty? + "No tasks found." + else + tasks.map { |task| format_list_item(task) }.join("\n") + end - lines = tasks.map { |task| format_list_item(task) }.join("\n") - "#{lines}\n\n#{format_stats_line(tasks, total_count: total_count, global_folder_stats: global_folder_stats)}" + "#{body}\n\n#{stats_line}" end STATUS_ORDER = %w[draft pending in-progress done blocked skipped cancelled].freeze diff --git a/ace-task/lib/ace/task/version.rb b/ace-task/lib/ace/task/version.rb index 67a50f73ad..dd6e3bfda9 100644 --- a/ace-task/lib/ace/task/version.rb +++ b/ace-task/lib/ace/task/version.rb @@ -2,6 +2,6 @@ module Ace module Task - VERSION = "0.31.0" + VERSION = "0.31.3" end end diff --git a/ace-task/test/commands/list_test.rb b/ace-task/test/commands/list_test.rb index 9bf7ee2337..9f6eb80952 100644 --- a/ace-task/test/commands/list_test.rb +++ b/ace-task/test/commands/list_test.rb @@ -91,6 +91,7 @@ def test_list_empty_shows_message end.first assert_match(/No tasks found/, output) + assert_match(/Tasks:.*0 total/, output) end def test_list_shows_stats_line diff --git a/ace-task/test/molecules/task_display_formatter_test.rb b/ace-task/test/molecules/task_display_formatter_test.rb index ff18f5a5ec..becfa9c794 100644 --- a/ace-task/test/molecules/task_display_formatter_test.rb +++ b/ace-task/test/molecules/task_display_formatter_test.rb @@ -152,10 +152,25 @@ def test_format_list_shows_compact_items assert_includes output, "Second task" end - def test_format_list_returns_message_for_empty_list + def test_format_list_empty_returns_no_tasks_message_with_stats output = Ace::Task::Molecules::TaskDisplayFormatter.format_list([]) - assert_equal "No tasks found.", output + assert_equal "No tasks found.\n\nTasks: • 0 total", output + end + + def test_format_list_empty_includes_folder_summary_when_totals_exist + output = Ace::Task::Molecules::TaskDisplayFormatter.format_list( + [], + total_count: 10, + global_folder_stats: {nil => 2, "_maybe" => 3, "_archive" => 5} + ) + + assert_includes output, "No tasks found." + assert_includes output, "Tasks:" + assert_includes output, "• 0 of 10" + assert_includes output, "next 2" + assert_includes output, "maybe 3" + assert_includes output, "archive 5" end def test_format_list_shows_tags_inline From c66ee88e3f864af7afd24073ae45b8a884148b02 Mon Sep 17 00:00:00 2001 From: Michal Czyz Date: Thu, 26 Mar 2026 01:23:03 +0000 Subject: [PATCH 2/7] fix(support-packages): tighten empty stats formatting Normalize the status bucket prefix so the footer renders cleanly when no statuses are present. Add a regression test for the zero-bucket case. --- ace-support-items/CHANGELOG.md | 8 ++++++++ .../ace/support/items/atoms/stats_line_formatter.rb | 6 +++++- ace-support-items/lib/ace/support/items/version.rb | 2 +- .../test/atoms/stats_line_formatter_test.rb | 13 +++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ace-support-items/CHANGELOG.md b/ace-support-items/CHANGELOG.md index b639322a4d..0cbc33c289 100644 --- a/ace-support-items/CHANGELOG.md +++ b/ace-support-items/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.15.4] - 2026-03-26 + +### Fixed +- `StatsLineFormatter`: corrected empty-status output formatting to avoid the malformed `Tasks: • 0 total` footer when no status buckets are present. + +### Technical +- Added regression coverage for zero-status summary formatting in `stats_line_formatter_test.rb`. + ## [0.15.3] - 2026-03-22 ### Technical diff --git a/ace-support-items/lib/ace/support/items/atoms/stats_line_formatter.rb b/ace-support-items/lib/ace/support/items/atoms/stats_line_formatter.rb index 125d12c658..9f6efa5103 100644 --- a/ace-support-items/lib/ace/support/items/atoms/stats_line_formatter.rb +++ b/ace-support-items/lib/ace/support/items/atoms/stats_line_formatter.rb @@ -35,7 +35,11 @@ def self.format(label:, stats:, status_order:, status_icons:, folder_stats: nil, parts << "#{icon} #{count}" end - line = "#{label}: #{parts.join(" | ")}" + line = if parts.empty? + "#{label}:" + else + "#{label}: #{parts.join(" | ")}" + end shown = stats[:total] total = total_count || shown diff --git a/ace-support-items/lib/ace/support/items/version.rb b/ace-support-items/lib/ace/support/items/version.rb index a1e109c621..8ed5f18c5c 100644 --- a/ace-support-items/lib/ace/support/items/version.rb +++ b/ace-support-items/lib/ace/support/items/version.rb @@ -3,7 +3,7 @@ module Ace module Support module Items - VERSION = "0.15.3" + VERSION = "0.15.4" end end end diff --git a/ace-support-items/test/atoms/stats_line_formatter_test.rb b/ace-support-items/test/atoms/stats_line_formatter_test.rb index 01077cd6f2..3f4703bfc2 100644 --- a/ace-support-items/test/atoms/stats_line_formatter_test.rb +++ b/ace-support-items/test/atoms/stats_line_formatter_test.rb @@ -68,6 +68,19 @@ def test_format_single_status assert_equal "Tasks: ✓ 5 • 5 total", line end + def test_format_with_no_status_parts + stats = {total: 0, by_field: {}} + + line = Ace::Support::Items::Atoms::StatsLineFormatter.format( + label: "Tasks", + stats: stats, + status_order: %w[pending done], + status_icons: {"pending" => "○", "done" => "✓"} + ) + + assert_equal "Tasks: • 0 total", line + end + def test_format_includes_unknown_statuses stats = {total: 5, by_field: {"pending" => 2, "draft" => 3}} From ee853ee61c94b34f1250f0cc2bf324f33c6f936a Mon Sep 17 00:00:00 2001 From: Michal Czyz Date: Thu, 26 Mar 2026 01:23:03 +0000 Subject: [PATCH 3/7] chore(project default): refresh release metadata Update the top-level changelog entries and locked dependency versions to capture the latest package release state. --- CHANGELOG.md | 16 ++++++++++++++++ Gemfile.lock | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e340ec920c..d22b7b501a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [0.9.928] - 2026-03-26 + +### Fixed +- **ace-task v0.31.3**: Consolidated empty-list stats footer formatting into a single return path and added command-level coverage for zero-total footer output. + +## [0.9.927] - 2026-03-26 + +### Fixed +- **ace-support-items v0.15.4**: corrected zero-status summary formatting in `StatsLineFormatter` so empty lists render `Tasks: • 0 total` without dangling spacing. +- **ace-task v0.31.2**: aligned empty-task list output with the formatter fix and added exact output regression coverage. + +## [0.9.926] - 2026-03-26 + +### Fixed +- **ace-task v0.31.1**: `ace-task list` now shows the stats footer for empty results, including filtered `0 of N` summaries. + ## [0.9.925] - 2026-03-23 ### Fixed diff --git a/Gemfile.lock b/Gemfile.lock index be2ee97096..5555c5d3ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -278,7 +278,7 @@ PATH PATH remote: ace-support-items specs: - ace-support-items (0.15.3) + ace-support-items (0.15.4) ace-b36ts (~> 0.7) ace-support-core (~> 0.25) @@ -323,7 +323,7 @@ PATH PATH remote: ace-task specs: - ace-task (0.31.0) + ace-task (0.31.3) ace-b36ts (~> 0.7) ace-support-cli (~> 0.3) ace-support-core (~> 0.25) From 92fa255ad9717d8448183077af2426d3d3c94324 Mon Sep 17 00:00:00 2001 From: Michal Czyz Date: Thu, 26 Mar 2026 01:23:03 +0000 Subject: [PATCH 4/7] spec(retro-specs): record the stats footer follow-up Add a retrospective entry covering the empty-list footer fix, lessons learned, and next steps. --- ...-0vy-empty-task-list-stats-footer.retro.md | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .ace-retros/8qp1ai-t-0vy-empty-task-list/8qp1ai-t-0vy-empty-task-list-stats-footer.retro.md diff --git a/.ace-retros/8qp1ai-t-0vy-empty-task-list/8qp1ai-t-0vy-empty-task-list-stats-footer.retro.md b/.ace-retros/8qp1ai-t-0vy-empty-task-list/8qp1ai-t-0vy-empty-task-list-stats-footer.retro.md new file mode 100644 index 0000000000..2539e7eeda --- /dev/null +++ b/.ace-retros/8qp1ai-t-0vy-empty-task-list/8qp1ai-t-0vy-empty-task-list-stats-footer.retro.md @@ -0,0 +1,29 @@ +--- +id: 8qp1ai +title: t-0vy-empty-task-list-stats-footer +type: standard +tags: [task, ace-task, list-output] +created_at: "2026-03-26 00:51:40" +status: active +--- + +# t-0vy-empty-task-list-stats-footer + +## What Went Well +- The target behavior was narrow and clearly specified, so implementation stayed limited to one formatter method and one test file. +- Existing `ace-idea` empty-list behavior provided a direct reference pattern, reducing ambiguity and rework. +- Verification stayed fast and reliable (`ace-test` focused + package profile run), and all tests passed on first run. + +## What Could Be Improved +- The `ace-task plan` command took noticeable time with no immediate output, which can look like a stall during automation. +- Pre-commit review fallback (`ace-lint`) surfaced style warnings on pre-existing lines unrelated to this change; this adds noise to gate reports. + +## Key Learnings +- For list-formatting changes, reusing existing stats formatter paths avoids divergence between empty and non-empty rendering. +- Empty-state UX still benefits from global context (`0 of N`, folder breakdown), especially for filtered views. +- In assignment subtrees, explicit scoped commands and per-step reports make recovery and auditability straightforward. + +## Action Items +- Continue: Mirror behavior from sibling formatters (`ace-idea` / `ace-task`) before introducing new output logic. +- Start: Consider a small enhancement to `ace-task plan` user feedback for long-running plan generation. +- Stop: Treating style-only lint warnings as if they were release blockers when `pre_commit_review_block` is false. From 6d834a5d21b0981c6a166f47a5ae18d0148da137 Mon Sep 17 00:00:00 2001 From: Michal Czyz Date: Thu, 26 Mar 2026 01:23:03 +0000 Subject: [PATCH 5/7] spec(task-specs): mark the footer task complete Advance the task spec from in progress to done after the formatter and test updates landed. --- .../8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ace-tasks/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md b/.ace-tasks/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md index 1ab95c53ab..2cdf559831 100644 --- a/.ace-tasks/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md +++ b/.ace-tasks/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md @@ -1,6 +1,6 @@ --- id: 8qp.t.0vy -status: in-progress +status: done priority: medium created_at: "2026-03-26 00:35:31" estimate: TBD From 06bb388c45161ce7dc1fa4c311b911e214a0aa81 Mon Sep 17 00:00:00 2001 From: Michal Czyz Date: Thu, 26 Mar 2026 01:28:18 +0000 Subject: [PATCH 6/7] spec(ace-tasks): archive completed task spec --- .../8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .ace-tasks/{ => _archive/8q/y}/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md (100%) diff --git a/.ace-tasks/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md b/.ace-tasks/_archive/8q/y/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md similarity index 100% rename from .ace-tasks/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md rename to .ace-tasks/_archive/8q/y/8qp.t.0vy-show-stats-footer-in-ace/8qp.t.0vy-show-stats-footer-in-ace-task-list.s.md From 1b77718a0d5f936f608fd223e4f0ba239453ea1c Mon Sep 17 00:00:00 2001 From: Michal Czyz Date: Thu, 26 Mar 2026 01:29:02 +0000 Subject: [PATCH 7/7] spec(retros): add batch retro for t.0vy stats footer work --- .../8qp27m-batch-t-0vy-stats-footer.retro.md | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .ace-retros/8qp27m-batch-t-0vy-stats-footer/8qp27m-batch-t-0vy-stats-footer.retro.md diff --git a/.ace-retros/8qp27m-batch-t-0vy-stats-footer/8qp27m-batch-t-0vy-stats-footer.retro.md b/.ace-retros/8qp27m-batch-t-0vy-stats-footer/8qp27m-batch-t-0vy-stats-footer.retro.md new file mode 100644 index 0000000000..69def0473e --- /dev/null +++ b/.ace-retros/8qp27m-batch-t-0vy-stats-footer/8qp27m-batch-t-0vy-stats-footer.retro.md @@ -0,0 +1,39 @@ +--- +id: 8qp27m +title: batch-t-0vy-stats-footer +type: standard +tags: [] +created_at: "2026-03-26 01:28:28" +status: active +--- + +# batch-t-0vy-stats-footer + +## What Went Well + +- **Fork delegation worked smoothly**: The 8-step work-on-task subtree (010.01) completed autonomously without intervention — onboard through retro in one pass. +- **Review cycle efficiency**: Three review cycles (valid, fit, shine) executed in parallel fork subtrees. Valid cycle caught a real formatting issue (dangling space in empty stats), fit found only false positives, shine contributed two low-priority polish improvements. +- **Small, focused change**: The core fix was ~15 lines of production code. The ATOM architecture kept the change isolated to one molecule (TaskDisplayFormatter) with clear test boundaries. +- **Release automation**: Three patch releases (v0.31.1 → v0.31.3) were bumped automatically with proper CHANGELOG entries and lockfile updates. +- **Commit reorganization**: 12 interleaved commits were cleanly reorganized into 5 logical groups by ace-git-commit's scope detection. + +## What Could Be Improved + +- **Pre-existing test failure**: ace-docs has a failing test (`DocumentRegistryTest#test_discovers_frontmatter_free_readme_without_yaml`) unrelated to this work. This creates noise in suite verification and requires manual assessment each time. +- **Multiple patch releases**: Three successive patch bumps (0.31.1/0.31.2/0.31.3) within one PR is noisy. The valid review cycle found a real issue, so the second bump was justified, but the shine cycle's changes could have been folded into the same release. +- **ace-support-items side-effect**: The valid review cycle's fix touched ace-support-items (StatsLineFormatter), adding it to the release scope. Cross-package side-effects in review cycles should be flagged earlier. + +## Key Learnings + +### Review Cycle Analysis +- **Valid cycle**: 1 medium finding (real formatting bug) — high value, led to code change + test + release. +- **Fit cycle**: 1 finding marked invalid (false positive) — zero code changes, release correctly skipped as no-op. +- **Shine cycle**: 2 low-priority findings, both applied as quick wins — refactored shared return path, extended CLI test coverage. +- **False positive rate**: 1/4 total findings (25%) were false positives — reasonable for LLM review on a small change. + +## Action Items + +- **Continue**: Using fork delegation for review cycles — keeps driver clean and subtrees independent. +- **Start**: Tracking pre-existing test failures in a task so they don't create confusion during suite verification. +- **Consider**: Consolidating review-cycle releases when changes are minimal (e.g., shine-only changes could skip release if prior cycle already bumped). +