FN-7517: add task detail oversight quick-controls (level change, manual nudge, stop, explain-current-action)

Adds task detail modal controls that let an operator quickly change a task's
oversight level, nudge the planner with a manual instruction, stop oversight
entirely, and request an explanation of the overseer's current action,
backed by new dashboard API routes and engine/core plumbing.

- Add oversight quick-controls UI (level change, manual nudge, stop
  oversight, explain-current-action) to TaskDetailModal with supporting
  styles in TaskDetailModal.css and TaskCard.css
- Add dashboard legacy API + task-workflow routes to handle the new
  oversight actions (register-task-workflow-routes.ts, api/legacy.ts)
- Extend planner-overseer-state and planner-overseer-runtime-snapshot to
  track/report manual nudge and stop-oversight state
- Extend PlannerRecoveryController and project-engine to apply manual
  oversight actions (level change, nudge, stop, explain) end-to-end
- Add tests: TaskDetailModal.oversight-controls.test.tsx,
  tasks-overseer-controls.test.ts,
  planner-recovery-controller-manual-action.test.ts, plus updates to
  planner-overseer-runtime-snapshot.test.ts and test-helpers
- Update docs/dashboard-guide.md and docs/settings-reference.md

Files changed:
 docs/dashboard-guide.md                            |   2 +
 docs/settings-reference.md                         |   2 +-
 packages/core/src/planner-overseer-state.ts        |  18 +
 packages/dashboard/app/api/legacy.ts               |  33 ++
 packages/dashboard/app/components/TaskCard.css     |  13 +
 packages/dashboard/app/components/TaskDetailModal.css   | 122 +++++++
 packages/dashboard/app/components/TaskDetailModal.tsx   | 374 ++++++++++++++++++++-
 packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-controls.test.tsx | 290 ++++++++++++++++
 packages/dashboard/app/components/__tests__/TaskDetailModal.test-helpers.ts      |  11 +
 packages/dashboard/src/routes/__tests__/tasks-overseer-controls.test.ts      | 191 +++++++++++
 packages/dashboard/src/routes/register-task-workflow-routes.ts    |  68 ++++
 packages/engine/src/__tests__/planner-overseer-runtime-snapshot.test.ts      |  24 +-
 packages/engine/src/__tests__/planner-recovery-controller-manual-action.test.ts |  84 +++++
 packages/engine/src/planner-overseer-runtime-snapshot.ts       |  11 +
 packages/engine/src/planner-recovery-controller.ts |  40 +++
 packages/engine/src/project-engine.ts              | 102 ++++++
 16 files changed, 1380 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7517

Fusion-Task-Lineage: eded7ff5-d126-429d-acbb-9f4bfff5ae2a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-04 16:48:34 -07:00
parent ad744aa28a
commit 6498d028f2
16 changed files with 1380 additions and 5 deletions

View File

@@ -96,6 +96,7 @@ import type {
CommitAssociationDiffBackfillReport,
} from "@fusion/core";
import type { PlanningQuestion, PlanningSummary } from "@fusion/core";
import type { PlannerOverseerRuntimeSnapshot } from "@fusion/core";
import type { GithubIssueAction, ScheduledTask, ScheduledTaskCreateInput, ScheduledTaskUpdateInput, AutomationRunResult, Routine, RoutineCreateInput, RoutineUpdateInput, RoutineExecutionResult } from "@fusion/core";
import type { DiscoveredSkill, CatalogEntry, CatalogFetchResult, ToggleSkillResult, SkillContent, SkillFileEntry, SkillFileContent } from "@fusion/dashboard";
import type { MilestoneValidationTelemetry, MissionInterviewDraftSummary } from "../components/mission-types";
@@ -818,6 +819,38 @@ export function unpauseTask(id: string, projectId?: string): Promise<Task> {
return api<Task>(withProjectId(`/tasks/${id}/unpause`, projectId), { method: "POST" });
}
/*
FNXC:PlannerOversight 2026-07-04-17:00:
FN-7517 task-detail planner-overseer controls. `nudgeOverseer` asks the
engine to inject one steering-guidance comment into the task's currently
watched stage right now (guidance-only — never a merge/PR/destructive side
effect); `stopOverseer` disables active oversight for the task (writes the
per-task `plannerOversightLevel: "off"` override); `explainOverseer` is a
read of the current overseer runtime state (watched stage, reason, last
action, attempt count/limit) for the "explain current action" panel. Each
returns an `applied: false`/`snapshot: null` style result rather than
throwing when oversight is off/inactive or the engine runtime is
unavailable — callers should treat that as a normal disabled state, not an
error toast.
*/
export interface OverseerControlResult {
applied: boolean;
reason: string;
task?: Task;
}
export function nudgeOverseer(id: string, projectId?: string): Promise<OverseerControlResult> {
return api<OverseerControlResult>(withProjectId(`/tasks/${id}/overseer/nudge`, projectId), { method: "POST" });
}
export function stopOverseer(id: string, projectId?: string): Promise<OverseerControlResult> {
return api<OverseerControlResult>(withProjectId(`/tasks/${id}/overseer/stop`, projectId), { method: "POST" });
}
export function explainOverseer(id: string, projectId?: string): Promise<{ snapshot: PlannerOverseerRuntimeSnapshot | null }> {
return api<{ snapshot: PlannerOverseerRuntimeSnapshot | null }>(withProjectId(`/tasks/${id}/overseer/explain`, projectId), { method: "GET" });
}
export function archiveTask(id: string, projectId?: string, options?: ArchiveTaskOptions): Promise<Task> {
const search = new URLSearchParams();
if (options?.removeLineageReferences) {