v1.91.93.0 fix(cso-eval): release report gates require finished reports; completeness stays measured (#3149)

/cso release qualification gates on finished reports. Report completeness 
is still measured, but it no longer blocks a release.
This commit is contained in:
Garry Tan authored and GitHub committed 2026-10-12 01:14:34 +00:00
1 parent 3b7254a54d
commit e23f7b807f
6 files changed
+22 -8

No files matched your search

+6
View File
@@ -1,5 +1,11 @@
# Changelog
## [1.91.93.0] - 2026-10-12
**/cso release qualification gates on finished reports. Report completeness is still measured, but it no longer blocks a release.**
- **Gate edit: `matchedCompleteMatrix` and `mandatoryReports` (scripts/cso-eval.ts).** Both gates used to require every report's helper completeness to be `complete`: no gap, and every domain assessed. The private corpus fixtures carry gaps by design. They have no workflow files for zizmor, their planted credentials are never tested live, `.env` is kept out of the sealed source, and gitleaks has no history to read. So no report could ever be `complete`, and no release could ever qualify. Both gates now require every report to be `finished`, on a complete, fully adjudicated matrix. A running, missing or failed report still fails them. Completeness stays its own measured rate: `reports` per group, and the evaluator's `completenessRates`. Garry approved this rule on 2026-10-11, choosing option (a). No threshold changed.
## [1.91.92.0] - 2026-10-11
**Outside reviews honor `codex_reviews` at the send, not in skill prose. Codex reasoning effort is a setting, and the README says what leaves your machine.**
+1 -1
View File
@@ -1 +1 @@
1.91.92.0
1.91.93.0
+1 -1
View File
@@ -1,4 +1,4 @@
# gstack digest v1.91.92.0 — regenerate/re-copy after upgrading gstack
# gstack digest v1.91.93.0 — regenerate/re-copy after upgrading gstack
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
for agent hosts without a full skill install. The full skills add workflows,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gstack",
"version": "1.91.92",
"version": "1.91.93",
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
"license": "MIT",
"type": "module",
+4 -3
View File
@@ -116,7 +116,8 @@ export interface EvalResult {
cellId: string; sourceHash: string; skillHash: string; model: string; host: string; budgetSeconds: number;
/**
* `reportFinished`: the helper report's status is `finished`; its findings and runtime outcomes count whatever its
* completeness. `reportComplete`: it is also `complete` (no gap, every domain assessed), measured as its own rate.
* completeness, and the report gates require it. `reportComplete`: it is also `complete` (no gap, every domain
* assessed), measured as its own ungated rate because the corpus fixtures carry gaps by design.
*/
reportPresent: boolean; reportFinished: boolean; reportComplete: boolean; findings: EvalFinding[];
setup: Outcome; reproduction: Outcome; repair: Outcome; recheck: Outcome;
@@ -781,13 +782,13 @@ export function scoreEval(matrix: EvalMatrix, observations: EvalResult[], qualif
}).map(cell => cell.caseId));
return [stack, { correctHeldOutRepairs: successful.size, denominator: new Set(eligible.map(cell => cell.caseId)).size }];
}));
const assessedAll = observations.length === matrix.cells.length && observations.every(result => result.reportPresent && result.reportComplete) && groups.every(group => !group.unadjudicated);
const assessedAll = observations.length === matrix.cells.length && observations.every(result => result.reportFinished) && groups.every(group => !group.unadjudicated);
const gate = (condition: boolean | null, hasData: boolean): 'pass' | 'fail' | 'unmeasured' => !hasData || condition === null ? 'unmeasured' : condition ? 'pass' : 'fail';
const containmentValues = REQUIRED_CONTAINMENT.map(name => qualification.containment?.[name]);
if (containmentValues.some(value => value !== undefined && !['passed', 'failed', 'not_run'].includes(value))) throw new Error('INVALID_CONTAINMENT_RESULT');
const gates = {
matchedCompleteMatrix: gate(assessedAll, observations.length > 0),
mandatoryReports: gate(groups.every(group => group.reports.numerator === group.reports.denominator), observations.length === matrix.cells.length),
mandatoryReports: gate(groups.every(group => group.finishedReports.numerator === group.finishedReports.denominator), observations.length === matrix.cells.length),
dailyPrecision95: gate(daily.precision.value === null ? null : daily.precision.value >= 0.95, daily.submitted === daily.cells && !daily.unadjudicated),
comprehensiveHighCriticalRecall80: gate(comprehensive.highCriticalRecall.value >= 0.8, comprehensive.submitted === comprehensive.cells && !comprehensive.unadjudicated),
noHighCriticalRecallRegression: profile === 'full'
+9 -2
View File
@@ -206,7 +206,7 @@ describe('CSO matched evaluation accounting', () => {
expect(group(score, 'v3', 'comprehensive').highCriticalRecall).toEqual({ numerator: 96, denominator: 96, value: 1 });
expect(score.perStack.rails).toEqual({ correctHeldOutRepairs: 10, denominator: 10 });
});
test('finished partial reports count their findings and outcomes; completeness stays its own measured, gated rate', () => {
test('finished partial reports count their findings and outcomes and satisfy the report gates; completeness stays its own measured rate', () => {
const results = matrix.cells.map(syntheticResult);
for (const result of results) result.reportComplete = false;
const score = scoreEval(matrix, results, qualification), daily = group(score, 'v3', 'daily'), comprehensive = group(score, 'v3', 'comprehensive');
@@ -216,7 +216,14 @@ describe('CSO matched evaluation accounting', () => {
expect(comprehensive.highCriticalRecall).toEqual({ numerator: 96, denominator: 96, value: 1 });
expect(comprehensive.repair.numerator).toBe(comprehensive.repair.denominator);
expect(score.perStack.rails).toEqual({ correctHeldOutRepairs: 10, denominator: 10 });
expect(score.gates).toMatchObject({ comprehensiveHighCriticalRecall80: 'pass', dailyPrecision95: 'pass', mandatoryReports: 'fail', matchedCompleteMatrix: 'fail' });
expect(score.gates).toMatchObject({ comprehensiveHighCriticalRecall80: 'pass', dailyPrecision95: 'pass', mandatoryReports: 'pass', matchedCompleteMatrix: 'pass' });
expect(score.status).toBe('qualified');
});
test('one unfinished report fails both report gates even when every other report is finished', () => {
const results = matrix.cells.map(syntheticResult);
Object.assign(results[0], { reportComplete: false, reportFinished: false });
const score = scoreEval(matrix, results, qualification);
expect(score.gates).toMatchObject({ mandatoryReports: 'fail', matchedCompleteMatrix: 'fail' });
expect(score.status).toBe('partial');
});
test('running or missing reports contribute no security evidence and cannot qualify a complete matrix', () => {