v1.91.134.0 feat(evals): readiness-gated paid dispatch (R1), verdict reuse (R2a/R2), receipt store that restores (#3262)

* feat(evals): readiness-gated paid dispatch (R1), restamp-only gate reuse (R2a), and a receipt store that restores

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* feat(evals): R2 verdict reuse across main moves; review fixes (newer-run classification, receipt parser, manual acceptance)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(evals): R2 own-diff signature covers release-output content and CHANGELOG deletions and preamble

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(evals): R2 normalises release outputs by stamp pattern only; compares stamp-file modes; unreadable blobs refuse

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* chore: stamp v1.91.134.0

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(evals): autoplan-guard-pty actor continues through the phase boundary; name PHASE_BOUNDARY_STOP

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-10-18 06:03:18 +00:00
1 parent fd13cf25e8
commit a2a6cabfa6
21 files changed
+1758 -84

No files matched your search

+9 -4
View File
@@ -209,9 +209,13 @@ function allowedOutput(plan: Plan, root: string, rel: string): boolean {
}
interface Hunk { removed: string[]; added: string[]; at: number }
export interface FileDiff { path: string; binary: boolean; hunks: Hunk[]; status: 'M' | 'A' | 'D' | 'R' }
export interface FileDiff { path: string; binary: boolean; hunks: Hunk[]; status: 'M' | 'A' | 'D' | 'R'; modeChanged?: boolean }
/** Parse `git diff --unified=0` into per-file hunks of removed/added lines (shared with lib/tree-receipt.ts). */
/**
* Parse `git diff --unified=0` into per-file hunks of removed/added lines (shared with lib/tree-receipt.ts).
* File headers come only before a file's first hunk: inside a hunk every `-`/`+` line is content, so a
* body line that begins `--` or `++` (`---`/`+++` in the diff) is never dropped as a header.
*/
export function parseUnifiedDiff(text: string): FileDiff[] {
const files: FileDiff[] = [];
let cur: FileDiff | null = null;
@@ -225,11 +229,12 @@ export function parseUnifiedDiff(text: string): FileDiff[] {
} else if (!cur) continue;
else if (line.startsWith('new file mode')) cur.status = 'A';
else if (line.startsWith('deleted file mode')) cur.status = 'D';
else if (!hunk && (line.startsWith('old mode ') || line.startsWith('new mode '))) cur.modeChanged = true;
else if (line.startsWith('rename to ')) cur.status = 'R';
else if (line.startsWith('Binary files')) cur.binary = true;
else if (line.startsWith('@@')) { hunk = { removed: [], added: [], at: Number(/^@@ -\d+(?:,\d+)? \+(\d+)/.exec(line)?.[1] ?? 0) }; cur.hunks.push(hunk); }
else if (hunk && line.startsWith('-') && !line.startsWith('---')) hunk.removed.push(line.slice(1));
else if (hunk && line.startsWith('+') && !line.startsWith('+++')) hunk.added.push(line.slice(1));
else if (hunk && line.startsWith('-')) hunk.removed.push(line.slice(1));
else if (hunk && line.startsWith('+')) hunk.added.push(line.slice(1));
}
return files;
}
+1
View File
@@ -72,6 +72,7 @@ function classifyFile(repoRoot: string, f: FileDiff, gated: string, current: str
const changed = (rule: string, residual: string, line = f.hunks[0]?.at): FileVerdict => ({ path: f.path, rule, verdict: 'changed', residual, line });
const stamp = (rule: string): FileVerdict => ({ path: f.path, rule, verdict: 'stamp' });
if (f.binary) return changed('binary', 'binary content differs');
if (f.modeChanged) return changed('mode', 'file mode changed');
if (f.status !== 'M') return changed('path', `${f.status === 'A' ? 'added' : f.status === 'D' ? 'deleted' : 'renamed'}`);
if (policy.stamp_files.length && !matchesAny(policy.stamp_files, f.path)) return changed('stamp_files', 'not in the repo\'s stamp_files allowlist');
const before = blob(repoRoot, gated, f.path);