import: status reports the plans filed away done
A done: section under the in-flight list, whole counts, and nothing
about next steps when nothing is in flight.

Assisted-by: GLM-5.3 via pi
change slumykxzzxzrqtrwzypvusslmpzzkrpt
commit cdfb0922310ae7b330fddfe85d420750af8b9fb2
author Alpha Chen <alpha@kejadlen.dev>
date
parent ynzmspuw
diff --git a/AGENTS.md b/AGENTS.md
index 9092477..5843f81 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -39,8 +39,9 @@ rake import:macos:finalize # Finalize the contacts the oldest
 rake import:execute   # Land the oldest plan still to land on a host
                       # (host in data/import/config.yml; PLAN=dir for
                       # another)
-rake import:status    # Summarize the plans in data/import and what
-                      # execute and finalize would carry next
+rake import:status    # Summarize the plans in data/import — in
+                      # flight and filed away done — and what execute
+                      # and finalize would carry next
 rake profile:install  # Download carddav.mobileconfig from the app and
                       # stage it for approval
 ```
diff --git a/docs/plans/2026-09-19-import-under-data-import.md b/docs/plans/2026-09-19-import-under-data-import.md
index a0c396f..ac467b6 100644
--- a/docs/plans/2026-09-19-import-under-data-import.md
+++ b/docs/plans/2026-09-19-import-under-data-import.md
@@ -48,6 +48,6 @@ still finishes and files away; nothing is rewritten on disk.
 A plan whose every contact is done is finished (`Plan#done?`). The
 finalize task files one away into `done/` as its last step, and the
 status read sweeps any a dead run left in `active/` before listing —
-so what status lists is what still has work, and the finished plans
-are out of the way but kept, with their cards and sources, for as
-long as `data/` is.
+so its in-flight list is what still has work, and the finished plans
+appear under a `done:` section below, kept with their cards and
+sources for as long as `data/` is.
diff --git a/tasks/import.rake b/tasks/import.rake
index f78c211..a8d558b 100644
--- a/tasks/import.rake
+++ b/tasks/import.rake
@@ -95,37 +95,51 @@ namespace :import do
     end
   end
 
-  desc "Summarize the plans in data/import and what execute and finalize would carry next"
+  desc "Summarize the plans in data/import — in flight and filed away done — and what execute and finalize would carry next"
   task :status do
     require "pro_tacts/import/plan"
 
     # A finished plan files away; this sweeps any a dead run left in
-    # active/, so what is listed is what still has work — which is also
-    # why nothing here is ever finished: the sweep took it.
+    # active/, so the in-flight list below is what still has work —
+    # which is also why nothing in it is ever finished: the sweep took
+    # it.
     ProTacts::Import::Plan.all(ImportTasks::Config::ACTIVE).each do |plan|
       ImportTasks.file_away(plan) if plan.done?
     end
 
     plans = ProTacts::Import::Plan.all(ImportTasks::Config::ACTIVE)
-    if plans.empty?
+    filed = ProTacts::Import::Plan.all(ImportTasks::Config::DONE)
+    if plans.empty? && filed.empty?
       puts "no plans in #{ImportTasks::Config::ACTIVE}; run rake import:macos:plan"
       next
     end
 
-    # One line per plan, as far along as it is: the fraction counts
-    # everything past “planned”, because from “landed” on the card is
-    # on the host — which is the state a glance wants. The plan names
-    # are the directories', copy-pasteable into PLAN=.
-    plans.each do |plan|
-      done = plan.contacts.size - plan.with_status(nil).size
-      puts "#{plan.dir.basename}  #{done}/#{plan.contacts.size} contacts"
-    end
+    # One line per plan in flight, as far along as it is: the fraction
+    # counts everything past “planned”, because from “landed” on the
+    # card is on the host — which is the state a glance wants. The
+    # plan names are the directories', copy-pasteable into PLAN=.
+    in_flight = plans.map {
+      carried = it.contacts.size - it.with_status(nil).size
+      "#{it.dir.basename}  #{carried}/#{it.contacts.size} contacts"
+    }
 
-    puts ""
     landing = plans.find(&ImportTasks::TO_LAND)
     finalizing = plans.find(&ImportTasks::TO_FINALIZE)
-    puts "next: import:execute would land #{landing.dir.basename}" if landing
-    puts "next: import:macos:finalize would finish #{finalizing.dir.basename}" if finalizing
+    next_up = [
+      ("next: import:execute would land #{landing.dir.basename}" if landing),
+      ("next: import:macos:finalize would finish #{finalizing.dir.basename}" if finalizing),
+    ].compact
+
+    # What was carried through, whole counts because every contact
+    # reached the final state — the fraction above can never appear
+    # here.
+    done = filed.map { "#{it.dir.basename}  #{it.contacts.size} contacts" }
+
+    # Sections separated by a blank line only where one follows
+    # another, so a status with no plans in flight says nothing of
+    # next steps and still reports its history.
+    sections = [in_flight, next_up, done.empty? ? [] : ["done:", *done]].reject(&:empty?)
+    puts sections.map { it.join("\n") }.join("\n\n")
   end
 
   desc "Land the oldest plan in data/import/active still to land, or the one in PLAN, on the pro-tacts at the host in data/import/config.yml, a base URL such as https://contacts"
diff --git a/test/tasks/test_import.rb b/test/tasks/test_import.rb
index 51e426e..e8c780a 100644
--- a/test/tasks/test_import.rb
+++ b/test/tasks/test_import.rb
@@ -35,9 +35,22 @@ class ImportTasksTest < Minitest::Test
       assert_includes out, "macos-20260916T180412Z  0/1 contacts\n"
       assert_includes out, "next: import:execute would land macos-20260916T180412Z\n"
       assert_includes out, "next: import:macos:finalize would finish macos-20260901T000000Z\n"
+      assert_includes out, "done:\nmacos-20260831T000000Z  2 contacts\n"
       assert (root / "data/import/done/macos-20260831T000000Z/plan.yml").file?
       refute (plans / "macos-20260831T000000Z").directory?
-      refute_includes out, "macos-20260831T000000Z  "
+      refute_includes out, "macos-20260831T000000Z  2/2 contacts"
+    end
+  end
+
+  def test_status_with_only_done_plans_reports_them_alone
+    Dir.mktmpdir do |root|
+      root = Pathname.new(root)
+      plan = Plan.write(root / "data/import/done/macos-20260831T000000Z", source: "macos", created_at: Time.utc(2026, 8, 31), entries: [entry("qxqmqmqmqmqm")])
+      plan.contacts.each { it.status or plan.record(it.id, Plan::DONE) }
+
+      out, = run_status(root)
+
+      assert_equal "done:\nmacos-20260831T000000Z  1 contacts\n", out
     end
   end