diff --git a/biome.json b/biome.json index 33207c298..0ec473c77 100644 --- a/biome.json +++ b/biome.json @@ -16,7 +16,8 @@ "!!**/rust-engine/npm", "!!**/*.min.js", "!!packages/coding-agent/src/core/export-html/template.css", - "!!src/resources/skills/create-sf-extension/templates" + "!!src/resources/skills/create-sf-extension/templates", + "!!scripts/tmp-check-test-imports" ] }, "formatter": { diff --git a/src/resources/extensions/sf/auto/loop.js b/src/resources/extensions/sf/auto/loop.js index 7279589bd..360b0e67b 100644 --- a/src/resources/extensions/sf/auto/loop.js +++ b/src/resources/extensions/sf/auto/loop.js @@ -18,6 +18,7 @@ import { resolveEngine } from "../engine-resolver.js"; import { getErrorMessage } from "../error-utils.js"; import { NOTICE_KIND } from "../notification-store.js"; import { sfRoot } from "../paths.js"; +import { dispatchSelfFeedbackInlineFixIfNeeded } from "../self-feedback-drain.js"; import { recordSelfFeedback } from "../self-feedback.js"; import { getDatabase } from "../sf-db.js"; import { @@ -613,6 +614,12 @@ export async function autoLoop(ctx, pi, s, deps) { recentUnits: persisted.recentUnits, stuckRecoveryAttempts: persisted.stuckRecoveryAttempts, consecutiveFinalizeTimeouts: 0, + // Iteration at which the autonomous loop last invoked the + // self-feedback inline-fix dispatcher. Used by the mid-loop + // triage-drain hook below to avoid spamming the dispatcher on + // every iteration while still picking up entries filed during + // the run (which previously sat until next session_start). + lastInlineFixDispatchIteration: 0, }; let consecutiveErrors = 0; let consecutiveCooldowns = 0; @@ -632,6 +639,30 @@ export async function autoLoop(ctx, pi, s, deps) { } iteration++; debugLog("autoLoop", { phase: "loop-top", iteration }); + // ── Mid-loop self-feedback inline-fix dispatcher ────────────────── + // Bootstrap drains the triage queue once at session_start (see + // src/headless.ts:647). Entries filed DURING the autonomous run + // previously sat until the next sf restart — defeats the + // self-heal thesis for long-running sessions. Re-invoke the + // inline-fix dispatcher every MID_LOOP_TRIAGE_INTERVAL iterations + // so any high/critical entry filed mid-run gets a triage pass + // without waiting for restart. The dispatcher already debounces + // via claim file (see dispatchSelfFeedbackInlineFixIfNeeded) and + // is fire-and-forget on the headless surface, so this is safe to + // call on every Nth iteration. + const MID_LOOP_TRIAGE_INTERVAL = 5; + if ( + iteration > 1 && + iteration - loopState.lastInlineFixDispatchIteration >= + MID_LOOP_TRIAGE_INTERVAL + ) { + try { + dispatchSelfFeedbackInlineFixIfNeeded(s.basePath, ctx, pi); + } catch { + // Never block the loop on triage-dispatch failure. + } + loopState.lastInlineFixDispatchIteration = iteration; + } // ── Halt watchdog: detect idle/stuck iterations ── const { stuck, elapsedMs } = watchdog.check(ctx, iteration); if (stuck) {