WEB / WEB-09.02
Browser and shared HTTP caches
A cache decides when to reuse a copy as well as whether to store it. Compare browser and shared caches using one response, explicit clocks, and separate policies.
1. Core · Mechanism
Read every scenario without motion
Shared hit
- Repeat GET
Duru requests the same public target; the shared entry is supplied complete with matching Vary context.
- Browser / Duru
- GET ready
- Shared cache
- Copy stored; Age at receive12
- Origin / Atlas
- No new request
- Browser HTTP cache
- Same policy; lifetime60
- Request arrived
The GET arrives at the shared cache; the origin has not seen this request.
- Browser / Duru
- Waiting response
- Shared cache
- GET received; copy candidate
- Origin / Atlas
- No new request
- Browser HTTP cache
- Same policy; lifetime60
- Calculate current age
The UTC fixture gives initial14 plus resident10 equals age24, fresh against shared lifetime30.
- Browser / Duru
- Waiting response
- Shared cache
- Fresh: age24 < lifetime30
- Origin / Atlas
- No new request
- Browser HTTP cache
- Same age24 < lifetime60
- Cached 200 arrived
The shared cache sends the stored body with Age24; this exchange has no origin round trip.
- Browser / Duru
- 200 received; Çay; Age24
- Shared cache
- Served stored body; Age24
- Origin / Atlas
- No new request
- Browser HTTP cache
- Copy eligible; lifetime60
- Select boundary time
At now26 resident16 produces age30; advancing a local clock is not a wire packet.
- Browser / Duru
- Last received Age24
- Shared cache
- age30 = shared lifetime30
- Origin / Atlas
- No new request
- Browser HTTP cache
- age30 < private lifetime60
- Separate reuse decision
The shared entry is no longer fresh and s-maxage requires validation; the browser copy can remain fresh.
- Browser / Duru
- Displayed copy unchanged
- Shared cache
- Next shared reuse needs validation
- Origin / Atlas
- No new request
- Browser HTTP cache
- Private copy still fresh
Private copy
- Select private response
In this separate exchange the origin will return private,max-age60; no new copy exists initially.
- Browser / Duru
- GET ready
- Shared cache
- Empty for this exchange
- Origin / Atlas
- private response policy selected
- Browser HTTP cache
- Empty
- GET reached cache
The shared cache receives the request; no usable stored response exists and origin forwarding is prepared.
- Browser / Duru
- Waiting response
- Shared cache
- GET received; miss
- Origin / Atlas
- No request yet
- Browser HTTP cache
- Empty
- GET reached origin
The forwarded request reaches the origin; private response policy is selected but has not reached the client.
- Browser / Duru
- Waiting response
- Shared cache
- Waiting origin
- Origin / Atlas
- GET received; 200 private ready
- Browser HTTP cache
- Empty
- Private 200 arrived
The shared cache receives the response and does not store the new body because of unqualified private.
- Browser / Duru
- Waiting response
- Shared cache
- 200 received; shared store=false
- Origin / Atlas
- 200 private ready
- Browser HTTP cache
- Empty
- Reached browser
The private response reaches the browser; its private-cache storage decision can now occur locally.
- Browser / Duru
- 200 received; Çay
- Shared cache
- Forwarded; shared store=false
- Origin / Atlas
- 200 private ready
- Browser HTTP cache
- Not yet stored
- Local private store
The browser cache stores the private copy because the other supplied eligibility rules are satisfied.
- Browser / Duru
- 200 received; Çay
- Shared cache
- No copy stored
- Origin / Atlas
- Exchange complete
- Browser HTTP cache
- Private copy stored; lifetime60
Validation required
- Fresh no-cache copy
The browser holds a no-cache,max-age60 copy; age24 is fresh but successful validation has not occurred.
- Browser / Duru
- GET intent
- Shared cache
- Not on selected direct path
- Origin / Atlas
- No request yet
- Browser HTTP cache
- Stored; age24; validated=false
- Local reuse gate
Unqualified no-cache stops reuse; storage and reuse are different gates.
- Browser / Duru
- Validation request prepared
- Shared cache
- Not on selected direct path
- Origin / Atlas
- No request yet
- Browser HTTP cache
- Stored but cannot reuse
- Validation arrived
The browser sends a conditional GET to the origin; matching context and validator are supplied.
- Browser / Duru
- Waiting validation
- Shared cache
- Not on selected direct path
- Origin / Atlas
- Conditional GET received
- Browser HTTP cache
- Stored but cannot reuse
- Select changed result
The origin selects a changed representation and prepares a full 200 instead of validating the old body.
- Browser / Duru
- Waiting validation
- Shared cache
- Not on selected direct path
- Origin / Atlas
- 200 full replacement ready
- Browser HTTP cache
- Stored old copy
- Full response arrived
New 200 content reaches the browser; WEB-09.03 separately shows body retention after 304.
- Browser / Duru
- New 200 received; Atlas note
- Shared cache
- Not on selected direct path
- Origin / Atlas
- 200 full replacement ready
- Browser HTTP cache
- Stored old copy
- Local replacement
The new eligible response replaces the old copy; if it is no-cache, the next reuse again needs validation.
- Browser / Duru
- Use newly received body
- Shared cache
- Not on selected direct path
- Origin / Atlas
- Exchange complete
- Browser HTTP cache
- New copy stored; next reuse validates
No-store response
- Policy change
This exchange fetches a new origin response separately from an older entry; no purge guarantee is supplied.
- Browser / Duru
- New GET ready
- Shared cache
- Old entry retained separately
- Origin / Atlas
- No request yet
- Browser HTTP cache
- Old entry retained separately
- GET reached origin
The direct GET reaches the origin; no-store is selected for the new response rather than a retroactive store operation.
- Browser / Duru
- Waiting response
- Shared cache
- Old entry retained separately
- Origin / Atlas
- GET received; no-store policy
- Browser HTTP cache
- Old entry retained separately
- New 200 prepared
The origin prepares harmless new content with no-store; cache policy does not imply encryption.
- Browser / Duru
- Waiting response
- Shared cache
- Old entry retained separately
- Origin / Atlas
- 200 no-store ready
- Browser HTTP cache
- Old entry retained separately
- No-store arrived
The browser receives the response; caching and future reuse of this immediate response are prohibited.
- Browser / Duru
- 200 no-store received
- Shared cache
- Old entry retained separately
- Origin / Atlas
- 200 no-store ready
- Browser HTTP cache
- Old entry retained separately
- Do not store new copy
The browser does not write the new response into its cache; the earlier entry is not marked automatically erased.
- Browser / Duru
- Use immediate body
- Shared cache
- Old entry retained separately
- Origin / Atlas
- Exchange complete
- Browser HTTP cache
- New store=false; old entry retained
- Separate earlier state
The fixture retains the earlier ledger entry; later use of an old copy requires a separate eligibility decision.
- Browser / Duru
- New response not reusable
- Shared cache
- No retroactive purge guarantee
- Origin / Atlas
- Exchange complete
- Browser HTTP cache
- No retroactive purge guarantee
ACTORS · STATE · DATA FLOW
Who is the copy stored for?
Duru opens the same public tea page again. A browser HTTP cache can be a private cache for one user, while a shared proxy or CDN serves multiple clients. Service Worker Cache Storage is a separate API/store; this lesson examines HTTP-cache decisions. Shared does not mean every representation is suitable for every user.
Storage eligibility and reuse are separate gates. Method/status, target, and any request fields selected by Vary must be appropriate. A stored response can still be unusable because of policy or freshness. The fixture selects a public GET with a complete body and matching Vary: Accept context rather than authenticated or partial content.
A cache response does not mean the origin saw the current request. In a fresh shared hit, the request reaches the proxy and a stored response goes to Duru. A fresh browser copy can avoid an external request entirely. Drawing local lookup as a network hop would hide the benefit caching provides.
For HTTPS, a shared cache needs a trusted endpoint/termination arrangement that lets it see HTTP content. A proxy carrying only an opaque TLS tunnel cannot read the encrypted response body and make this cache decision. The Atlas scene supplies an authorized shared endpoint observing decoded HTTP messages; it does not model TLS termination or certificate validation.
Where does the age clock start?
The artifact has Date 00:00:00, request_time 00:00:08, response_time 00:00:10, and received Age 12 seconds on the same synthetic UTC day. apparent_age=max(0,10−0)=10, response_delay=10−8=2, and corrected_age_value=12+2=14. This fixture selects conservative corrected_initial_age=max(10,14)=14. The RFC also permits corrected_age_value itself; the max form is not presented as the only mandatory formula for every implementation.
At now=00:00:20, resident_time=20−10=10 and current_age=14+10=24. Using received Age 12 alone omits transit and local residence. Response Date is not the business object’s modification time. Clocks are supplied and synchronized here; real drift and resolution are separate limitations.
With Cache-Control: public, max-age=60, s-maxage=30, private/browser lifetime is 60 and shared lifetime is 30. A response is fresh when its freshness lifetime exceeds current_age. At now=00:00:26, age is 30: the shared entry is no longer fresh while the browser entry still is. s-maxage overrides max-age/Expires for shared caches and requires validation before stale reuse. No stale-serving extension is selected here.
Three directives make different decisions
Unqualified private prevents a shared cache from storing the response; a private browser cache can store it if other rules allow. It is neither content encryption nor session isolation. Unqualified no-cache permits storage but requires forwarding to the origin and successful validation before reuse, even when age is below the freshness lifetime.
no-store requires that the immediate request/response not be stored by caches or reused for later requests. It is not a command to retroactively delete a previously stored response for the URL. A policy change needs a separate invalidation/validation strategy for old copies. The fixture keeps an older entry separately; the new no-store response is not written as its replacement.
The no-cache and private directives here have no field-name arguments; qualified forms have narrower rules and are outside this example. Connect directives to who stores, who reuses, and when validation occurs. Do not claim an HTTP-cache model measures all browser-history or back/forward-cache behavior.
2. Red · Trust & Impact
Read every scenario without motion
Storage scope
- The private directive was tied to cache type
The private, max-age=60 row has sharedMayStore false and privateMayStore true. Storage in a private browser cache is not independently a violation. Private implies neither encryption nor user-identity proof.
- Cache policy ledger
- Private: shared store false / private store true
- Store/reuse gate
- Decision pending
- Recipient boundary
- No verdict
- Freshness did not repair storage eligibility
A shared cache may not store this private response, even if its age is zero. Copying public Çay eligibility into a personalized response creates the wrong recipient boundary. Storage policy retains its predicate independently of age.
- Cache policy ledger
- Private: shared store false / private store true
- Store/reuse gate
- Private shared storage disallowed regardless of age
- Recipient boundary
- No verdict
- Cache classification was not permission
Freshness establishes neither authentication, object permission nor correct representation selection. Application-account state changes do not automatically repair every cache; affected representations need explicit handling.
- Cache policy ledger
- Private: shared store false / private store true
- Store/reuse gate
- Private shared storage disallowed regardless of age
- Recipient boundary
- Fresh ≠ authorized recipient
- No-store was read as policy for the new response
The no-store row disallows shared and private storage of the new response. retroactiveEraseGuaranteed is false and priorEntryInLedgerRetained true. The directive is not a command that deletes every previous copy.
- Cache policy ledger
- No-store: new storage false / old entry retained
- Store/reuse gate
- Private shared storage disallowed regardless of age
- Recipient boundary
- Fresh ≠ authorized recipient
- Purging was separated from storage control
reuseThisResponsePermitted is false for this response. Retention of an older entry is a separate policy and cache-behavior question. no-store does not establish automatic erasure of all browser history or Service Worker state.
- Cache policy ledger
- No-store: new storage false / old entry retained
- Store/reuse gate
- New response not reused / purge separate
- Recipient boundary
- Fresh ≠ authorized recipient
- Storage review retained its risk boundary
This inert ledger distinguishes policy meanings without cross-user serving or a real browser cache. Confidentiality review needs recipient, response classification and actual store/reuse evidence. A directive name alone does not verify the full boundary.
- Cache policy ledger
- No-store: new storage false / old entry retained
- Store/reuse gate
- New response not reused / purge separate
- Recipient boundary
- Policy meaning known / actual confidentiality unmeasured
Validation gate
- No-cache separated storage from reuse
Shared and private caches may store a no-cache, max-age=60 response. reuseRequiresValidation is true. Being within its freshness lifetime does not remove that requirement; no-cache does not mean never store.
- Cache policy ledger
- May store / validation required before reuse
- Store/reuse gate
- Decision pending
- Recipient boundary
- No verdict
- Reuse was withheld until validation completed
With validationCompleteSupplied false, reusePermitted stays false. Freshness and validation are different gates. Storing a response does not establish successful consultation with the origin.
- Cache policy ledger
- May store / validation required before reuse
- Store/reuse gate
- Validation false / reuse false
- Recipient boundary
- No verdict
- Pending validation remained an ordinary condition
This wait is neither malicious cache behavior nor application denial. Review must observe the origin round trip and policy decision separately. Timeout and stale serving are not enabled in this fixture.
- Cache policy ledger
- May store / validation required before reuse
- Store/reuse gate
- Validation false / reuse false
- Recipient boundary
- Validation pending / stale serving not enabled
- A changed representation entered the validation ledger
The stored tag is atlas-v1 with body Çay. For If-None-Match, the origin supplies current atlas-v2 and Atlas note with status 200. The new response carries ten content bytes, rather than retaining the old body as with 304.
- Cache policy ledger
- Validation response 200 / atlas-v2 / Atlas note
- Store/reuse gate
- Validation false / reuse false
- Recipient boundary
- Validation pending / stale serving not enabled
- Replacement updated the tag and body together
The ledger sets cacheAfterTag atlas-v2 and cacheAfterBody Atlas note. nextReuseRequiresValidation remains true; one successful validation does not permanently remove no-cache policy. Store update and later reuse remain separate decisions.
- Cache policy ledger
- Validation response 200 / atlas-v2 / Atlas note
- Store/reuse gate
- Cached v2/body replaced / next validation required
- Recipient boundary
- Validation pending / stale serving not enabled
- Normal validation was not application trust
Store/reuse predicates are explicit for this public GET ledger. Authenticated caching, production permission and full dependency invalidation are unmeasured. Correct cache policy cannot repair wrong user/object authorization.
- Cache policy ledger
- Validation response 200 / atlas-v2 / Atlas note
- Store/reuse gate
- Cached v2/body replaced / next validation required
- Recipient boundary
- Validation semantics known / authz separate
ASSUMPTION · BOUNDARY · CONTROL
Fresh does not establish the correct user
An account summary can have been generated seconds ago and still violate policy if stored in a shared cache. Correct age arithmetic verifies neither identity, permissions, nor representation selection. The failure condition is classifying a personalized response like public tea and reducing reuse eligibility to time alone.
Potential effects include serving content to the wrong recipient or displaying a copy governed by an old policy. Review response classification, private/no-store requirements, and selected representation context together. Requests carrying Authorization have additional shared-reuse rules; the mere presence of credentials is not a universal never-cached guarantee.
Application transitions such as login/logout do not automatically correct every intermediary cache. A cache invalidates the target after receiving a non-error 2xx/3xx response to an unsafe method, but they do not imply clearing every dependent URL or browser display. The product contract must identify the affected representations.
Do not substitute policy names for each other
Interpreting no-cache as never store, private as encrypted, and no-store as delete history creates three different incorrect acceptance rules. Reusing a fresh no-cache entry without validation is wrong; a private entry in a private cache is not itself a violation. An older copy surviving a later no-store response illustrates the absence of a retroactive purge.
Controls require more than seeing response headers: observe storage decisions and reuse on a subsequent normal request. This lesson explains conditions, consequences, and expected controls using an inert policy ledger. It uses no personal data and provides no cache-poisoning, key-collision, or third-party targeting exercise.
3. Blue · Secure development & defense
Read every scenario without motion
Age ledger
- Three timestamps were separated from origin Date
The example calculator produces the timing ledger; a synthetic observation fixture supplies validationRequired/validated/reused rows. These are not real cache logs. A public hit sends no request to the origin; origin evidence in private/no-cache branches exists only after that message arrives. A missing response or reuse record cannot prove correct behavior. Date is 00:00:00, request time 00:00:08 and response time 00:00:10. Received Age is 12 seconds. Response delay 2 and apparent age 10 are calculated independently; Age is not business-modification time.
- Time/policy record
- Apparent age 10 / response delay 2 / received Age 12
- Age/validation review
- Decision pending
- Evidence verdict
- No verdict
- Conservative initial age used the correct inputs
Corrected age value is 12+2=14. The selected conservative rule max(10,14) yields initial age 14. This uses supplied clocks without measuring drift, origin-clock accuracy or actual cache transit.
- Time/policy record
- Apparent age 10 / response delay 2 / received Age 12
- Age/validation review
- Corrected initial age max(10,14)=14
- Evidence verdict
- No verdict
- Resident time was added separately to current age
At now 00:00:20, resident time is 10 and currentAgeSeconds 24. The shared hit generates Age 24. Forwarding received Age 12 unchanged would ignore elapsed residence.
- Time/policy record
- Resident 10 / current age 24 / hit Age 24
- Age/validation review
- Corrected initial age max(10,14)=14
- Evidence verdict
- No verdict
- Freshness was compared with the cache-type lifetime
The public policy supplies private lifetime 60 and shared lifetime 30. Age 24 is fresh in both. At later now 00:00:26, age is 30; equality makes sharedFresh false while privateFresh stays true.
- Time/policy record
- Resident 10 / current age 24 / hit Age 24
- Age/validation review
- At age30: shared stale / private fresh
- Evidence verdict
- No verdict
- Eligibility assumptions accompanied the freshness verdict
Complete GET 200, matching target/Vary, absent Authorization and no stale extension are supplied. The calculation covers this context. Transferring fresh-hit results to authenticated requests or another representation exceeds evidence scope.
- Time/policy record
- Resident 10 / current age 24 / hit Age 24
- Age/validation review
- At age30: shared stale / private fresh
- Evidence verdict
- Age known under supplied eligibility
- Clock regression did not claim actual runtime behavior
Timestamp and age arithmetic are reproducible without running a browser/proxy cache. Cache type, selecting fields and current age are reviewed together. One Age field yields no privacy or authorization verdict.
- Time/policy record
- Resident 10 / current age 24 / hit Age 24
- Age/validation review
- At age30: shared stale / private fresh
- Evidence verdict
- Arithmetic reproducible / runtime unmeasured
Validation gap
- The selector selected the required-validation decision
The example calculator produces the timing ledger; a synthetic observation fixture supplies validationRequired/validated/reused rows. These are not real cache logs. A public hit sends no request to the origin; origin evidence in private/no-cache branches exists only after that message arrives. A missing response or reuse record cannot prove correct behavior. Normal XML reports validationRequired true, validated false and reused false. This authored observation agrees with the no-cache gate. The XML fields are not presented as a real cache-product log schema.
- Time/policy record
- Required=true / validated=false / reused=false
- Age/validation review
- Decision pending
- Evidence verdict
- No verdict
- Normal and positive controls tested one predicate
The normal count is zero. Positive XML has validated false with reused true and produces one match. This tests the oracle’s ability to select a violation observation, not occurrence of a real cache violation.
- Time/policy record
- Required=true / validated=false / reused=false
- Age/validation review
- Normal 0 / positive control 1
- Evidence verdict
- No verdict
- A missing reuse event can yield zero matches
The alternative review lacks a reuse-decision observation. The selector may find no existing inconsistent row. Copying reused false from the normal fixture into the missing event would conceal an actual coverage gap.
- Time/policy record
- Reuse observation absent
- Age/validation review
- Normal 0 / positive control 1
- Evidence verdict
- No verdict
- Storage evidence did not replace validation evidence
An existing cache entry does not establish completed validation. Origin response, selected candidate and next-reuse policy need separate observation. The cause of pending validation cannot be inferred from a missing row alone.
- Time/policy record
- Reuse observation absent
- Age/validation review
- Stored entry ≠ validation completed
- Evidence verdict
- No verdict
- Reuse correctness remained unknown
Reuse correctness remains UNKNOWN until validation and reuse coverage are complete. A missing event proves neither a clean cache nor malicious serving. Required policy and actual observations retain separate sources.
- Time/policy record
- Reuse observation absent
- Age/validation review
- Stored entry ≠ validation completed
- Evidence verdict
- UNKNOWN: validation/reuse coverage
- New evidence was bounded to minimal context
Further review needs policy class, selected entry, validation outcome and reuse decision, not full content or credentials. Ordinary hits and origin round trips are evaluated as separate observations.
- Time/policy record
- Reuse observation absent
- Age/validation review
- Stored entry ≠ validation completed
- Evidence verdict
- Needed: policy/entry/validation/reuse scope
IMPLEMENTATION · SECURITY CONTROL · VERIFICATION
Recalculate the timing ledger
The example calculator produces the timing ledger; a synthetic observation fixture supplies validationRequired/validated/reused rows. These are not real cache logs. A public hit sends no request to the origin; origin evidence in private/no-cache branches exists only after that message arrives. A missing response or reuse record cannot prove correct behavior. Begin the manual exercise by finding Date, request_time, response_time, received Age, and now. Calculate apparent age and response delay independently and explain the selected conservative initial age of 14. Record resident_time and current_age at now 20 and 26 separately rather than copying a single Age header.
Select the cache type next: lifetime 30 for shared, 60 for browser. Compare the equality boundary where freshness becomes false. When serving a stored response without validation, a cache generates Age from current_age; Duru receives Age 24 in the scene. Forwarding the originally received Age 12 would not express the current observation.
The selector finds authored observations with validationRequired=true, validated=false, and reused=true. Normal and positive fixtures yield 0 and 1; a missing event returning 0 cannot verify reuse control. This XML is not a cache-product log schema. Actual decisions need request/response and timing context.
Define separate acceptance criteria for storage and reuse
For the public branch, expect an eligible fresh copy to be served without reaching the origin. For private, check shared store false and browser store true. In no-cache, note that storage is allowed but reuse requires completed origin validation. In no-store, the new response is not stored and there is no general purge guarantee for earlier entries.
Treat normal hits, origin round trips, and policy changes as separate observations. Serving stale while disconnected follows additional rules and is not enabled here. WEB-09.03 develops validators and how successful 304 validation retains a body. This policy ledger is not execution of an actual browser or proxy cache.
A handler should generate Cache-Control from the response’s audience and permitted use. Choose private when personalized content may be stored only by that client; a cookie does not automatically tell a shared cache to keep it private. no-store for no storage of the new response and no-cache for origin validation before each reuse are different decisions. Verify storage and reuse expectations separately instead of copying the public Çay policy onto personal content.
NOW APPLY IT TO THE CASE
What separate decisions arise from freshness, private/no-cache/no-store and validation?
The UTC ledger gives the Çay response an age of 24 seconds. Shared lifetime is 30 seconds and private lifetime 60; their outcomes diverge at age 30. Private storage, no-cache validation and no-store retention have different predicates.
Which cache owner supplies the case representation? Evaluate key scope, freshness and viewer context together; a hit does not establish the correct viewer.
Open the related case file ↗READ THE EXAMPLE TOGETHER
Cache-policy and UTC-age ledger
Select a field and examine what it supports and where the evidence ends.
Read the raw artifact and field explanations
{
"target": "https://library.atlas.example/tea?view=plain",
"representation": {
"content": "Çay",
"contentOctets": 4,
"vary": "Accept",
"originalRequestAccept": "text/plain"
},
"clock": {
"date": "2026-10-08T00:00:00Z",
"requestTime": "2026-10-08T00:00:08Z",
"responseTime": "2026-10-08T00:00:10Z",
"receivedAgeSeconds": 12,
"now": "2026-10-08T00:00:20Z",
"apparentAgeSeconds": 10,
"responseDelaySeconds": 2,
"correctedAgeValueSeconds": 14,
"selectedInitialAgeRule": "conservative max(apparent_age, corrected_age_value)",
"correctedInitialAgeSeconds": 14,
"residentTimeSeconds": 10,
"currentAgeSeconds": 24
},
"publicPolicy": {
"cacheControl": "public, max-age=60, s-maxage=30",
"privateLifetimeSeconds": 60,
"sharedLifetimeSeconds": 30,
"sharedFreshNow": true,
"privateFreshNow": true,
"sharedHitGeneratedAge": 24,
"laterNow": "2026-10-08T00:00:26Z",
"laterResidentSeconds": 16,
"laterCurrentAgeSeconds": 30,
"laterSharedFresh": false,
"laterPrivateFresh": true
},
"policies": [
{
"id": "private",
"cacheControl": "private, max-age=60",
"sharedMayStore": false,
"privateMayStore": true,
"reuseRequiresValidation": false
},
{
"id": "no-cache",
"cacheControl": "no-cache, max-age=60",
"sharedMayStore": true,
"privateMayStore": true,
"reuseRequiresValidation": true,
"validationCompleteSupplied": false,
"reusePermitted": false
},
{
"id": "no-store",
"cacheControl": "no-store",
"sharedMayStore": false,
"privateMayStore": false,
"reuseThisResponsePermitted": false,
"retroactiveEraseGuaranteed": false,
"priorEntryInLedgerRetained": true
}
],
"eligibilitySupplied": {
"completeGet200": true,
"targetAndVaryMatch": true,
"requestAuthorizationAbsent": true,
"noStaleExtensionEnabled": true,
"noQualifiedFieldNameDirectives": true
},
"selector": {
"language": "XPath",
"xml": "<observations><reuse validationRequired=\"true\" validated=\"false\" reused=\"false\"/></observations>",
"xpath": "count(/observations/reuse[@validationRequired=\"true\" and @validated=\"false\" and @reused=\"true\"])",
"expected": 0,
"positiveFixtureXml": "<observations><reuse validationRequired=\"true\" validated=\"false\" reused=\"true\"/></observations>",
"positiveExpected": 1,
"scope": "Only authored protocol-decision observations, not product log field names or a live HTTP capture.",
"missingFieldBehavior": "Missing observation is insufficient evidence; zero matches is not proof of correct runtime behavior."
},
"validationExchange": {
"storedBeforeTag": "\"atlas-v1\"",
"storedBeforeBody": "Çay",
"requestHeader": {
"If-None-Match": "\"atlas-v1\""
},
"originCurrentTagSupplied": "\"atlas-v2\"",
"originCurrentBodySupplied": "Atlas note",
"responseStatus": 200,
"responseBody": "Atlas note",
"responseContentOctets": 10,
"responseCacheControl": "no-cache, max-age=60",
"cacheAfterTag": "\"atlas-v2\"",
"cacheAfterBody": "Atlas note",
"nextReuseRequiresValidation": true
}
}- clock
- Response age from origin/cache transit and local residence, not business modification time.
- publicPolicy
- Private60/shared30 for the same age; equality makes shared freshness false.
- policies
- Separate storage, validation, and reuse decisions.
- priorEntryInLedgerRetained
- Instructional state that does not assume no-store automatically erases earlier entries.
Clocks, storage eligibility, and policy engine are authored/supplied. Browser history, Service Workers, actual proxies, drift, stale extensions, and authenticated caching are not measured.
Two reality checks
A response with no-cache cannot exist in a cache.
It can be stored; unqualified no-cache prevents subsequent reuse without successful origin validation.
no-store deletes every previous copy; Age is just the received header number.
no-store is not retroactive purge. current_age includes response delay and local residence in addition to received Age.
YOUR TURN
Work through this story.
Predict the outcome, find the evidence boundary, and explain it in your own words.
Current age is 30, shared lifetime 30 and private lifetime 60. Which cache is fresh?
- Shared is stale; private is fresh.
- Both are fresh; equality provides another second.
Read the explained answer
Shared is stale; private is fresh. — Shared age equals its lifetime and is not fresh. The selected private lifetime is not yet exhausted.
Why is reusePermitted=false although a no-cache response can be stored?
Selected lesson artifact fields; teaching example
- policies[1]
- {"id":"no-cache","cacheControl":"no-cache, max-age=60","sharedMayStore":true,"privateMayStore":true,"reuseRequiresValidation":true,"validationCompleteSupplied":false,"reusePermitted":false}
- no-cache and no-store are identical; storage is impossible.
- Successful validation has not yet been supplied.
Read the explained answer
Successful validation has not yet been supplied. — No-cache is not a storage prohibition; reuseRequiresValidation=true and validationCompleteSupplied=false close the gate.
Date apparent age 10, received Age 12, response delay 2 and residence 10. Why is current age 24; why is Age 12 alone insufficient?
Read the explained answer
Corrected age value is 12+2=14; the selected conservative max(10, 14)=14 is the initial age. Adding residence 10 yields 24. Treating an Age-header snapshot as current age omits elapsed cache residence. This supplied clock ledger is not an actual cache-timer measurement.
□ I included response delay and residence.
□ I did not treat the supplied-clock calculation as an actual runtime measurement.
Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples
Sources and scope
- RFC 9111 — HTTP Caching1 Introduction · 3 Storing Responses in Caches · 3.2 Updating Stored Header Fields · 3.5 Storing Responses to Authenticated Requests · 4 Constructing Responses from Caches · 4.1 Calculating Cache Keys with the Vary Header Field · 4.2 Freshness · 4.2.1 Calculating Freshness Lifetime · 4.2.3 Calculating Age · 4.3.3 Handling a Validation Response · 4.3.4 Freshening Stored Responses upon Validation · 4.4 Invalidating Stored Responses · 5.2.2.4 no-cache · 5.2.2.5 no-store · 5.2.2.7 private · 5.2.2.10 s-maxage
- MDN — HTTP cachingPrivate caches · Shared cache · Fresh and stale based on age · Provide up-to-date content every time · Validation