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.

Key tables

Tasks: task definitions (relativeCost, duration, body/mind weights, timing fields, essential flag, and default details copy). TaskOccurrences: canonical per-instance schedule and state rows (dueDatetime, completion/cancellation/deferral, per-instance edits). Every task is seeded with at least one persisted occurrence row at creation time (including timingType=none) so ingest paths are uniform. For recurring tasks, due slots are generated in the active horizon window at read time and inserted idempotently using deterministic occurrence keys before compute runs. CheckIns: daily body/mind/mood ratings, check-in tier, day-type classification. Events: append-only audit log; source of truth for rebuilding derived state. ManaCalibrationSnapshots: per-day derived calibration state (algorithmVersion, pool/coefficient EWMA, confidence, alpha/bias, daily spend ratio inputs) used for deterministic fast reads and migration checkpoints. ManaCalibrationMigrations: append-only algorithm migration/rollback records (fromVersion, toVersion, migration type, timestamp, optional rollback checkpoint reference).
manaCost is not stored as source-of-truth. It is computed at read time from task properties and today’s axis factor.

Key fields

TableFieldTypeNotes
Taskdetailsstring?default details/instructions for this task
TaskrelativeCostdoubleeffort relative to baseline
TaskisEssentialbooluser-controlled
TasktimingTypeenumnone, deadline, scheduled
TaskrecurrenceRulestring?RFC 5545 RRule
TaskOccurrenceidintauto-increment local surrogate ID
TaskOccurrencetaskIdstringFK to task definition (Tasks.id)
TaskOccurrencedueDatetimedatetimecanonical due timestamp for this instance
TaskOccurrenceoccurrenceKeystringdeterministic identity key: `taskIddueDatetimeUtcMillis`
TaskOccurrencedetailsstring?per-instance override; if null, UI can use Task.details
CheckIncheckInDatedatetimelocal calendar day identity, normalized to local midnight
CheckIncheckInTierenumfull, quick, momentum, none with confidence weights 1.0, 0.7, 0.4, 0.1
CheckIndayTypeenumnormal, packed, blocked, unusual; carries opportunity weights 1.0, 0.25, 0.0, 0.0
ManaCalibrationSnapshotdaydatetimenormalized local day identity for the snapshot
ManaCalibrationSnapshotalgorithmVersionintexplicit algorithm state version tag
ManaCalibrationSnapshotpoolEwmadoublepersisted pool EWMA state
ManaCalibrationSnapshotcoefficientEwmadoublepersisted coefficient EWMA state
ManaCalibrationSnapshotconfidencedoublepersisted confidence value used for bias
ManaCalibrationSnapshotbaselineSpenddoubleday-level baseline spend input for EWMA updates
ManaCalibrationSnapshotdailyRatiodoublebaselineSpend / allocatedMana ratio used for coefficient learning
ManaCalibrationMigrationfromVersion / toVersionintversion transition boundary
ManaCalibrationMigrationtypeenum-like stringparameter_only, state_transform, recompute, rollback
UserProfilelastCheckInDatedatetimeabsence detection
UserProfilereturnRecoveryDaysRemainingint3-step return recovery
PemEventattributionConfidencedouble0.4-1.0 window-based
PemEventuserAttributedTriggerstring?optional user attribution
PersonalTaskEntryobservedHRResponseJSON?reserved for wearable integration

Schema examples by task type

Atemporal task (timingType = none)

Task:
  id:              "abc…"
  timingType:      "none"
  recurrenceRule:  null
  relativeCost:    1.5
  durationMinutes: 30

TaskOccurrence (seeded at creation, due = createdAt):
  occurrenceKey:   "abc…|1762214400000"
  dueDatetime:     2026-05-04T00:00:00
  state:           "active"

Deadline task (timingType = deadline, non-recurring)

Task:
  timingType:      "deadline"
  recurrenceRule:  null

TaskOccurrence (seeded at creation):
  dueDatetime:     2026-05-10T17:00:00   ← hard deadline
  state:           "active"
Missed state is derived at read time: if dueDatetime is in the past and state = active, surfacing derives missed.

Scheduled task (timingType = scheduled, recurring)

Task:
  timingType:      "scheduled"
  recurrenceRule:  "DTSTART:20260505T090000\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR"

Generated due slots (horizon window): 2026-05-05, 2026-05-07, 2026-05-09…

TaskOccurrence (persisted when state changes):
  occurrenceKey:              "task-id|1746435600000"
  dueDatetime:                2026-05-05T09:00:00
  state:                      "completed"
  completedAt:                2026-05-05T09:45:00
  partialCompletionFraction:  null

Recurrence exception (edit this occurrence only)

TaskOccurrence:
  dueDatetime:         2026-05-07T09:00:00   ← original slot
  dueDatetimeOverride: 2026-05-07T14:00:00   ← moved to afternoon
  state:               "active"

Partial completion

TaskOccurrence:
  state:                      "active"   ← still open
  partialCompletionFraction:  0.5        ← half done
  completedAt:                null
Mana cost displayed = full cost × (1 - 0.5) = 50% of base cost.

Storage model

  • Encrypted local SQLite via Drift + SQLCipher
  • No remote DB, no cloud sync
  • Offline-first behavior
  • Encryption key in platform keystore (not cloud backed up)
Settings and feature flags are in shared_preferences and persist across health-data reset.

Runtime recurrence query

dueSlots = generateFromRRule(task.recurrenceRule, horizonStart, horizonEnd)
TaskOccurrences.insertMissing(dueSlots, key = taskId|dueDatetimeUtcMillis)
occurrences = merge(dueSlots, TaskOccurrences.persistedRows)
activeOccurrence = nearest unresolved future dueDatetime

Recurrence parsing contract

  • Stored recurrence input may be either:
    • a full content line (RRULE:FREQ=...)
    • or a bare rule value (FREQ=...)
  • If DTSTART exists in the stored string, it is used as the recurrence anchor.
  • If DTSTART is absent, the anchor defaults to Task.createdAt.
  • Line parsing splits on both Unix and Windows line endings (\\n, \\r\\n).
  • Implementation detail: the parser uses regex pattern [\\r\\n]+ to split lines.
    • \\r matches carriage return, \\n matches newline, + collapses one-or-more line break chars into one separator.
    • Example: DTSTART:...\\r\\nRRULE:... and DTSTART:...\\n\\nRRULE:... both split into the same two logical lines.
  • Invalid recurrence strings fail soft:
    • no generated slots are returned
    • a typed warning is emitted by the recurrence service
Example:
DTSTART:20260310T090000
RRULE:FREQ=DAILY;COUNT=2
Generates:
2026-03-10 09:00
2026-03-11 09:00

Derived status contract

  • missed is derived at read time in domain scheduling logic.
  • missed is not persisted in TaskOccurrences.
  • deferredUntil shifts an occurrence’s effective due time used by scheduling.