The Cache Decides What Is Saved
Written later and filed to this date, as part of filling in every day of the year.
The offline page of my history reader used to open with a promise: anything you’ve read before is cached and still here. Then it rendered your library, the two hundred most recent reads from the log the browser keeps, as a list of links. It was a reasonable thing to say and it was not true, in three separate ways, and each of the three was a different part of the app being trusted to answer a question that only one part could.
The first was the shell. The page itself was precached by the service worker, so it loaded offline, but the script that turns the page into a library was not on the precache list. Offline, the page came up and the island that fills it never hydrated, and the message it fell back to was “your library is empty.” A reader with two hundred reads was told they had none, by a page that had promised the opposite one line up.
The second was the list. The log of reads and the worker’s cache are two different stores that diverge by design. The log records everything you opened. The cache holds only the pages fetched while the worker controlled the tab, which excludes the first visit and anything opened before the worker installed. So the library listed every read as a link, and most of the links led back to the offline page, which listed them again. A loop with the reader inside it.
The third was the pictures. The article images come from a public commons and arrive cross-origin, which means the worker sees them as opaque responses, status zero, not marked ok. The cache rule stored only responses that were ok. Every cached read therefore rendered offline with every image broken, which is a strange way to keep a promise about history.
The fix is one decision and its consequences. The decision is the rule, and the module that implements it opens with it:
The offline library must ask the cache, not the log, which reads it can genuinely open.
So the library, in offline mode, enumerates the cache’s keys, maps each back to a read id, and treats that set as the truth. Reads in the log but not in the cache are still shown, labelled plainly as needing a connection, which is a list a reader can act on later instead of a list of trapdoors. The worker’s cache rule was widened to keep opaque image responses, because storing them is the only way a saved read shows its pictures. And the promise on the page became a smaller one: here is what is saved on this device.
What I take from it is the shape of the rule rather than its content. The old page had three sources of truth about one question and consulted the wrong one each time: the log for what exists, the cache’s ok flag for what to keep, the precache list for what to load. The new page has one. Where there are two stores for the same fact and they can disagree, the one that will actually be read from at the moment of need is the only one allowed to speak, and the other is demoted to a hint.