From a5f6e14df3a1ec7324437784e21421759b7cc823 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 17 Oct 2026 20:36:00 +0000 Subject: [PATCH] fix(docs-candidate): the compare reject never sends an agent to re-snapshot after the child audit (W3-2) A post-audit snapshot over the candidate replaces the before-audit baseline, so the ownership check would compare current files with themselves. The fix line now says the candidate must be the record the Prepare snapshot wrote, that the Prepare snapshot is rerun only before dispatching the child audit, and that the post-child snapshot uses a different --out (-post.json). The helper test pins the text. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- bin/gstack-docs-candidate | 5 ++++- test/gstack-docs-candidate.test.ts | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bin/gstack-docs-candidate b/bin/gstack-docs-candidate index dee6c867b..d8dfe40a0 100755 --- a/bin/gstack-docs-candidate +++ b/bin/gstack-docs-candidate @@ -139,7 +139,10 @@ function main(argv: string[]): void { const problems = record === undefined ? ['not valid JSON'] : recordProblems(record); if (problems.length) { throw new Error(`${file} is not a gstack-docs-candidate record: ${problems.join('; ')}. ` - + 'Fix: run gstack-docs-candidate snapshot --out --audit-id --mode edit --base and compare the file it writes.'); + + 'Fix: the candidate must be the record the Prepare snapshot wrote. To rebuild it, rerun the Prepare snapshot ' + + '(gstack-docs-candidate snapshot --out --audit-id --mode edit --base ...) only before dispatching ' + + 'the child audit. After the audit, never snapshot over it: the post-child snapshot uses a different --out ' + + '(-post.json).'); } process.chdir(fs.realpathSync(git(['rev-parse', '--show-toplevel']).trim())); const now = state(record.base); diff --git a/test/gstack-docs-candidate.test.ts b/test/gstack-docs-candidate.test.ts index 3e163da1a..296d3d60b 100644 --- a/test/gstack-docs-candidate.test.ts +++ b/test/gstack-docs-candidate.test.ts @@ -123,7 +123,9 @@ describe('gstack-docs-candidate', () => { test('compare names the record path, each missing or wrong field and the snapshot fix, keeping exit 1', () => { const { dir, root } = repo(); - const fix = 'Fix: run gstack-docs-candidate snapshot --out --audit-id --mode edit --base and compare the file it writes.'; + // A post-audit snapshot over the candidate would replace the before-audit baseline, so the ownership + // check would compare current files with themselves; the fix line must never send an agent there. + const fix = 'Fix: the candidate must be the record the Prepare snapshot wrote. To rebuild it, rerun the Prepare snapshot (gstack-docs-candidate snapshot --out --audit-id --mode edit --base ...) only before dispatching the child audit. After the audit, never snapshot over it: the post-child snapshot uses a different --out (-post.json).'; const cases: Array<[string, string, string[]]> = [ ['legacy.json', JSON.stringify({ audit_id: 'a', base_sha: 'x', content_hashes: {} }), ['missing or wrong schema_version (want 1)', 'missing or wrong base (want the base commit SHA string)', 'missing or wrong hashes (want an object of path -> blob id)']],