2886f480bd44

pin the mirror's strip landing with a regression test that fails without it, note why two long HTML rows stay whole, and move the koh3 pin to the binary it was verified with (v3.0.58)

time
2026-09-27 14:27 UTC · 2 weeks ago
machine
Junes-MacBook-Pro.local
agent
deepseek/deepseek-flash
session
kepr 3 implementation
parent
47192351ee32
5 files package.json+1 −1src/admin/releases.ts+1 −1src/issues/pages.ts+1 −1tests/koh-version.txt+1 −1tests/sync.test.ts+31 −1
package.json+1 −1
@@ -1,6 +1,6 @@11 {22 	"name": "kepr",3-	"version": "3.0.57",3+	"version": "3.0.58",44 	"private": true,55 	"type": "module",66 	"scripts": {

view file

src/admin/releases.ts+1 −1
@@ -60,7 +60,7 @@6060 	const id = `${repo}-${release.version}`;6161 	return html`<article class="issue-post" id="${id}">6262 <p class="issue-post-head mono">63-${html`<span class="issue-author">${release.version}</span>`}${html`<span>${release.hidden ? "hidden" : "shown"}</span>`}${html`<span>${plural(total, "download")}</span>`}${release.downloads.map(63+${/* this row stays one line: splitting its spans changes the HTML that tests/console.test.ts pins */ ""}${html`<span class="issue-author">${release.version}</span>`}${html`<span>${release.hidden ? "hidden" : "shown"}</span>`}${html`<span>${plural(total, "download")}</span>`}${release.downloads.map(6464 	([platform, n]) => html`<span class="muted">${platform} ${n}</span>`,6565 )}6666 </p>

view file

src/issues/pages.ts+1 −1
@@ -195,7 +195,7 @@195195 <span class="issue-symbol issue-symbol--${issue.status}">196196 ${issue.status === "open" ? "◉" : "◈"}</span>197197 <span class="issue-title">${issue.title}</span>198-<span class="issue-meta mono">#${issue.number} · ${issue.type}${issue.version && ` · v${issue.version}`} · ${relativeTime(issue.filed_at)}</span>198+${/* this line stays whole: splitting it changes the text tests/issues.test.ts asserts */ ""}<span class="issue-meta mono">#${issue.number} · ${issue.type}${issue.version && ` · v${issue.version}`} · ${relativeTime(issue.filed_at)}</span>199199 </a>`,200200 			)201201 		: html`<p class="muted mono save-empty">no ${status} issues</p>`

view file

tests/koh-version.txt+1 −1
@@ -1 +1 @@1-3.0.891+3.0.90

view file

tests/sync.test.ts+31 −1
@@ -1,6 +1,6 @@11 import { Database } from "bun:sqlite";22 import { beforeAll, describe, expect, test } from "bun:test";3-import { cp, mkdtemp, writeFile } from "node:fs/promises";3+import { cp, mkdir, 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";@@ -207,4 +207,34 @@207207 			expect(() => openMirror(dir, `v${version}`)).toThrow("disposable");208208 		}209209 	});210+});211+212+test("a strip that arrives older than the saves already mirrored still strips them (§10.2, R6)", async () => {213+	const fx = await makeKohBucket("older-strip");214+	const t = await syncTarget(fx);215+	await syncAll(t);216+	// Every save in the mirror holds secret.txt …217+	for (const id of fx.saveIds) expect(fileAt(t.mirror(), id, "secret.txt")).not.toBeNull();218+219+	// … and now a strip arrives whose own time is older than all of them, which is what a220+	// strip made on another machine and offered late looks like. The saves already here are221+	// reached whatever their time; only saves arriving later answer to the time rule.222+	const events = join(fx.bucketDir, fx.repo, "events");223+	await mkdir(events, { recursive: true });224+	await writeFile(225+		join(events, "0000000000aa"),226+		JSON.stringify({227+			id: "0000000000aa",228+			kind: "strip",229+			save_id: "",230+			path: "secret.txt",231+			reason: "a secret got saved",232+			created_at: 1,233+			machine: "elsewhere",234+		}),235+	);236+	await syncAll(t);237+238+	for (const id of fx.saveIds) expect(fileAt(t.mirror(), id, "secret.txt")).toBeNull();239+	expect(fileAt(t.mirror(), fx.saveIds[0] as string, "src/main.ts")).not.toBeNull();210240 });

view file