Executable Knowledge: Cases Episode 01

No-cache is not no-store
Three cached pages and one private account page. Two HTTP directives that sound alike, and an answer for each that shows the rule it came from.
5 min5 cases
Jump to an Arxo answer
AI-generated podcast with synthetic hosts and AI-generated music. Every verdict and its stated grounds come from a recorded Arxo run; the facts, full answers and hashes are below.
Transcript
Plain textSarahRoger, a question for every web developer listening. You put no-cache on a response. Did you just tell the cache not to keep it?
RogerMost people think so. Today we find out what you actually told it.
RogerQuick housekeeping first. We're both synthetic voices, the music is generated too, and so is this show. The answers aren't invented, though. Every result you'll hear comes from a recorded Arxo run, and the facts and hashes for each one are in the show notes.
SarahShow notes. Got it.
RogerThis is Executable Knowledge: Cases.
RogerPicture yourself setting cache headers for a site. Two directives look almost identical: no-cache and no-store. The rules come from RFC 9111, the HTTP caching standard. We loaded the two sections that matter into a small Arxo package, and we'll hand it five cases.
SarahWhat does a cache do by default?
RogerEvery response here is a plain GET that came back 200. By default the cache may keep it, and reuse it while it's fresh. The package even calls that rule reuse while fresh.
SarahStart easy, then.
RogerThe home page. Fresh, and sent without any directives.
Arxo answerResult: true. Rule applied: Reuse While Fresh.
SarahA yes, from the rule you just named.
RogerNow the news page. Also fresh. But it was sent with no-cache.
SarahAnd this is where I'd say: no-cache, so it isn't cached at all. Right?
Arxo answerResult: false.
RogerNo reuse. So you're half right. But listen to how it lost.
Arxo answerReuse While Fresh is defeated by No Cache Needs Validation, by priority.
SarahSo the reuse rule actually fired... and then lost?
RogerIt fired, and it was defeated by priority. And the rule that beat it says what it wants, right in its name.
Arxo answerRule applied: No Cache Needs Validation.
SarahNo cache needs validation. So not never. Just not without asking first.
RogerExactly. Not without checking with the origin server first.
SarahSo what happens when the cache does check?
RogerThat's the prices page. No-cache again, but this time the cache has validated the response with the origin.
Arxo answerResult: true. Rule applied: Reuse After Validation.
SarahBack to yes.
RogerAnd this one stacks two priorities. Listen.
Arxo answerNo Cache Needs Validation is defeated by Reuse After Validation, by priority. Reuse While Fresh is defeated by No Cache Needs Validation, by priority.
RogerValidation beats no-cache. No-cache beats plain freshness. That's all no-cache ever said: reuse, but only after validation.
SarahOkay. Then what's no-store for?
RogerA different kind of answer entirely. A proxy receives a private account page, sent with no-store. Nothing gets switched off here. The package sets up a prohibition, addressed to the proxy, from the day the response arrived.
Arxo answerProhibition: store response, on the proxy. Status: active.
SarahActive. So nothing has gone wrong yet.
RogerNothing yet. Last case. Same proxy, same page, and a record showing the proxy stored it anyway.
Arxo answerProhibition: store response, on the proxy. Status: violated.
SarahViolated.
RogerViolated, and the answer names who was bound by it: the proxy. That's the difference in one line. No-cache is about when a cache may reuse a response. No-store makes storing it a breach.
SarahSo no-cache means not without asking. And no-store means someone is on the hook.
RogerBefore you pick a directive, name the action you want to control: keeping the response, or using it again. Five cases, each with the rule that decided it. The facts, the full answers and the hashes are in the show notes.
SarahNext time: castling through a square nobody checked.
RogerBoth voices synthetic, every answer from a real run. This was Executable Knowledge: Cases, from Arxo.
The cases behind the answers
Each answer was produced by a recorded Arxo run. Open a case to see the facts it was given, the full answer and the hashes that pin the run.
home (fresh, no directives): may be reusedTRUE_ONLY
Result: true. Rule applied: Reuse While Fresh.
Facts given
get_200(urn:demo:http:home)fresh(urn:demo:http:home)get_200(urn:demo:http:news)fresh(urn:demo:http:news)no_cache(urn:demo:http:news)get_200(urn:demo:http:prices)fresh(urn:demo:http:prices)no_cache(urn:demo:http:prices)validated(urn:demo:http:prices)
Hashes
- resultHash
sha256:37f616609157665df0904580c18e0f007f323ad50a6e55e5dda8a61f97c5cf8a- proofHash
sha256:a9e4c5c3924d4cf68aa1531dcb46bd24e69c2c91db7f75e224326c5c4fee51cf- caseHash
sha256:3efc6cf2838ff6fec7a125223c5f5acf9cdc4a9bbc5b2f9b85a338ecf0cb2968- programHash
sha256:0d5c34a3a5448085830f57b45a78799b4834f249b14277b7c3af622904811c8c- semanticHash
sha256:0cf2216f830cd57d486c8abe018a5aa2df833bf246392f4043e846d914ef7ebd
news (no-cache, not validated yet): may not be reusedFALSE_ONLY
Result: false. Rule applied: No Cache Needs Validation. Reuse While Fresh is defeated by No Cache Needs Validation, by priority.
Facts given
get_200(urn:demo:http:home)fresh(urn:demo:http:home)get_200(urn:demo:http:news)fresh(urn:demo:http:news)no_cache(urn:demo:http:news)get_200(urn:demo:http:prices)fresh(urn:demo:http:prices)no_cache(urn:demo:http:prices)validated(urn:demo:http:prices)
Hashes
- resultHash
sha256:c6f10c29e22c49b47e5abfe52b060110005c5ebbe3d6d1b0fcb303b620ad187f- proofHash
sha256:efeaa2cb58e2ad29d863bab76180d4906fce872f08e63602934d423be50e398e- caseHash
sha256:3efc6cf2838ff6fec7a125223c5f5acf9cdc4a9bbc5b2f9b85a338ecf0cb2968- programHash
sha256:0d5c34a3a5448085830f57b45a78799b4834f249b14277b7c3af622904811c8c- semanticHash
sha256:0cf2216f830cd57d486c8abe018a5aa2df833bf246392f4043e846d914ef7ebd
prices (no-cache, validated with the origin): may be reusedTRUE_ONLY
Result: true. Rule applied: Reuse After Validation. No Cache Needs Validation is defeated by Reuse After Validation, by priority. Reuse While Fresh is defeated by No Cache Needs Validation, by priority.
Facts given
get_200(urn:demo:http:home)fresh(urn:demo:http:home)get_200(urn:demo:http:news)fresh(urn:demo:http:news)no_cache(urn:demo:http:news)get_200(urn:demo:http:prices)fresh(urn:demo:http:prices)no_cache(urn:demo:http:prices)validated(urn:demo:http:prices)
Hashes
- resultHash
sha256:b1fb3617d5e7dd028591a8203d3c2df42d6c1957edbcb1aa210edb18e17c5324- proofHash
sha256:bb53c5551bf63ece694ecfb4ae77a8f4ece9be293ea5808c7fce5a703fe97c73- caseHash
sha256:3efc6cf2838ff6fec7a125223c5f5acf9cdc4a9bbc5b2f9b85a338ecf0cb2968- programHash
sha256:0d5c34a3a5448085830f57b45a78799b4834f249b14277b7c3af622904811c8c- semanticHash
sha256:0cf2216f830cd57d486c8abe018a5aa2df833bf246392f4043e846d914ef7ebd
no-store: the prohibition on storing is activeACTIVE
Prohibition: store response, on the proxy. Status: active.
Facts given
received(urn:demo:http:proxy, urn:demo:http:account, 2026-01-10)get_200(urn:demo:http:account)no_store(urn:demo:http:account)
Hashes
- resultHash
sha256:8bb1751002cff7a3a71a93e4a9fecbe0ffb23a478fec63027d5e5fc6762132e2- proofHash
sha256:371d736d6aa4b767ec1b7ef741cb8b5b4bd0a5f85fce9e1e61a7575f82fc9d4e- caseHash
sha256:19b2a3ed25d0e966da92f4339bd456db226626a7088844dfbd93fa74ffb61510- programHash
sha256:0d5c34a3a5448085830f57b45a78799b4834f249b14277b7c3af622904811c8c- semanticHash
sha256:b5fcba2a9c37bd38098c876c5f354f8b1ee7d24c34682fc50340966699bf6b6e
no-store, and the proxy stored it anyway: violatedVIOLATED
Prohibition: store response, on the proxy. Status: violated.
Facts given
received(urn:demo:http:proxy, urn:demo:http:account, 2026-01-10)get_200(urn:demo:http:account)no_store(urn:demo:http:account)stored(urn:demo:http:proxy, urn:demo:http:account)
Hashes
- resultHash
sha256:9bfdd0a02d3c2d8fd713fe87b7d23f595f939253aed20ccf7c6be2b131133306- proofHash
sha256:ccb95130f82e50bbfd72be192695e877ebe371545c384cf2cad7803f8c2ad135- caseHash
sha256:03d7790954770f61cf87bc7dc6b18bd2bc8151d7cd73eca7ce56d289b6aee999- programHash
sha256:0d5c34a3a5448085830f57b45a78799b4834f249b14277b7c3af622904811c8c- semanticHash
sha256:97736655c65996fea311ea62c2df51a6b613d071e6219cd655d62880aeb01805
Run it again
Engine semantics law.core/0.2.7. Source: RFC 9111, sections 5.2.2.4 (no-cache) and 5.2.2.5 (no-store), in the Arxo playground example "HTTP cache directives".
./law engine lower apps/site/play-examples/http-cache/http-cache.law > program.lawir.json
./law engine evaluate-test apps/site/play-examples/http-cache/tests/http-cache.lawtest --test <N> --program program.lawir.json --out run/