Expand description
tda domain core — entities, capability components, the decider, and ports.
Zero I/O dependencies (spec §5): only serde (serialization) and derive_more.
Modules§
- testing
- Deterministic
Clock/IdGeneratorfixtures, store- and app-agnostic, so every crate’s tests (app, conformance, adapters) can share one definition.
Structs§
- Actor
- A human or agent. Not persisted via a port in M1 (the spec lists no
ActorRepository);Assignment/Claimonly ever reference an actorId. - Archived
Archivedcapability: an orthogonal flag, independent ofStatus(a task can bedoneand archived, or archived without beingdone) — presence is the flag, no payload needed. Hidden from default views by callers passingFilter { archived: Some(false), .. }(spec §13 Q4 direction);QueryEngine/Filteritself stay neutral (None= no restriction).- Assignment
- One assignee on a task;
claimedflips when that actor claims it (§8). - Assignments
Assignmentcapability: the whole assignee list is one component value (empty ⇒ remove it). Its presence/contents driveClaim(spec §8).- Attachment
- One attachment: a
Linknever has ablob(it’s just a URL);File/Imagemay or may not have one —urlkeeps the original source path/URL either way (e.g. from an import),blobisSomeonce actual bytes have been stored viacrate::BlobStore. - Attachments
Attachmentscapability: the whole list is one component value (empty ⇒ remove it), likeTags/Assignments.- Collection
- A saved tree or saved query (spec §7).
specholds the query forquerykind. - Date
- A calendar date (
Schedule/due dates). Serializes as an ISO-8601YYYY-MM-DDstring (jiff’s own serde impl) — the same shape the field had as a rawString. - Decide
Ctx - Facts a guard needs beyond the task itself. Just the derived
blockedflag for now (spec §8 start-gate); grow as systems need more. - Denied
- A refused command, with a human/agent-readable reason (spec §5a).
- Due
- A due date with an optional time-of-day (spec: a “rendez-vous” due can
carry a time; overdue/eta rollups (
Aggregate::earliest_due,project_finish_date) stay day-granularity and only ever read.date—.timeis display-only, never compared. - Duration
- An effort/elapsed duration (
Estimate,TimeSpent), minute precision. Serializes as an integer number of minutes — the same shape the field had as a rawu32. - Estimate
Estimatecapability (effort estimate).- Filter
- Id
- Stable identity for tasks, actors, collections. Opaque string (a random ULID in real adapters; a sequence in tests). Serializes transparently as that string.
- Issue
Ref IssueRefcapability: a static reference to an external issue tracker’s issue (e.g. imported from another tool).provideris freeform (no closed enum) — no live sync, no computed URL.- Link
- A typed, ordered directed edge.
childis a single-parent tree;blocksis a DAG (invariants enforced intodoapp-app). - Notes
Notescapability: Markdown body.- Position
- Fractional index (spec §7): insert between two neighbours by averaging, so a reorder or subtree move touches one row, never the siblings.
- Query
- Recurrence
Recurrencecapability: a task carrying this resets in place on completion instead of stayingdone— spec decision: no per-occurrence task spawning, the same task’sScheduleadvances and itsStatusgoes back totodo(see theEvent::StatusSet(Status::Done)apply arm).- Schedule
Schedulecapability: a due date, optionally with a time-of-day.- SortKey
- Tags
Tagscapability: the whole set is one component value (empty ⇒ remove it).- Time
- A time-of-day (minute precision), for a due date’s optional rendez-vous time. Naive/local, like the rest of the codebase — no zone is stored.
- TimeLog
TimeLogcapability: a per-day breakdown of time spent, keyed by calendar date.TimeSpentstays the fast-path cumulative total — it’s recomputed as this map’s sum whenever it’s set (see theEvent::TimeLogSetapply arm), so aggregation (FR-13) keeps readingTimeSpentunchanged. Mixing this with the plainAddTimeSpentcommand (no date) can leave the two slightly inconsistent — a known, accepted edge case, not guarded against.- Time
Spent TimeSpentcapability (accumulated time).- Timestamp
- An instant (task
created_at/updated_at). Serializes as epoch milliseconds (a bare integer), matching the pre-jiffTimestamp(i64)shape. - Title
- Required
Titlecapability.
Enums§
- Actor
Kind - Attachment
Kind - Collection
Kind - Command
- Intent to mutate one task. (
Createis [TaskState::new], not a command.) - Dir
- DueFilter
- Event
- The decided result of a command, folded by
apply. - Link
Kind - Repeat
Cycle - A recurrence rule (spec §3): how often a
Recurrence-carrying task’s due date advances when it’s completed (seeRecurrence::next_due). Covers the common cases (daily interval, weekly weekday set, monthly same-day) — not a full RRULE engine. - Resolved
Id - Result of resolving a user-typed id or prefix against the full id set.
- Sort
Field - Status
- Required
Statuscapability (spec §8).blockedis derived, not stored. Transitions between any two values are unrestricted (no guard) —rankis just for ordering/display, not a legality check. - Weekday
- A day of the week, for
RepeatCycle::Weekly. A local enum (not jiff’s) so serde stays as simple asStatus’s.
Traits§
- Blob
Store - Blob storage for
Attachmentfile/image content (spec §3): separate fromComponentStoresince blobs aren’t a per-task-capability row — a task’sAttachmentscomponent only carries ablobid reference. - Clock
- Injected time source — deterministic in tests.
- Collection
Repository - Component
- A capability component (spec §3): a unit of data keyed by task
Idin the store. Presence of the value is the capability — there is no monolithicTaskstruct; a task is the set of components attached to its id, fetched and mutated one capability at a time (store.get::<Status>(id)/store.set(id, Status::Wip)).NAMEkeys the per-capability map/table (spec §7). Adding a capability = a newComponenttype; the generic store needs no change. - Component
Store - Capability-keyed component access (spec §3/§7), ECS/column-store style: read,
write, or detach one capability at a time, keyed by task
Id. There is no whole-task load/save — a caller (or a guard) touches only the capabilities it needs. Generic methods make this not object-safe, so callers hold a concrete store (Services<St>), not&dyn. - IdGenerator
- Injected id source — deterministic in tests.
- Link
Repository - Query
Engine - Evaluate a query’s filter — the ids of tasks that match (unsorted).
todayis the reference date fordue:today/overdue. Object-safe (no generic methods), so it rides inServicesas&dyn. Sorting + breadcrumbs are the caller’s job (todoapp-app), identical across stores. - Task
Entity Store - The minimal
taskentity (spec §7): identity + timestamps only. Everything else is aComponent.deletecascades every component of the id.
Functions§
- apply
- Write an event back as components (spec §7 presence-as-capability): a
collection that becomes empty is
removed, not stored empty. - decide
- Run
cmdthrough the ordered guards (first denial wins, spec §13 Q2 default), reading current state fromstore. On allow, emit the events. Async: guardsgetonly the capabilities they inspect. - descendants
- All descendants of
idviachildlinks (excludesid). Iterative. - resolve_
id_ prefix - Resolve a typed id/prefix (e.g. from a CLI arg or TUI lookup) the way git/jj do: an exact full-id match always wins, even if it’s also a prefix of other ids; otherwise the prefix must match exactly one id. Case-insensitive: ids are generated lowercase, but older stores may still hold uppercase ULIDs, and typing case shouldn’t matter either way.
- select_
matching - Task ids matching
filter(unsorted). Loads only the components a given predicate needs, matching the in-app snapshot semantics exactly. - shortest_
unique_ prefixes - Shortest prefix of each id that’s unique among
ids— the length is picked so the prefix differs from both lexical neighbours once sorted.