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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user