diff --git a/.changeset/fn-8453-unified-concurrency.md b/.changeset/fn-8453-unified-concurrency.md index 4db09715e2..da258247b8 100644 --- a/.changeset/fn-8453-unified-concurrency.md +++ b/.changeset/fn-8453-unified-concurrency.md @@ -4,4 +4,4 @@ summary: Unify max concurrency across planning/execution/review and simplify board capacity indicators. category: feature -dev: maxConcurrent caps all top-level working agents per project; maxTriageConcurrent removed from UI (Settings, Command Center, Engine Control) and admission; free slots admit oldest createdAt via per-project atomic admission coordinator across lanes; footer Waiting/Running/Blocked; column headers remain card totals; Running counts unpaused WIP membership (sessionFile is not a DB/board field — do not require it); nested runNested helpers remain parent-internal soft-breach by design. +dev: maxConcurrent caps all top-level working agents per project; maxTriageConcurrent removed from UI (Settings, Command Center, Engine Control) and admission; free slots admit oldest createdAt via per-project atomic admission coordinator across lanes; footer Waiting/Running/Blocked; column headers show executing/total via shared Running predicate; Running counts unpaused WIP membership (sessionFile is not a DB/board field — do not require it); nested runNested helpers remain parent-internal soft-breach by design. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index f5bbd54fc5..40936bb092 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -1258,7 +1258,7 @@ Features: -- **Overview controls dashboard** includes AI engine stop/start backed by `globalPause`, the shared Global Max Concurrent slider, and current-project **Max concurrency** plus **Max worktrees** controls. Max concurrency caps top-level working agents across planning, execution, and review/merge; free capacity is admitted oldest-first within the project. The footer reports **Waiting**, **Running (N/max)**, and **Blocked**; column headers report the card count in each lane. Nested helper agents remain parent-internal and may temporarily exceed the displayed top-level count. +- **Overview controls dashboard** includes AI engine stop/start backed by `globalPause`, the shared Global Max Concurrent slider, and current-project **Max concurrency** plus **Max worktrees** controls. Max concurrency caps top-level working agents across planning, execution, and review/merge; free capacity is admitted oldest-first within the project. The footer reports **Waiting**, **Running (N/max)**, and **Blocked**; column headers report executing/total (live agents in the lane over card count). Nested helper agents remain parent-internal and may temporarily exceed the displayed top-level count. - **Team tab — Org export / import** lets an operator download a portable organization JSON bundle or paste one for a dry-run preview before confirming the apply step. Exports are secret-scrubbed by default: credentials and tokens are never included, while safe secret references can remain for setup in the destination project. - **Configuration versions** lives in **Settings → Project → Configuration Versions**. It lists recorded project-setting revisions newest first; select **Roll back** on any revision and confirm once to restore it. The restore is recorded as a new forward revision, so it can itself be undone without manually reconstructing settings. diff --git a/packages/dashboard/app/components/Column.tsx b/packages/dashboard/app/components/Column.tsx index 4979031a89..ef438b17ae 100644 --- a/packages/dashboard/app/components/Column.tsx +++ b/packages/dashboard/app/components/Column.tsx @@ -4,6 +4,7 @@ import { useFlashOnIncrease } from "../hooks/useFlashOnIncrease"; import { useConfirm } from "../hooks/useConfirm"; import type { Task, TaskDetail, Column as ColumnType, ColumnId, TaskCreateInput, GithubIssueAction, MergeResult } from "@fusion/core"; import { COLUMN_LABELS, COLUMN_DESCRIPTIONS, getErrorMessage } from "@fusion/core"; +import { enrichRunningAgentTaskShapeFromFlags, isRunningAgentTask } from "../../../core/src/live-agent-count"; import { isNearDuplicateCanonicalInactive } from "../../../core/src/near-duplicate-canonical"; import { TaskCard } from "./TaskCard"; import { WorktreeGroup } from "./WorktreeGroup"; @@ -287,10 +288,14 @@ function ColumnComponent({ column, tasks, projectId, maxConcurrent, showWorktree */ const showWorktreeGroups = showWorktreeGrouping === true && isWipProcessingColumn; /* - FNXC:BoardColumnCount 2026-07-21-18:47: - Column headers show the card count in that lane, not live-agent active/total. - FN-8453 briefly rendered isRunningAgentTask counts as N/total, which read as broken for Todo (always 0/N waiting) and often for In Progress when board slim rows lack durable session/checkout liveness. Capacity Running/Waiting stays on the footer status bar. + FNXC:BoardColumnCount 2026-07-21-19:30: + Column header is executing/total (e.g. 3/4). Executing uses the same Running predicate as the + footer (unpaused WIP, live planners, active review). Total is the card count in this lane. */ + const activeTaskCount = useMemo( + () => tasks.filter((task) => isRunningAgentTask(enrichRunningAgentTaskShapeFromFlags(task, columnFlags))).length, + [tasks, columnFlags], + ); // When search is active, skip pagination so all matching tasks are visible const shouldPaginate = !isArchived && !isSearchActive && !showWorktreeGroups && tasks.length > PAGINATED_COLUMN_THRESHOLD; @@ -661,7 +666,12 @@ function ColumnComponent({ column, tasks, projectId, maxConcurrent, showWorktree

{workflowMode ? (columnDisplayName ?? COLUMN_LABELS[column] ?? column) : COLUMN_LABELS[column]}

- {tasks.length} + + {activeTaskCount}/{tasks.length} + {(workflowMode ? isReviewColumn : column === "in-review") && onToggleAutoMerge && (