<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title>Cache Invalidation — Posts</title>
<id>https://www.cache-invalidation.com/posts/</id>
<link rel="alternate" href="https://www.cache-invalidation.com/posts/"/>
<link rel="self" type="application/atom+xml" href="https://www.cache-invalidation.com/posts/atom.xml"/>
<updated>2026-08-15T12:00:00Z</updated>
<author><name>Christoph Lühr</name></author>
<entry xml:base="https://www.cache-invalidation.com/posts/2026-08-15-cache-keys.html">
<title>What a cache key is really claiming</title>
<id>https://www.cache-invalidation.com/posts/2026-08-15-cache-keys.html</id>
<link rel="alternate" href="https://www.cache-invalidation.com/posts/2026-08-15-cache-keys.html"/>
<updated>2026-08-15T12:00:00Z</updated>
<summary type="text">A cache key is a promise, and it is worth reading it as one. It says: any two requests that hash to this string will accept the same answer. Everything that goes wrong with caching goes wrong because…</summary>
<content type="html">  &lt;p&gt;A cache key is a promise, and it is worth reading it as one. It says: any two requests that hash to this string will accept the same answer. Everything that goes wrong with caching goes wrong because that promise was made carelessly.&lt;/p&gt;
  &lt;h2 id=&quot;the-key-is-the-dependency-list&quot;&gt;The key is the dependency list&lt;/h2&gt;
  &lt;p&gt;Write out what a cached value was computed from — every input, every flag, every piece of ambient state the code read without mentioning it — and you have written the key. If the list is complete, the key is correct by construction. If something is missing, you have not built a cache, you have built a way of serving one user&amp;apos;s answer to another.&lt;/p&gt;
  &lt;p&gt;That reframing is most of the work. It turns an invalidation problem, which is about time and is therefore hard, into a naming problem, which is about being honest and is merely tedious.&lt;/p&gt;
  &lt;blockquote&gt;
    &lt;p&gt;Invalidation is a question about everything the cached answer was derived from, and about which of those inputs can change without anyone announcing it.&lt;/p&gt;
  &lt;/blockquote&gt;
  &lt;h2 id=&quot;what-that-looks-like-here&quot;&gt;What that looks like here&lt;/h2&gt;
  &lt;p&gt;The generator that built this page keys a rendered page on its own bytes, the config, the theme, and the set of icon files the capsule ships. That last one is not obvious, and it was not there at first: adding a favicon changes the head of every page, so a key that ignored it would serve pages from before the favicon existed, forever, with no way to notice.&lt;/p&gt;
  &lt;p&gt;Nothing in that key is a timestamp. A modification time answers a question nobody asked — it says when a file was touched, not whether what it says is still true — and a fresh checkout rewrites every one of them without changing a byte of content.&lt;/p&gt;
  &lt;ul role=&quot;list&quot;&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.cache-invalidation.com/gemtext.html&quot;&gt;The seven line types this site is built from&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.cache-invalidation.com/how-it-works.html&quot;&gt;How this page works, and why the markers are not really there&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;the-failure-mode-is-the-interesting-part&quot;&gt;The failure mode is the interesting part&lt;/h2&gt;
  &lt;p&gt;An under-specified key does not crash. It serves a wrong answer at full speed, with no error and no log line, and it keeps doing it until somebody notices by eye. That is why the honest move is to make the key say too much rather than too little: an over-specified key costs you a cache miss, which shows up in a graph, and an under-specified one costs you correctness, which does not.&lt;/p&gt;
  &lt;a href=&quot;https://www.cache-invalidation.com/posts/index.html&quot;&gt;Back to the posts&lt;/a&gt;</content>
</entry>
<entry xml:base="https://www.cache-invalidation.com/posts/2026-07-02-seven-line-types.html">
<title>Writing under seven line types</title>
<id>https://www.cache-invalidation.com/posts/2026-07-02-seven-line-types.html</id>
<link rel="alternate" href="https://www.cache-invalidation.com/posts/2026-07-02-seven-line-types.html"/>
<updated>2026-07-02T12:00:00Z</updated>
<summary type="text">Gemtext has seven kinds of line and no inline markup at all. No bold, no italic, no link inside a sentence, no footnote. After a few weeks of writing under that constraint the surprise is not what it…</summary>
<content type="html">  &lt;p&gt;Gemtext has seven kinds of line and no inline markup at all. No bold, no italic, no link inside a sentence, no footnote. After a few weeks of writing under that constraint the surprise is not what it costs. It is what it removes the temptation to do.&lt;/p&gt;
  &lt;h2 id=&quot;emphasis-has-to-be-earned&quot;&gt;Emphasis has to be earned&lt;/h2&gt;
  &lt;p&gt;With no way to set a word in bold, stress has to come from word order and from what you choose to say. A sentence that needs a bold word to land is usually a sentence that has not decided what it is about. The format will not let you paper over that, so you rewrite it instead.&lt;/p&gt;
  &lt;p&gt;The same goes for the aside in parentheses that wants to be a footnote. There are no footnotes. Either the thought belongs in the paragraph or it belongs in a different paragraph, and deciding which is the writing.&lt;/p&gt;
  &lt;h2 id=&quot;a-link-is-a-whole-line&quot;&gt;A link is a whole line&lt;/h2&gt;
  &lt;p&gt;This is the constraint with the widest blast radius. A link cannot sit inside a sentence, so every link stands alone with its own label — which means every label has to make sense read aloud, out of context, by somebody who cannot see what surrounds it.&lt;/p&gt;
  &lt;p&gt;That is exactly what accessibility guidelines ask of link text at their strictest level, arrived at here by accident rather than by effort. The format made the rule unavoidable before anyone thought to argue for it.&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;Links arrive in runs, so a run of them is a list, and a reader can be told how many there are&lt;/li&gt;
    &lt;li&gt;Every target clears a large touch area without any inline exception&lt;/li&gt;
    &lt;li&gt;Nothing depends on seeing a typeface change&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;what-it-is-bad-at&quot;&gt;What it is bad at&lt;/h2&gt;
  &lt;p&gt;It would be dishonest to only list the wins. Gemtext cannot quote its own syntax — a preformatted block is closed by the first fence inside it, so the one thing this page cannot show you is a fence. Tables do not exist. Anything with two axes has to become prose or a picture.&lt;/p&gt;
  &lt;p&gt;And the format has no place to put metadata, which is why the date on this post lives in the link line that points at it rather than in the file you are reading.&lt;/p&gt;
  &lt;a href=&quot;https://www.cache-invalidation.com/posts/index.html&quot;&gt;Back to the posts&lt;/a&gt;</content>
</entry>
</feed>
