/freshness-contract
EXPERIMENTAL. A lookup, not a judgment ritual: it should cost LESS than the vibes it replaces. Fires only when prior evidence is about to be reused for a decision — never on every read, never as per-phase bookkeeping. It decides whether old proof still counts; what fresh proof must show belongs to your verification tools.
The design is deliberately isomorphic to HTTP caching (RFC 9111): explicit invalidation beats heuristics, conflicting signals resolve restrictively, and nothing is served stale silently. No TTL numbers ship in v1 — every "how old is too old" constant would be invented; the table routes by class and events, which are observable.
Step 1 — classify the artifact (volatility class)
| Class |
Meaning |
Examples |
| stable |
exact version-pinned evidence, used for a question about that exact version — byte stability is not applicability: a superseded spec's old bytes still match while the governing version moved |
a released spec consulted AS that release, a frozen/hash-pinned artifact, an archived record. Supersession or a dependency-version change is a named invalidator whenever the decision asks what is CURRENT |
| write-coupled |
valid until someone writes to the source |
a file you read this session, an index entry, a config, a map/roster document |
| env-coupled |
valid until the environment shifts |
a passing test that touches network/services/installed tools, a capability probe, a build result |
| clock-coupled |
decays with time regardless of writes |
anything embedding "current" state: prices, live statuses, date-dependent results |
| report |
someone's account of state, not state itself |
worker/subagent reports, peer summaries, self-reports of any kind |
Class is assigned per artifact kind at first encounter, not re-judged per use by whoever wants to skip a re-read.
Step 2 — check the observable signals
- Intervening writes — has the source (or its declared dependencies) changed since
as_of? (fingerprint, mtime, generation stamp, commit)
- Named invalidators — did a declared invalidating event occur? (roster change, deploy, sync, schema bump, "re-prime after write")
- Decision leverage — is the reuse load-bearing for a decision, release, or Handler-facing claim, or merely orientation? Leverage is non-downgradable when the result supports a release, an irreversible or external action, a formal gate, or a Handler-facing recommendation — those are high, not judgment calls.
- Discriminator availability — does a cheap signal exist that is exclusive to the fresh state (a hash to recompute, a header to stat, a count to re-derive)?
Step 3 — the table (first match wins)
| Situation |
Policy |
| Any named invalidator fired, or intervening write on a write-coupled source |
re-verify |
| Conflicting or ambiguous signals, whatever the class |
re-verify (restrictive conflict rule) |
| stable + fingerprint still matches |
reuse |
| write-coupled + no intervening write + low/medium leverage |
reuse |
| write-coupled + no intervening write + high leverage |
spot-check the discriminator |
| env-coupled or clock-coupled + low/medium leverage |
spot-check the discriminator |
| env-coupled or clock-coupled + high leverage |
re-verify |
| report, any age, load-bearing |
re-verify (a report is never promoted to state by aging) |
| report, orientation only |
reuse, labeled as report |
| no cheap discriminator exists for a spot-check row |
re-verify or accept-labeled-risk — say which, in the output |
| unclassified artifact kind (DEFAULT ROW) |
spot-check; classify the kind before next reuse |
accept-labeled-risk is agent-electable ONLY on the no-cheap-discriminator row — it is never a bypass for a re-verify result elsewhere in the table. On any other row, proceeding despite a re-verify verdict requires explicit Handler authority (that is a Handler override, not a table output). Where it applies, it is never silent: the staleness risk is named next to the conclusion it feeds.
Output record (one line to a few lines, inline where the evidence is used)
freshness = { artifact, class, as_of, signals: {writes|invalidators|leverage},
decision: reuse|spot-check|re-verify|accept-labeled-risk,
discriminator_used?: <what was checked> }
No dedicated log stream, no cards, no sink — the record rides inside whatever report or decision consumed the evidence.
Safety boundary
- Signals are observable properties of sources and events — never the agent's feeling of confidence about its memory.
- The table may be narrowed by a Handler's local policy (stricter rows); agents never loosen a row.
- TTLs, if ever added, must come from logged staleness observations, not authorship-day guesses; until then age alone never justifies reuse or refusal.
- Foreign freshness metadata (another party's "this is current" claim) is a report, not a signal — classify accordingly.
Self-improvement. On completion, run the Self-Improvement Protocol (self-improve/SKILL.md): if this run surfaced a concrete, blocking-or-recurring weakness in this skill, propose a specific fix for the handler to approve. Conservative — silent otherwise. Never auto-apply.
1---2name: freshness-contract3description: Categorical decision table for reusing cached evidence — when an artifact you already read, a banked test result, a primer, a worker report, or a probe verdict is still trustworthy, and when it must be spot-checked or re-verified. Inputs are observable (artifact class, age anchors, intervening writes, named invalidators); output is reuse / spot-check / re-verify / accept-labeled-risk. Conservative by construction — unclassified artifacts and conflicting signals always take the more restrictive path; no invented TTLs. Trigger when the user runs /freshness-contract, asks "is this still current", "can I trust what I read earlier", "do I need to re-check this", or before reusing prior evidence for a decision after time, writes, or environment changes. Not /double-check (re-verifies one claim's content) or /verify (formal phase gate) — freshness-contract decides whether OLD evidence still counts before those tools decide what NEW evidence shows.4---56# /freshness-contract78> **EXPERIMENTAL.** A lookup, not a judgment ritual: it should cost LESS than the vibes it replaces. Fires only when prior evidence is about to be **reused for a decision** — never on every read, never as per-phase bookkeeping. It decides whether old proof still counts; what fresh proof must show belongs to your verification tools.910The design is deliberately isomorphic to HTTP caching (RFC 9111): explicit invalidation beats heuristics, conflicting signals resolve restrictively, and nothing is served stale silently. No TTL numbers ship in v1 — every "how old is too old" constant would be invented; the table routes by *class and events*, which are observable.1112## Step 1 — classify the artifact (volatility class)1314| Class | Meaning | Examples |15|---|---|---|16| **stable** | **exact version-pinned evidence, used for a question about that exact version** — byte stability is not applicability: a superseded spec's old bytes still match while the governing version moved | a released spec consulted AS that release, a frozen/hash-pinned artifact, an archived record. **Supersession or a dependency-version change is a named invalidator whenever the decision asks what is CURRENT** |17| **write-coupled** | valid until someone writes to the source | a file you read this session, an index entry, a config, a map/roster document |18| **env-coupled** | valid until the environment shifts | a passing test that touches network/services/installed tools, a capability probe, a build result |19| **clock-coupled** | decays with time regardless of writes | anything embedding "current" state: prices, live statuses, date-dependent results |20| **report** | someone's account of state, not state itself | worker/subagent reports, peer summaries, self-reports of any kind |2122Class is assigned per artifact **kind** at first encounter, not re-judged per use by whoever wants to skip a re-read.2324## Step 2 — check the observable signals2526- **Intervening writes** — has the source (or its declared dependencies) changed since `as_of`? (fingerprint, mtime, generation stamp, commit)27- **Named invalidators** — did a declared invalidating event occur? (roster change, deploy, sync, schema bump, "re-prime after write")28- **Decision leverage** — is the reuse load-bearing for a decision, release, or Handler-facing claim, or merely orientation? **Leverage is non-downgradable when the result supports a release, an irreversible or external action, a formal gate, or a Handler-facing recommendation — those are high, not judgment calls.**29- **Discriminator availability** — does a cheap signal exist that is exclusive to the fresh state (a hash to recompute, a header to stat, a count to re-derive)?3031## Step 3 — the table (first match wins)3233| Situation | Policy |34|---|---|35| Any named invalidator fired, or intervening write on a write-coupled source | **re-verify** |36| Conflicting or ambiguous signals, whatever the class | **re-verify** (restrictive conflict rule) |37| stable + fingerprint still matches | **reuse** |38| write-coupled + no intervening write + low/medium leverage | **reuse** |39| write-coupled + no intervening write + high leverage | **spot-check** the discriminator |40| env-coupled or clock-coupled + low/medium leverage | **spot-check** the discriminator |41| env-coupled or clock-coupled + high leverage | **re-verify** |42| report, any age, load-bearing | **re-verify** (a report is never promoted to state by aging) |43| report, orientation only | **reuse, labeled as report** |44| no cheap discriminator exists for a spot-check row | **re-verify or accept-labeled-risk** — say which, in the output |45| **unclassified artifact kind (DEFAULT ROW)** | **spot-check**; classify the kind before next reuse |4647`accept-labeled-risk` is **agent-electable ONLY on the no-cheap-discriminator row** — it is never a bypass for a `re-verify` result elsewhere in the table. On any other row, proceeding despite a `re-verify` verdict requires explicit Handler authority (that is a Handler override, not a table output). Where it applies, it is never silent: the staleness risk is named next to the conclusion it feeds.4849## Output record (one line to a few lines, inline where the evidence is used)5051```text52freshness = { artifact, class, as_of, signals: {writes|invalidators|leverage},53 decision: reuse|spot-check|re-verify|accept-labeled-risk,54 discriminator_used?: <what was checked> }55```5657No dedicated log stream, no cards, no sink — the record rides inside whatever report or decision consumed the evidence.5859## Safety boundary6061- Signals are observable properties of sources and events — never the agent's feeling of confidence about its memory.62- The table may be narrowed by a Handler's local policy (stricter rows); agents never loosen a row.63- TTLs, if ever added, must come from logged staleness observations, not authorship-day guesses; until then age alone never justifies reuse or refusal.64- Foreign freshness metadata (another party's "this is current" claim) is a report, not a signal — classify accordingly.6566> **Self-improvement.** On completion, run the Self-Improvement Protocol (`self-improve/SKILL.md`): if this run surfaced a concrete, blocking-or-recurring weakness in this skill, propose a specific fix for the handler to approve. Conservative — silent otherwise. Never auto-apply.