Skip to content

fix(list): keep project to-dos out of someday - #228

Merged
ryanlewis merged 1 commit into
mainfrom
fix/issue-211-someday-parent
Sep 10, 2026
Merged

ryanlewis merged 1 commit into
mainfrom
fix/issue-211-someday-parent

Conversation

@ryanlewis

Copy link
Copy Markdown
Owner

Closes #211

What changed

someday now returns only rows with no parent project. Things' Someday list is the deferred things you have not filed under a project: a to-do inside a project stays inside that project however it is deferred, and the app shows it greyed within the project rather than in the global list. The CLI returned those to-dos, so things list someday answered a different question from the one the app answers.

The view gains p.uuid IS NULL. Because p is resolved through COALESCE(t.project, h.project), a to-do filed under a project heading is excluded by the same clause rather than slipping through as unparented. Project rows have no parent project of their own, so they still list, which is what #206 established.

The rule was measured, not assumed

The issue proposed excluding Someday to-dos "whose parent project is not itself in Someday". That is not the rule, and the difference mattered enough to test rather than guess.

Two rules fit the existing data equally well, because every one of the nine to-dos the CLI wrongly returned had an Anytime parent:

  • A. exclude a Someday to-do whose parent project is not itself in Someday (the issue's hypothesis)
  • B. exclude a Someday to-do that has any parent project

They differ only for a Someday to-do inside a Someday project, and this database contained no Someday projects at all, so the discriminating case did not exist. With the user's approval I created it through the app and measured it.

A throwaway project PROBE-someday-20260910-122504 was created in Things via AppleScript, moved to Someday, given a deadline, and one to-do added inside it via the things:///add URL scheme with when=someday, so that both project and child sat in Someday with the child properly parented. Reading the app's own list membership:

in the app's Someday list
the probe project (Someday, has a deadline) yes
its child to-do (Someday, parent is that Someday project) no

The app's Someday list went from 6 rows to 7, gaining only the project. So the test is the presence of a parent, not the parent's bucket: rule B. The probe project also appeared in the app's Later Projects list, which is where Things files deferred projects, and that list was empty before and after.

Both probe items were then deleted through the app. The app's Someday list is back to 6, Later Projects back to 0, and the four probe rows sit in the Trash.

Verified against the real database

With rule B implemented, things list someday returns 6 rows and the app's Someday list holds 6, with no difference in either direction by uuid.

count
App's Someday list 6
CLI list someday before 15
CLI list someday after 6
Rows in one and not the other 0

The nine dropped are the eight named in the issue plus GXHKQn2Y12ChTiGXLdqQvB, which the issue did not list. All nine are Someday to-dos with an Anytime parent project.

--project on someday is now an error

Narrowing this view to a project asks for the contents of a project the view has already excluded, so the two clauses contradict and the listing is empty whatever the project holds. On main that command listed a project's deferred to-dos, so leaving it silently empty would have been a regression with no explanation attached.

It now fails with an error naming the view and pointing at things --project "Name", which does return a project's own deferred to-dos. That follows the precedent this repo already set twice: #124 rejects date filters on this same view for the same reason, and --include-completed is rejected everywhere but today. Both the flag form and the positional form (things someday "Name") are covered.

This is a small CLI surface change rather than something #211 asked for, so it is worth a reviewer's eye. The alternative is a command that returns nothing and says nothing.

Tests

Five tests in internal/db/tasks_test.go over a new seedSomedayParents helper, which seeds an Anytime parent and a Someday parent so the discriminating case is in the fixture rather than only in the prose:

  • to-dos inside a project are excluded; the Someday project and the unparented to-dos remain
  • the discriminating case on its own — a Someday to-do inside a Someday project stays hidden while its parent lists
  • a to-do reaching its project through a heading is excluded by the same clause
  • narrowing does not empty the view: --area still finds the project row and the unparented to-do, and --project can no longer match anything here
  • the narrowing is someday-only — a parented to-do still lists in anytime

TestRunListSomedayRejectsProjectFilter in cmd/things/run_test.go covers the new error in both its flag and positional forms, and asserts bare someday and someday --area still work.

TestTemplateProjectChildrenExcludedFromOpenViews drove each view with a template's child and an ordinary project's child, expecting the ordinary one to list. Someday no longer carries either, so that sibling cannot exist there and the case has moved to TestTemplateChildExcludedFromSomeday, which asserts both children stay out while a top-level to-do and a Someday project row still list. Coverage of the template guard on this view is kept, not dropped.

Docs

internal/skill/SKILL.md, docs/content/commands.md, docs/content/agents.md and README.md describe Someday as the deferred things not filed under a project, say explicitly that the rule holds even when the parent project is itself in Someday, and point at things --project "Name" for a project's own deferred to-dos.

Closes #211

Things' Someday list holds the deferred things you have not filed under a
project. A to-do inside a project stays inside it however it is deferred:
the app shows it greyed within the project rather than in the global list.
The CLI returned those to-dos, so `things list someday` answered a
different question from the one the app answers.

The view gains p.uuid IS NULL. Because p resolves through
COALESCE(t.project, h.project), a to-do filed under a project heading is
excluded by the same clause rather than slipping through as unparented.
Project rows have no parent project, so they still list (issue #206).

The rule was measured, not assumed. The issue proposed excluding Someday
to-dos whose parent project is not itself in Someday, but the database
held no Someday projects, so that could not be told apart from the
simpler rule. With the user's approval a throwaway project was created in
Things, in Someday and holding one Someday to-do, and the app's own list
membership read back: the project appeared in Someday, the child did not.
The test is the presence of a parent, not the parent's bucket. The probe
was deleted afterwards and the app's list is back to its 6 rows.

Verified by uuid: the app lists 6, the CLI listed 15 before and 6 after,
with no difference in either direction. The nine dropped are the eight
named in the issue plus GXHKQn2Y12ChTiGXLdqQvB.

--project on someday now errors instead of returning an empty list: the
clauses contradict, so it could never match. It names the view and points
at `things --project NAME`, the same call issue #124 made for date
filters on this view.
@ryanlewis
ryanlewis force-pushed the fix/issue-211-someday-parent branch from 80e6261 to d0988cf Compare September 10, 2026 11:39
@ryanlewis
ryanlewis merged commit a7cfb5f into main Sep 10, 2026
10 checks passed
@ryanlewis
ryanlewis deleted the fix/issue-211-someday-parent branch September 10, 2026 11:41
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.

bug: things list someday shows Someday to-dos inside Anytime projects that the app keeps out of its Someday list

1 participant