fix(ci): стабилизировать релизный proof на main (#619)

Issue: #619
User-Visible: no
This commit is contained in:
Claude
2026-09-23 06:09:08 +03:00
parent 0e0a0e54e5
commit 0d047450ce
7 changed files with 67 additions and 23 deletions
+11 -5
View File
@@ -355,12 +355,18 @@ export function evaluateCiProof({
return result('green', `${policy?.name || 'consumer'} proof is complete`);
}
/** Newest relevant proof wins; cancelled and policy-inadequate stale runs do not. */
/**
* A complete green proof is content-addressed evidence for the candidate and
* remains valid regardless of a later duplicate run (#619). When no green
* proof exists, keep the newest decisive state so failures still fail closed.
*/
export function selectCiProofVerdict(evaluations) {
for (const item of evaluations || []) {
if (item?.status === 'cancelled' || item?.status === 'stale') continue;
return item;
}
const relevant = (evaluations || []).filter(
(item) => item?.status !== 'cancelled' && item?.status !== 'stale',
);
const green = relevant.find((item) => item?.status === 'green');
if (green) return green;
if (relevant.length) return relevant[0];
return { status: 'missing', note: 'no run carries a proof for the requested policy', url: null };
}
+5 -1
View File
@@ -76,7 +76,11 @@ export async function classifyValidateProofs({
}
}
const current = evaluations.at(-1);
if (current.status !== 'cancelled' && current.status !== 'stale') break;
// #619: a complete proof is immutable evidence for this exact SHA/tree.
// A later duplicate may fail for workflow topology rather than product
// content, so only a green proof ends the search; failures remain the
// fallback verdict when no run proves the candidate green.
if (current.status === 'green') break;
}
return selectCiProofVerdict(evaluations);
}