fix(sdk): verify outcome gates advance correctly + regression tests

Address review findings from #1454:

1. runVerifyStep now returns success:false when gaps persist after
   exhausting retries (was always returning success:true)
2. human_needed + callback accept correctly sets outcome to passed
3. retryOnce skips retry for verification outcomes (gaps_found,
   human_needed) which have their own internal retry logic
4. Updated 3 existing tests to expect success:false on exhausted gaps
5. Added 3 regression tests:
   - persistent gaps_found does NOT append Advance step
   - persistent gaps_found does NOT call phaseComplete
   - verifier disabled still advances normally
This commit is contained in:
odmrs
2026-03-28 14:13:49 -03:00
parent 39d8688245
commit c5e4fea697
2 changed files with 80 additions and 7 deletions

View File

@@ -239,6 +239,8 @@ export class PhaseRunner {
if (!this.config.workflow.verifier) {
this.logger?.debug('Skipping verify: config.workflow.verifier=false');
} else {
// Verify has its own internal retry logic (gap closure). retryOnce only
// retries on unexpected session throws, not on verification outcomes like gaps_found.
const verifyResult = await this.retryOnce('verify', () => this.runVerifyStep(phaseNumber, sessionOpts, callbacks, options));
steps.push(verifyResult);
@@ -300,6 +302,9 @@ export class PhaseRunner {
const result = await fn();
if (result.success) return result;
// Don't retry verify outcomes (gaps_found, human_needed) — they have their own retry logic.
if (result.error?.startsWith('verification_')) return result;
this.logger?.warn(`Step "${label}" failed, retrying once...`);
return fn();
}
@@ -842,6 +847,7 @@ export class PhaseRunner {
});
if (decision === 'accept') {
outcome = 'passed';
break; // Treat as passed
} else if (decision === 'retry' && gapRetryCount < maxGapRetries) {
gapRetryCount++;
@@ -916,6 +922,7 @@ export class PhaseRunner {
}
const durationMs = Date.now() - stepStart;
const verifySuccess = outcome === 'passed';
this.eventStream.emitEvent({
type: GSDEventType.PhaseStepComplete,
@@ -923,15 +930,17 @@ export class PhaseRunner {
sessionId: lastResult?.sessionId ?? '',
phaseNumber,
step: PhaseStepType.Verify,
success: true,
success: verifySuccess,
durationMs,
...(!verifySuccess && { error: `verification_${outcome}` }),
});
return {
step: PhaseStepType.Verify,
success: true,
success: verifySuccess,
durationMs,
planResults: allPlanResults,
...(!verifySuccess && { error: `verification_${outcome}` }),
};
}