diigo-cache: a short page before the stated end peeks at the next page

The real fill failed at "diigo returned 44 items for page 167 of 168":
diigo's `total` overstates what load_user_items returns, so the true
last page looked short and the guard took it for a capped page size.

A short page that isn't the last by `total` now fetches the next page
(paced like any diigo call): empty means the data really ends there —
accepted, with a "total-overstated" notice logging total vs actual;
anything else means items would be skipped — refused, the message now
giving both counts. The fake gains an account whose total claims 60
more than it has; a fill on it runs to done.

Generated-by: Claude Opus 5.5
This commit is contained in:
dckc committed 2026-10-07 05:04:04 -05:00
1 parent f4b68f1b59
commit f5d57f73d3
4 files changed
+65 -17

No files matched your search

+16 -1
View File
@@ -78,7 +78,7 @@ describe("page size", () => {
// settle the RPC promise ourselves: expect().rejects on a DO stub's
// promise leaves the rejection unhandled
const failure = () => stub.page(1, PAGE_SIZE).then(() => null, (e: unknown) => String(e));
expect(await failure()).toMatch(/returned 64 items for page 1 of 3 \(asked for 100\)/);
expect(await failure()).toMatch(/returned 64 items for page 1 of 3 \(asked for 100\), then 64 for page 2/);
expect(spy.mock.calls.map((c) => c[0]).filter((e) => e?.outcome === "short-page")).toHaveLength(1);
// nothing was stored: asking again refuses again
expect(await failure()).toMatch(/page size not honored/);
@@ -87,6 +87,21 @@ describe("page size", () => {
}
});
it("a short page whose next page is empty is the real end: diigo's total overstated, noted not refused", async () => {
const spy = vi.spyOn(console, "log");
try {
const stub = testEnv.CACHE_DO.get(testEnv.CACHE_DO.newUniqueId());
await stub.setup({ webappId: "fake-overstated-webapp" });
// 250 items claimed as 310: page 3 holds the last 50, "of 4"
const page = await stub.page(3, PAGE_SIZE);
expect(page.items).toHaveLength(50);
const notes = spy.mock.calls.map((c) => c[0]).filter((e) => e?.outcome === "total-overstated");
expect(notes).toEqual([expect.objectContaining({ page: 3, total: 310, actual: 250 })]);
} finally {
spy.mockRestore();
}
});
it("the last page may be short", async () => {
const stub = testEnv.CACHE_DO.get(testEnv.CACHE_DO.newUniqueId());
await stub.setup({ webappId: WEBAPP_ID });