# Missions [← Docs index](./README.md) Missions provide structured planning across multiple related tasks. > Roadmaps are a separate lightweight planning model (`Roadmap → RoadmapMilestone → RoadmapFeature`) used for standalone planning. Missions remain the richer execution-oriented hierarchy when you need slice activation, autopilot, and feature-to-task delivery tracking. ## Mission Hierarchy Fusion models delivery as: **Mission → Milestone → Slice → Feature → Task** Example: ```text Mission: Improve Reliability Milestone: Stabilize execution pipeline Slice: Retry and recovery hardening Feature: Stuck task recovery improvements Task: FN-210 Task: FN-214 ``` ## Agent task-creation admission Mission lineage is an admission requirement only for **autonomous no-task heartbeat** creates and delegations. Those idle patrol calls must supply a valid active Mission → Milestone → Slice → Feature chain; an allow rule for `task_agent_mutation` cannot bypass this requirement. Missing or invalid lineage is rejected before a task is persisted with an explicit mission-lineage remedy. Interactive/user-supervised, task-scoped heartbeat, executor, triage, and workflow-step calls may create or delegate freeform tasks without lineage. They remain governed by the normal `task_agent_mutation` permission policy, including category and exact-tool allow, approval, and block rules. A valid active lineage may name a hand-authored `defined` feature only for its first task. Fusion atomically claims the feature, links that exact task, and promotes the feature to `triaged`; an already-linked feature rejects rather than overwriting its canonical task. This bootstrap exception does not make `defined` executable: later scheduler and symbol-lock admission still uses the stricter contract below. ## Canonical lineage approval for autonomous symbol locks Before autonomous scheduler work may acquire a symbol lock, it resolves the task's Mission → Milestone → Slice → Feature lineage and evaluates the single `@fusion/core` contract: `evaluateMissionLineageApproval`. Resolution and lock acquisition remain scheduler responsibilities; downstream schedulers must not redefine the approval rule. Approval requires every one of these statuses: - Mission: `active` - Milestone: `active` - Slice: `active` - Feature: `triaged` or `in-progress` (never `defined`; defined is only allowed at the first-task bootstrap boundary) When the scheduler passes `planApprovalRequired: true`, the linked task must also have an `approvedPlanFingerprint` that is a non-empty string after trimming whitespace. The predicate does not recompute the fingerprint; `plan-approval.ts` owns its generation and validation. When plan approval is not required, the fingerprint is ignored. The predicate is pure and returns `{ approved, reason }`. Its stable reasons are `approved`, `missing-mission`, `missing-milestone`, `missing-slice`, `missing-feature`, `mission-not-active`, `milestone-not-active`, `slice-not-active`, `feature-not-implementable`, and `plan-not-approved`. A false result is the scheduler's `lineage-blocked` outcome; only an approved result is eligible for symbol-lock admission. ## Mission → Goal linkage Missions and goals are stored independently, with an optional many-to-many linkage persisted in the `mission_goals` join table. - Columns: `missionId`, `goalId`, `createdAt` - Primary key: `(missionId, goalId)` - Foreign keys: `missionId → missions.id`, `goalId → goals.id` - Delete behavior: both foreign keys use `ON DELETE CASCADE`, so removing either parent deletes only the corresponding join rows - Reverse lookups are indexed via `idxMissionGoalsGoalId` `MissionStore` owns the persisted linkage CRUD surface: - `linkGoal(missionId, goalId)` — idempotently create a link and return `{ missionId, goalId, createdAt }` - `unlinkGoal(missionId, goalId)` — remove a link and report whether anything changed - `listGoalIdsForMission(missionId)` — list linked goals in deterministic creation order - `listMissionIdsForGoal(goalId)` — list linked missions in deterministic creation order ### No-backfill decision Existing missions are intentionally **not** auto-linked to any goals. Fusion does not run a migration backfill for pre-existing missions, so a mission with no links should be treated as genuinely unlinked until an operator or agent associates it with one or more goals. ### Manual linkage workflow Mission ↔ goal links are created and removed deliberately as part of normal planning and operations work. The dashboard exposes the relationship from both directions: Mission detail has an active-goal picker plus linked-goal chips with unlink controls, and each Goals view card has a mission picker plus linked-mission chips with unlink controls. Archived goals are never offered for new links, duplicate link attempts are no-ops at the store/API layer, and removing the last link restores the empty-state copy rather than leaving an empty control shell. The workflow is intentionally manual so teams can choose the correct strategic relationship per mission instead of inheriting guessed links from older data. ### Unlinked mission indicator Mission Manager shows an **Unlinked** indicator on active mission cards when `linkedGoalCount` is zero. Linking or unlinking from either dashboard surface refreshes this count so operators can quickly find active missions that still need an explicit goal association. The engine also emits a workflow insight with advisory key `unlinked_missions_advisory` when it first observes one or more active missions with zero goal links. The insight is advisory only, includes only the affected mission ids plus a count, and is deduped to one stable row so it does not spam on every scheduler heartbeat. ### Task → Goal provenance When a mission feature is linked or triaged into a task, Fusion does **not** copy goal ids onto the task row. Instead, task goal provenance is always derived from the mission link owned by `MissionStore`: - `listGoalIdsForTask(taskId)` resolves the owning mission from the linked feature hierarchy first (`feature -> slice -> milestone -> mission`), then falls back to the live task row's `missionId` when needed. - `listGoalsForTask(taskId)` maps those ids back to full `Goal` records using the same goals-table read path as `getMissionWithHierarchy`, so mission reads and task provenance stay in sync. - Unknown, unlinked, or partially missing hierarchy state resolves fail-soft to `[]`. - Archived goals remain part of provenance; only missing goal rows are dropped. This derived bridge lets downstream systems recover which strategic goals a task serves without duplicating mission-goal linkage during task creation. ### Goal-injection diagnostics provenance field The engine's `resolveAndEmitGoalContext` seam still injects only the always-on active-goal context into prompts, but diagnostics now add `provenanceGoalIds: string[]` alongside the existing injected `goalIds` / `goalCount` fields. - `goalIds` / `goalCount` continue to describe the active goals injected into the prompt. - `provenanceGoalIds` records which mission-linked goals the task serves. - Diagnostics and run-audit metadata persist ids/counts only — never goal titles, descriptions, or prompt text. ## Creating Missions ### Mission base branch defaults Missions support an optional `baseBranch` field. When set, feature triage (`triageFeature`) and slice triage (`triageSlice`) inherit this value as the task `baseBranch` whenever a triage request does not explicitly provide a base branch override. Precedence order during triage: 1. Explicit triage `branchSelection.baseBranch` / `baseBranch` 2. Mission `baseBranch` 3. Project default branch resolution ### Mission task prefix override Missions support an optional `taskPrefix` field. When set, feature triage (`triageFeature` / `triageSlice`) passes it as a transient minting hint on `TaskCreateInput` so the distributed task-id allocator issues ids under that prefix. When unset or cleared, triage inherits the project-wide `settings.taskPrefix`. The Mission Manager create/edit form exposes this as **Task prefix** (empty = project default). Clearing a previously saved prefix on edit sends `taskPrefix: null` so the stored override is removed. ### Mission branch strategy defaults Missions can also persist a `branchStrategy` used whenever triage is triggered without explicit branch options (manual triage and autopilot triage). Supported modes: - `project-default` (or absent): shared mode; each triaged feature gets a distinct per-task working branch (for example `/`) while the shared branch remains the mission group merge target - `auto-per-task`: sets `branchAssignment.mode = "per-task-derived"` (distinct per-task working branches with no shared mission group merge target) - `existing`: shared mode using `branchSelection.mode = "existing"` with `branchName` as the shared merge-target branch - `custom-new`: shared mode using `branchSelection.mode = "custom-new"` with `branchName` as the shared merge-target branch The Mission Manager create/edit form exposes this as **Branch strategy** plus a conditional **Branch name** field for `existing` and `custom-new`. ### Mission auto-merge override The **Merge behavior** control can inherit the project default, explicitly enable auto-merge, or select **Single pull request**. In-context help explains that auto-merge lands each feature individually while a single pull request retains all features on a shared branch for joint review. The latter persists `autoMerge: false` on the mission and stamps newly triaged feature tasks with the same false override, while preserving the mission's shared branch group. Returning the control to inherited clears the mission override. Once a shared branch has members, Mission detail displays its branch name, member count, and PR state. ### Shared branch-group invariant across entry points Across all branch entry points (planning/subtask creation, mission triage, and New Task `shared-group` creation), Fusion enforces one rule: - Persist a **per-task working branch** on each task (the checkout branch used for execution). - Persist the shared branch only as the **group merge target** via `branchContext.groupId` → `branch_groups.branchName`. - Never persist the shared branch itself as a task working/checkout branch. This keeps member execution isolated per task while still routing member landings into a single shared integration branch. ### Dashboard Use the Mission Manager UI to create missions and build hierarchy interactively. On mobile, Mission Manager surfaces the primary **Plan New Mission** CTA at the top of the mission list for faster access, while desktop keeps the split-layout sidebar CTA anchored in the bottom action region as the primary entry point. Mission detail refreshes now preserve expanded milestone/slice state and keep the selected milestone expanded, so persisted milestone acceptance criteria remain visible across live updates. Mission, milestone, slice, and feature read-only text surfaces in Mission Manager render Markdown (GFM) for descriptions, verification, and acceptance criteria; edit forms continue to use raw plain-text `