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

+13 -3
View File
@@ -13,6 +13,10 @@ const TOTAL = 250;
/** the plain account, capped below PAGE_SIZE (as diigo caps at 100) */
const CAPPED_WEBAPP = "fake-capped-webapp";
const CAP = 64;
/** the plain account, but its `total` claims 60 more items than it has
* (as diigo's does, observed 2026-10-07) */
const OVERSTATED_WEBAPP = "fake-overstated-webapp";
const OVERSTATEMENT = 60;
/** a second account, for date filters (goal 1d): 60 bookmarks, item n
* updated n-1 days + 1 hour before the call, in diigo's updated-desc
@@ -66,7 +70,7 @@ let calls = 0;
class FakeGet extends RpcTarget {
#path;
#params;
/** null (the plain account), "capped", "dated", or "deep" */
/** null (the plain account), "capped", "overstated", "dated", or "deep" */
#dated;
constructor(path, params, dated) {
super();
@@ -92,13 +96,19 @@ class FakeGet extends RpcTarget {
for (let n = (page - 1) * count + 1; n <= Math.min(page * count, total); n += 1) {
items.push(dated ? datedItem(n, now, this.#dated === "deep" ? "deep_dee" : "dated_dan") : item(n));
}
return JSON.stringify({ total, items });
return JSON.stringify({ total: this.#dated === "overstated" ? total + OVERSTATEMENT : total, items });
}
}
export class WebAppFactory extends WorkerEntrypoint {
async at(id) {
const kind = { [KNOWN_WEBAPP]: null, [CAPPED_WEBAPP]: "capped", [DATED_WEBAPP]: "dated", [DEEP_WEBAPP]: "deep" }[id];
const kind = {
[KNOWN_WEBAPP]: null,
[CAPPED_WEBAPP]: "capped",
[OVERSTATED_WEBAPP]: "overstated",
[DATED_WEBAPP]: "dated",
[DEEP_WEBAPP]: "deep",
}[id];
if (kind === undefined) throw new Error("fake webapp: unknown id");
return new FakeGet("", {}, kind);
}