Content-Keyed Cache Discipline
When to use this
Any time you think "this was already computed / already verified, don't do it again" — build artifact
caches, incremental testing, flattened data-page caches, memoization, cross-period artifact stores.
A cache is the first blade you reach for on performance, and correctness's most insidious enemy:
when a cache serves a wrong value, the value itself looks entirely reasonable (it was correct once),
only the source is stale — and nothing about it feels absurd enough to alert you at the moment it
happens. The most insidious bug a cache can ship: a plausible value from a stale source.
This skill is about making "fast" not something you pay for with "correct."
Core rules
Rule 1: A shortcut is provable equivalence, not a skipped check
"It hit the cache, so we don't recompute or re-verify" is legitimate only because of a provable chain
of reasoning: same content key → same bytes → same result, and those bytes were fully verified at
the moment they were built. Break any of the three links and the shortcut is a hole in verification.
- Key does not match → fall back to the full path, or bark; never wave it through as "doesn't
match but probably close enough." Waving it through silently is a hole.
- The last link in the chain (verified at build time) is Rule 4.
Rule 2: Keys must be composite; a bare hash is the doorway to silently wrong values
A content key is at minimum a three-part composite: content hash + size + identity (path/name).
- A short hash (a 32-bit CRC, say) used alone as a key can, in theory, be shared by two different
contents — and the consequence of a collision is not an error, it is silently serving the old
content as the new (last period's data page served as this period's), so everything downstream is
correct and every source is wrong.
- Adding size blocks "content changed, hash happened not to"; adding identity blocks "the same hash in
different places eating each other." All three would have to coincide at once, which pushes the
probability down to engineering-negligible.
- Key selection has its own economics too: a hash you can read straight from container metadata
(no decompression) beats one that requires expanding the full content — the entire reason the cache
exists is to save that expansion (for the cost reasoning, see engineering-economy).
Rule 3: Every cache entry carries a manifest, is verified on open, and never serves a value silently
Each cache entry writes a manifest at the moment the write completes: the source composite key +
scale statistics (row count / cell count) + a content digest + (where applicable) which verification
layers it already passed. Verify the manifest before every use:
- Mismatched / missing / truncated (a half-seeded entry from a crash) → treat it as a miss and
re-seed, and log the event; never serve a suspect entry as a good one.
- The digest must be able to catch "same row count, content tampered" (an XOR or rolling digest, not
just counting rows).
- Keep breaking tests on standby: truncate an entry → it must bark and re-seed; tamper with the
content → the digest must not match and it must bark; forge a manifest → it must bark. A gate whose
pre-check barks is a gate (echoing verification-discipline's "never trust a self-report" — a cache is
a form of self-report too).
Rule 4: A hit propagates the proof (the cache entry carries the verification conclusion)
An ordinary cache only saves the computation; recording in the manifest which verifications this
content passed when it was built means a hit also legitimately propagates the conclusion "already
verified" — the cache becomes the carrier of a verification conclusion, and that is what makes
incremental verification valid (for the parts that did not change, last time's pass still holds).
Two preconditions, and it is fake without either:
- The verification done at build time was complete (everything that layer should verify was
verified, not a spot-check masquerading as a full one);
- "Did not change" means Rule 1/2-grade unchanged (the composite key matches), not "nobody seems to
have touched it."
Any check the cache lets you skip must be traceable to an equivalent completion at build time — you are
saving repetition, not coverage (echoing verification-discipline's "should be there and isn't").
Rule 5: Cache hygiene — the cost you saved must not grow back somewhere else
A cache trades disk for time, and that ledger has to stay positive over time:
- The cache directory has a size limit and an eviction policy (LRU by mtime, for instance); a cache
without a limit is a slow disk leak.
- Orphan keys must be reclaimable: entries whose source no longer exists, or that can never be hit
again, must be identifiable and removable.
- Every entry reports its own disk usage so the total ledger is visible — "how much faster" and
"how much space" must both be measurable, not felt.
Rule 6: One scan feeds many consumers
Seeding a cache already requires scanning the source completely — that scan is a cost already paid,
so extract everything later consumers will want into the same cache entry along the way (values +
statistics + verification inputs + domain signals) instead of having each consumer scan for itself.
- The anti-pattern: the production flow scans once for values and the verification flow scans again for
statistics — the same large source expanded twice, with the cache rescuing only half of it.
- Extracting things opportunistically to "record now, assert later" also pays off: the signal sits in
the manifest, and when you do wire up a check it is a one-line change with no rescan needed
(for a gate whose decision is not yet made, get the ingredients ready first).
Case files from this project (supporting evidence, not required for the general rules)
- Rules 1/2 together: one financial-reporting automation project's dependency-page cache used a
three-part composite key (CRC32 + uncompressed size + part path) — the reviewer asked three separate
times for "the key's complete composition" before letting it through, on the grounds that "this cache
feeds the current period's correctness directly; a collision means silently serving the wrong
period." Reading the CRC straight from the ZIP central directory, avoiding decompressing 296MB, is
exactly Rule 2's key-selection economics.
- Rule 3: the cache entry (a SQLite value store) verifies its manifest on open (quick_check + cell
count), with a deep check via an XOR digest to catch "same cell count, values tampered"; both
breaking tests (truncate → re-seed with correct values; tamper → digest mismatch) actually barked
before it was accepted.
- Rule 4: thanks to "verify at build time + record the passed layers in the manifest," the
verification stage skipped re-parsing the dependency page entirely (a huge sheet with 245K formulas)
— one report's verification went from a 150-second full load to point lookups, while not a single
cell of the seven-dimension cell-by-cell verification on the report page was skipped: repetition
saved, coverage not.
- Rule 5: LRU eviction plus disk-usage reporting were pushed into the first version by the reviewer
on "don't move the waste elsewhere" grounds, rather than added afterwards.
- Rule 6: values and page-level statistics land in the same SQLite in the same streaming pass;
period signals were extracted into the manifest opportunistically, to "record now, assert later" —
the corresponding gate was still with the decision-maker at the time, so the ingredients were
prepared, and wiring it up after the ruling was a one-line change.
- Sister skills: the equivalence gate sitting at the content layer, and coincidence windows being
false greens → verification-discipline, Comparison 5; a cache's cost ledger and performance
assertions → engineering-economy Rule 12; the streaming physics of seeding a cache from a large file
→ xlsx-surgery Rule 8.
1---2name: cache-discipline3description: Content-Keyed Cache Discipline4---56# Content-Keyed Cache Discipline78## When to use this910Any time you think "this was already computed / already verified, don't do it again" — build artifact11caches, incremental testing, flattened data-page caches, memoization, cross-period artifact stores.12A cache is the first blade you reach for on performance, and **correctness's most insidious enemy**:13when a cache serves a wrong value, the value itself looks entirely reasonable (it *was* correct once),14only **the source is stale** — and nothing about it feels absurd enough to alert you at the moment it15happens. The most insidious bug a cache can ship: a plausible value from a stale source.16This skill is about making "fast" not something you pay for with "correct."1718---1920## Core rules2122### Rule 1: A shortcut is provable equivalence, not a skipped check2324"It hit the cache, so we don't recompute or re-verify" is legitimate only because of a provable chain25of reasoning: **same content key → same bytes → same result, and those bytes were fully verified at26the moment they were built**. Break any of the three links and the shortcut is a hole in verification.27- Key does not match → **fall back to the full path, or bark**; never wave it through as "doesn't28 match but probably close enough." Waving it through silently is a hole.29- The last link in the chain (verified at build time) is Rule 4.3031### Rule 2: Keys must be composite; a bare hash is the doorway to silently wrong values3233A content key is at minimum a three-part composite: **content hash + size + identity (path/name)**.34- A short hash (a 32-bit CRC, say) used alone as a key can, in theory, be shared by two different35 contents — and the consequence of a collision is not an error, it is **silently serving the old36 content as the new** (last period's data page served as this period's), so everything downstream is37 correct and every source is wrong.38- Adding size blocks "content changed, hash happened not to"; adding identity blocks "the same hash in39 different places eating each other." All three would have to coincide at once, which pushes the40 probability down to engineering-negligible.41- Key selection has its own economics too: a hash you can read straight from container metadata42 (no decompression) beats one that requires expanding the full content — the entire reason the cache43 exists is to save that expansion (for the cost reasoning, see engineering-economy).4445### Rule 3: Every cache entry carries a manifest, is verified on open, and never serves a value silently4647Each cache entry writes a manifest **at the moment the write completes**: the source composite key +48scale statistics (row count / cell count) + a content digest + (where applicable) which verification49layers it already passed. **Verify the manifest before every use**:50- Mismatched / missing / truncated (a half-seeded entry from a crash) → **treat it as a miss and51 re-seed**, and log the event; never serve a suspect entry as a good one.52- The digest must be able to catch "same row count, content tampered" (an XOR or rolling digest, not53 just counting rows).54- Keep **breaking tests on standby**: truncate an entry → it must bark and re-seed; tamper with the55 content → the digest must not match and it must bark; forge a manifest → it must bark. A gate whose56 pre-check barks is a gate (echoing verification-discipline's "never trust a self-report" — a cache is57 a form of self-report too).5859### Rule 4: A hit propagates the proof (the cache entry carries the verification conclusion)6061An ordinary cache only saves the computation; recording in the manifest **which verifications this62content passed when it was built** means a hit also legitimately propagates the conclusion "already63verified" — **the cache becomes the carrier of a verification conclusion**, and that is what makes64incremental verification valid (for the parts that did not change, last time's pass still holds).65Two preconditions, and it is fake without either:66- The verification done at build time was **complete** (everything that layer should verify was67 verified, not a spot-check masquerading as a full one);68- "Did not change" means **Rule 1/2-grade unchanged** (the composite key matches), not "nobody seems to69 have touched it."70Any check the cache lets you skip must be traceable to an equivalent completion at build time — you are71saving repetition, not coverage (echoing verification-discipline's "should be there and isn't").7273### Rule 5: Cache hygiene — the cost you saved must not grow back somewhere else7475A cache trades disk for time, and that ledger has to stay positive over time:76- The cache directory has a **size limit and an eviction policy** (LRU by mtime, for instance); a cache77 without a limit is a slow disk leak.78- **Orphan keys must be reclaimable**: entries whose source no longer exists, or that can never be hit79 again, must be identifiable and removable.80- Every entry **reports its own disk usage** so the total ledger is visible — "how much faster" and81 "how much space" must both be measurable, not felt.8283### Rule 6: One scan feeds many consumers8485Seeding a cache already requires scanning the source completely — that scan is a **cost already paid**,86so extract everything later consumers will want into the same cache entry along the way (values +87statistics + verification inputs + domain signals) instead of having each consumer scan for itself.88- The anti-pattern: the production flow scans once for values and the verification flow scans again for89 statistics — the same large source expanded twice, with the cache rescuing only half of it.90- Extracting things opportunistically to "record now, assert later" also pays off: the signal sits in91 the manifest, and when you do wire up a check it is a one-line change with no rescan needed92 (for a gate whose decision is not yet made, get the ingredients ready first).9394---9596## Case files from this project (supporting evidence, not required for the general rules)9798- **Rules 1/2 together**: one financial-reporting automation project's dependency-page cache used a99 three-part composite key (CRC32 + uncompressed size + part path) — the reviewer asked three separate100 times for "the key's complete composition" before letting it through, on the grounds that "this cache101 feeds the current period's correctness directly; a collision means silently serving the wrong102 period." Reading the CRC straight from the ZIP central directory, avoiding decompressing 296MB, is103 exactly Rule 2's key-selection economics.104- **Rule 3**: the cache entry (a SQLite value store) verifies its manifest on open (quick_check + cell105 count), with a deep check via an XOR digest to catch "same cell count, values tampered"; both106 breaking tests (truncate → re-seed with correct values; tamper → digest mismatch) actually barked107 before it was accepted.108- **Rule 4**: thanks to "verify at build time + record the passed layers in the manifest," the109 verification stage skipped re-parsing the dependency page entirely (a huge sheet with 245K formulas)110 — one report's verification went from a 150-second full load to point lookups, while not a single111 cell of the seven-dimension cell-by-cell verification on the report page was skipped: repetition112 saved, coverage not.113- **Rule 5**: LRU eviction plus disk-usage reporting were pushed into the first version by the reviewer114 on "don't move the waste elsewhere" grounds, rather than added afterwards.115- **Rule 6**: values and page-level statistics land in the same SQLite in the same streaming pass;116 period signals were extracted into the manifest opportunistically, to "record now, assert later" —117 the corresponding gate was still with the decision-maker at the time, so the ingredients were118 prepared, and wiring it up after the ruling was a one-line change.119- **Sister skills**: the equivalence gate sitting at the content layer, and coincidence windows being120 false greens → verification-discipline, Comparison 5; a cache's cost ledger and performance121 assertions → engineering-economy Rule 12; the streaming physics of seeding a cache from a large file122 → xlsx-surgery Rule 8.