Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7949a51
test(perf): benchmark the web build against local and deployed hosts
adulbrich Jul 31, 2026
1c055df
docs: design for persisting RAW conversions across reloads
adulbrich Jul 31, 2026
36ff2ed
docs: implementation plan for the persistent RAW cache
adulbrich Jul 31, 2026
96a273c
docs: settle the OPFS write path by measurement, and tighten two tests
adulbrich Jul 31, 2026
6458197
test(storage): probe OPFS and IndexedDB across every host
adulbrich Jul 31, 2026
588ac72
style: sort object keys in the benchmark report
adulbrich Jul 31, 2026
ce2b127
test(storage): probe chunked OPFS writes, and correct a confounded We…
adulbrich Jul 31, 2026
7d27026
fix(storage): correct the WebKit finding and harden the probe per review
adulbrich Jul 31, 2026
3411e45
refactor: extract sha256Hex so worker code can hash
adulbrich Jul 31, 2026
dda75c1
feat(storage): add updateDocument for atomic read-modify-write
adulbrich Jul 31, 2026
2dfb9ce
feat(raw): add the persistent cache tier, storage injected
adulbrich Jul 31, 2026
b4e0f45
feat(raw): reconcile the cache index against the blob store
adulbrich Jul 31, 2026
f8aff94
feat(raw): derive the cache key from content and tool identity
adulbrich Jul 31, 2026
976f3a6
fix(raw): guard the tool tag against a dropped flag set and a missing…
adulbrich Jul 31, 2026
eb0aec8
docs: the probe chose IndexedDB, so Task 7 becomes IndexedDB
adulbrich Jul 31, 2026
086c313
feat(raw): back the persistent cache with IndexedDB
adulbrich Jul 31, 2026
3a01297
docs: point Tasks 8-10 at the IndexedDB blob store
adulbrich Jul 31, 2026
390bbf2
feat(raw): answer conversions from the persistent cache
adulbrich Jul 31, 2026
4a531b9
fix(raw): close the onblocked deadlock and a rejected-connection cach…
adulbrich Jul 31, 2026
0abeb00
feat(settings): show and clear the RAW conversion cache
adulbrich Jul 31, 2026
47fcfa9
fix(raw): clear the cached connection before onversionchange closes i…
adulbrich Jul 31, 2026
b8fedf9
fix(raw): make clear() honest about what it actually reclaimed
adulbrich Jul 31, 2026
dde6e0d
test(perf): measure that a reload reuses converted frames
adulbrich Jul 31, 2026
a110b6d
docs(perf): say what the control run does and does not settle
adulbrich Jul 31, 2026
ceb76b1
fix: apply final whole-branch review findings (F1-F3) before merge
adulbrich Aug 1, 2026
a797c8c
fix(storage): stop the probe failing on the backend it rejected
adulbrich Aug 1, 2026
d28d5ac
docs(storage): match the design doc's WebKitGTK row to the CI run it …
adulbrich Aug 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 43 additions & 12 deletions __tests__/app-storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,42 @@ import { describe, expect, it } from "@jest/globals";

const documents = new Map<string, unknown>();

jest.mock("../src/lib/storage/kv", () => ({
getDocument: (key: string) => {
const value = documents.get(key);
if (value === "THROW") {
return Promise.reject(new Error("store unavailable"));
jest.mock("../src/lib/storage/kv", () => {
// A real subclass, not a bare object shape: F1's fix to `readJson` tells
// this class apart with `instanceof`, and a mock that only matched by
// duck-typing would leave that check untested against the one thing it
// actually has to distinguish. Assigned rather than declared with `class
// DatabaseVersionError`, which would shadow the real export this file also
// imports by that name for its own assertions.
const MockDatabaseVersionError = class extends Error {
constructor() {
super("stored data is newer than this build can open");
this.name = "DatabaseVersionError";
}
return Promise.resolve(value);
},
putDocument: (key: string, value: unknown) => {
documents.set(key, value);
return Promise.resolve();
},
}));
};
return {
DatabaseVersionError: MockDatabaseVersionError,
getDocument: (key: string) => {
const value = documents.get(key);
if (value === "THROW") {
return Promise.reject(new Error("store unavailable"));
}
if (value === "VERSION_ERROR") {
return Promise.reject(new MockDatabaseVersionError());
}
return Promise.resolve(value);
},
putDocument: (key: string, value: unknown) => {
documents.set(key, value);
return Promise.resolve();
},
};
});

declare const jest: typeof import("@jest/globals").jest;

import { readJson, STORAGE_VERSION, writeJson } from "../src/lib/app-storage";
import { DatabaseVersionError } from "../src/lib/storage/kv";

describe("app storage", () => {
it("round-trips a value and stamps the version", async () => {
Expand Down Expand Up @@ -62,4 +81,16 @@ describe("app storage", () => {
runs: [],
});
});

it("rethrows DatabaseVersionError instead of returning the fallback", async () => {
// F1: a stored-data-is-newer-than-this-build condition is not "nothing
// stored badly" -- the data is intact, and papering over it with the
// fallback is what used to make a rolled-back deploy render as an empty
// app with nothing to explain why.
documents.set("history/newer.json", "VERSION_ERROR");

await expect(
readJson("history/newer.json", { runs: [] })
).rejects.toBeInstanceOf(DatabaseVersionError);
});
});
Loading
Loading