fix: inject observability warnings into agent prompt for enforcement (#174)

emitObservabilityWarnings only called ctx.ui.notify — the agent never
saw the warnings and ignored them entirely. Validator caught real issues
(missing observability sections, placeholder diagnostics) but had zero
enforcement.

Rename to collectObservabilityWarnings (returns issues), add
buildObservabilityRepairBlock to format issues as actionable prompt
instructions. Appended to the unit prompt so the agent reads flagged
files and fixes gaps before proceeding with the unit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lex Christopherson 2026-03-13 09:20:19 -06:00
parent 788c356a25
commit 498614c95f

View file

@ -1262,7 +1262,7 @@ async function dispatchNextUnit(
return;
}
await emitObservabilityWarnings(ctx, unitType, unitId);
const observabilityIssues = await collectObservabilityWarnings(ctx, unitType, unitId);
// Idempotency: skip units already completed in a prior session.
const idempotencyKey = `${unitType}/${unitId}`;
@ -1402,6 +1402,13 @@ async function dispatchNextUnit(
}
}
// Inject observability repair instructions so the agent fixes gaps before
// proceeding with the unit (see #174).
const repairBlock = buildObservabilityRepairBlock(observabilityIssues);
if (repairBlock) {
finalPrompt = `${finalPrompt}${repairBlock}`;
}
// Switch model if preferences specify one for this unit type
// Try primary model, then fallbacks in order if setting fails
const modelConfig = resolveModelWithFallbacksForUnit(unitType);
@ -2365,17 +2372,17 @@ function ensurePreconditions(
// ─── Diagnostics ──────────────────────────────────────────────────────────────
async function emitObservabilityWarnings(
async function collectObservabilityWarnings(
ctx: ExtensionContext,
unitType: string,
unitId: string,
): Promise<void> {
): Promise<import("./observability-validator.ts").ValidationIssue[]> {
const parts = unitId.split("/");
const mid = parts[0];
const sid = parts[1];
const tid = parts[2];
if (!mid || !sid) return;
if (!mid || !sid) return [];
let issues = [] as Awaited<ReturnType<typeof validatePlanBoundary>>;
@ -2387,12 +2394,38 @@ async function emitObservabilityWarnings(
issues = await validateCompleteBoundary(basePath, mid, sid);
}
if (issues.length === 0) return;
if (issues.length > 0) {
ctx.ui.notify(
`Observability check (${unitType}) found ${issues.length} warning${issues.length === 1 ? "" : "s"}:\n${formatValidationIssues(issues)}`,
"warning",
);
}
ctx.ui.notify(
`Observability check (${unitType}) found ${issues.length} warning${issues.length === 1 ? "" : "s"}:\n${formatValidationIssues(issues)}`,
"warning",
);
return issues;
}
function buildObservabilityRepairBlock(issues: import("./observability-validator.ts").ValidationIssue[]): string {
if (issues.length === 0) return "";
const items = issues.map(issue => {
const fileName = issue.file.split("/").pop() || issue.file;
let line = `- **${fileName}**: ${issue.message}`;
if (issue.suggestion) line += `${issue.suggestion}`;
return line;
});
return [
"",
"---",
"",
"## Pre-flight: Observability gaps to fix FIRST",
"",
"The following issues were detected in plan/summary files for this unit.",
"**Read each flagged file, apply the fix described, then proceed with the unit.**",
"",
...items,
"",
"---",
"",
].join("\n");
}
async function recoverTimedOutUnit(