mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-01 06:24:41 +01:00
fix(ship-budget): check prints the reservation id alone as RESERVATION_ID: <id>; the review prose reads that line
gstack-evals #36 round 3: a child misparsed a reservation id out of the RESERVATION: line, which gave UNMEASURED and then BUDGET_CHECK_SKIPPED at close. check keeps RESERVATION: and adds RESERVATION_ID: <id>; the pass program, Steps 9, 11 and 14.5 and the Capy skill pass that line's value to --reservation. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c24e7d6c96
commit
2aa160dda2
13 files changed
+36
-12
No files matched your search
@@ -44,7 +44,7 @@ Capy checklist for `/autoplan`: drive `gstack-autoplan`, never a hand adaptation
|
||||
|
||||
Token caps on /ship: pass a brief's cap as `--token-cap <n>`. /ship reads `cost.tokens` from `tools.thread.get({ thread_id: "<your own jam id>" })` (its own jam, subagents included; `"this"` names the root thread, so only a root run may pass it) inside the same execute program as the `gstack-ship-budget` command that takes it as `--reading <n>`, never in a call of its own, and obeys `verdict=` (`docs/ship-budget.md`).
|
||||
|
||||
/ship reviewers on Capy (`docs/review-policy.md#reviewer-packets`): one execute program per review pass, in this order: (1) `gstack-review-packet build` with the pass's plan flags (a later build in the same pass, the Red Team or Step 11's packets, is `build --like <first build dir>`, never hand-copied flags); (2) under a token cap, `gstack-ship-budget check --next "$BUDGET_NEXT"` (build's `BUDGET_NEXT:` value, `role@bytes` per packet, so each reader is priced from its packet), then `gstack-review-log --start <skill> --reservation <id>` once per row the step logs; (3) the counter reading `BEFORE` (a check in this program takes this same reading); (4) `tools.subagent.create`, one subagent per `PACKET:` line (at most 10 per call), `machine: "shared"`, on the lane's model at reasoning `medium` (red-team and adversarial keep the lane's reasoning; a cross-family outside voice stays as it is), starting at most the free slots of the running-subagent cap and retrying refused starts as slots free; (5) a poll of `tools.subagent.get` with `transcript: "none"` every ~20 s until every reviewer settles; (6) the reading `AFTER`, then `gstack-ship-budget settle --run <id> --reservation <id> --dispatched-at <BEFORE> --reading <AFTER> --readers <n readers created>`; (7) `gstack-review-packet collect --dir <dir>`, returning only its output. Each brief is the packet brief with that packet's `read=` ranges, plus one more parallel call in turn 1: `install.sh --check --for review-voice` in bash; a reviewer then finishes in about three calls (the parallel reads, at most one turn of extra ranges, one write). The parent makes no model call while the program runs, so only that pair measures the readers; a batch settled from a later program (a rerun poll) omits `--dispatched-at` and stays `UNMEASURED`. Keep one program under ~8 minutes and rerun the poll until collect has run (a lost program loses no reviewer); never read a reviewer's transcript. `gstack-review-log --finish` stays at the step that persists the pass: it records the parent's verdict.
|
||||
/ship reviewers on Capy (`docs/review-policy.md#reviewer-packets`): one execute program per review pass, in this order: (1) `gstack-review-packet build` with the pass's plan flags (a later build in the same pass, the Red Team or Step 11's packets, is `build --like <first build dir>`, never hand-copied flags); (2) under a token cap, `gstack-ship-budget check --next "$BUDGET_NEXT"` (build's `BUDGET_NEXT:` value, `role@bytes` per packet, so each reader is priced from its packet), then `gstack-review-log --start <skill> --reservation <id>` (`<id>` from check's `RESERVATION_ID:` line) once per row the step logs; (3) the counter reading `BEFORE` (a check in this program takes this same reading); (4) `tools.subagent.create`, one subagent per `PACKET:` line (at most 10 per call), `machine: "shared"`, on the lane's model at reasoning `medium` (red-team and adversarial keep the lane's reasoning; a cross-family outside voice stays as it is), starting at most the free slots of the running-subagent cap and retrying refused starts as slots free; (5) a poll of `tools.subagent.get` with `transcript: "none"` every ~20 s until every reviewer settles; (6) the reading `AFTER`, then `gstack-ship-budget settle --run <id> --reservation <id> --dispatched-at <BEFORE> --reading <AFTER> --readers <n readers created>`; (7) `gstack-review-packet collect --dir <dir>`, returning only its output. Each brief is the packet brief with that packet's `read=` ranges, plus one more parallel call in turn 1: `install.sh --check --for review-voice` in bash; a reviewer then finishes in about three calls (the parallel reads, at most one turn of extra ranges, one write). The parent makes no model call while the program runs, so only that pair measures the readers; a batch settled from a later program (a rerun poll) omits `--dispatched-at` and stays `UNMEASURED`. Keep one program under ~8 minutes and rerun the poll until collect has run (a lost program loses no reviewer); never read a reviewer's transcript. `gstack-review-log --finish` stays at the step that persists the pass: it records the parent's verdict.
|
||||
|
||||
## Plan, approve, ship
|
||||
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ With a cap set and no readable meter, start refuses
|
||||
| `call_floor`, `above_floor` | The host's per-call floor (see Delegation) and the charge above it, max(0, call − floor); the delegate rule compares `above_floor` |
|
||||
| `next`, `projected` | What the check was for and its projection: the prior times the run's factor for that kind |
|
||||
| `calibration` | The run's step and dispatch factors (see Calibration), or `prior` before the first measurement |
|
||||
| `verdict` | `continue` (exit 0, prints `RESERVATION:` under a cap), `delegate` (exit 0), `stop` (exit 3) |
|
||||
| `verdict` | `continue` (exit 0, prints `RESERVATION:` and the bare id as `RESERVATION_ID: <id>` under a cap), `delegate` (exit 0), `stop` (exit 3) |
|
||||
|
||||
Any exit other than 0 means the next step does not start. Exit 2 is a usage or validation
|
||||
error on stderr with the code, the value and the repair. GSTACK_RESULT appears only on a stop,
|
||||
|
||||
@@ -165,7 +165,7 @@ export function decide(l: Ledger, step: string, next: Next, call: number | null,
|
||||
if (hold) lines.push(`CONTEXT_HIGH: call=${call ?? 'unknown'} call_floor=${p.floor} above_floor=${above ?? 'unknown'} threshold=${threshold} next=${nextId} depth=${depth}; continuing: ${hold}`);
|
||||
if (l.cap !== null) {
|
||||
const r = reserveIn(l, { kind: 'step', step, next: nextId, tokens: projected, prior });
|
||||
lines.push(`RESERVATION: id=${r.id} next=${nextId} tokens=${projected}`);
|
||||
lines.push(`RESERVATION: id=${r.id} next=${nextId} tokens=${projected}`, `RESERVATION_ID: ${r.id}`);
|
||||
}
|
||||
return { stdout: lines, exit: 0 };
|
||||
}
|
||||
@@ -197,7 +197,7 @@ function admitBatch(l: Ledger, step: string, roles: string[], call: number | nul
|
||||
}
|
||||
const kept = bytes?.slice(0, k);
|
||||
const r = reserveIn(l, { kind: 'dispatch', step, next: nextId, tokens: cost(k), prior: p.project({ kind: 'dispatch', roles: admitted, ...(kept ? { bytes: kept } : {}) }).prior, roles: admitted, ...(kept ? { bytes: kept } : {}), ...(remaining.length ? { remaining } : {}) });
|
||||
lines.push(`RESERVATION: id=${r.id} next=${nextId} tokens=${cost(k)}`);
|
||||
lines.push(`RESERVATION: id=${r.id} next=${nextId} tokens=${cost(k)}`, `RESERVATION_ID: ${r.id}`);
|
||||
return { stdout: lines, exit: 0 };
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
above 0 the plan lists it beside the batched specialist), print `ADVERSARIAL: skipped (review plan)`;
|
||||
with neither line, take decision 3 of Finish the adversarial phase. Under a token cap,
|
||||
reserve the planned voices as one batch (`gstack-ship-budget check --next <the BUDGET_NEXT value
|
||||
Step 11's packet build prints>`, never packet names); every `--start adversarial-review` below (the native pass's and each outside voice's PASS_START) takes `--reservation <id>`, one start per voice on that reservation.
|
||||
Step 11's packet build prints>`, never packet names); every `--start adversarial-review` below (the native pass's and each outside voice's PASS_START) takes `--reservation <id>` (check's `RESERVATION_ID:` line), one start per voice on that reservation.
|
||||
|
||||
## Step 11: Adversarial review
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
above 0 the plan lists it beside the batched specialist), print `ADVERSARIAL: skipped (review plan)`;
|
||||
with neither line, take decision 3 of Finish the adversarial phase. Under a token cap,
|
||||
reserve the planned voices as one batch (`gstack-ship-budget check --next <the BUDGET_NEXT value
|
||||
Step 11's packet build prints>`, never packet names); every `--start adversarial-review` below (the native pass's and each outside voice's PASS_START) takes `--reservation <id>`, one start per voice on that reservation.
|
||||
Step 11's packet build prints>`, never packet names); every `--start adversarial-review` below (the native pass's and each outside voice's PASS_START) takes `--reservation <id>` (check's `RESERVATION_ID:` line), one start per voice on that reservation.
|
||||
|
||||
{{ADVERSARIAL_STEP}}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Field-by-field reference: docs/ship-budget.md. Exit 0 continue or delegate, 3 st
|
||||
|
||||
**Every boundary.** `gstack-ship-budget check --run <id> --step <done> --next <step> --reading <n>`.
|
||||
Before each dispatch batch, reserve the batch as one sum, one role per `DISPATCH:` line, then pass the printed id once
|
||||
(`READING` is the current counter reading; `RESERVATION_ID` is the id the check prints;
|
||||
(`READING` is the current counter reading; `RESERVATION_ID` is the check's `RESERVATION_ID:` line, copied whole;
|
||||
`--next` is the `BUDGET_NEXT:` value the batch's `gstack-review-packet build` printed, one
|
||||
role per packet, never packet names):
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Field-by-field reference: docs/ship-budget.md. Exit 0 continue or delegate, 3 st
|
||||
|
||||
**Every boundary.** `gstack-ship-budget check --run <id> --step <done> --next <step> --reading <n>`.
|
||||
Before each dispatch batch, reserve the batch as one sum, one role per `DISPATCH:` line, then pass the printed id once
|
||||
(`READING` is the current counter reading; `RESERVATION_ID` is the id the check prints;
|
||||
(`READING` is the current counter reading; `RESERVATION_ID` is the check's `RESERVATION_ID:` line, copied whole;
|
||||
`--next` is the `BUDGET_NEXT:` value the batch's `gstack-review-packet build` printed, one
|
||||
role per packet, never packet names):
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ never writes a doc. Under a token cap the dispatch is one program, like a review
|
||||
`gstack-ship-budget check --run <id> --step 14.5 --next "$BUDGET_NEXT"` (build's line), the reading `BEFORE`
|
||||
right before the reader starts, `tools.subagent.create`, a `tools.subagent.get` poll until it settles,
|
||||
the reading `AFTER`, then `gstack-ship-budget settle --run <id> --reservation <id> --dispatched-at <BEFORE> --reading <AFTER> --readers 1`,
|
||||
all in that same program; a settle from a later program is unmeasured.
|
||||
all in that same program (`--reservation` is check's `RESERVATION_ID:` line); a settle from a later program is unmeasured.
|
||||
|
||||
````text
|
||||
You are the /ship documentation auditor (Step 14.5). Read-only: edit no file, run no command, never commit, push or start another workflow. The parent applies your proposed edits mechanically and owns every decision you return. Audit id: <audit-id>. Mode: <mode>.
|
||||
|
||||
@@ -43,7 +43,7 @@ never writes a doc. Under a token cap the dispatch is one program, like a review
|
||||
`gstack-ship-budget check --run <id> --step 14.5 --next "$BUDGET_NEXT"` (build's line), the reading `BEFORE`
|
||||
right before the reader starts, `tools.subagent.create`, a `tools.subagent.get` poll until it settles,
|
||||
the reading `AFTER`, then `gstack-ship-budget settle --run <id> --reservation <id> --dispatched-at <BEFORE> --reading <AFTER> --readers 1`,
|
||||
all in that same program; a settle from a later program is unmeasured.
|
||||
all in that same program (`--reservation` is check's `RESERVATION_ID:` line); a settle from a later program is unmeasured.
|
||||
|
||||
````text
|
||||
You are the /ship documentation auditor (Step 14.5). Read-only: edit no file, run no command, never commit, push or start another workflow. The parent applies your proposed edits mechanically and owns every decision you return. Audit id: <audit-id>. Mode: <mode>.
|
||||
|
||||
@@ -105,7 +105,7 @@ This pass is static; defer product probes to Step 9.2.1.
|
||||
|
||||
1. Read `~/.claude/skills/gstack/review/checklist.md`. If the file cannot be read, **STOP** and report the error.
|
||||
|
||||
2. Before reading the diff, run `~/.claude/skills/gstack/bin/gstack-review-log --start review` and save its token as REVIEW_START (under a token cap, run Step 9.1's `gstack-review-packet build` and `gstack-ship-budget check` first, then `gstack-review-log --start review --reservation <id>`; 9.1's program then dispatches that batch with no second check or start; a later batch of the same Step 9 pass (the Red Team or an ADMIT remainder) takes no start, and `--finish REVIEW_START` settles it). Then run `git diff origin/<base>` (`git diff $RANGE_BASE` from pass 2 on). Read non-ignored untracked source files too (`git ls-files --others --exclude-standard`); the snapshot includes them.
|
||||
2. Before reading the diff, run `~/.claude/skills/gstack/bin/gstack-review-log --start review` and save its token as REVIEW_START (under a token cap, run Step 9.1's `gstack-review-packet build` and `gstack-ship-budget check` first, then `gstack-review-log --start review --reservation <id>` (`<id>` is check's `RESERVATION_ID:` line); 9.1's program then dispatches that batch with no second check or start; a later batch of the same Step 9 pass (the Red Team or an ADMIT remainder) takes no start, and `--finish REVIEW_START` settles it). Then run `git diff origin/<base>` (`git diff $RANGE_BASE` from pass 2 on). Read non-ignored untracked source files too (`git ls-files --others --exclude-standard`); the snapshot includes them.
|
||||
|
||||
Every pass captures a full token (no `--fix-range`), so the record binds the
|
||||
whole tree even when reviewers read only the range.
|
||||
|
||||
@@ -50,7 +50,7 @@ This pass is static; defer product probes to Step 9.2.1.
|
||||
|
||||
1. Read `~/.claude/skills/gstack/review/checklist.md`. If the file cannot be read, **STOP** and report the error.
|
||||
|
||||
2. Before reading the diff, run `~/.claude/skills/gstack/bin/gstack-review-log --start review` and save its token as REVIEW_START (under a token cap, run Step 9.1's `gstack-review-packet build` and `gstack-ship-budget check` first, then `gstack-review-log --start review --reservation <id>`; 9.1's program then dispatches that batch with no second check or start; a later batch of the same Step 9 pass (the Red Team or an ADMIT remainder) takes no start, and `--finish REVIEW_START` settles it). Then run `git diff origin/<base>` (`git diff $RANGE_BASE` from pass 2 on). Read non-ignored untracked source files too (`git ls-files --others --exclude-standard`); the snapshot includes them.
|
||||
2. Before reading the diff, run `~/.claude/skills/gstack/bin/gstack-review-log --start review` and save its token as REVIEW_START (under a token cap, run Step 9.1's `gstack-review-packet build` and `gstack-ship-budget check` first, then `gstack-review-log --start review --reservation <id>` (`<id>` is check's `RESERVATION_ID:` line); 9.1's program then dispatches that batch with no second check or start; a later batch of the same Step 9 pass (the Red Team or an ADMIT remainder) takes no start, and `--finish REVIEW_START` settles it). Then run `git diff origin/<base>` (`git diff $RANGE_BASE` from pass 2 on). Read non-ignored untracked source files too (`git ls-files --others --exclude-standard`); the snapshot includes them.
|
||||
|
||||
Every pass captures a full token (no `--fix-range`), so the record binds the
|
||||
whole tree even when reviewers read only the range.
|
||||
|
||||
@@ -139,6 +139,22 @@ describe('gstack-review-log --start under a token cap', () => {
|
||||
expect(close.code, close.out).toBe(0);
|
||||
});
|
||||
|
||||
// Value: protects=the reservation id is printed alone on its own line, so a child copies it without parsing the RESERVATION: line (gstack-evals #36 round 3: a misparsed id gave UNMEASURED, then BUDGET_CHECK_SKIPPED at close); fails_when=check prints no RESERVATION_ID: line, or it differs from RESERVATION: id=;
|
||||
// why_new=every test reads the id out of the RESERVATION: line; seam=none; no_claim=that the agent copies the right line
|
||||
test('check prints RESERVATION_ID: <id> alone beside the RESERVATION: line, for a dispatch and a step, and the id starts a review', () => {
|
||||
const h = fresh();
|
||||
const run = capped(h);
|
||||
const dispatch = h.sb(['check', '--run', run.run, '--step', '9', '--next', 'dispatch:specialist', '--reading', '0']);
|
||||
const step = h.sb(['check', '--run', run.run, '--step', '1', '--next', '2', '--reading', '0']);
|
||||
for (const out of [dispatch.out, step.out]) {
|
||||
const ids = out.split('\n').filter(l => l.startsWith('RESERVATION_ID:'));
|
||||
expect(ids).toHaveLength(1);
|
||||
expect(ids[0]).toBe(`RESERVATION_ID: ${h.field(out, 'RESERVATION', 'id')}`);
|
||||
}
|
||||
const id = /^RESERVATION_ID: (\S+)$/m.exec(dispatch.out)![1]!;
|
||||
expect(h.reviewLog(['--start', 'review', '--reservation', id]).code).toBe(0);
|
||||
});
|
||||
|
||||
test('close prints one BUDGET_CHECK_SKIPPED line per unreserved dispatch and ends incomplete', () => {
|
||||
const h = fresh();
|
||||
const run = capped(h);
|
||||
|
||||
@@ -69,6 +69,14 @@ describe('ship budget skill structure', () => {
|
||||
expect(capy).toMatch(/all in that same (?:execute )?program/);
|
||||
});
|
||||
|
||||
// Value: protects=every prose site that takes a reservation id reads the RESERVATION_ID: line, never a field cut from RESERVATION:; fails_when=a dispatch section or the Capy skill names the id without that line;
|
||||
// why_new=the line is new; seam=none; no_claim=the agent copies it
|
||||
test('the review pass, Steps 9, 11 and 14.5 and the Capy skill read the id from the RESERVATION_ID: line', () => {
|
||||
for (const rel of ['ship/sections/budget-handoff.md.tmpl', 'ship/sections/review-army.md.tmpl', 'ship/sections/adversarial.md.tmpl', 'ship/sections/documentation.md.tmpl', 'capy/skill/gstack/SKILL.md']) {
|
||||
expect(read(rel), rel).toContain('`RESERVATION_ID:`');
|
||||
}
|
||||
});
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user