diff --git a/doc/plans/2026-10-24-recurring-server-sleep-stack.md b/doc/plans/2026-10-24-recurring-server-sleep-stack.md index 6170fb203df..5b8d1134f00 100644 --- a/doc/plans/2026-10-24-recurring-server-sleep-stack.md +++ b/doc/plans/2026-10-24-recurring-server-sleep-stack.md @@ -1835,3 +1835,13 @@ settlement. The new source guard excludes this duty from periodic maintenance. Full local acceptance, remote review/checks and publication are pending here. This supersedes the audit-only slice-32 status above. All older stack gates and every remaining original obligation remain required; no PR is merged. + +Slice 32 is now draft [#17651](https://github.com/paperclipai/paperclip/pull/17651). +Initial workspace types/build pass; full chat/startup acceptance passes 1,511 of +1,512, with a prior retry-notice test fake-clock CONNECT_TIMEOUT retained and +corrected. Initial CI passes 51 gates but fails a plugin test at a cron boundary +and its aggregate. A controlled timestamp diagnostic establishes an additional +owed cron occurrence; fixing that fixture clock passes all 28 plugin tests. +Thirteen selected chat lifecycle cases pass after the retry-notice wait fix. +Initial Greptile is 5/5 without findings. Fresh full acceptance and corrected-head +remote gates remain required; see the slice-32 audit for all retained failures. diff --git a/doc/plans/2026-10-25-terminal-confirmation-sleep-audit.md b/doc/plans/2026-10-25-terminal-confirmation-sleep-audit.md index 129e0bbfa72..6e30190f032 100644 --- a/doc/plans/2026-10-25-terminal-confirmation-sleep-audit.md +++ b/doc/plans/2026-10-25-terminal-confirmation-sleep-audit.md @@ -175,3 +175,43 @@ process loss. concurrency test was added. A final typecheck is still required. - Quiet assertions advance 120 seconds and count root database select/transaction calls after startup and settlement. They do not establish provider suspension. + +## Broad verification and test-clock corrections + +At implementation head `aeaaed7b3e17e1377433165a38fef558acacb631`, workspace +`pnpm -r typecheck` and `pnpm build` passed. The fresh full chat/startup run passed +1,511 of 1,512 tests in 450.49 seconds (`/tmp/sleep32-full-chat.log`, database +`paperclip_sleep32_full_20261025_test`). Every new confirmation test passed. The +old failed-retry notice test's disabled case captured a real +`CONNECT_TIMEOUT localhost:55438` while its result wait advanced fake time by +30 seconds during DB work. The prior slice had corrected a different wait loop; +this remaining jump is now 10ms, with explicit advancement to the saved resume +deadline. Strict error and quiet assertions remain. + +Initial remote CI passed 51 checks but failed server shard 4/12 and the dependent +aggregate. The failed test was `plugin-scheduled-work.test.ts`, independent jobs +while completion persistence is unavailable: it expected two runs and observed +four. Direct job log: `/tmp/sleep32-ci-server4-direct.log`, run 40228214324, +job 121274198575. A controlled test clock at 19:59:55 reproduced an extra run +(`/tmp/sleep32-plugin-hour-boundary-before.log`). Added diagnostic timestamps +showed the same job's original owed timestamp at 19:59:54 and another legitimate +cron occurrence at 20:00:00, rather than replay of one occurrence +(`/tmp/sleep32-plugin-hour-boundary-diagnostic.log`). The CI log did not retain +those per-run scheduled timestamps; the controlled reproduction establishes the +failure mechanism, not every timing detail of that CI execution. + +The final plugin correction fixes its test clock at 12:10:00 before each case. +An intermediate experiment also reduced its wait steps to 10ms; that prevented +its existing 30-second startup/retry deadlines from being reached and cascaded +into fixture cleanup failures (27 plugin cases failed in +`/tmp/sleep32-check-fixes.log`). Those step changes were reverted. The same +combined run passed all 13 selected chat lifecycle cases, including the five +corrected retry-notice cases. The final one-line plugin clock fix passes all 28 +plugin scheduling tests on fresh `paperclip_sleep32_plugin_fixed_20261025_test` +(`/tmp/sleep32-plugin-fixed.log`). No production scheduling code was changed for +these two test failures. Earlier databases and logs are retained. + +The initial implementation received Greptile 5/5 with no inline findings. The +corrected head still requires a fresh full chat/startup run, final typecheck, +and new remote checks/review. No unchanged-job retry was used. The PR is +[#17651](https://github.com/paperclipai/paperclip/pull/17651), still draft. diff --git a/server/src/__tests__/chat-channels.integration.test.ts b/server/src/__tests__/chat-channels.integration.test.ts index 6c5fd9a18eb..eb993ba498e 100644 --- a/server/src/__tests__/chat-channels.integration.test.ts +++ b/server/src/__tests__/chat-channels.integration.test.ts @@ -62975,6 +62975,7 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => { await vi.waitFor(() => expect(idleWorkSnapshot().active).toBe(0)); expect(await readChatPublicationsByEndpointId(context.endpoint.id)).toHaveLength(0); await quiet(); canRun = true; + if (coordinator.nextWakeAt() !== null) await vi.advanceTimersByTimeAsync(Math.max(0, coordinator.nextWakeAt()! - Date.now())); if (mode === "stopped") { await context.service.processPublicationMaintenance(); expect(await readChatPublicationsByEndpointId(context.endpoint.id)).toHaveLength(0); @@ -62984,7 +62985,7 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => { } } await vi.waitFor(async () => { - await vi.advanceTimersByTimeAsync(30_000); + await vi.advanceTimersByTimeAsync(10); expect(await readChatPublicationsByEndpointId(context.endpoint.id)).toEqual([expect.objectContaining({ payload: mode === "disabled" ? { text: "This retry was not started. Open the task in Paperclip for details.", progressState: "failed" } diff --git a/server/src/__tests__/plugin-scheduled-work.test.ts b/server/src/__tests__/plugin-scheduled-work.test.ts index 48fb5c41b84..6bee3f920d5 100644 --- a/server/src/__tests__/plugin-scheduled-work.test.ts +++ b/server/src/__tests__/plugin-scheduled-work.test.ts @@ -34,6 +34,7 @@ const support = external ? { supported: true } : await getEmbeddedPostgresTestSu await db.insert(plugins).values({ id: pluginId, pluginKey: pluginId, packageName: pluginId, version: "1.0.0", manifestJson: {} as never }); await Promise.all(Array.from({ length: 6 }, () => db.execute(sql`select pg_sleep(0.01)`))); vi.useFakeTimers({ toFake: ["Date", "setTimeout", "clearTimeout", "setInterval", "clearInterval"], shouldAdvanceTime: true }); + vi.setSystemTime(new Date("2026-10-25T12:10:00.000Z")); }); afterEach(async () => { await scheduler?.stop(); await coordinator?.stop(); scheduler = undefined; coordinator = undefined;