fix: a failed shadow publish journals under the run lock and never throws (wave browse review pass 2)

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-02 09:24:12 +00:00
1 parent bd8561dcbf
commit e7a429df7e
2 files changed
+15 -2

No files matched your search

+6 -2
View File
@@ -417,8 +417,12 @@ function publish(out: string, claim: ShadowClaim, r: { rows?: Array<Record<strin
}, { waitMs: RELOCK_MS });
} catch (e: any) {
const code = e instanceof RunError && e.code === 'RUN_LOCKED' ? 'locked' : 'internal';
if (!resultRow(readJournal(out), rev)) journal(out, { event: 'shadow_failed', gate_rev: rev, code, detail: String(e?.message ?? e).slice(0, 500), attempts, usd, retrospective: claim.retrospective });
dropLease(out, rev);
try {
withRunLock(out, () => {
if (!resultRow(readJournal(out), rev) && !fs.existsSync(recordFile(out, rev))) journal(out, { event: 'shadow_failed', gate_rev: rev, code, detail: String(e?.message ?? e).slice(0, 500), attempts, usd, retrospective: claim.retrospective });
dropLease(out, rev);
}, { waitMs: 2_000 });
} catch { /* still locked: the lease expires and the next command settles the revision */ }
return { status: 'failed', code, line: `SHADOW: failed ${code} (${e?.message ?? e}); the gate stands` };
}
}
+9
View File
@@ -292,6 +292,15 @@ describe('runShadow: retry, truncation, failures and the deadline', async () =>
expect(claimShadow(out)).toEqual({});
expect(f.requests().length).toBe(1);
});
test('runShadow never throws when the journal cannot be appended', async () => {
const f = await fake('journal-readonly', [{ mode: 'valid' }]);
const out = gateRun();
const { claim } = claimShadow(out);
fs.chmodSync(path.join(out, 'attempts.jsonl'), 0o444);
try {
expect(await runShadow(out, claim!, { env: { ...process.env, ...f.env } })).toMatchObject({ status: 'failed' });
} finally { fs.chmodSync(path.join(out, 'attempts.jsonl'), 0o644); }
});
test('a record already published makes a later claim a no-op: no second call is paid', async () => {
const { f, out } = await shadowed('noop', [{ mode: 'valid' }]);
const before = fs.readFileSync(recordFile(out, 1));