You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As a user who starts a Focus sprint on an Outcome that has no current Action, finishes it, and gives it a verdict, I want it struck off for the session like any other, so the session view does not keep demanding attention for something I have already handled.
Observed Behaviour
An Outcome on the day's Plan that is Actionless (no current Action) can be started from the Now screen — _StartButton offers a sprint on any Plan member regardless of Action state. Complete the sprint and give any non-done verdict ("More to do…", "Waiting For", "Someday") and the row never strikes off, and never will.
Marking the Outcome done still works (that is a different arm of the predicate).
Why it cannot settle, by construction
The Settled predicate introduced by #693 has two arms: Completion recorded, or an Action of the Outcome was completed within this FocusSession and the Outcome was re-clarified at or after that completion. The second arm is anchored on a completed Action, and for an Actionless Outcome there is none to anchor to:
TimeLogDao.openLog resolves action_id from the Outcome's current Action; with none, the log is opened with action_id = NULL.
ActionDao.applyCompleteCurrentAction no-ops when there is no current Action.
The settlement anchor subquery (MAX(a.done_at) over actions joined to time_logs on action_id) is therefore NULL, so arm (b) can never be satisfied.
This is documented in the DAO docstring, pinned by a test, and named in ADR-0048 — deliberately, so the behaviour is a decision rather than an accident. The reading "nothing was completed, so nothing settled" is defensible in the model. It is still a hole from the user's side: they did work, gave a verdict, and the UI disagrees.
The same applies to an off-Plan Outcome engaged with action_id IS NULL.
Scope
Decide whether an Actionless Outcome should be startable at all. The likely shape — and the one that fits the model rather than patching around it — is that starting a sprint should first give the Outcome an Action, using the title-as-action fallback the codebase already applies elsewhere (an empty next-action phrase means the Outcome's title, written only while the Outcome is Actionless — TodoDao.setCurrentActionTextIfActionless; issue Saving an empty next action during review should resolve the item as Next and advance, not stall on the item #691). Then arm (b) works with no change to the predicate.
The alternative — teaching the settlement anchor to accept a NULL-action TimeLog — is not preferred: it would make "an Action was completed" mean something it does not, and the Settled predicate is deliberately the session-scoped negation of Stale.
Whichever is chosen, _StartButton's affordance and the resulting state must agree.
Acceptance Criteria
Starting a sprint on an Actionless Plan member, completing it, and giving a non-done verdict strikes the row off for the session.
The Settled predicate is not weakened to achieve it — arm (b) still means an Action was genuinely completed in this session.
The same holds for an off-Plan Outcome engaged during the session.
The existing test pinning today's "Actionless never settles" behaviour is updated deliberately, not deleted.
ADR-0048's note recording this hole is updated to record how it was closed.
docs/adr/0048-session-settlement-is-derived.md — records this hole in its arm-two paragraph.
The title-as-action fallback a fix would reuse: TodoDao.setCurrentActionTextIfActionless and _nextWithDialog in app/lib/widgets/process_to_handlers.dart (issue Saving an empty next action during review should resolve the item as Next and advance, not stall on the item #691). Its ADR, 0049-empty-next-action-means-the-title.md, was removed in 816381a6 as one of the bug-fix ADRs; reasoning recoverable with git show 816381a6^:docs/adr/0049-empty-next-action-means-the-title.md.
app/lib/screens/focus_screen.dart (_StartButton), app/lib/database/daos/time_log_dao.dart (openLog), app/lib/database/daos/action_dao.dart (applyCompleteCurrentAction), app/lib/database/daos/focus_session_dao.dart (the settlement anchor).
User Story
As a user who starts a Focus sprint on an Outcome that has no current Action, finishes it, and gives it a verdict, I want it struck off for the session like any other, so the session view does not keep demanding attention for something I have already handled.
Observed Behaviour
An Outcome on the day's Plan that is Actionless (no
currentAction) can be started from the Now screen —_StartButtonoffers a sprint on any Plan member regardless of Action state. Complete the sprint and give any non-done verdict ("More to do…", "Waiting For", "Someday") and the row never strikes off, and never will.Marking the Outcome done still works (that is a different arm of the predicate).
Why it cannot settle, by construction
The Settled predicate introduced by #693 has two arms: Completion recorded, or an Action of the Outcome was completed within this FocusSession and the Outcome was re-clarified at or after that completion. The second arm is anchored on a completed Action, and for an Actionless Outcome there is none to anchor to:
TimeLogDao.openLogresolvesaction_idfrom the Outcome'scurrentAction; with none, the log is opened withaction_id = NULL.ActionDao.applyCompleteCurrentActionno-ops when there is no current Action.MAX(a.done_at)overactionsjoined totime_logsonaction_id) is therefore NULL, so arm (b) can never be satisfied.This is documented in the DAO docstring, pinned by a test, and named in ADR-0048 — deliberately, so the behaviour is a decision rather than an accident. The reading "nothing was completed, so nothing settled" is defensible in the model. It is still a hole from the user's side: they did work, gave a verdict, and the UI disagrees.
The same applies to an off-Plan Outcome engaged with
action_id IS NULL.Scope
TodoDao.setCurrentActionTextIfActionless; issue Saving an empty next action during review should resolve the item as Next and advance, not stall on the item #691). Then arm (b) works with no change to the predicate.NULL-action TimeLog — is not preferred: it would make "an Action was completed" mean something it does not, and the Settled predicate is deliberately the session-scoped negation of Stale._StartButton's affordance and the resulting state must agree.Acceptance Criteria
Related
docs/adr/0048-session-settlement-is-derived.md— records this hole in its arm-two paragraph.TodoDao.setCurrentActionTextIfActionlessand_nextWithDialoginapp/lib/widgets/process_to_handlers.dart(issue Saving an empty next action during review should resolve the item as Next and advance, not stall on the item #691). Its ADR,0049-empty-next-action-means-the-title.md, was removed in816381a6as one of the bug-fix ADRs; reasoning recoverable withgit show 816381a6^:docs/adr/0049-empty-next-action-means-the-title.md.app/lib/screens/focus_screen.dart(_StartButton),app/lib/database/daos/time_log_dao.dart(openLog),app/lib/database/daos/action_dao.dart(applyCompleteCurrentAction),app/lib/database/daos/focus_session_dao.dart(the settlement anchor).