ci+fix: run snapshot tests in CI and load .env only when recording

Holistic-review fixes for integration gaps the per-commit reviews missed:

- CI now runs `pnpm run test:snapshot` (a step after the coverage gate). It was
  wired into pre-push but not .github/workflows/ci.yml, so the RFC/AGENTS claim
  that snapshot replay runs in the default PR gate was only half-true — CI is
  the real gate.
- vitest.snapshot.config.ts loads the repo .env ONLY when DSH_SNAPSHOT=record.
  Loading it unconditionally contradicted the replay safety story (replay must
  never reach the network), and runScenario forwards process.env to the child.
  Non-ENOENT load errors now surface instead of being swallowed.
- start.ts: the graceful-shutdown comment said "RECORD runs" but the path
  applies to both snapshot modes (replay also closes stdin → dispose → exit).
- docs/development.md: list the new pre-push snapshot job and the CI snapshot
  gate.
This commit is contained in:
Tianyi Cui
2026-06-19 04:28:09 +08:00
parent f09cc81c03
commit 9a5a3835c8
4 changed files with 30 additions and 14 deletions

View File

@@ -45,12 +45,14 @@ await ctx.loader.create({
},
})
// Graceful shutdown for snapshot RECORD runs: when the client closes our stdin
// (it is done driving the session), dispose the whole context. Disposal awaits
// the agent-loop teardown and the persistence backend's final `session/flush`,
// so the recorded `.jsonl` is fully written before the process exits and the
// harness harvests it. (In a normal editor session stdin stays open for the
// connection's lifetime; the editor kills the process, so this never fires.)
// Graceful shutdown for snapshot runs (both replay and record): when the client
// closes our stdin (it is done driving the session), dispose the whole context.
// Disposal awaits the agent-loop teardown and the persistence backend's final
// `session/flush`, so the session `.jsonl` is fully written before the process
// exits and the harness harvests it (and the subprocess exits cleanly so the
// harness's waitForExit resolves). (In a normal editor session stdin stays open
// for the connection's lifetime; the editor kills the process, so this never
// fires.)
if (snapshotMode !== undefined) {
process.stdin.on('end', () => {
void ctx.fiber.dispose().then(() => { process.exit(0) })