fd5e11c6a76c
test that a whole-history strip already in the mirror strips late-arriving saves made before it and spares one made after (v3.0.47)
- time
- 2026-09-26 21:26 UTC · 2 weeks ago
- machine
- Junes-MacBook-Pro.local
- agent
- claude-opus-5-5
- session
- kepr 3 implementation
- parent
- 009e5c4064e1
↓ kepr-fd5e11c6.tar.gzatlas at this save
files changed2 files
package.json+1 −1tests/sync.test.ts+46 −1package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "kepr",3- "version": "3.0.46",3+ "version": "3.0.47",44 "private": true,55 "type": "module",66 "scripts": {tests/sync.test.ts+46 −1
@@ -1,6 +1,6 @@11 import { Database } from "bun:sqlite";22 import { beforeAll, describe, expect, test } from "bun:test";3-import { mkdtemp, writeFile } from "node:fs/promises";3+import { cp, mkdtemp, writeFile } from "node:fs/promises";44 import { tmpdir } from "node:os";55 import { join } from "node:path";66 import { openBucket } from "../src/bucket/reader.ts";@@ -143,6 +143,51 @@143143 last_sync_error: string;144144 };145145 expect(row.last_sync_error).toContain('remote format "koh-remote 2"');146+});147+148+test("a whole-history strip in the mirror reaches arriving saves made up to its time only (§10.2)", async () => {149+ const fx = await makeKohBucket("late");150+ const koh = (...args: string[]) =>151+ Bun.spawnSync(["koh3", ...args], {152+ cwd: fx.repoDir,153+ env: { PATH: process.env.PATH, HOME: join(fx.repoDir, "../../home"), NO_COLOR: "1" },154+ });155+ // Every save so far holds secret.txt. These pre-strip records stand in for saves another machine156+ // made before the strip and offers after it: koh3 rewrites only the records already on the remote.157+ const before = await mkdtemp(join(tmpdir(), "kepr-before-"));158+ await cp(join(fx.bucketDir, fx.repo), before, { recursive: true });159+ expect(await Bun.file(join(before, "saves", fx.saveIds[0] as string)).text()).toContain(160+ '"secret.txt"',161+ );162+ Bun.sleepSync(1100);163+ await fx.strip("secret.txt");164+ Bun.sleepSync(1100);165+ // Strip leaves the working tree alone, so this save holds secret.txt again, made after the strip.166+ await writeFile(join(fx.repoDir, "after.txt"), "after\n");167+ koh("save", "save again after the strip");168+ koh("offer");169+ const after = JSON.parse(koh("log", "--json").stdout.toString()).head_id as string;170+171+ const view = await mkdtemp(join(tmpdir(), "kepr-view-"));172+ const viewRepo = join(view, fx.repo);173+ await cp(before, viewRepo, { recursive: true });174+ await cp(join(fx.bucketDir, fx.repo, "events"), join(viewRepo, "events"), { recursive: true });175+ // First sync: the remote as it stood at the first save, plus the strip event.176+ await writeFile(join(viewRepo, "head"), fx.saveIds[3] as string);177+ const t = await syncTarget({ ...fx, bucketDir: view });178+ await syncAll(t);179+ expect(t.mirror().query("SELECT count(*) AS n FROM events WHERE kind = 'strip'").get()).toEqual({180+ n: 1,181+ });182+ // Then the later saves arrive: the pre-strip ones as first written, and the one made after.183+ await cp(join(fx.bucketDir, fx.repo), viewRepo, { recursive: true });184+ for (const id of fx.saveIds.slice(0, 3)) {185+ await cp(join(before, "saves", id), join(viewRepo, "saves", id));186+ }187+ await syncAll(t);188+ expect(headId(t.mirror())).toBe(after);189+ for (const id of fx.saveIds) expect(fileAt(t.mirror(), id, "secret.txt")).toBeNull();190+ expect(fileAt(t.mirror(), after, "secret.txt")).not.toBeNull();146191 });147192 148193 describe("the mirror's schema version", () => {