fix(916): cross-family state is per round, and the orchestrator reads cross_family before a verdict
A substitute that failed in round one said nothing about the tree that lands after round two, yet the flag was sticky and doomed the run; the xfamily string was never reset either, so clearing the stickiness alone would have let a stale "substitute ALSO failed" sentence into the PR body. Both reset at the top of review(). The harness runner is round-aware (ran per round, its own counter reset) and a two-round case pins the fix; restoring the sticky flag reddens it in both scripts. Step 4 of the mechanics page tells the referee to read cross_family, not only error, before posting on a rubric-class PR. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
This commit is contained in:
@@ -50,12 +50,14 @@ function run(script, args, { reviewRounds, landOverrides = {}, postRebase = null
|
||||
calls.push({ label, prompt, opts });
|
||||
if (label.startsWith('impl:') || label.startsWith('fix:#')) return { done: true, summary: '', verified: '', left: '', commits: IMPL_COMMITS, head_sha: 'aaaaaaa' };
|
||||
if (label.startsWith('review:codex:')) {
|
||||
lensesReturned = 0;
|
||||
lensesReturnedWhenRunnerStarted.push(lensesReturned);
|
||||
return { verdict: 'merge', findings: [], ran: false };
|
||||
const spec = reviewRounds[round] || {};
|
||||
return { verdict: 'merge', findings: [], ran: spec.runnerRan === true };
|
||||
}
|
||||
if (label.startsWith('review:fallback:')) {
|
||||
lensesReturnedWhenFallbackStarted.push(lensesReturned);
|
||||
if (fallbackNull) return null;
|
||||
if (fallbackNull === true || (Array.isArray(fallbackNull) && fallbackNull.includes(round))) return null;
|
||||
const spec = reviewRounds[round - 1] || { findings: [] };
|
||||
return { verdict: 'merge', findings: spec.findings };
|
||||
}
|
||||
@@ -175,6 +177,18 @@ describe.each(cases)('%s review loop', (name, args) => {
|
||||
expect(result.error).toMatch(/^the post-rebase review round produced no reviews/);
|
||||
});
|
||||
|
||||
it('a substitute failure in round one does not doom a run whose landing round had a real cross-family review', async () => {
|
||||
const rubricArgs = { ...args, risk: 'rubric' };
|
||||
const { result, calls } = await run(script, rubricArgs, {
|
||||
reviewRounds: [{ findings: [finding('should-fix')] }, { findings: [], runnerRan: true }],
|
||||
fallbackNull: [1],
|
||||
});
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.cross_family).toBe('codex');
|
||||
expect(finisherPrompt(calls)).not.toContain('substitute ALSO failed');
|
||||
expect(calls.filter((c) => c.label.startsWith('review:codex:')).length).toBe(2);
|
||||
});
|
||||
|
||||
it('a rubric round whose runner and substitute both fail is an error, never a landed PR', async () => {
|
||||
const rubricArgs = { ...args, risk: 'rubric' };
|
||||
const { result, calls } = await run(script, rubricArgs, { reviewRounds: [{ findings: [] }], fallbackNull: true });
|
||||
|
||||
Reference in New Issue
Block a user