Skip to content

docs(projects): document taskCount and openCount - #207

Merged
ryanlewis merged 1 commit into
mainfrom
feat/issue-203-project-counts
Sep 10, 2026
Merged

ryanlewis merged 1 commit into
mainfrom
feat/issue-203-project-counts

Conversation

@ryanlewis

Copy link
Copy Markdown
Owner

Closes #203

What changed

Docs only. things projects -j has reported taskCount and openCount since the counts were added to drive the progress icon, but nothing said what they count, so the only documented way to find a project whose work had all landed was one things list per project. This documents both fields and adds a jq recipe for the daily reconcile.

  • internal/skill/SKILL.md — a bullet in "Output and --json", two comment lines on the things projects reference line, and a "projects with no open to-dos" recipe in "Common flows".
  • docs/content/commands.md — a block in "Listing", after the paragraph about projects carrying start / startBucket / startDate / deadline.
  • docs/content/agents.md — a bullet in "Script it with --json" and a line in the recipe block.

No new flags, no new JSON fields, no change to plain-text output, no Go code touched. The user decided to keep the existing field names rather than the openTodoCount / completedTodoCount the issue proposed, and to leave the ● progress icon as the human-output answer.

Why these semantics, and how they were verified

The fields come straight from Things' own columns untrashedLeafActionsCount and openUntrashedLeafActionsCount. Rather than infer the meaning from the column names, I checked them against real data with sqlite3 -readonly on the live database and on a backup snapshot, recounting each project's children and comparing:

Database Projects compared Match Diverge
Live 82 82 0
Backup 2026-09-01 63 63 0

A deliberately wrong value matched zero rows, confirming the comparison detects divergence rather than passing vacuously.

What that established, and what the docs now say:

  • To-dos under a heading are included. A to-do filed under a heading has project NULL and points only at heading, so a correct recount has to union direct children with the children of the project's headings. Ignoring headings gives the wrong total for exactly the 7 projects here that have them.
  • Heading rows themselves are never counted, nor are trashed to-dos or checklist items. The trashed exclusion is real rather than theoretical: counting trashed to-dos would change the total for 13 projects.

Three caveats, each documented

Each one can mislead someone acting on the recipe:

  • taskCount - openCount counts to-dos that are no longer open, which means completed or cancelled. 23 projects here contain at least one cancelled to-do, so a project whose to-dos were all cancelled matches the same filter.
  • Under --completed the ● icon marks any completed project, including one with no to-dos at all, so the icon and the filter are not identical there. Verified against a fixture database.
  • A repeating to-do makes a project unreachable by the filter. Things counts the hidden template row as an open to-do and a template never completes. Measured on the backup snapshot: the project holding two templates reports 68/21, which matches the recount only when the templates are included; excluding them gives 66/19. All open contributions came from the template rows themselves, with no open generated instance. things list -p hides that template, so the two disagree, and that is now called out.

How it was verified

  • make test and make lint green (lint reports 0 issues; the warning names a stale sibling worktree unrelated to this change).
  • All three jq recipes were run as written.
  • Against a fixture database, the filter selects the all-done project and correctly excludes both the half-done and the empty one.
  • hugo builds the site and renders the new sections.
  • The new text ships in the binary, confirmed via things skill show.

Rebased on main after #201 (#205) landed. It also appended a bullet to the same SKILL.md list, so both bullets are kept, that one first.

`things projects -j` has reported `taskCount` and `openCount` since the
counts were added for the progress icon, but nothing said what they
count, so the only documented way to find a project whose work has all
landed was one `things list` per project.

Document both fields in the three places project JSON is described, and
add a "projects with no open to-dos" recipe for the daily reconcile.

The semantics were verified against the live database rather than
inferred from the column names: across 82 projects the cached counters
`untrashedLeafActionsCount` and `openUntrashedLeafActionsCount` match a
recount of untrashed type-0 children exactly, including to-dos filed
under a heading, which carry `heading` but not `project`. Heading rows,
trashed to-dos and checklist items are excluded.

Three caveats are documented because each one can mislead a caller
acting on the recipe:

- `taskCount - openCount` is to-dos that are no longer open, which means
  completed or cancelled. A project whose to-dos were all cancelled
  matches the same filter.
- The `●` icon marks any completed project under `--completed`,
  including one with no to-dos at all, so it is not identical to the
  filter there.
- A repeating to-do makes a project unreachable by the filter: Things
  counts the hidden template row as an open to-do and it never
  completes, while `things list -p` hides that template, so the two
  disagree.

No behaviour change; no Go code touched.

Closes #203
@ryanlewis
ryanlewis merged commit 894fa57 into main Sep 10, 2026
10 checks passed
@ryanlewis
ryanlewis deleted the feat/issue-203-project-counts branch September 10, 2026 10:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: surface projects with no open to-dos (open/completed counts on projects, or --empty)

1 participant