From 3d551020911002dd683ce6fad254afcc612f6786 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sat, 4 Jul 2026 20:24:29 -0700 Subject: [PATCH] FN-7546: clarify planner-oversight Nudge/Explain controls with visible label and in-DOM disabled reason Add a visible group label and an in-DOM disabled-reason helper to the task-detail oversight controls so the Nudge/Explain cluster is no longer confusing when greyed out, and make Explain always-openable since it is read-only. - Add a `detail-oversight-controls-label` group label above the Nudge/Stop/Explain buttons, gated by the same visibility condition as the buttons (mobile and desktop clusters) - Add a `detail-overseer-nudge-disabled-reason` in-DOM helper line explaining why Nudge is unavailable, instead of relying only on a hover title - Remove the disabled gate from Explain (it's read-only/non-mutating) and update its title copy to reflect that it always opens and shows last-known state when inactive - Add regression tests covering the new label/helper text and Explain's always-enabled behavior - Add a patch changeset and a docs/dashboard-guide.md note Files changed: .changeset/FN-7546-oversight-controls-clarity.md | 7 +++ docs/dashboard-guide.md | 2 + .../dashboard/app/components/TaskDetailModal.css | 42 +++++++++++++ .../dashboard/app/components/TaskDetailModal.tsx | 41 +++++++++++-- .../TaskDetailModal.oversight-controls.test.tsx | 69 ++++++++++++++++++++++ 5 files changed, 157 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-7546 Fusion-Task-Lineage: d1f342ea-2de0-4b54-9930-9b3d540c7af6 Co-authored-by: Fusion (runfusion.ai) --- .../FN-7546-oversight-controls-clarity.md | 7 ++ docs/dashboard-guide.md | 2 + .../app/components/TaskDetailModal.css | 42 +++++++++++ .../app/components/TaskDetailModal.tsx | 41 +++++++++-- ...askDetailModal.oversight-controls.test.tsx | 69 +++++++++++++++++++ 5 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 .changeset/FN-7546-oversight-controls-clarity.md diff --git a/.changeset/FN-7546-oversight-controls-clarity.md b/.changeset/FN-7546-oversight-controls-clarity.md new file mode 100644 index 0000000000..9c9f5ac826 --- /dev/null +++ b/.changeset/FN-7546-oversight-controls-clarity.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Clarify the task-detail planner-oversight Nudge/Explain controls with a visible label, an in-DOM disabled reason, and an always-openable Explain panel. +category: fix +dev: TaskDetailModal now renders a `detail-oversight-controls-label` group label and `detail-overseer-nudge-disabled-reason` helper text (both gated by the existing oversight-cluster visibility condition); Explain no longer disables on `!canExplainOverseer` since it is read-only. Nudge's `canNudgeOverseer` gate and Stop's confirm dialog are unchanged. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index 7398348be0..f0b36d9e02 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -198,6 +198,8 @@ Features: - The task detail modal's inline meta-controls cluster (next to Priority/Execution mode) adds four planner-overseer controls: a **quick oversight-level select** (`data-testid="detail-oversight-level-select"`) that writes the per-task `plannerOversightLevel` override (Off/Observe/Steer/Autonomous recovery) or clears it back to the inherited workflow/project default via an "Inherit" option; a **manual nudge** button (`data-testid="detail-overseer-nudge"`) that asks the overseer to inject one guidance-only steering comment into the currently watched stage right now (never a merge/PR/destructive action), disabled when the overseer is off/inactive or the task is user-paused/done/archived/`autoMerge:false` in-review; a **stop oversight** button (`data-testid="detail-overseer-stop"`) that disables active oversight for the task (confirmation-gated), hidden once oversight is already off; and an **explain current action** button (`data-testid="detail-overseer-explain"`) that toggles a small read-only panel (`data-testid="detail-overseer-explain-panel"`) showing the overseer's watched stage, reason, last action, and attempt count/limit, with a non-empty-shell inactive state when the overseer is not currently watching. All three action controls call the `POST /tasks/:id/overseer/nudge`, `POST /tasks/:id/overseer/stop`, and `GET /tasks/:id/overseer/explain` routes. + +- The FN-7517 controls above carry a visible, non-interactive **`"Overseer controls"` group label** (`data-testid="detail-oversight-controls-label"`) so Nudge/Stop/Explain read as an identifiable cluster rather than unlabeled chips; the label is gated by the same `(hasTaskOversightOverride || workflowOversightResolved) && !oversightIsOff` condition as the buttons, so it never renders an empty shell when oversight is Off/unresolved. When **Nudge** is disabled, an always-visible helper line (`data-testid="detail-overseer-nudge-disabled-reason"`) states the reason in-DOM (mirroring the existing hover `title`) instead of relying on a mouse-hover tooltip alone. **Explain** is read-only and non-mutating, so it is never disabled purely because the overseer is inactive — clicking it always opens/closes the panel, which shows the overseer's live state when watching or an informative "not currently watching this task" message otherwise. Nudge's mutating enablement rule (`canNudgeOverseer`, including the human-control suppression cases) and Stop's confirmation dialog are unchanged. - On mobile (viewport ≤ 768px), the level-select/nudge/stop/explain controls above collapse behind a single compact **"Oversight" overflow-menu button** (`data-testid="detail-oversight-menu-trigger"`, `MoreVertical` icon, `aria-haspopup="menu"`) that opens a `role="menu"` popover (mirroring the existing move-action dropdown pattern) listing the same controls as full-width, comfortably tappable `role="menuitem"` entries with the SAME testids and enablement/visibility rules as the desktop inline controls. The trigger itself is withheld entirely when none of those controls would render (no empty-shell overflow button for the oversight-off + overseer-inactive default). Desktop (>768px) keeps the inline cluster unchanged. diff --git a/packages/dashboard/app/components/TaskDetailModal.css b/packages/dashboard/app/components/TaskDetailModal.css index 4adf9aef49..aadb3477ed 100644 --- a/packages/dashboard/app/components/TaskDetailModal.css +++ b/packages/dashboard/app/components/TaskDetailModal.css @@ -528,6 +528,35 @@ renders at a uniform height. opacity: 0.5; } +/* +FNXC:PlannerOversight 2026-07-04-20:30: +FN-7546 — group label + always-visible disabled-reason helper for the +Nudge/Stop/Explain cluster, so operators no longer rely on a mouse-hover +`title` alone to understand what the controls are or why Nudge is inert. +Both are gated by the same condition as the buttons themselves (never an +empty shell when oversight is Off/unresolved). Uses the same muted-text / +small-caption convention as `.detail-overseer-explain-panel__empty` rather +than a one-off style. +*/ +.detail-oversight-controls-label { + display: inline-flex; + align-items: center; + min-height: var(--detail-priority-control-min-height); + color: var(--text-muted); + font-size: var(--font-size-sm, 0.875rem); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.detail-oversight-controls-helper { + display: inline-flex; + align-items: center; + flex-basis: 100%; + color: var(--text-muted); + font-size: var(--font-size-sm, 0.875rem); +} + .detail-overseer-explain-panel { margin-top: var(--space-xs); padding: var(--space-sm); @@ -669,6 +698,19 @@ button.detail-oversight-menu-item svg { height: 1em; } +/* +FNXC:PlannerOversight 2026-07-04-20:30: +FN-7546 — the same group label / disabled-reason helper as the desktop +cluster above, adapted to the mobile overflow-menu's padded list-item layout +so they read as ordinary (non-interactive) menu rows rather than floating +text. +*/ +.detail-oversight-menu .detail-oversight-controls-label, +.detail-oversight-menu .detail-oversight-controls-helper { + padding: var(--space-xs) var(--space-md); + min-height: 0; +} + /* FNXC:PlannerOversight 2026-07-04-18:00: FN-7519 Intervention Timeline styles. Attaches to the closest existing seam diff --git a/packages/dashboard/app/components/TaskDetailModal.tsx b/packages/dashboard/app/components/TaskDetailModal.tsx index b5d2c2388d..07c96a3545 100644 --- a/packages/dashboard/app/components/TaskDetailModal.tsx +++ b/packages/dashboard/app/components/TaskDetailModal.tsx @@ -3873,6 +3873,11 @@ export function TaskDetailContent({ ))} + {!oversightIsOff && ( + + {t("taskDetail.oversight.controlsLabel", "Overseer controls")} + + )} {!oversightIsOff && ( )} + {!oversightIsOff && !canNudgeOverseer && ( + + {t("taskDetail.oversight.nudgeDisabledTitle", "Nudge unavailable: overseer is not actively watching this task")} + + )} {showStopOverseer && ( )} + {(hasTaskOversightOverride || workflowOversightResolved) && !oversightIsOff && !canNudgeOverseer && ( + + {t("taskDetail.oversight.nudgeDisabledTitle", "Nudge unavailable: overseer is not actively watching this task")} + + )} {(hasTaskOversightOverride || workflowOversightResolved) && showStopOverseer && (