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
2 files package.json+1 −1tests/sync.test.ts+46 −1
package.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": {

view file

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", () => {

view file