FN-5898: add unlinked mission goal indicator

Document the manual no-backfill mission-goal policy and flag active missions that still need explicit goal links.

- document the mission→goal linkage model, explicit no-backfill decision, and manual linkage workflow in missions docs
- include linkedGoalCount in mission summaries and cover single-summary/batched-summary behavior in MissionStore tests
- show an Unlinked badge for active non-interview missions with zero linked goals and add MissionManager coverage

Files changed:
 .changeset/fn-5898-mission-goal-unlinked-indicator.md     |  5 ++
 docs/missions.md                                   | 18 ++++--
 packages/core/src/__tests__/mission-store.test.ts  | 32 +++++++++-
 packages/core/src/mission-store.ts                 | 25 +++++++-
 packages/dashboard/app/components/MissionManager.css    |  6 ++
 packages/dashboard/app/components/MissionManager.tsx    | 14 ++++
 packages/dashboard/app/components/__tests__/MissionManager.test.tsx   | 74 ++++++++++++++++++++++
 packages/dashboard/app/components/mission-types.ts |  1 +
 8 files changed, 166 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-5898

Fusion-Task-Lineage: e31e9544-4e03-4b52-afbb-e372314b997e
This commit is contained in:
gsxdsm
2026-06-02 18:15:14 -07:00
parent cc18206bc5
commit 577ce12a18
8 changed files with 166 additions and 9 deletions

View File

@@ -23,9 +23,9 @@ Mission: Improve Reliability
Task: FN-214
```
## Mission Goal persistence
## Mission Goal linkage
Missions and goals are stored independently, but Fusion now persists an optional many-to-many linkage in the `mission_goals` join table.
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)`
@@ -33,14 +33,24 @@ Missions and goals are stored independently, but Fusion now persists an optional
- 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 linkage CRUD surface:
`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
Existing missions are **not** backfilled with goal links as part of this schema change; that decision is deferred to FN-5898.
### 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. Read surfaces can show current associations, and operator-facing write surfaces can add or remove links when a mission should explicitly support a goal. 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. This is a read-only attention badge so operators can quickly find active missions that still need an explicit goal association.
## Creating Missions