Skip to content

ADR-0003: Unit-Type Ontology

  • Status: Accepted (revised)
  • Date: 2026-04-20
  • Supersedes: initial v1 "Max Six Unit-Types" (2026-04-14)

Context and Problem Statement

Planning ontologies tend to grow without upper bound: epics, stories, sub-stories, initiatives, spikes, tickets, tasks, subtasks. Each new type fragments workflows, multiplies templates, and forces the user to internalize yet another naming distinction. For nubos-pilot the question is: how many user-facing planning nouns exist, and what are they?

For the purpose of this ADR, a unit-type is a user-facing, persistence-bearing noun with its own template, its own file path in the project-state tree, and its own lifecycle. An AI prompt variable, an internal helper module, a configuration key, or a subsection inside a file are not unit-types; they are implementation details invisible to the user's mental model.

Decision

nubos-pilot uses a fixed three-level execution ontology plus three lightweight capture types:

Execution ontology (three levels)

  1. Milestone: a top-level project goal. Each milestone lives at .nubos-pilot/milestones/M<NNN>/ and contains its own CONTEXT/ROADMAP/META files plus a slices/ subdirectory. Milestones are what the user plans, executes, and verifies as a unit.

  2. Slice: an execution wave inside a milestone. Each slice lives at .nubos-pilot/milestones/M<NNN>/slices/S<NNN>/ and contains its own PLAN/ASSESSMENT/UAT files plus a tasks/ subdirectory. All tasks inside one slice run in parallel; slices run serially. Cross-slice dependencies flow forward only.

  3. Task: an atomic unit of work inside a slice. Each task lives at .nubos-pilot/milestones/M<NNN>/slices/S<NNN>/tasks/T<NNNN>/ with its own T<NNNN>-PLAN.md and T<NNNN>-SUMMARY.md. A task is the smallest unit that produces exactly one git commit (ADR-0004).

Capture types (three)

  1. Todo: a captured-on-the-fly idea under .nubos-pilot/todos/pending/. Todos are the lightweight capture path for ideas that surface during execution but don't yet belong to any milestone.

  2. Note: a free-form scratch note under .nubos-pilot/notes/ (project-scoped, committed) or ~/.nubos-pilot/notes/ (global, uncommitted).

  3. Thread: a cross-session context store at .nubos-pilot/threads/<slug>.md with a lifecycle frontmatter (OPEN → IN_PROGRESS → RESOLVED).

Naming note on "phase"

The user-facing slash-commands keep the word "phase" as a synonym for "milestone" for continuity: /np:plan-phase 1 plans milestone M001, /np:execute-phase 1 executes it. This is purely a command-name choice; on disk and in IDs the noun is milestone.

Consequences

  • Good: execution ontology is exactly three levels (milestone / slice / task). Users internalize it quickly.
  • Good: slice = wave semantics collapse two concepts into one: there is no separate "wave" type.
  • Good: every task has a globally unique ID M<NNN>-S<NNN>-T<NNNN> that carries its position in the hierarchy.
  • Bad: users coming from Jira-like tools must map "epic" / "story" / "sprint" / "initiative" onto Milestone / Slice. Accepted trade-off.
  • Neutral: adding a seventh capture type is not forbidden forever; it requires a superseding ADR.

Rejected Alternatives

  • Milestone / Phase / Plan / Task (four-level execution). The intermediate "Plan" level added artifacts (PLAN.md distinct from the phase) without producing distinct deliverables. Collapsed into "Slice == Plan" and the file is simply S<NNN>-PLAN.md.
  • Open-ended type system. Fragments the workflow library; every np:* either swallows unknown types or errors. Rejected.
  • Flat "ticket" model. Loses granularity between a 5-minute Todo and a 3-week Milestone. Rejected.

Enforcement

Type boundaries are enforced at the file-path level by lib/layout.cjs (milestone / slice / task path helpers are the only supported constructors). Lifecycle is enforced by lib/tasks.cjs (TASK_STATUS_ENUM) and lib/verify.cjs (milestone status derived from per-SC verdicts).

More Information

  • Related ADR: ADR-0004. One commit per task.
  • Related ADR: ADR-0005. Source / Install-Payload / Project-State trees stay disjoint.
  • Code: lib/layout.cjs is the authoritative ID + path module.