FN-5902: make mission validation AI-run all criteria
Route every mission feature through validator-backed completion checks. - lazily restore a managed feature assertion before validation instead of auto-passing zero-assertion features - thread milestone acceptance criteria into validator prompts and system instructions as enforced requirements - update MissionManager copy/tests to present criteria as AI-validated runtime gates and remove informational-only/zero-assertion warnings - document the all-criteria AI-run contract and add a changeset for @runfusion/fusion Files changed: .changeset/fn-5902-mission-validation-ai-run.md | 5 + AGENTS.md | 2 +- docs/architecture.md | 2 +- docs/missions-completion-contract.md | 198 ++++++--------------- docs/missions.md | 5 +- packages/core/src/__tests__/mission-store.test.ts | 23 ++- packages/core/src/mission-store.ts | 10 ++ packages/dashboard/app/components/MissionManager.css | 31 ---- packages/dashboard/app/components/MissionManager.tsx | 86 +++------ packages/dashboard/app/components/__tests__/MissionManager.test.tsx | 60 +++++-- packages/engine/src/__tests__/mission-execution-loop.test.ts | 111 +++++++++--- packages/engine/src/__tests__/reliability-interactions/mission-validation-trigger-gap.test.ts | 57 +++--- packages/engine/src/mission-execution-loop.ts | 78 ++++---- 13 files changed, 318 insertions(+), 350 deletions(-) Fusion-Task-Id: FN-5902 Fusion-Task-Lineage: 5f25caad-33c9-42ff-822b-1ea092afc29f
This commit is contained in:
@@ -1779,7 +1779,7 @@ Reliability-layer changes are in scope. Interaction regression backstops live in
|
||||
- FN-5830 backstop: `packages/engine/src/__tests__/reliability-interactions/branch-group-promotion.test.ts` guards branch-group completion-gate + promotion lifecycle so promotion happens exactly once after all members land, re-calls are idempotent, and gated paths emit `merge:branch-group-promotion-gated` without default-branch promotion.
|
||||
- FN-5819/FN-5846 backstop: `packages/engine/src/__tests__/reliability-interactions/shared-group-member-integration.test.ts` and `shared-branch-group-lifecycle.test.ts` guard the scoped autoMerge-off exception and deterministic finalize path so shared members integrate into the single group branch, produce `mergeTargetSource: "branch-group-integration"`/`mergeTargetBranch`, do not land on main, and are not moved backward by self-healing maintenance.
|
||||
- FN-5901 backstop: `packages/engine/src/__tests__/reliability-interactions/mission-validator-run-reaper.test.ts` guards stale mission-validator-run recovery across manual and automatic trigger types, verifies `mission:validator-run-reaped` audit metadata, ensures archived/complete parents keep their terminal feature state untouched, and proves reaped active features resume validation instead of staying wedged behind abandoned `running` rows.
|
||||
- FN-5738 backstop: `packages/engine/src/__tests__/reliability-interactions/mission-validation-trigger-gap.test.ts` extends coverage so zero-assertion auto-pass deterministically advances `loopState` to `passed`, sets `lastValidatorStatus="passed"`, emits `validation_auto_passed_no_assertions`, and does not re-fire on repeated recovery passes.
|
||||
- FN-5738 backstop (superseded by FN-5902): `packages/engine/src/__tests__/reliability-interactions/mission-validation-trigger-gap.test.ts` no longer permits zero-assertion auto-pass. Current coverage proves legacy zero-link features lazily restore a managed assertion, route through validator runs, and do not emit `validation_auto_passed_no_assertions` during recovery replays.
|
||||
- FN-5741 backstop: `packages/engine/src/__tests__/reliability-interactions/merge-request-shadow-handoff.test.ts` guards Phase-1 merge-request contract shadow writes: flag OFF is a no-op, flag ON writes marker/record strictly after legacy handoff, and `autoMerge:false` remains `manual-required` without shadow running transitions.
|
||||
- FN-5742 backstop: `packages/engine/src/__tests__/reliability-interactions/dual-observe-merge-seam.test.ts` guards Phase-2 dual-observe invariants: legacy dependency satisfaction remains authoritative while parity diffs emit, and shadow dequeue selection never advances `manual-required` rows.
|
||||
- FN-5743 backstop: `packages/engine/src/__tests__/reliability-interactions/merge-request-cancel-on-hard-cancel.test.ts` and `packages/core/src/__tests__/merge-request-record.test.ts` guard Phase-3 cutover invariants: transient merge retries mutate merge-request state (no column rebound), user hard-cancel after accepted handoff cancels pending merge requests, and non-user rebounds preserve legacy fail-soft semantics.
|
||||
|
||||
@@ -2,175 +2,93 @@
|
||||
|
||||
## Status
|
||||
|
||||
- **Decision date:** 2026-05-30
|
||||
- **Task:** FN-5718
|
||||
- **Depends on enforcement behavior from:** FN-5715 (reference implementation of the trigger/recovery path)
|
||||
- **Scope:** Product contract and implementation requirements only (no code changes in this task)
|
||||
- **Implementation status:** Realized by FN-5733 (loop auto-pass advancement, mission/store guard telemetry, MissionManager label reconciliation)
|
||||
- **Decision date:** 2026-06-02
|
||||
- **Current contract task:** FN-5902
|
||||
- **Supersedes:** FN-5718 baseline contract
|
||||
- **Depends on runtime trigger/recovery behavior from:** FN-5715
|
||||
- **Implementation status:** Realized by FN-5902
|
||||
|
||||
## Problem
|
||||
## Decision
|
||||
|
||||
Mission validation has had a recurring ambiguity: users can see feature acceptance text and milestone "completion criteria" text, but autopilot enforcement is actually driven by assertion linkage + validator outcomes. This document defines the canonical enforced gate so mission completion cannot silently stall or be misread.
|
||||
Mission completion now uses an **all-criteria AI-run contract**:
|
||||
|
||||
## Canonical Completion Gate (Enforced)
|
||||
|
||||
### Decision
|
||||
|
||||
A feature is autopilot-complete only when **its linked contract assertions are satisfied**.
|
||||
|
||||
Canonical authored source and enforcement path:
|
||||
|
||||
1. `MissionFeature.acceptanceCriteria` is the canonical authored criteria text (authoring surface).
|
||||
2. MissionStore must maintain a **store-managed per-feature `MissionContractAssertion`** derived from feature content, with text priority:
|
||||
1. `MissionFeature.acceptanceCriteria` is the canonical authored feature criteria text.
|
||||
2. MissionStore must maintain or lazily restore **one store-managed per-feature `MissionContractAssertion`** derived from feature content with text priority:
|
||||
- `feature.acceptanceCriteria`
|
||||
- `feature.description`
|
||||
- `Verify implementation of: {feature.title}`
|
||||
3. The mission validator enforces completion using the feature's **linked assertions** (including its store-managed assertion and any additional linked milestone assertions).
|
||||
4. Feature/slice/mission advance is gated by the validator outcome (or explicit no-assertions auto-pass behavior defined below).
|
||||
3. The mission validator must run for every feature completion trigger. Runtime validation may lazily call `ensureFeatureAssertionLinked(feature.id)` before starting the validator so legacy missing-link rows still become validator-backed.
|
||||
4. `milestone.acceptanceCriteria` is also part of the enforced gate by being threaded into the validator prompt for every feature in that milestone.
|
||||
5. Feature, slice, milestone, and mission advancement are gated by the validator result — **not** by an informational-only path.
|
||||
|
||||
### Precedence and interpretation rules
|
||||
## Enforcement Model
|
||||
|
||||
- `MissionFeature.acceptanceCriteria` is the canonical authoring field for feature-level intent.
|
||||
- The **linked assertion set** is the canonical enforcement set.
|
||||
- Milestone `MissionContractAssertion` rows are additive contract rows. They are enforced **only when linked to a feature**.
|
||||
- `milestone.acceptanceCriteria` is descriptive/informational milestone text and is not directly executed by the validator.
|
||||
### Feature-level enforcement
|
||||
|
||||
### Worked examples
|
||||
A feature is autopilot-complete only when the validator passes after evaluating:
|
||||
|
||||
1. **Feature has acceptance criteria; store-managed assertion linked; validator passes**
|
||||
- Result: feature may move to done/passed and contribute to slice completion.
|
||||
2. **Feature has acceptance criteria; additive milestone assertion also linked; one linked assertion fails**
|
||||
- Result: feature is not complete; no slice advance.
|
||||
3. **Feature has acceptance criteria visible, but no linked assertions (legacy FN-5696 shape)**
|
||||
- Result: data inconsistency; must not be interpreted by operators as a separate enforced gate. Repair links (FN-5696 backfill) so enforcement matches displayed intent.
|
||||
- the feature's linked contract assertions, including its store-managed assertion, and
|
||||
- the parent milestone's `acceptanceCriteria` text when present.
|
||||
|
||||
## Enforced vs. Informational Surfaces
|
||||
### Milestone-level enforcement
|
||||
|
||||
| Surface | Category | Contract meaning |
|
||||
|---|---|---|
|
||||
| `MissionFeature.acceptanceCriteria` | Informational authoring source | Canonical authored feature criteria text; enforcement happens through derived/linked assertions |
|
||||
| Store-managed per-feature `MissionContractAssertion` | Enforced | Primary validator gate for the feature |
|
||||
| Additive milestone `MissionContractAssertion` (linked to feature) | Enforced | Additional validator gate for that linked feature |
|
||||
| Additive milestone `MissionContractAssertion` (unlinked) | Informational until linked | Contract candidate, not yet a feature gate |
|
||||
| `milestone.acceptanceCriteria` | Informational | Milestone summary/pass-bar text for humans; not directly validator-executed |
|
||||
| MissionManager `milestone-feature-acceptance-rollup` UI (`data-testid="milestone-feature-acceptance-rollup"`) | Informational display | Display-only rendering of feature acceptance text, not a separate enforcement mechanism |
|
||||
`milestone.acceptanceCriteria` is no longer informational-only. FN-5902 enforces it by threading the milestone pass-bar text into the validator prompt for each feature under that milestone.
|
||||
|
||||
## Zero-Assertion Behavior and FN-5696 Failure Shape
|
||||
This is intentionally **prompt-threading**, not per-feature milestone assertion row synthesis:
|
||||
|
||||
### Zero-assertions runtime behavior (canonical FN-5738 path)
|
||||
- store-managed per-feature assertions remain the canonical feature assertion rows,
|
||||
- milestone acceptance text remains milestone-authored prose,
|
||||
- the validator sees both and must satisfy both.
|
||||
|
||||
When a feature reaches completion trigger points and has **zero linked assertions**, mission execution must take exactly one canonical auto-pass path (not a silent stall and not a competing behavior):
|
||||
### Legacy data and lazy repair
|
||||
|
||||
- mark feature terminal as `status="done"`, `loopState="passed"`, `lastValidatorStatus="passed"`,
|
||||
- emit explicit observability/audit evidence with mission event code `validation_auto_passed_no_assertions`,
|
||||
- continue normal slice/mission advancement checks idempotently (no duplicate re-fire on repeated recovery).
|
||||
Legacy missions can still contain features with missing assertion links. Runtime enforcement no longer depends on pre-running backfill:
|
||||
|
||||
### FN-5696 legacy shape clarification
|
||||
- mission execution lazily restores the store-managed feature assertion just before validation, and
|
||||
- `fn_mission_backfill_assertions` / `backfillFeatureAssertions()` remain available as operator repair tooling for data hygiene and visibility.
|
||||
|
||||
A feature can show acceptance text while links are missing (legacy pre-repair data). This must be treated as a **linkage/data integrity problem**, not as proof that milestone text alone is enforced. Assertion authoring/backfill (FN-5696) is outside the execution loop; the loop must not synthesize `mission_feature_assertions` rows. The contract prevents ambiguity by separating:
|
||||
## Removed behavior (FN-5902 inversion)
|
||||
|
||||
- authored/informational text surfaces, from
|
||||
- linked assertion enforcement surfaces.
|
||||
FN-5718's zero-assertion auto-pass behavior is superseded.
|
||||
|
||||
Operators should use the mission assertion backfill operator path to restore expected store-managed linkage for FN-5696 legacy rows:
|
||||
Removed contract:
|
||||
|
||||
- Agent/tool: `fn_mission_backfill_assertions` with `{ missionId?, dryRun? }` (defaults to dry-run).
|
||||
- API: `POST /api/missions/:missionId/backfill-assertions` with body `{ dryRun?: boolean }` (defaults to `true`).
|
||||
- Run dry-run first, then apply (`dryRun=false`) once repaired rows look correct.
|
||||
- This remediation is additive: it derives/links one store-managed assertion per unlinked feature so runtime enforcement uses validator-linked assertions rather than the zero-assertion auto-pass branch.
|
||||
- no `validation_auto_passed_no_assertions` completion path,
|
||||
- no silent or explicit rubber-stamp pass because assertions were missing,
|
||||
- no informational-only feature criteria bucket in MissionManager.
|
||||
|
||||
## Slice Status and Mission Autopilot Advance Derivation
|
||||
Instead, features are routed through validator execution after lazy assertion ensure.
|
||||
|
||||
Autopilot may advance only when each active-slice feature is resolved under this contract:
|
||||
## Worked examples
|
||||
|
||||
- Feature with linked assertions: all linked assertions must pass.
|
||||
- Feature with zero linked assertions: explicit auto-pass path completes it.
|
||||
- Feature with failed/blocked validation: slice remains incomplete.
|
||||
- Feature stranded without a task link in an active autopilot slice (`taskId == null`): startup + maintenance reconciliation must repair it (title-match link first, otherwise defined-status re-triage) so `allDone` remains reachable instead of stalling on never-triaged features.
|
||||
1. **Feature has acceptance criteria; no linked assertion row is present yet**
|
||||
- Runtime calls `ensureFeatureAssertionLinked(feature.id)`.
|
||||
- Validator runs against the restored managed assertion.
|
||||
- Result gates completion normally.
|
||||
|
||||
Then:
|
||||
2. **Feature has acceptance criteria and milestone acceptance criteria**
|
||||
- Validator evaluates the linked feature assertion(s).
|
||||
- Validator also evaluates the milestone acceptance text in the prompt.
|
||||
- Feature passes only when both are satisfied.
|
||||
|
||||
1. All features resolved complete → slice flips to `complete`.
|
||||
2. Completed active slice with pending next slice → next slice activates.
|
||||
3. All milestone slices complete → milestone complete.
|
||||
4. All mission milestones complete → mission complete.
|
||||
3. **Operator runs backfill on legacy data**
|
||||
- Backfill pre-restores missing managed assertions for visibility/reporting.
|
||||
- Runtime behavior is unchanged because lazy ensure already guarantees validator-backed enforcement.
|
||||
|
||||
This keeps completion logic deterministic and consistent with FN-5715 trigger/recovery behavior.
|
||||
## UI contract
|
||||
|
||||
## UI Reconciliation Requirements (for follow-on engineering task)
|
||||
MissionManager must present mission criteria as **AI-validated** rather than informational:
|
||||
|
||||
✅ Implemented in FN-5733 with MissionManager labels:
|
||||
- `Contract assertions (autopilot gate)` + enforced indicator
|
||||
- `Feature acceptance criteria (informational)` + not-enforced indicator
|
||||
- warning badge when `hasProseButNoAssertions === true`
|
||||
- assertion heading text reflects AI validation,
|
||||
- informational / not-enforced labels are removed,
|
||||
- zero-assertion warning guard is removed,
|
||||
- fallback feature-criteria rollups, when shown for missing loaded assertions, describe runtime AI validation rather than non-enforced prose.
|
||||
|
||||
Target surface: `packages/dashboard/app/components/MissionManager.tsx`
|
||||
## Success invariant
|
||||
|
||||
1. **Disambiguate labels**
|
||||
- Use distinct wording for:
|
||||
- feature-authored acceptance text, and
|
||||
- milestone contract assertions.
|
||||
- Do not reuse "Completion criteria" to refer to both categories.
|
||||
- Required wording baseline (or semantically equivalent copy):
|
||||
- Feature rollup heading: `Feature acceptance criteria (informational source)`
|
||||
- Assertion list heading: `Contract assertions (validator-enforced when linked)`
|
||||
For any mission feature that reaches validation trigger points:
|
||||
|
||||
2. **Per-row enforcement indicator**
|
||||
- Every displayed row in the assertions/criteria area must show whether it is:
|
||||
- `Enforced gate` (validator-blocking when linked), or
|
||||
- `Informational` (display-only).
|
||||
|
||||
3. **Empty-state contract-correct copy**
|
||||
- Replace the current implication that completion criteria are absent when assertion rows are empty.
|
||||
- Empty-state text must acknowledge when feature acceptance text exists but no assertion rows are defined/linked.
|
||||
- Required behavior:
|
||||
- If feature acceptance text exists but no assertion rows are present, show copy equivalent to: `No contract assertions are linked yet. Feature acceptance criteria are present below and remain informational until assertions are linked.`
|
||||
- If neither feature acceptance text nor assertions exist, show copy equivalent to: `No feature acceptance criteria or contract assertions defined yet.`
|
||||
|
||||
4. **No button/mobile scope expansion**
|
||||
- No button touch-target/mobile-reflow requirements (standing directive).
|
||||
|
||||
## Engineering Acceptance Criteria (follow-on implementation)
|
||||
|
||||
✅ Implemented in FN-5733:
|
||||
- Auto-pass path now advances `loopState` to `passed` and emits mission event code `validation_auto_passed_no_assertions` while preserving the `validation:passed` emit contract (`"No assertions linked"` summary).
|
||||
- Milestone rollup/store guard now exposes `hasProseButNoAssertions` and emits warning mission event code `milestone_missing_structured_assertions` (debounced on transition into condition).
|
||||
- MissionManager UI now distinguishes enforced assertion gate vs informational feature acceptance criteria.
|
||||
|
||||
1. **Data/model contract**
|
||||
- Preserve the canonical relationship: feature-authored criteria -> store-managed assertion -> linked assertion enforcement.
|
||||
- If any model/UI metadata is added for enforced-vs-informational badges, it must be backward compatible with existing mission rows.
|
||||
|
||||
2. **Validator/loop behavior**
|
||||
- Maintain FN-5715 invariants:
|
||||
- done mission-linked tasks with linked assertions trigger validation,
|
||||
- completion-trigger starts loop if needed,
|
||||
- startup recovery replays done-implementing features with unpassed assertions,
|
||||
- periodic self-heal maintenance replays the same `recoverActiveMissions` path so historically stranded `implementing` features recover without restart,
|
||||
- zero-linked-assertions path remains explicit canonical auto-pass.
|
||||
|
||||
3. **UI behavior**
|
||||
- Implement the Step-2 label reconciliation and per-row indicator requirements.
|
||||
- Ensure no shared ambiguous terminology remains between feature acceptance text and assertion rows.
|
||||
|
||||
4. **Regression coverage**
|
||||
- Add at least one regression test pinning the Goals-mission shape:
|
||||
- feature has `acceptanceCriteria`,
|
||||
- parent milestone has zero `MissionContractAssertion` rows / no links,
|
||||
- autopilot behavior is deterministic and observable (explicit auto-pass path, no silent stall).
|
||||
|
||||
5. **Operational observability**
|
||||
- Ensure mission/audit surfaces make no-assertions auto-pass and subsequent advance decisions queryable in logs/events.
|
||||
|
||||
## Success Metric
|
||||
|
||||
For 30 days after the follow-on implementation ships:
|
||||
|
||||
- **Primary metric:** zero autopilot stalls of the FN-5715 class (done mission task + unresolved validation trigger gap) in production mission runs.
|
||||
- **Evidence source:** mission audit/event stream (`feature_completed`, `slice_completed`, `mission_completed`) plus `mission_validator_runs` records showing:
|
||||
- explicit no-assertions auto-pass evidence (summary/reason path such as `No assertions linked` when no validator run is started), and
|
||||
- downstream advancement evidence without stalled active slices.
|
||||
|
||||
## Follow-on Task Requirement
|
||||
|
||||
Implementation must land in a separate engineering task that references this document and FN-5715 as the enforcement baseline.
|
||||
- a validator run must occur,
|
||||
- the feature must not auto-pass due to missing assertion links,
|
||||
- milestone acceptance text must be visible to the validator when present,
|
||||
- advancement decisions must derive from validator outcomes only.
|
||||
|
||||
@@ -512,7 +512,7 @@ A feature transitions to `blocked` when:
|
||||
|
||||
On engine restart, `recoverActiveMissions()` re-enqueues features in `validating` or `needs_fix` states, ensuring no validation work is lost. It also re-triggers `implementing` features whose linked task is already `done`/`archived` and whose assertion validation has not passed yet. When the stale-run reaper has already converted an abandoned validator run into `needs_fix`, `processTaskOutcome()` promotes the feature back through `implementing` and re-validates instead of skipping it. The same recovery path is replayed during periodic self-heal maintenance, so historically stranded `implementing` features can self-heal without requiring an engine restart.
|
||||
|
||||
For features with zero linked assertions, the completion path is explicit: the loop marks the feature `done`, advances `loopState` to `passed`, emits `validation:passed` with summary `"No assertions linked"`, and records mission event code `validation_auto_passed_no_assertions`. Contract details (including canonical no-assertions behavior and FN-5696 assertion-authoring separation) are defined in [Mission Completion Gate Contract](./missions-completion-contract.md).
|
||||
For features with missing linked assertions, the completion path is now validator-first: the loop lazily restores the store-managed per-feature assertion just before validation, then runs the AI validator instead of auto-passing. Milestone `acceptanceCriteria` is threaded into the validator prompt for every feature in that milestone, so all mission criteria are AI-evaluated. Contract details are defined in [Mission Completion Gate Contract](./missions-completion-contract.md).
|
||||
|
||||
### Autopilot / Scheduler Interplay
|
||||
|
||||
@@ -543,8 +543,7 @@ These are independent tracking mechanisms — autopilot monitors mission progres
|
||||
**MissionEvent audit types:**
|
||||
- `slice_activated`, `feature_planned`, `feature_completed`
|
||||
- `validation:started`, `validation:passed`, `validation:failed`, `validation:blocked`
|
||||
- `validation_auto_passed_no_assertions` (reason: `"No assertions linked"`)
|
||||
- `milestone_missing_structured_assertions` (warning when prose criteria exist with zero structured assertions)
|
||||
- `milestone_missing_structured_assertions` (legacy-data warning surface; enforcement still lazy-restores managed assertions at runtime)
|
||||
- `fix_feature:created`, `feature:blocked`
|
||||
|
||||
**Validator run telemetry:**
|
||||
|
||||
Reference in New Issue
Block a user