Skip to main content

Temporal task types

Deadline-window task

Flexible completion by a due date/time. Mana is spent on the day it is completed.

Appointment task

Fixed event on a specific date/time. Mana is effectively committed to that day.

Actionable definition

Home shows actionable work: items the user can usefully act on today.
Task typeActionable today whenNon-actionable preview when
Flexible (timingType = none)The task fits remaining mana, is essential, or user policy allows over-pool visibilityNot applicable
Deadline-window (timingType = deadline)The task is inside its horizon window, due today, or carried over after the due timeOutside horizon and over remaining mana
Appointment (timingType = scheduled)The scheduled date is today, or the scheduled time has passed and still needs an updateInside horizon before the scheduled date
Day-quality (timingType = day_quality)The task matches today’s day-quality rule and passes the same capacity filters as flexible workToday’s day quality does not match
Non-actionable previews can appear in gentle planning surfaces such as Gentle Upcoming. They are not part of the user’s to-do list for today.

Horizon window

The horizon window determines how early a temporal task starts surfacing.
baseCost    = relativeCost x durationMinutes x personalCoefficient x 0.5
typicalPool = 30-day median of poolEwma
horizonDays = clamp(ceil(baseCost / (typicalPool x 0.30)), 2, 7)
Task cost as % of typical poolHorizon window
< 30%2 days
30-60%2-3 days
60-90%3 days
90-120%4 days
120-180%4-5 days
180%+6-7 days
When inside horizon window:
  1. Task becomes visible regardless of remaining pool
  2. Card uses horizon framing copy
  3. Scheduled tasks contribute to pre-warning logic
For deadline-window tasks, horizon visibility makes the task actionable because the work can happen before the due time. For appointment tasks, horizon visibility is a preview only until the appointment day.

Cost preview framing

Future-day previews always use axis factor = 1.0:
“On a typical day this costs about [X] mana.”
This prevents false precision for unknown future states.

Deadline copy in horizon window

Days remainingCopy
3+ days”This needs to happen by [Day] - on a typical day it costs about [X] mana.”
2 days”This needs to happen by [Day] - on a typical day it costs about [X] mana.”
1 day”This needs to happen by tomorrow - on a typical day it costs about [X] mana.”
0 days, in pool”This is due today - on a typical day it costs about [X] mana.”
0 days, over pool”This is due today and costs more than today’s mana. It may need to be your priority.”
“DUE” is not used as all-caps urgency language in user copy. Preferred phrasing is “needs to happen by” and “due today”.

Surfacing logic

Surfacing rules are policy-driven. The defaults below are the recommended profile, but teams should treat visibility behavior as user-configurable and wire those choices into onboarding.

Configurable policy surface

These policy switches should be selectable in onboarding and editable later in Settings:
  • Standard tasks over pool: hide (default), showWithCaution, showAlways
  • Scheduled tasks on due day when over pool: show (default), hideWhenOverPool
  • Mid-day refresh behavior: dynamic (default, hide/reveal as remaining pool changes), morningSnapshot (fixed list for that day)

Deadline tasks

if timingType == 'deadline':
  if dueDatetime < now and state == 'active':
    surface as carried-over/actionable
  elif today == dueDatetime.localDay:
    surface as due-today/actionable
  elif today >= dueDatetime - horizonDays:
    surface as actionable with pool exemption
  else:
    standard surfacing (cost <= remainingPool)

Scheduled tasks

if timingType == 'scheduled':
  if today == dueDatetime:
    surface as active/completable
  elif dueDatetime < now and state == 'active':
    surface as needs-update/actionable
  elif today >= dueDatetime - horizonDays:
    surface with horizon framing, not completable
  else:
    hidden
The snippet above reflects default policy values. If onboarding preferences differ, the surfacing layer applies the selected policy at runtime.

Current app surfacing surfaces (May 2026)

Temporal surfacing is consumed by feature-sliced app surfaces:
  • Home projection and sections (app/lib/features/home/presentation/widgets/home_screen.dart)
  • Tasks list (app/lib/features/tasks/presentation/widgets/tasks_screen.dart)
  • Orchard list for orchard-tagged surfaced tasks (app/lib/features/orchard/presentation/widgets/orchard_screen.dart)
  • Mana notices and reserve/conflict messaging (app/lib/features/mana/)
The Home IA target is documented in Home Information Architecture. If runtime behavior lags this contract, treat the mana docs here as the product behavior source of truth and capture app changes as implementation follow-ups. Primary surfacing implementation lives in:
  • app/lib/features/mana/domain/engine/surfacing/surfacing_rule_engine.dart
  • app/lib/features/mana/domain/engine/surfacing/surfacing_candidate_resolver.dart
  • app/lib/core/domain/application/home/home_view.dart

Scheduled copy in horizon window

Days remainingCopy
2+ days”You have [Task Name] on [Day] - on a typical day it’ll use about [X] mana.”
1 day”You have [Task Name] tomorrow - on a typical day it’ll use about [X] mana.”
0 daysStandard task card; horizon copy removed

Day-before pre-warning

For scheduled tasks, show a quiet contextual note if significant load is coming. Single-task trigger:
baseCost > typicalPool x 0.20
Multi-task conflict escalation:
sum(baseCost on dueDatetime) > typicalPool x 0.85
Lookahead runs across 7 days so warnings can appear early enough for planning.

UI differentiation

TypeIconDate label
Deadlineoutline diamondby Thursday
Scheduledsolid calendar dotThursday
Scheduled with timesolid calendar dotThursday, 2:00pm
Deadline iconography should feel softer/flexible; scheduled should feel fixed.

Recurring tasks

Storage model

  • Root Task stores recurrence rule (RRule) and timing type
  • TaskOccurrences stores canonical per-instance due/state rows
  • Future recurring due slots are generated in the active horizon read window and persisted idempotently, then matched against existing rows
Runtime query shape:
dueSlots = generateFromRRule(rule, horizonStart, horizonEnd)
persistedRows = upsertMissingByDeterministicKey(dueSlots)
occurrences = merge(dueSlots, persistedRows)
activeOccurrence = nearest unresolved future dueDatetime
Only nearest unresolved future occurrence is surfaced. Missed recurring cycles are skipped automatically.

Recurrence setup UI

Two-step interaction:
  1. Frequency type: every few days, weekly, every few weeks, monthly
  2. Refinement: interval/day toggles depending on choice
Complex edge patterns are intentionally excluded to reduce cognitive burden.

Recurrence setup nudge

If baseCost > typicalPool x 0.25, show once during recurrence setup:
“This task costs about [X] mana on a typical day - on recurrence days, it’ll take a meaningful part of your budget.”
Informational only; never blocks setup.

Post-deadline state

StateMeaningSource
completeddoneuser action
misseddue date/time passed without completion; reframed in UI as carried over or needs updatingautomatic
cancelledwill not happen / called offuser action
cancelled is available for all task types. There is no overdue state. A passed deadline-window task can remain actionable if it is still relevant, or the user can cancel/archive it. A passed appointment enters a neutral update flow so the user can mark it attended, defer follow-up, or cancel it.

Partial completion

A user may mark a task as partially completed when they can do only a fraction of the work.
  • Stored as partialCompletionFraction (0.0–1.0) on TaskOccurrence
  • Occurrence remains state = active (not completed) until fully done or explicitly completed
  • Mana cost shown = baseCost × (1 - fraction) - the remaining effort only
  • On save, the UI prompts: “Defer the rest to tomorrow?” - auto-creating a deferred occurrence
  • No punitive framing; partial completion is presented as normal pacing behaviour

Recurrence exceptions

Recurring task edits support these scopes:
ScopeMechanism
Skip this occurrenceSet state = cancelled on the specific TaskOccurrence
Edit this occurrence onlySet dueDatetimeOverride on the specific TaskOccurrence (shifts effective due time)
Edit this and all futureEXDATE the current slot in the root task’s RRULE; create a new sibling task from that date with the modified rule
Edit all recurring tasks in the seriesUpdate the root task recurrence definition for the full series
dueDatetimeOverride takes precedence over dueDatetime for all scheduling and surfacing calculations. It does not change the occurrenceKey (which is still keyed to dueDatetime). EXDATE lines are stored in the task’s recurrenceRule field alongside DTSTART and RRULE:
DTSTART:20260505T090000
RRULE:FREQ=WEEKLY;BYDAY=MO
EXDATE:20260512T090000

Missed-state copy contract

Missed temporal states must remain actionable without moralized framing.
  • Allowed framing: “missed”, “still needs attention”, “scheduled item was missed”
  • Avoided framing: “failed”, “you should have”, “behind”, all-caps urgency
  • Actions remain available so users can recover without punitive UI

Implementation follow-ups

These docs define the product contract. Current app behavior may lag in these areas:
  • Scheduled previews need to remain non-completable until the appointment day.
  • Home needs to keep non-completable appointment previews out of Actionable Today and place them in Gentle Upcoming or planning notices.
  • Partial completion has schema and costing support, but app-level edit and defer flows still need end-to-end implementation.
  • Temporal visual treatments must follow the Temporal Copy Contract, not older urgency-oriented design-system language.