Files
fusion/packages/dashboard/app/api/settings/settings.ts
gsxdsm a010dc42bf FN-9185: enforce effective task concurrency limits
Unify task concurrency around authoritative project settings and expose the effective admission ceiling.

- Resolve maxConcurrent and maxWorktrees through a shared core capacity model with consistent defaults.
- Apply the effective limit across scheduler, engine, runtime, CLI, API, and project-manager admission paths.
- Surface configured and binding concurrency values in dashboard controls, status views, diagnostics, and documentation.
- Add regression coverage for settings persistence, routing, scheduling, UI surfaces, and worktree-bound capacity.

Files changed:
 .../fn-9185-max-concurrent-effective-limit.md      |   7 +
 docs/architecture.md                               |   8 +-
 docs/cli-reference.md                              |   1 +
 docs/dashboard-guide.md                            |   4 +
 docs/settings-reference.md                         |   4 +-
 .../dashboard-concurrency-settings.test.ts         | 166 +++++++++++++++++++++
 packages/cli/src/commands/dashboard.ts             |  28 ++--
 packages/cli/src/commands/onboard.ts               |   4 +-
 packages/cli/src/project-resolver.ts               |  27 +++-
 .../concurrency-capacity-resolver.test.ts          |  46 ++++++
 .../src/__tests__/worktree-capacity-limit.test.ts  |  51 +++++--
 packages/core/src/index.gate.ts                    |   2 +-
 packages/core/src/index.ts                         |   2 +-
 packages/core/src/workflows/workflow-capacity.ts   |  61 ++++++--
 packages/dashboard/app/App.tsx                     |   2 +
 .../app/__tests__/concurrency-ui-surfaces.test.tsx | 155 +++++++++++++++++++
 .../scheduling-effective-concurrency.test.tsx      |  48 ++++++
 packages/dashboard/app/api/projects/projects.ts    |  10 +-
 packages/dashboard/app/api/settings/settings.ts    |  14 +-
 packages/dashboard/app/components/Board.tsx        |   7 +-
 packages/dashboard/app/components/Column.tsx       |  13 +-
 .../dashboard/app/components/EngineControlMenu.tsx |  17 ++-
 .../command-center/CommandCenterControls.tsx       |  17 ++-
 .../components/command-center/areas/TeamArea.tsx   |  10 +-
 .../app/components/dashboard/MainContent.tsx       |   3 +
 .../dashboard/app/components/dashboard/types.ts    |   2 +
 .../settings/sections/SchedulingSection.tsx        |  12 +-
 packages/dashboard/app/hooks/useAppSettings.ts     |   9 +-
 packages/dashboard/app/hooks/useExecutorStats.ts   |  10 +-
 .../app/utils/__tests__/worktreeGrouping.test.ts   |  12 +-
 packages/dashboard/app/utils/worktreeGrouping.ts   |   8 +-
 packages/dashboard/src/routes.ts                   |   6 +-
 ...concurrency-authoritative-source-routes.test.ts |  90 +++++++++++
 .../register-config-mcp-pi-settings-routes.test.ts |  29 +++-
 .../register-config-mcp-pi-settings-routes.ts      |  17 ++-
 .../src/routes/register-project-routes.ts          |  14 +-
 .../concurrency-effective-limit-surfaces.test.ts   |  34 +++++
 .../src/__tests__/project-engine-manager.test.ts   |  19 +++
 .../__tests__/scheduler-workflow-cutover.test.ts   |   6 +-
 packages/engine/src/concurrency/concurrency.ts     |  23 ++-
 packages/engine/src/concurrency/hybrid-executor.ts |  35 ++++-
 .../engine/src/executor/create-spawn-agent-tool.ts |   8 +-
 packages/engine/src/project-engine-manager.ts      |  50 +++++--
 packages/engine/src/project-engine.ts              |  12 +-
 packages/engine/src/project/project-manager.ts     |  26 +++-
 packages/engine/src/runtimes/in-process-runtime.ts |  12 +-
 packages/engine/src/scheduler.ts                   |  31 ++--
 packages/engine/src/triage.ts                      |  15 +-
 48 files changed, 1028 insertions(+), 159 deletions(-)

Fusion-Task-Id: FN-9185
Fusion-Task-Lineage: 6294456c-d417-40a5-a5fa-2035c6b964a6
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-08-21 10:57:44 -07:00

76 lines
2.6 KiB
TypeScript

/**
* FNXC:CodeOrganization 2026-07-16-14:00:
* Settings/config/update client API peeled from legacy.ts.
*/
import type { Settings } from "@fusion/core";
import { api } from "../client/client.js";
import type { FetchOptions } from "../client/client.js";
import { withProjectId } from "../client/health.js";
import type { UpdateCheckResponse } from "../client/health.js";
import { dedupe } from "../client/dedupe.js";
export function fetchConfig(projectId?: string): Promise<{
maxConcurrent: number;
effectiveMaxConcurrent: number;
concurrencyBindingKnob: "maxConcurrent" | "maxWorktrees";
rootDir: string;
}> {
const path = withProjectId("/config", projectId);
return dedupe(path, () => api<{
maxConcurrent: number;
effectiveMaxConcurrent: number;
concurrencyBindingKnob: "maxConcurrent" | "maxWorktrees";
rootDir: string;
}>(path));
}
export function fetchSettings(projectId?: string, options?: FetchOptions): Promise<Settings> {
const path = withProjectId("/settings", projectId);
return dedupe(path, () => api<Settings>(path), options);
}
export function fetchTaskEffectiveSettings(taskId: string, projectId?: string, options?: FetchOptions): Promise<Settings> {
const path = withProjectId(`/tasks/${taskId}/effective-settings`, projectId);
return dedupe(path, () => api<Settings>(path), options);
}
export function updateSettings(settings: Partial<Settings>, projectId?: string): Promise<Settings> {
return api<Settings>(withProjectId("/settings", projectId), {
method: "PUT",
body: JSON.stringify(settings),
});
}
export function checkForUpdate(projectId?: string): Promise<UpdateCheckResponse> {
return api<UpdateCheckResponse>(withProjectId("/update-check", projectId));
}
export function refreshUpdateCheck(projectId?: string): Promise<UpdateCheckResponse> {
return api<UpdateCheckResponse>(withProjectId("/update-check/refresh", projectId), {
method: "POST",
});
}
export interface UpdateInstallResponse {
currentVersion: string;
latestVersion: string | null;
updated: boolean;
outcome?: "installed" | "no-update-available" | "check-failed" | "unsupported-install-method" | "failed";
message?: string;
error?: string;
restartAttempted?: boolean;
restartScheduled?: boolean;
/** PID of the process that accepted an automatic update restart. */
priorPid?: number;
}
/** The old dashboard process retains this successful install until it restarts. */
export type PendingUpdateInstall = UpdateInstallResponse;
export function installUpdate(projectId?: string): Promise<UpdateInstallResponse> {
return api<UpdateInstallResponse>(withProjectId("/update-check/install", projectId), {
method: "POST",
});
}