Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions .github/scripts/run-autofix-review-verification.sh
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,14 @@ baseline_also_fails() {
} > "${WORKDIR}/gate-rejection.md" || true
exit 1
fi
# Every retryable exit below hands the tree to the repair agent with
# dist/ REBUILT FROM BASELINE SOURCES (the restore checkout brings back
# tracked files only) — the mirror of the dist confound that exempted
# typecheck from the A/B. The note seeds the repair feedback so the
# agent rebuilds before it trusts any dist-consuming check. The
# pre-existing exit is the exception: no repair runs for it, so the
# note stays out of its document.
if [[ "${rc}" -ne 1 ]]; then
Comment thread
wenshao marked this conversation as resolved.
Resolved
# Both retryable exits below hand the tree to the repair agent with
# dist/ REBUILT FROM BASELINE SOURCES (the restore checkout brings back
# tracked files only) — the mirror of the dist confound that exempted
# typecheck from the A/B. The note seeds the repair feedback so the
# agent rebuilds before it trusts any dist-consuming check.
echo "⚠️ the baseline leg rebuilt dist/ from baseline sources — run npm run build before typecheck/tests" >> "${GATE_LOG}"
echo "🔁 baseline is green — the failure belongs to this round" \
| tee -a "${GATE_LOG}"
Expand All @@ -185,9 +187,12 @@ baseline_also_fails() {
# verdict-less gate crash.
# (sig_head was extracted before the detach.)
sig_base="$(fail_signature "${ab_log}")" || true
new_in_round="$(comm -23 <(printf '%s\n' "${sig_head}") <(printf '%s\n' "${sig_base}"))" ||
new_in_round="$(comm -23 <(printf '%s\n' "${sig_head}") <(printf '%s\n' "${sig_base}"))" || {
Comment thread
wenshao marked this conversation as resolved.
Resolved
echo "⚠️ the baseline leg rebuilt dist/ from baseline sources — run npm run build before typecheck/tests" >> "${GATE_LOG}"
return 1
}
Comment thread
wenshao marked this conversation as resolved.
Resolved
if [[ -z "${sig_head}" || -z "${sig_base}" ]] || [[ -n "${new_in_round}" ]]; then
Comment thread
wenshao marked this conversation as resolved.
Resolved
echo "⚠️ the baseline leg rebuilt dist/ from baseline sources — run npm run build before typecheck/tests" >> "${GATE_LOG}"
Comment thread
wenshao marked this conversation as resolved.
Resolved
echo "🔁 baseline fails for a DIFFERENT reason — charged to the round" \
| tee -a "${GATE_LOG}"
return 1
Expand Down
32 changes: 32 additions & 0 deletions scripts/tests/qwen-autofix-workflow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11582,6 +11582,7 @@ describe('review verification gate: baseline A/B on deterministic rejection', ()
hugeFail = false,
noIdentity = false,
trackedDirt = false,
commFail = false,
}) => {
const dir = mkdtempSync(join(tmpdir(), 'gate-ab-'));
try {
Expand Down Expand Up @@ -11698,6 +11699,13 @@ describe('review verification gate: baseline A/B on deterministic rejection', ()
].join('\n'),
);
chmodSync(join(bin, 'npm'), 0o755);
if (commFail) {
// Shadows the system comm via PATH precedence: the signature
// comparison itself fails (the SIGPIPE-under-pipefail class), so
// the gate takes its fail-closed retryable exit.
writeFileSync(join(bin, 'comm'), '#!/bin/bash\nexit 1\n');
chmodSync(join(bin, 'comm'), 0o755);
}
const rt = join(dir, 'rt');
mkdirSync(rt);
writeFileSync(
Expand Down Expand Up @@ -11795,6 +11803,11 @@ describe('review verification gate: baseline A/B on deterministic rejection', ()
// The baseline leg's own transcript is the ONLY proof behind the
// verdict — it must reach the rejection document.
expect(r.rejection).toContain(`stub build FAILED at ${r.baselineSha}`);
// No repair runs for a pre-existing failure — the dist/ steering note
// is for the repair agent and stays out of this document.
expect(r.rejection).not.toContain(
'run npm run build before typecheck/tests',
);
expect(r.headAfter).toBe('feature');
});

Expand Down Expand Up @@ -11934,6 +11947,25 @@ describe('review verification gate: baseline A/B on deterministic rejection', ()
expect(r.outputs).toContain('retryable=true');
expect(r.outputs).not.toContain('preexisting=true');
expect(r.stdout).toContain('DIFFERENT reason');
// The same repair handoff as the green path — the dist/ warning must
// seed this rejection too.
expect(r.rejection).toContain('run npm run build before typecheck/tests');
});

it('seeds the dist-rebuild warning when the signature comparison itself fails', () => {
// comm failing (SIGPIPE under pipefail, an infrastructure hiccup)
// takes the same retryable handoff as the green/different-signature
// exits — without the note the repair agent trusts baseline-built
// dist/ and chases phantom dist-consuming failures.
const r = runGate({
failAt: ['feature', 'origin/feature'],
commFail: true,
});
expect(r.status).toBe(1);
expect(r.outputs).toContain('retryable=true');
expect(r.outputs).not.toContain('preexisting=true');
expect(r.rejection).toContain('run npm run build before typecheck/tests');
expect(r.headAfter).toBe('feature');
});

it('keeps the green path intact', () => {
Expand Down
Loading