The last E2 story — completes the E2 epic (F→O auto-sync, "safe but silent").
A "Catch up now" button forces an immediate shallow + deep sweep out of cadence,
so the DM doesn't wait for the next jittered tick before trusting the vault is
current. Gated by foundryPoll (default off).
- src/foundry-poll.ts catchUpNow(): cancels pending shallow + deep timers, runs
an immediate shallowPoll, then on completion immediately triggers a deepPoll
(no cadence wait). Debounced (returns {skipped: true} if either is in flight).
Reuses the same shallowPoll/deepPoll methods (no parallel code path — same
mapPool, same lock, same routing). On completion: activity panel summary
{shallow: {new, renamed, missing}, deep: {pulled, skipped, conflicts},
durationMs}, lastPoll updated, regular cadence resumes from now. Persistent
errors halt; transient errors logged.
- src/server.ts POST /api/foundry-poll/catchup (gated by foundryPoll; 404 when
off; 400 when poll not enabled): calls catchUpNow(), returns the summary.
- src/dashboard.html: "Catch up now" button in the live-new-entries panel header.
catchUpNow() POSTs + toasts the result (or "catch-up already running").
- tests/e2-6-catchup.test.ts: 5 tests — catchUpNow returns a summary with
durationMs; debounced (skipped if in flight); endpoint 200 with summary; 400
when poll not enabled; 404 when foundryPoll off.
tsc clean; 271 passing project-wide (18 pre-existing fixture-missing unchanged).
E2 epic COMPLETE (all 6 stories E2.1–E2.6).
Co-Authored-By: Claude <noreply@anthropic.com>