Files
fusion/packages/dashboard/app/components/settings/sections/SchedulingSection.search.ts
gsxdsm 3ed31e9907 FN-8815: retry execution after first tool failure
Retry executor work after the first terminal tool-call failure by default.

- Set the default tool-failure threshold to one while preserving explicit project overrides.
- Expose and document the first-error default in Settings, translations, and the settings reference.
- Cover threshold resolution, save lifecycle, and executor retry behavior.

Files changed: .changeset/fn-8815-retry-first-tool-failure.md     |  7 +++
 docs/settings-reference.md                         |  4 +-
 .../core/src/__tests__/settings-defaults.test.ts   |  6 +-
 packages/core/src/config/settings-schema.ts        | 10 ++-
 packages/core/src/tasks/in-review-stall.ts         | 15 ++++-
 packages/core/src/types/settings/settings-scope.ts | 10 ++-
 .../dashboard/app/components/SettingsModal.tsx     |  7 ++-
 .../SettingsModal.scheduling-merge.test.tsx        | 61 +++++++++++++++++-
 .../settings/sections/SchedulingSection.search.ts  |  2 +-
 .../settings/sections/SchedulingSection.tsx        |  4 +-
 .../settings-default-descriptions.test.tsx         | 12 ++++
 .../__tests__/executor-tool-failure-retry.test.ts  | 73 +++++++++++++++++++---
 packages/i18n/locales/en/app.json                  |  2 +-
 packages/i18n/src/resources.d.ts                   | 17 +++--
 14 files changed, 200 insertions(+), 30 deletions(-)

Fusion-Task-Id: FN-8815

Fusion-Task-Lineage: 909181e7-2da5-4a27-92ee-4182732d9695

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-08-06 08:35:36 -07:00

245 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Search entries for the Scheduling section.
*
* FNXC:SettingsSearch 2026-07-15-17:35:
* One entry per descriptor row the section renders, co-located so a setting and its index entry change in the same edit. Labels and help mirror the section's `t()` calls verbatim: the index matches on the copy operators actually read, so a paraphrase here would make search miss the words on screen.
* The `overlapIgnorePaths` repeating-row editor, the Global/This-project scope group headers, and the moved step-execution stub are deliberately absent — they are bespoke chrome or a repeating editor, not descriptor rows.
*/
import type { SettingsSearchEntry } from "../search/types";
export const schedulingSearchEntries: SettingsSearchEntry[] = [
{
sectionId: "scheduling",
key: "maxConcurrent",
labelKey: "settings.scheduling.maxConcurrentTasks",
labelFallback: "Max Concurrent Tasks",
helpKey: "settings.scheduling.maxConcurrentTasksHint",
helpFallback: "Default: 2.",
/*
FNXC:SettingsSearch 2026-07-15-17:35:
This row's help is just "Default: 2.", so the label is nearly all the index has to match on. The keywords carry the vocabulary the copy never spells out — an operator hunting for how many tasks run at once has no other way to land here.
*/
keywords: ["parallelism", "capacity", "how many tasks at once", "agents", "cap"],
},
{
sectionId: "scheduling",
key: "maxConcurrentVerifications",
labelKey: "settings.scheduling.maxConcurrentVerifications",
labelFallback: "Max Concurrent Verifications",
helpKey: "settings.scheduling.maxConcurrentVerificationsHint",
helpFallback: "Caps stacked typecheck/build verification across tasks. Default: 1. Range: 1–8.",
keywords: ["parallelism", "tests", "cpu", "load"],
},
{
sectionId: "scheduling",
key: "executorToolFailureRetryCount",
labelKey: "settings.scheduling.executorToolFailureRetryCount",
labelFallback: "Executor tool-failure retries",
helpKey: "settings.scheduling.executorToolFailureRetryCountHelp",
helpFallback: "Same-model retries after consecutive tool-call failures. Set 0 to disable. Default: 2.",
keywords: ["executor", "tool error", "auto retry", "same model", "failure"],
},
{
sectionId: "scheduling",
key: "executorToolFailureRetryBackoffMs",
labelKey: "settings.scheduling.executorToolFailureRetryBackoffMs",
labelFallback: "Tool-failure retry backoff (ms)",
helpKey: "settings.scheduling.executorToolFailureRetryBackoffMsHelp",
helpFallback: "Unref'd wait before retrying. Default: 2000.",
keywords: ["executor", "delay", "wait", "auto retry", "tool error"],
},
{
sectionId: "scheduling",
key: "executorToolFailureThreshold",
labelKey: "settings.scheduling.executorToolFailureThreshold",
labelFallback: "Consecutive tool failures",
helpKey: "settings.scheduling.executorToolFailureThresholdHelp",
helpFallback: "Terminal tool errors required before retrying. Default: 1.",
keywords: ["executor", "tool error", "threshold", "auto retry"],
},
{
sectionId: "scheduling",
key: "executorModelEscalationEnabled",
labelKey: "settings.scheduling.executorModelEscalationEnabled",
labelFallback: "Escalate after tool-failure retries",
helpKey: "settings.scheduling.executorModelEscalationEnabledHelp",
helpFallback: "After same-model retries are exhausted, try one configured alternate model or node. Disabled by default.",
keywords: ["executor", "model", "node", "escalation", "tool error"],
},
{
sectionId: "scheduling",
key: "executorEscalationNodeId",
labelKey: "settings.scheduling.executorEscalationNodeId",
labelFallback: "Escalation node ID",
helpKey: "settings.scheduling.executorEscalationNodeIdHelp",
helpFallback: "Optional configured node; a node target re-enters scheduler routing.",
keywords: ["executor", "node", "routing", "escalation"],
},
{
sectionId: "scheduling",
key: "pollIntervalMs",
labelKey: "settings.scheduling.pollIntervalMs",
labelFallback: "Poll Interval (ms)",
helpKey: "settings.scheduling.pollIntervalMsHint",
helpFallback: "Default: 15000 (15 seconds).",
keywords: ["tick", "engine loop", "frequency", "refresh"],
},
{
sectionId: "scheduling",
key: "heartbeatScopeDiscipline",
labelKey: "settings.scheduling.heartbeatScopeDiscipline",
labelFallback: "Heartbeat Scope Discipline",
helpKey: "settings.scheduling.strictCoordinationFocusedHigherPerTickTokensLite",
helpFallback:
"Strict — coordination-focused; higher per-tick tokens. Lite — pre-2026-05-11 behavior. Off — minimal procedure.",
keywords: ["agent prompt", "token cost"],
},
{
sectionId: "scheduling",
key: "engineerBacklogAutoClaim",
labelKey: "settings.scheduling.letEngineerAgentsAutoClaimBacklogTasks",
labelFallback: " Let engineer agents auto-claim backlog tasks ",
helpKey: "settings.scheduling.backlogNoTaskAutoClaimIsExecutorOnly",
helpFallback:
"Backlog/no-task auto-claim is executor-only by default. Enable to let engineer-role agents auto-claim unowned backlog tasks; explicit routing and delegation are unchanged. Default: off.",
keywords: ["pick up work", "unassigned", "todo"],
},
{
sectionId: "scheduling",
key: "taskStuckTimeoutMs",
labelKey: "settings.scheduling.stuckTaskTimeoutMinutes",
labelFallback: "Stuck Task Timeout (minutes)",
helpKey: "settings.scheduling.timeoutInMinutesForDetectingStuckTasksWhen",
helpFallback:
"Timeout in minutes for detecting stuck tasks. When a task's agent session shows no activity for longer than this duration, the task is terminated and retried. Leave empty to disable. Suggested: 10. Default: 10 minutes (600000ms).",
keywords: ["hung", "frozen", "watchdog", "kill"],
},
{
sectionId: "scheduling",
key: "buildTimeoutMs",
labelKey: "settings.scheduling.buildTimeoutMinutes",
labelFallback: "Build/Verification Timeout (minutes)",
helpKey: "settings.scheduling.maximumTimeInMinutesForBuildVerificationCommands",
helpFallback:
"Maximum time in minutes for build/verification commands before they are killed. Raise for large monorepo or Docker builds. Default: 5.",
keywords: ["test timeout", "compile", "slow build"],
},
{
sectionId: "scheduling",
key: "staleHighFanoutBlockerAgeThresholdMs",
labelKey: "settings.scheduling.staleHighFanOutEscalationHours",
labelFallback: "Stale High Fan-out Escalation (hours)",
helpKey: "settings.scheduling.escalateHighFanOutBlockersOnlyAfterThey",
helpFallback:
"Escalate high fan-out blockers only after they remain in in-progress or in-review for this many hours (age source: columnMovedAt, fallback updatedAt). Default: 2 hours.",
keywords: ["dependencies", "alert", "notify"],
},
{
sectionId: "scheduling",
key: "preserveProgressOnStuckRequeue",
labelKey: "settings.scheduling.preserveStepProgressOnStuckTaskRequeue",
labelFallback: " Preserve step progress on stuck-task requeue ",
helpKey: "settings.scheduling.whenTheStuckDetectorKillsAndReQueues",
helpFallback:
"When the stuck detector kills and re-queues a task, keep completed step statuses so the agent can resume from where it left off. Disable to reset every step to pending on each stuck retry. Default: enabled.",
keywords: ["resume", "restart", "retry"],
},
{
sectionId: "scheduling",
key: "specStalenessEnabled",
labelKey: "settings.scheduling.enablePlanStalenessEnforcement",
labelFallback: " Enable plan staleness enforcement ",
helpKey: "settings.scheduling.whenEnabledTasksWithStalePlansPROMPTMd",
helpFallback:
"When enabled, tasks with stale plans (PROMPT.md older than the threshold) are automatically sent back to planning for replanning. Default: disabled.",
keywords: ["spec", "replan", "outdated"],
},
{
sectionId: "scheduling",
key: "specStalenessMaxAgeMs",
labelKey: "settings.scheduling.staleSpecThresholdHours",
labelFallback: "Stale Spec Threshold (hours)",
helpKey: "settings.scheduling.maximumAgeInHoursBeforeAPlanIs",
helpFallback: "Maximum age in hours before a plan is considered stale. Default: 6 hours.",
keywords: ["PROMPT.md", "replan", "age"],
},
{
sectionId: "scheduling",
key: "autoArchiveDoneTasksEnabled",
labelKey: "settings.scheduling.enableAutomaticTaskArchiving",
labelFallback: " Enable automatic task archiving ",
helpKey: "settings.scheduling.completedTasksOlderThanTheThresholdAreMoved",
helpFallback:
"Completed tasks older than the threshold are moved out of the active task database. Default: enabled.",
keywords: ["done column", "cleanup", "prune", "board clutter"],
},
{
sectionId: "scheduling",
key: "autoArchiveDoneAfterMs",
labelKey: "settings.scheduling.archiveCompletedTasksAfterDays",
labelFallback: "Archive Completed Tasks After (days)",
helpKey: "settings.scheduling.numberOfDaysATaskCanStayIn",
helpFallback:
"Number of days a task can stay in Done before it is archived. Default: 2 days (48 hours).",
keywords: ["retention", "cleanup", "age"],
},
{
sectionId: "scheduling",
key: "archiveAgentLogMode",
labelKey: "settings.scheduling.archiveAgentLog",
labelFallback: "Archive Agent Log",
helpKey: "settings.scheduling.compactModeKeepsArchiveSizeLowWhilePreserving",
helpFallback:
"Compact mode keeps archive size low while preserving recent agent activity for context. Default: compact.",
keywords: ["history", "transcript", "disk space", "retention"],
},
{
sectionId: "scheduling",
key: "autoArchiveDuplicateTasksEnabled",
labelKey: "settings.scheduling.autoArchiveDuplicateTasks",
labelFallback: " Automatically archive duplicate tasks ",
helpKey: "settings.scheduling.autoArchiveDuplicateTasksHelp",
helpFallback:
"Automatically archive tasks detected as same-agent duplicates on creation (off by default). When disabled, duplicates are flagged in place with the yellow Duplicate chip and Keep/Archive actions instead of being archived automatically.",
keywords: ["near duplicate", "dedupe", "repeat"],
},
{
sectionId: "scheduling",
key: "triageDuplicateResolution",
labelKey: "settings.scheduling.triageDuplicateResolution",
labelFallback: "Triage duplicate resolution",
helpKey: "settings.scheduling.triageDuplicateResolutionHelp",
helpFallback: "Block triage-detected duplicates for a Keep/Delete decision with a link to the duplicate (default), keep automatically, or delete automatically.",
keywords: ["duplicate", "triage", "keep", "delete", "decision"],
},
{
sectionId: "scheduling",
key: "maxStuckKills",
labelKey: "settings.scheduling.maxStuckRetries",
labelFallback: "Max Stuck Retries",
helpKey: "settings.scheduling.maximumStuckDetectorRetriesBeforeATaskIs",
helpFallback: "Maximum stuck-detector retries before a task is marked failed. Default: 6.",
keywords: ["give up", "attempts", "hung"],
},
{
sectionId: "scheduling",
key: "groupOverlappingFiles",
labelKey: "settings.scheduling.serializeTasksWithOverlappingFiles",
labelFallback: " Serialize tasks with overlapping files ",
helpKey: "settings.scheduling.whenEnabledTasksThatModifyTheSameFiles",
helpFallback:
"When enabled, tasks that modify the same files are queued serially to avoid merge conflicts. Default: enabled.",
keywords: ["file scope", "collision", "queue", "lease"],
},
{
sectionId: "scheduling",
key: "ignoreHiddenOverlapPaths",
labelKey: "settings.scheduling.ignoreHiddenDotPathsInOverlapChecks",
labelFallback: " Ignore hidden dot paths in overlap checks ",
helpKey: "settings.scheduling.ignoreHiddenDotPathsHelp",
helpFallback:
"When enabled, overlap checks ignore hidden path segments such as .fusion/, .changeset/, .github/, .env, and nested .cache/ directories. Uncheck to restore legacy counting for stricter serialization. Default: enabled.",
keywords: ["dotfiles", "collision", "file scope"],
},
];