fix(ship-budget): Step 9's Red Team batch takes no start of its own; --finish settles it

gstack-evals #34 round 3: the pass program's start-once-per-role rule gave the
Red Team batch an extra --start review token that no row ever finished. A later
batch of the same Step 9 pass (the Red Team or an ADMIT remainder) now takes no
start, and --finish REVIEW_START settles the open later batches of the step
reserved after the started one, so none stays reserved at close.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-30 03:12:00 +00:00
1 parent 682def4cca
commit 2d3d90cd0c
7 files changed
+40 -7

No files matched your search

+22
View File
@@ -117,6 +117,28 @@ describe('gstack-review-log --start under a token cap', () => {
expect(close.code, close.out).toBe(0);
});
// Value: protects=a later batch of the same Step 9 pass (the Red Team, built after collect) takes no start of its own and still settles when the pass finishes, so no start token is left unfinished and no reservation stays open (gstack-evals #34 round 3: an extra red-team --start review token was never finished); fails_when=--finish settles only reservations a start consumed, leaving the Red Team's open and counted as reserved at close;
// why_new=the --finish tests above start every batch; seam=none; no_claim=that the program's own settle ran
test('--finish REVIEW_START settles the pass\'s later Red Team batch that took no start; close finds nothing reserved or unreserved', () => {
const h = fresh();
const run = capped(h);
const first = reserve(h, run.run, 'dispatch:specialist');
const start = h.reviewLog(['--start', 'review', '--reservation', first]);
expect(start.code, start.err).toBe(0);
const redTeam = reserve(h, run.run, 'dispatch:red-team');
const earlier = h.ledger(run.ledger).reservations.find((r: any) => r.id === redTeam);
expect(earlier.state).toBe('open');
const row = { skill: 'review', timestamp: new Date().toISOString(), status: 'clean', issues_found: 0, critical: 0, informational: 0 };
const fin = h.reviewLog([JSON.stringify(row), '--finish', start.out.trim()]);
expect(fin.code, fin.err).toBe(0);
expect(fin.err).toContain(`settled budget reservations ${first},${redTeam}`);
expect(h.ledger(run.ledger).reservations.filter((r: any) => r.kind === 'dispatch').map((r: any) => r.state)).toEqual(['settled', 'settled']);
const close = h.sb(['close', '--run', run.run, '--reading', '10']);
expect(close.out).toContain('reserved=0');
expect(close.out).not.toContain('BUDGET_CHECK_SKIPPED');
expect(close.code, close.out).toBe(0);
});
test('close prints one BUDGET_CHECK_SKIPPED line per unreserved dispatch and ends incomplete', () => {
const h = fresh();
const run = capped(h);
+8
View File
@@ -48,6 +48,14 @@ describe('ship budget skill structure', () => {
expect(handoff).not.toContain('once per role on the printed reservation');
});
// Value: protects=the pass program says a later batch of the same Step 9 pass takes no start, so the Red Team leaves no unfinished token; fails_when=the section tells every batch to start once per role;
// why_new=the start test above pins the row rule only; seam=none; no_claim=the agent follows it
test('a later batch of the same Step 9 pass (Red Team, an ADMIT remainder) takes no start of its own', () => {
for (const rel of ['ship/sections/budget-handoff.md.tmpl', 'ship/sections/review-army.md.tmpl']) {
expect(read(rel), rel).toMatch(/later batch of the same (?:Step 9 )?pass \(the Red Team or an ADMIT remainder\) takes no start/);
}
});
test('every review-log --start in the dispatch sections takes a reservation when a cap is set', () => {
for (const rel of ['ship/sections/review-army.md.tmpl', 'ship/sections/adversarial.md.tmpl']) expect(read(rel)).toContain('--reservation');
});