import type { AssertableState } from "../utils/assertable-state"; import type { TestDefinition } from "../test-definition"; export const catchupCreateAndUpdateNotSkippedTest: TestDefinition = { description: "Client 1 disconnects (sync disabled). Client 0 creates a doc and " + "then updates it. When Client 1 reconnects, the server's catch-up " + "stream sends only the doc's *latest* version (the update), not " + "the full history. Client 1 must still pick up the doc — any handler " + "that gates the create-on-untracked path on a server-supplied " + "'is this the first version' flag would drop it (the latest version " + "is not the create), silently leaking the doc. The client treats " + "every untracked-doc RemoteChange as a fresh create.", clients: 2, steps: [ { type: "enable-sync", client: 0 }, { type: "enable-sync", client: 1 }, // Establish a baseline so Client 1's last_seen is non-zero before // we take it offline. This makes the bug genuinely about catch-up // missing the create rather than just an empty-vault first sync. { type: "create", client: 0, path: "warmup.md", content: "w\n" }, { type: "barrier" }, // Client 1 goes offline. { type: "disable-sync", client: 1 }, // Client 0 creates the doc (vault_update_id v_C, after Client 1's // watermark). Client 1 doesn't see this because it's offline. { type: "create", client: 0, path: "doc.md", content: "v1\n" }, // Wait for the create's HTTP to land before the update; otherwise // both writes are coalesced into a single POST and the server // never sees the doc as "create followed by update". { type: "sync", client: 0 }, // Client 0 updates the doc (vault_update_id v_X > v_C). The // server's `latest_document_versions` view now returns the // *update* row — the create row is no longer the latest. { type: "update", client: 0, path: "doc.md", content: "v1\nupdate\n" }, { type: "sync", client: 0 }, // Client 1 reconnects. Server's catch-up replays docs with // `vault_update_id > last_seen`. For doc.md it sends v_X; Client // 1 has no record of the doc, so it treats the RemoteChange as a // fresh create and downloads the latest content. { type: "enable-sync", client: 1 }, { type: "barrier" }, { type: "assert-consistent", verify: (state: AssertableState): void => { state.assertFileCount(2); state.assertFileExists("doc.md"); state.assertContent("doc.md", "v1\nupdate\n"); state.assertContent("warmup.md", "w\n"); } } ] };