fix(ship): the start probe stops on an unreadable start directory, runs once per stage, and logStart is validated; brief wording stays main's (GST-776)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-11-01 13:08:58 +00:00
1 parent a097560766
commit f9ff08110d
5 files changed
+41 -26

No files matched your search

+6 -10
View File
@@ -585,22 +585,18 @@ describe('the REVIEWED_TREE line as GBRA-218 readers wrote it (GST-776)', () =>
const top = fs.realpathSync(spawnSync('git', ['rev-parse', '--show-toplevel'], { cwd: ROOT, encoding: 'utf8', timeout: 30_000 }).stdout.trim());
const tree = spawnSync('git', ['rev-parse', 'HEAD^{tree}'], { cwd: ROOT, encoding: 'utf8', timeout: 30_000 }).stdout.trim();
const command = `cd '${top}' && echo "REVIEWED_TREE: $(git rev-parse 'HEAD^{tree}') $(git rev-parse --show-toplevel)"`;
// Value: protects=a reader that reviewed the right checkout is not failed for how it wrote its fingerprint; fails_when=the brief asks for "the line <command> prints" (two Sonnet 5.5 low readers then wrote `printed: REVIEWED_TREE: …` and were failed as reported="none"), or a `printed:` prefix lets a wrong tree through;
// why_new=GBRA-218 pass restarts on gstack 1.92.25.0; seam=lib/review-brief.ts workspaceParagraph and checkReviewedTree via gstack-review-dispatch collect; no_claim=that every model now writes the bare line
test('the brief asks for the bare line first and gives the command only as the way to get it', () => {
const p = workspaceParagraph(top);
expect(p).not.toContain('the line `cd');
const bare = p.indexOf('`REVIEWED_TREE: <tree> <toplevel>`');
expect(bare).toBeGreaterThan(0);
expect(p.indexOf(command)).toBeGreaterThan(bare);
});
// Value: protects=a reader that reviewed the right checkout is not failed for how it wrote its fingerprint; fails_when=a reply that echoes the command and then writes `printed: REVIEWED_TREE: …` (two Sonnet 5.5 low readers) is failed as reported="none", or a `printed:` label lets a wrong tree, toplevel or other label through;
// why_new=GBRA-218 pass restarts on gstack 1.92.25.0; seam=lib/review-brief.ts checkReviewedTree via gstack-review-dispatch collect; no_claim=the brief's wording, which stays main's until a no-loss replay
test('the echoed command then a printed: line is read; the same shape with a wrong tree or checkout is still refused', () => {
const reply = (fingerprint: string) => `${command}\nprinted: REVIEWED_TREE: ${fingerprint}\nNO FINDINGS\n`;
expect(checkReviewedTree(reply(`${tree} ${top}`), `${tree} ${top}`)).toMatchObject({ ok: true });
expect(checkReviewedTree(reply(`${'b'.repeat(40)} ${top}`), `${tree} ${top}`)).toMatchObject({ ok: false, moved: true, reported: `${'b'.repeat(40)} ${top}` });
expect(checkReviewedTree(reply(`${tree} /elsewhere`), `${tree} ${top}`)).toMatchObject({ ok: false, moved: false, reported: `${tree} /elsewhere` });
expect(checkReviewedTree(`Note: REVIEWED_TREE: ${tree} ${top}\nNO FINDINGS`, `${tree} ${top}`).reported).toBe('none');
for (const line of ['`printed: REVIEWED_TREE: ' + tree + ' ' + top + '`', `**Printed:** REVIEWED_TREE: ${tree} ${top}`]) {
expect(checkReviewedTree(line, `${tree} ${top}`).ok, line).toBe(true);
expect(checkReviewedTree(line.replace(tree, 'c'.repeat(40)), `${tree} ${top}`).ok, line).toBe(false);
}
const out = tmp();
const ledger = path.join(out, 'review-ledger.jsonl');
+14
View File
@@ -594,6 +594,20 @@ describe('readers on a shared machine review the checkout the pass ships (GST-48
expect(started.creates.length).toBeGreaterThan(0);
const outside = host(path.dirname(wt), env);
expect(await runPass(outside, { base: 'main', out: path.join(wt, '.state/run/p3'), pass: 'w0p3', cwd: wt, planFlags: ['--depth-floor', 'full'] })).toContain('NEXT: judge (Phase 4)');
const broken = tmp('rp-broken-');
fs.writeFileSync(path.join(broken, '.git'), 'garbage\n');
const unreadable = host(broken, env);
expect(await runPass(unreadable, { base: 'main', out: path.join(wt, '.state/run/p4'), pass: 'w0p4', cwd: wt, planFlags: ['--depth-floor', 'full'] })).toContain('STOP: cannot read the directory readers on the shared machine start in: fatal: invalid gitfile format');
expect(unreadable.creates.length).toBe(0);
const slow = host(wt, env, { pollsToFinish: 30 });
let probes = 0;
const bash = slow.tools.capy.bash;
slow.tools.capy.bash = async (a) => { if (a.command.startsWith('if d=$(git rev-parse')) probes++; return bash(a); };
const input = { base: 'main', out: path.join(wt, '.state/run/p5'), pass: 'w0p5', cwd: wt, planFlags: ['--depth-floor', 'full'] };
expect(await runPass(slow, input)).toContain('NEXT: poll');
expect(await runPass(slow, input)).toContain('NEXT: poll');
expect(probes).toBe(1);
expect(await runPass(host(wt, env), { ...input, logStart: [7] })).toStartWith('STOP: input.logStart must be a list');
}, 240_000);
// Value: protects=a reader that never left the machine's default checkout cannot hand /ship a review of another tree; fails_when=collect merges a reply whose REVIEWED_TREE names the primary checkout while the pass ships a worktree, or a reply with no such line;