Closes the remaining test gaps identified by the post-Phase-2 audit:
test/autopilot-fanout-wiring.test.ts (5 cases) — static-shape regression
for autopilot.ts ↔ dispatchPerSource. The fan-out helper itself has 27
unit tests; this file pins the WIRING in autopilot.ts:
- imports dispatchPerSource + resolveFanoutMax
- calls dispatchPerSource inside the shouldFullCycle branch (not the
targeted-plan path)
- updates lastFullCycleAt after dispatch
- does NOT regress to the pre-PR single-job dispatch (regex-grep guard
against the legacy `autopilot-cycle:${slot}` idempotency-key shape
reappearing in autopilot.ts)
Same canonical static-shape pattern as test/autopilot-supervisor-wiring.test.ts.
test/e2e/list-all-sources-postgres.test.ts (10 cases) — Postgres parity
for engine.listAllSources + updateSourceConfig. The PGLite path has
unit-level coverage; the Postgres path has separate impls (sql.json
serialization, sql.count semantics) that could drift. Specifically pins:
- returns rows, filters archived/localPath correctly
- JSONB config parses to object (autopilot reads last_full_cycle_at)
- default source sorts first
- updateSourceConfig: not-found returns false, patch merges, same-key
overwrites, idempotent on repeat
- jsonb_typeof regression: round-trip stores real JSONB object, NOT
a JSON-encoded string (feedback_postgres_jsonb_double_encode class)
test/e2e/autopilot-fanout-postgres.test.ts (6 cases) — end-to-end
integration on Postgres:
- 3 sources fan out as 3 distinct jobs with per-source idempotency keys
- re-dispatch within same slot dedupes (idempotency-key coalesce)
- last_full_cycle_at < 60min ago sources are skipped by gate
- end-to-end: updateSourceConfig → listAllSources → selectSourcesForDispatch
correctly classifies fresh sources
- fan-out cap honored (5 sources, fanoutMax=2 → 2 dispatched)
- empty federated brain falls back to legacy single-job dispatch
21 new test cases. Brings the v0.38 wave coverage to 132 unit + 16 e2e.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>