diff --git a/.changeset/fn-7542-remove-overseer-state-badge.md b/.changeset/fn-7542-remove-overseer-state-badge.md new file mode 100644 index 0000000000..3491a6b29d --- /dev/null +++ b/.changeset/fn-7542-remove-overseer-state-badge.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Remove the per-card overseer-state ("Executor") badge from task cards. +category: fix +dev: Deleted the FN-7516 `card-overseer-state-badge` render, its card-local `deriveOverseerCardWatchedStage` helper/label maps, and its CSS; the sibling oversight-level badge (`card-oversight-badge`) is unaffected. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index e3c4c39f84..9ed83dd6fe 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -185,7 +185,7 @@ Features: - Task cards show a read-only **oversight-level badge** (`Observe`, `Steer`, or `Auto-recovery`) in the meta-badges cluster reflecting the effective planner-oversight level, but only when oversight is *meaningfully configured* — an explicit per-task override (including an explicit `autonomous` override), or a resolved workflow/effective tier of `observe`/`steer` (`data-testid="card-oversight-badge"`). A card that merely **inherits** the schema default `autonomous` tier (no per-task override, no non-default workflow tier) renders no badge and no empty `.card-meta-badges` shell. The badge is also absent when the effective level is explicitly "off", **and** while an inherited (no per-task-override) workflow tier is still being resolved (in flight or not yet fetched) — it never shows a guessed default during that window. -- Task cards also show a read-only **active-overseer-state indicator** (`.card-overseer-state-badge`, `data-testid="card-overseer-state-badge"`) — "Executor", "Reviewer", "Merger", "Pull request", or "Workflow gate" — while the task is in a monitorable stage (in-progress/in-review, or paused on a workflow input/approval gate) and the effective oversight level is not "off" (and is known, per the same resolution gate as the oversight badge above). The indicator is suppressed (no empty shell) when the task is user-paused, agent-paused off a workflow gate, `done`, or `archived`. + - 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. diff --git a/packages/dashboard/app/components/TaskCard.css b/packages/dashboard/app/components/TaskCard.css index 2d7c94c06a..04dc029390 100644 --- a/packages/dashboard/app/components/TaskCard.css +++ b/packages/dashboard/app/components/TaskCard.css @@ -522,66 +522,6 @@ falling through to an unstyled transparent shell. color: var(--text-muted); } -/* -FNXC:PlannerOversight 2026-07-04-00:00: -`.card-overseer-state-badge` shows the FN-7516 active-overseer-state indicator, -rendered only while the card-local watched-stage derivation resolves a stage -and the task is not paused/done/archived (see TaskCard.tsx `deriveOverseerCardWatchedStage` -and `showOverseerStateBadge`). Chip sizing mirrors `.card-oversight-badge` so it -participates in the same `.card-meta-badges` wrap/height invariants. Per-stage -modifiers reuse existing semantic status tokens rather than new hex values. -*/ -.card-overseer-state-badge { - display: inline-flex; - align-items: center; - gap: 3px; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-size: 0.625rem; - font-weight: 600; - line-height: 1; - letter-spacing: 0.4px; - text-transform: uppercase; - padding: calc(var(--space-xs) / 2) var(--space-sm); - border: var(--btn-border-width) solid transparent; - border-radius: var(--radius-pill); - background: color-mix(in srgb, var(--color-info) 15%, transparent); - color: var(--color-info); -} - -.card-overseer-state-badge svg { - width: 0.6875rem; - height: 0.6875rem; - flex-shrink: 0; -} - -.card-overseer-state-badge--executor { - background: color-mix(in srgb, var(--color-info) 15%, transparent); - color: var(--color-info); -} - -.card-overseer-state-badge--reviewer { - background: color-mix(in srgb, var(--color-warning) 15%, transparent); - color: var(--color-warning); -} - -.card-overseer-state-badge--merger { - background: color-mix(in srgb, var(--triage) 15%, transparent); - color: var(--triage); -} - -.card-overseer-state-badge--pull-request { - background: color-mix(in srgb, var(--color-info) 15%, transparent); - color: var(--color-info); -} - -.card-overseer-state-badge--workflow-gate { - background: color-mix(in srgb, var(--color-warning) 18%, transparent); - color: var(--color-warning); -} - .card.failed { border-left: 3px solid var(--color-error-dark); } @@ -1733,8 +1673,7 @@ executing. These map 1:1 to the unified progress status so the dot color encodes .card-size-badge, /* FNXC:PlannerOversight 2026-07-04-00:00: mobile-scale the FN-7516 oversight badge alongside the other .card-meta-badges chips at narrow widths. */ - .card-oversight-badge, - .card-overseer-state-badge { + .card-oversight-badge { font-size: 0.5625rem; padding: calc(var(--space-xs) / 4) calc((var(--space-xs) * 3) / 2); } diff --git a/packages/dashboard/app/components/TaskCard.tsx b/packages/dashboard/app/components/TaskCard.tsx index 70e28bc7c0..d8ca402cfe 100644 --- a/packages/dashboard/app/components/TaskCard.tsx +++ b/packages/dashboard/app/components/TaskCard.tsx @@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next"; import type { TFunction } from "i18next"; import { memo, useCallback, useState, useRef, useEffect, useLayoutEffect, useMemo, type CSSProperties, type ReactElement } from "react"; import { createPortal } from "react-dom"; -import { Link, Clock, Layers, Pencil, ChevronDown, Folder, Target, Bot, Trash2, RotateCw, Zap, GitBranch, GitPullRequest, AlertTriangle, ArrowUpRight, Eye } from "lucide-react"; +import { Link, Clock, Layers, Pencil, ChevronDown, Folder, Target, Bot, Trash2, RotateCw, Zap, GitBranch, GitPullRequest, AlertTriangle, ArrowUpRight } from "lucide-react"; import type { Task, TaskDetail, Column, ColumnId, PrInfo, IssueInfo, TaskPriority, GithubIssueAction, MergeResult, PlannerOversightLevel } from "@fusion/core"; import { DEFAULT_PLANNER_OVERSIGHT_LEVEL, @@ -212,99 +212,6 @@ const OVERSIGHT_BADGE_MODIFIER: Record, st autonomous: "autonomous", }; -/* - * FNXC:PlannerOversight 2026-07-04-00:00: - * FN-7516 active-overseer-state indicator. The real FN-7511/FN-7512 monitor/ - * recovery state lives only in-memory on the engine (`PlannerOverseerMonitor`, - * `PlannerRecoveryController`) with no persistence onto `Task` or dashboard API - * route today, and `@fusion/engine` is a server-only package the client bundle - * must not import (dashboard's `app/` tree has no existing `@fusion/engine` - * import; only `src/` server routes use it). Rather than render nothing, this - * card derives a display-only proxy for "is the overseer actively watching this - * task" from the SAME already-on-`Task` fields the engine's own stage resolver - * (`resolveWatchedStage` in packages/engine/src/planner-overseer.ts) reads — - * `column`, `paused`, `pausedReason`, `prInfo`, `reviewState`, and - * `workflowTransitionNotification` — mirroring its precedence exactly: - * workflow-gate > pull-request > merger > reviewer > executor. This keeps the - * badge card-local (no new engine plumbing, no new props through the five - * `` call sites) while giving operators a real, stage-accurate signal - * instead of a permanently-deferred stub. - */ -const OVERSEER_STATE_LABEL: Record = { - executor: "Executor", - reviewer: "Reviewer", - merger: "Merger", - "pull-request": "Pull request", - "workflow-gate": "Workflow gate", -}; -const OVERSEER_STATE_MODIFIER: Record = { - executor: "executor", - reviewer: "reviewer", - merger: "merger", - "pull-request": "pull-request", - "workflow-gate": "workflow-gate", -}; - -type OverseerCardWatchedStage = "executor" | "reviewer" | "merger" | "pull-request" | "workflow-gate"; - -/** The minimal task shape {@link deriveOverseerCardWatchedStage} reads. */ -type OverseerCardTaskRef = Pick< - Task, - "column" | "paused" | "pausedReason" | "prInfo" | "reviewState" | "workflowTransitionNotification" ->; - -/** - * FNXC:PlannerOversight 2026-07-04-00:00: - * Card-local mirror of the engine's `resolveWatchedStage` (see block comment - * above `OVERSEER_STATE_LABEL`). Never throws — missing/partial fields degrade - * to `null` ("not currently monitorable"). - */ -function deriveOverseerCardWatchedStage(task: Partial | null | undefined): OverseerCardWatchedStage | null { - try { - if (!task) return null; - - if (task.paused === true && typeof task.pausedReason === "string") { - if (task.pausedReason.startsWith("workflow-cli-approval:") || task.pausedReason.startsWith("workflow-input:")) { - return "workflow-gate"; - } - } - if (task.paused === true) { - return null; - } - - const column = task.column; - if (column !== "in-progress" && column !== "in-review") { - return null; - } - - if (column === "in-progress") { - return "executor"; - } - - const prInfo = task.prInfo; - if (prInfo && typeof prInfo === "object" && prInfo.status !== "merged" && prInfo.status !== "closed") { - return "pull-request"; - } - - const marker = task.workflowTransitionNotification; - if (marker && marker.kind === "manual-merge-hold") { - return "merger"; - } - if (prInfo && typeof prInfo === "object" && typeof prInfo.lastMergeError === "string" && prInfo.lastMergeError.length > 0) { - return "merger"; - } - - const reviewState = task.reviewState; - if (reviewState && typeof reviewState === "object") { - return "reviewer"; - } - - return "merger"; - } catch { - return null; - } -} - function getResolvedAgentNameFromMap( agentId: string | undefined, agentsMap: ReadonlyMap, @@ -874,15 +781,6 @@ function areTaskCardPropsEqual(previous: TaskCardProps, next: TaskCardProps): bo // selection lives in a separate `task_workflow_selection` table — so this // reuses the already-compared `workflowBadge` prop above rather than a // nonexistent task field. - // FNXC:PlannerOversight 2026-07-04-00:00: repaint when any field the card-local - // overseer-watched-stage derivation (`deriveOverseerCardWatchedStage`) reads - // changes, so the card-overseer-state-badge stays in sync (FN-7516). `column` - // and `paused` are already compared above; `prInfo` is compared via - // `areTaskBadgeInfosEqual` below. - previousTask.pausedReason === nextTask.pausedReason && - JSON.stringify(previousTask.workflowTransitionNotification ?? null) === - JSON.stringify(nextTask.workflowTransitionNotification ?? null) && - JSON.stringify(previousTask.reviewState ?? null) === JSON.stringify(nextTask.reviewState ?? null) && previousTask.missionId === nextTask.missionId && previousTask.assignedAgentId === nextTask.assignedAgentId && previousTask.mergeRetries === nextTask.mergeRetries && @@ -1111,10 +1009,10 @@ function TaskCardComponent({ * configured to Off/Observe/Steer, for the whole window before the fetch * resolved (and forever on fetch failure, since failures also cache * `undefined`). Track resolution explicitly via `workflowOversightResolved` - * and gate the badges (`showOversightBadge`/`showOverseerStateBadge` below) - * so nothing renders from the unresolved workflow tier — only a task-level - * override (known synchronously from the task payload) can show a badge - * before the workflow tier is known. + * and gate the badge (`showOversightBadge` below) so nothing renders from + * the unresolved workflow tier — only a task-level override (known + * synchronously from the task payload) can show a badge before the + * workflow tier is known. */ const workflowIdForOversight = workflowBadge?.workflowId; const [workflowOversightState, setWorkflowOversightState] = useState<{ level: PlannerOversightLevel | undefined; resolved: boolean }>(() => { @@ -1731,31 +1629,12 @@ function TaskCardComponent({ !isInheritedDefaultOversightLevel; /* - * FNXC:PlannerOversight 2026-07-04-00:00: - * Step 3 of FN-7516 ("active overseer state" indicator). See the FNXC block - * above `OVERSEER_STATE_LABEL` for why this is a card-local derivation rather - * than data read from a new engine-plumbed field. Gated on: effective - * oversight level not "off" (mirrors `PlannerOverseerMonitor.observeTask`, - * which records nothing when the level is "off"), the task not explicitly - * user-paused, and not done / not archived (mirrors `isDoneColumn`, - * `isArchived` used elsewhere in this component). A paused task only remains - * visible when `deriveOverseerCardWatchedStage` classifies the pause as a - * workflow input/approval gate; other agent-side pauses are not active - * overseer stages and render no state badge. Only an explicit user-initiated - * pause (`task.userPaused`) hides even a workflow-gate indicator. - * - * Also gated on the same `hasTaskOversightOverride || workflowOversightResolved` - * condition as `showOversightBadge` above (round-2 code-review fix): the - * overseer indicator derives from `effectiveOversightLevel`, so it must not - * render from an unresolved/guessed workflow tier either. + * FNXC:PlannerOversight 2026-07-04-HH:MM: + * FN-7542 removed the active-overseer-state ("Executor") chip that used to + * render here as unwanted per-card noise — it fired on nearly every + * in-progress card. The oversight-level badge (`showOversightBadge` above) + * is unaffected and continues to render per its own gate. */ - const overseerWatchedStage = deriveOverseerCardWatchedStage(task); - const showOverseerStateBadge = (hasTaskOversightOverride || workflowOversightResolved) - && effectiveOversightLevel !== "off" - && !task.userPaused - && !isDoneColumn - && !isArchived - && overseerWatchedStage != null; const showCreatePrQuickAction = task.column === "in-review" && !effectiveAutoMerge @@ -2696,14 +2575,19 @@ function TaskCardComponent({ && workflowBadge.workflowId.trim().length > 0 && typeof workflowBadge.workflowName === "string" && workflowBadge.workflowName.trim().length > 0; + /* + * FNXC:PlannerOversight 2026-07-04-HH:MM: + * FN-7542 removed the active-overseer-state ("Executor") chip from this + * guard — operators found it fired as noise on nearly every in-progress + * card. The oversight-level badge (`showOversightBadge`) is untouched. + */ const hasCardMetaBadges = showPriorityBadge || task.executionMode === "fast" || isAgentCreated // FNXC:PlannerOversight 2026-07-04-00:00: the oversight badge is opt-in // metadata (absent for the common "off" default) — include it in the wrapper // guard so `.card-meta-badges` only renders when it has a real child. - || showOversightBadge - || showOverseerStateBadge; + || showOversightBadge; if (isEditing) { return ( @@ -2990,17 +2874,6 @@ function TaskCardComponent({ {abbreviateBadge(OVERSIGHT_BADGE_LABEL[effectiveOversightLevel as Exclude], 14)} )} - {showOverseerStateBadge && overseerWatchedStage && ( - - - )} )} {task.noCommitsExpected === true && ( diff --git a/packages/dashboard/app/components/__tests__/TaskCard.oversight.test.tsx b/packages/dashboard/app/components/__tests__/TaskCard.oversight.test.tsx index 26848dfd09..b9266115a3 100644 --- a/packages/dashboard/app/components/__tests__/TaskCard.oversight.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskCard.oversight.test.tsx @@ -1,20 +1,21 @@ /* - * FNXC:PlannerOversight 2026-07-04-00:00: - * FN-7516 card-surface tests for the read-only effective oversight-level badge - * and the active-overseer-state indicator. Covers the Surface Enumeration data - * states: Observe/Steer/Autonomous render a labeled badge; an explicit "off" - * effective level renders nothing (no empty shell); an unset per-task override - * that resolves to the schema default ("autonomous") renders NO badge at all - * (FN-7539: an inherited default is not meaningfully-configured oversight), - * while an EXPLICIT per-task override of "autonomous" still renders the - * badge (explicit intent is preserved). The overseer-state indicator renders only while the - * card-local watched-stage derivation (`deriveOverseerCardWatchedStage` in - * TaskCard.tsx, mirroring the engine's `resolveWatchedStage`) resolves a stage - * AND the task is not paused/done/archived AND the effective oversight level - * is not "off". Round-2 code-review fix covered here: when a card must fetch - * the workflow's effective oversight tier (no synchronous per-task override), - * neither badge renders until that fetch resolves — the schema default must - * never render as a guess while the true workflow tier is unknown. + * FNXC:PlannerOversight 2026-07-04-HH:MM: + * FN-7516 card-surface tests for the read-only effective oversight-level badge. + * Covers the Surface Enumeration data states: Observe/Steer/Autonomous render a + * labeled badge; an explicit "off" effective level renders nothing (no empty + * shell); an unset per-task override that resolves to the schema default + * ("autonomous") renders NO badge at all (FN-7539: an inherited default is not + * meaningfully-configured oversight), while an EXPLICIT per-task override of + * "autonomous" still renders the badge (explicit intent is preserved). + * Round-2 code-review fix covered here: when a card must fetch the workflow's + * effective oversight tier (no synchronous per-task override), the badge does + * not render until that fetch resolves — the schema default must never render + * as a guess while the true workflow tier is unknown. + * + * FN-7542 removed the sibling active-overseer-state ("Executor") indicator as + * unwanted per-card noise; see the removal-regression describe block below + * asserting `card-overseer-state-badge` is gone across the surfaces it used + * to render on. */ import { afterEach, describe, it, expect, vi } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; @@ -149,29 +150,32 @@ describe("TaskCard effective oversight-level badge (FN-7516)", () => { }); }); -describe("TaskCard active-overseer-state indicator (FN-7516)", () => { +/* + * FNXC:PlannerOversight 2026-07-04-HH:MM: + * FN-7542 removal-regression coverage: `card-overseer-state-badge` must never + * render again. Every case below is set up with `plannerOversightLevel: "steer"` + * and a column/state combination that the pre-removal `deriveOverseerCardWatchedStage` + * code WOULD have resolved to a stage (Executor/Reviewer/Pull request/Merger/ + * Workflow gate), plus the already-nothing-rendered baselines (non-monitorable + * column, userPaused, off level) to confirm no regression there either. + */ +describe("TaskCard overseer-state badge removed (FN-7542)", () => { it.each([ - ["in-progress", {}, "executor", "Executor"], - ["in-review", { reviewState: { source: "reviewer-agent", items: [], addressing: [] } }, "reviewer", "Reviewer"], - ["in-review", { prInfo: { number: 1, status: "open" } }, "pull-request", "Pull request"], + ["in-progress", {}], + ["in-review", { reviewState: { source: "reviewer-agent", items: [], addressing: [] } }], + ["in-review", { prInfo: { number: 1, status: "open" } }], [ "in-review", { workflowTransitionNotification: { kind: "manual-merge-hold", column: "in-review", transitionId: "t1", createdAt: "2026-01-01" } }, - "merger", - "Merger", ], - ["in-review", {}, "merger", "Merger"], - ] as const)("renders the indicator for column=%s state=%o with stage=%s", (column, stateOverrides, stage, label) => { + ["in-review", {}], + ] as const)("renders no overseer-state badge for column=%s state=%o (previously would have shown a stage chip)", (column, stateOverrides) => { renderCard({ column, plannerOversightLevel: "steer", ...(stateOverrides as Partial) }); - const badge = screen.getByTestId("card-overseer-state-badge"); - expect(badge).toBeTruthy(); - expect(badge.className).toContain(`card-overseer-state-badge--${stage}`); - expect(badge.textContent).toContain(label); - expect(badge.getAttribute("title")).toBe(`Overseer: ${label}`); + expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); }); - it("renders the workflow-gate stage when paused on a workflow input/approval gate", () => { + it("renders no overseer-state badge when paused on a workflow input/approval gate", () => { renderCard({ column: "in-progress", plannerOversightLevel: "steer", @@ -179,55 +183,35 @@ describe("TaskCard active-overseer-state indicator (FN-7516)", () => { pausedReason: "workflow-cli-approval:node-1", }); - const badge = screen.getByTestId("card-overseer-state-badge"); - expect(badge).toBeTruthy(); - expect(badge.className).toContain("card-overseer-state-badge--workflow-gate"); - expect(badge.textContent).toContain("Workflow gate"); + expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); }); - it("renders no indicator (no empty shell) when the task is not in a monitorable column", () => { + it("renders no overseer-state badge when the task is not in a monitorable column (no regression)", () => { renderCard({ column: "todo", plannerOversightLevel: "steer" }); expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); }); - it("renders no indicator when the effective oversight level is off", () => { + it("renders no overseer-state badge when the effective oversight level is off (no regression)", () => { renderCard({ column: "in-progress", plannerOversightLevel: "off" }); expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); }); - it("suppresses the indicator when the task is user-paused", () => { + it("renders no overseer-state badge when the task is user-paused (no regression)", () => { renderCard({ column: "in-progress", plannerOversightLevel: "steer", userPaused: true }); expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); }); - it("suppresses the indicator when the task is agent-paused off a workflow gate", () => { - renderCard({ column: "in-progress", plannerOversightLevel: "steer", paused: true, pausedReason: "some-other-reason" }); - - expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); - }); - - it("suppresses the indicator when the task column is done", () => { - renderCard({ column: "done", plannerOversightLevel: "steer" }); - - expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); - }); - - it("suppresses the indicator when the task column is archived", () => { - renderCard({ column: "archived", plannerOversightLevel: "steer" }); - - expect(screen.queryByTestId("card-overseer-state-badge")).toBeNull(); - }); - - it("does not render an always-on empty card-meta-badges child when both level is off and overseer is inactive", () => { - const { container } = renderCard({ plannerOversightLevel: "off", column: "todo" }); + it("does not render an empty card-meta-badges shell when the overseer-state chip was the only would-be meta child", () => { + const { container } = renderCard({ column: "in-progress", plannerOversightLevel: "steer" }); const metaBadges = container.querySelector(".card-meta-badges"); + // Either the wrapper is entirely absent, or if present for some other + // reason it must not contain an overseer-state badge element. if (metaBadges) { expect(metaBadges.querySelector(".card-overseer-state-badge")).toBeNull(); - expect(metaBadges.querySelector(".card-oversight-badge")).toBeNull(); } }); }); @@ -342,7 +326,15 @@ describe("TaskCard workflow-effective oversight level (FN-7516 code-review fix)" }); }); -describe("TaskCard memo comparator — oversight level and overseer state (FN-7516)", () => { +/* + * FNXC:PlannerOversight 2026-07-04-HH:MM: + * FN-7542 dropped the `pausedReason`/`reviewState`/`workflowTransitionNotification` + * memo-comparator compares — they existed solely to repaint the now-removed + * overseer-state badge and none of those fields are read by any other render + * path in this component. `plannerOversightLevel` and `workflowBadge.workflowId` + * remain compared for the surviving oversight-level badge. + */ +describe("TaskCard memo comparator — oversight level (FN-7516)", () => { it("returns false when task.plannerOversightLevel changes, so the card repaints", () => { const base = makeTask({ plannerOversightLevel: "observe" }); const changed = makeTask({ plannerOversightLevel: "steer" }); @@ -355,45 +347,6 @@ describe("TaskCard memo comparator — oversight level and overseer state (FN-75 ).toBe(false); }); - it("returns false when task.reviewState changes, so the overseer-state badge repaints", () => { - const base = makeTask({ column: "in-review" }); - const changed = makeTask({ column: "in-review", reviewState: { source: "reviewer-agent", items: [], addressing: [] } }); - - expect( - __test_areTaskCardPropsEqual( - { task: base, onOpenDetail: noop, addToast: noop } as any, - { task: changed, onOpenDetail: noop, addToast: noop } as any, - ), - ).toBe(false); - }); - - it("returns false when task.pausedReason changes, so the workflow-gate stage repaints", () => { - const base = makeTask({ column: "in-progress", paused: true, pausedReason: "workflow-cli-approval:a" }); - const changed = makeTask({ column: "in-progress", paused: true, pausedReason: "workflow-cli-approval:b" }); - - expect( - __test_areTaskCardPropsEqual( - { task: base, onOpenDetail: noop, addToast: noop } as any, - { task: changed, onOpenDetail: noop, addToast: noop } as any, - ), - ).toBe(false); - }); - - it("returns false when task.workflowTransitionNotification changes, so the merger stage repaints", () => { - const base = makeTask({ column: "in-review" }); - const changed = makeTask({ - column: "in-review", - workflowTransitionNotification: { kind: "manual-merge-hold", column: "in-review", transitionId: "t1", createdAt: "2026-01-01" }, - }); - - expect( - __test_areTaskCardPropsEqual( - { task: base, onOpenDetail: noop, addToast: noop } as any, - { task: changed, onOpenDetail: noop, addToast: noop } as any, - ), - ).toBe(false); - }); - it("returns false when workflowBadge.workflowId changes, so the workflow-effective oversight tier re-resolves", () => { const task = makeTask({});