GCC Build OSv0
/api

Milestone Lifecyclemilestone

Lifecycle state machine for Milestone nodes. Milestones are time-bound events (Scope v2 §0.1) tied to a due_date. Health states surface through the AtRisk -> Slipped -> Achieved branch driven by the dependency scheduler (Scope v2 §1B.1.4). Recovery from AtRisk uses an explicit MilestoneRecovered event rather than reusing MilestoneStarted (see x-decisions-surfaced).

Node type
Milestone
Initial state
Planned
Terminal states
Achieved

Full machine

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://gcc.bootminds.com/ontology/state-machines/milestone.json",
  "title": "Milestone Lifecycle",
  "description": "Lifecycle state machine for Milestone nodes. Milestones are time-bound events (Scope v2 §0.1) tied to a due_date. Health states surface through the AtRisk -> Slipped -> Achieved branch driven by the dependency scheduler (Scope v2 §1B.1.4). Recovery from AtRisk uses an explicit MilestoneRecovered event rather than reusing MilestoneStarted (see x-decisions-surfaced).",
  "node_type": "Milestone",
  "initial_state": "Planned",
  "terminal_states": [
    "Achieved"
  ],
  "states": {
    "Planned": {
      "description": "Milestone has been authored with owner, due_date, exit criteria, and dependency links. Not yet started."
    },
    "InFlight": {
      "description": "Owner has marked the milestone as in flight (work toward its exit criteria is in progress). Tracked actively by the dependency scheduler."
    },
    "AtRisk": {
      "description": "Milestone is flagged as at risk of missing its due_date. May be set manually by a contributor (e.g., the work owner) or automatically by the dependency scheduler when an upstream slip propagates. Distinct from Slipped: AtRisk is a forward-looking warning; Slipped is a past-due fact."
    },
    "Slipped": {
      "description": "Milestone has missed its due_date without Achievement. Set automatically by the scheduler at due_date + 0 if not already Achieved. Recoverable via re-baselining and eventual MilestoneAchieved."
    },
    "Achieved": {
      "description": "Milestone's exit criteria are satisfied and recorded by the decision_maker. Terminal: no further transitions in normal flow. Reachable from InFlight (on-time), AtRisk (recovered late but still by due_date), or Slipped (achieved after slipping)."
    }
  },
  "transitions": [
    {
      "from": "Planned",
      "to": "InFlight",
      "trigger_event": "MilestoneStarted",
      "requires_role": "decision_maker",
      "requires_events": [],
      "guard_description": "The decision_maker (milestone owner) declares work has begun. Captures the actual start vs the planned start; the dependency scheduler starts tracking commitment health from this point."
    },
    {
      "from": "InFlight",
      "to": "AtRisk",
      "trigger_event": "MilestoneAtRisk",
      "requires_role": "contributor",
      "requires_events": [],
      "guard_description": "Manual flag by a contributor OR automatic flag by the dependency scheduler. When emitted by the scheduler, the actor_id on the event is the system actor; when emitted by a human, requires_role enforces 'contributor' (an inclusive role: the owner, a Bootminds advisor, or any RACI-attached stakeholder can raise the flag). The event payload SHOULD record source = 'manual' | 'scheduler' and the reason (upstream slip, owner-reported, etc.)."
    },
    {
      "from": "AtRisk",
      "to": "InFlight",
      "trigger_event": "MilestoneRecovered",
      "requires_role": "decision_maker",
      "requires_events": [],
      "guard_description": "Recovery path: conditions that triggered AtRisk no longer hold (upstream slip resolved, scope adjusted, owner reports back on track). The decision_maker (milestone owner) re-asserts that the milestone is in flight. Distinct event type rather than re-using MilestoneStarted, so audit and timeline reconstruction can clearly distinguish initial start from recovery (see x-decisions-surfaced)."
    },
    {
      "from": "AtRisk",
      "to": "Slipped",
      "trigger_event": "MilestoneSlipped",
      "requires_role": null,
      "requires_events": [],
      "guard_description": "Automatic transition emitted by the dependency scheduler / time-clock job when the milestone's due_date passes without Achievement. No human role required (system actor on the event). May also be emitted from InFlight directly if the milestone was never explicitly flagged AtRisk before due_date passed; (omitted as an explicit transition here because the canonical happy-but-degrading path runs InFlight -> AtRisk -> Slipped, and the scheduler should flag AtRisk before allowing a hard Slipped to fire. Tenants may differ; if the InFlight -> Slipped direct path is needed, surface it as a registry decision)."
    },
    {
      "from": "InFlight",
      "to": "Achieved",
      "trigger_event": "MilestoneAchieved",
      "requires_role": "decision_maker",
      "requires_events": [],
      "guard_description": "On-time achievement. The decision_maker records satisfaction of the exit criteria. Gate workflows that depend on this milestone unblock automatically as their exit-criteria checklists tick over (Build Plan §7.1.5)."
    },
    {
      "from": "Slipped",
      "to": "Achieved",
      "trigger_event": "MilestoneAchieved",
      "requires_role": "decision_maker",
      "requires_events": [],
      "guard_description": "Late achievement after a recorded slip. Same trigger event as the on-time achievement; the slip is preserved in the event history for Programme Memory and Programme Confidence (Scope v3 #4 Schedule Realism). The decision_maker records exit-criteria satisfaction."
    }
  ],
  "x-decisions-surfaced": [
    "Recovery uses a new event type MilestoneRecovered rather than reusing MilestoneStarted. Rationale: replaying the event log to reconstruct programme history must distinguish 'first time the milestone started' from 'milestone recovered from at-risk', and the dependency scheduler / Programme Confidence Schedule Realism component (Scope v3 #4) needs the signal for slip-pattern learning. The event-types.json registry MUST add MilestoneRecovered (surfaced for the agent authoring event-types.json in parallel).",
    "The direct path InFlight -> Slipped (skipping AtRisk) is intentionally omitted from the canonical state graph. The scheduler is expected to raise MilestoneAtRisk before the due_date passes; missing that flag is itself a scheduler bug worth surfacing. If real engagements show this is impractical, the registry can add InFlight -> Slipped later — additive change."
  ]
}