fix: filter cross-milestone errors from health tracker escalation (#1621)

Two bugs fixed:
1. recordHealthSnapshot counted ALL doctor issues including cross-milestone
   stale errors, inflating consecutiveErrorUnits past the escalation threshold
   from unfixable errors in other milestones. Now filters report.issues to
   only the current milestone before summarizing for health tracking.

2. matchesScope used unitId.startsWith(scope) without a delimiter, so scope
   "M004/S01" would false-match "M004/S010". Removed the redundant
   delimiter-less startsWith branch — exact match and slash-delimited
   startsWith are sufficient.

Closes #1579

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
TÂCHES 2026-03-20 10:47:49 -06:00 committed by GitHub
parent ce5f7b73b6
commit fb7b484d10
2 changed files with 11 additions and 4 deletions

View file

@ -172,13 +172,20 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
ctx.ui.notify(`Post-hook: applied ${report.fixesApplied.length} fix(es).`, "info");
}
// Proactive health tracking
const summary = summarizeDoctorIssues(report.issues);
// Proactive health tracking — filter to current milestone to avoid
// cross-milestone stale errors inflating the escalation counter
const currentMilestoneId = s.currentUnit.id.split("/")[0];
const milestoneIssues = currentMilestoneId
? report.issues.filter(i =>
i.unitId === currentMilestoneId ||
i.unitId.startsWith(`${currentMilestoneId}/`))
: report.issues;
const summary = summarizeDoctorIssues(milestoneIssues);
recordHealthSnapshot(summary.errors, summary.warnings, report.fixesApplied.length);
// Check if we should escalate to LLM-assisted heal
if (summary.errors > 0) {
const unresolvedErrors = report.issues
const unresolvedErrors = milestoneIssues
.filter(i => i.severity === "error" && !i.fixable)
.map(i => ({ code: i.code, message: i.message, unitId: i.unitId }));
const escalation = checkHealEscalation(summary.errors, unresolvedErrors);

View file

@ -297,7 +297,7 @@ async function markSliceUndoneInRoadmap(basePath: string, milestoneId: string, s
function matchesScope(unitId: string, scope?: string): boolean {
if (!scope) return true;
return unitId === scope || unitId.startsWith(`${scope}/`) || unitId.startsWith(`${scope}`);
return unitId === scope || unitId.startsWith(`${scope}/`);
}
function auditRequirements(content: string | null): DoctorIssue[] {