Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.canthus.org/llms.txt

Use this file to discover all available pages before exploring further.

Temporal task types

Deadline task

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

Scheduled task

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

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

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 today >= dueDatetime - horizonDays:
    always surface (pool exemption)
  else:
    standard surfacing (cost <= remainingPool)

Scheduled tasks

if timingType == 'scheduled':
  if today == dueDatetime:
    surface as active/completable
  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 (March 12, 2026)

There is no dedicated Home surface in the current app shell. Temporal surfacing is currently consumed via:
  • Tasks tab list (app/lib/ui/tasks/widgets/tasks_screen.dart)
  • Orchard tab list for orchard-tagged surfaced tasks (app/lib/ui/orchard/widgets/orchard_screen.dart)
  • Mana tab upcoming notices (app/lib/ui/mana/view_models/mana_viewmodel.dart)
Primary executable rule coverage for these surfaces currently lives in:
  • app/test/domain/mana/engine/surfacing/task_surfacing_service_test.dart
  • app/test/ui/tasks/widgets/tasks_screen_test.dart
  • app/test/ui/orchard/widgets/orchard_screen_test.dart
  • app/test/ui/mana/widgets/mana_screen_test.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 completionautomatic
cancelledwill not happen / called offuser action
cancelled is available for all task types.

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

Three edit scopes apply to recurring task occurrences:
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
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