Render-Side Freshness Contract
Every cached or derived surface vita renders β e-ink displays, memory views, briefing tiles, API responses, working memory β used to answer the question "can I trust this number?" on its own, or not at all. The freshness contract replaces N ad-hoc staleness checks with one:
A figure whose source is missing, stale, or suspect renders as unknown, never as a real value.
Status: shipped 2026-07-26 (forge idea 051, closing
plans/proposals/2026-04-29-epd-freshness-guard.mdafter 16 revisions). 20 sources registered, 60 tests. Live check:uv run python -m freshness --status.
Why this exists
The failure mode has a name in vita's working memory: render-fresh / engine-dark. A surface looks alive because it has a recent timestamp, while the engine that fills it has been dead for weeks. The Jul-6 2026 truth audit measured it on six independent surfaces:
| Surface | What it asserted | What was true |
|---|---|---|
| EPD display | CEO transformation: 0% |
no aggregator existed; real value unknown |
memory/views/* |
"current" | up to 85 days since last build |
| data-source-health | tokens_session_sync: never_synced |
syncing daily |
| Sleep-gate chain | 5.05h slept |
watch fell off; ~7.5h actually slept |
| Living briefing | live tiles | zero adapter writes for ~60 days |
data/doc-audit/latest.json |
"100% coverage" | file was ~5 months old |
Each was fixed by hand, individually. The contract exists so the next one isn't.
The finding that shaped the design
Building this turned up something sharper than the proposal assumed: the
guard had already shipped. On 2026-06-06, scripts/utils.render_metric
landed with 8 passing tests β and exactly one consumer. The EPD display it was
written for never imported it. Separately, memory/view_loader.load_view(),
the correct consumer-side primitive, has zero production consumers, while
scripts/sentinel/calendar_guard.py reimplements its own _load_view 100
lines away.
So the gap was never a missing check. A primitive nobody calls is indistinguishable from no primitive β the render-fresh/engine-dark pathology applied to its own fix. That is why this ship prioritized wiring over library surface, and why the registry is deliberately the cheap part.
Architecture
ββββββββββββββββββββββββββββββββββββ
registry.py βββββΆβ assess("view.health-snapshot") β
(20 sources, β β
each with its β pick probe by kind βββ β
OWN cadence ββββββββββββββββββββββββββΌβββββββββββ
+ named owner) β
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
probes.py β view β delegates to view_loader β
β sqlite_max β MAX(ts) of a table β
β json_field β dotted path + mtime bak β
β mtime β filesystem fallback β
β dated_file β newest of a glob β
ββββββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
validity.py β value plausible? coverage sufficient? β
β fresh-but-wrong β SUSPECT β
ββββββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
βββββββββββββββββββββ
β Verdict β
β state + age + β
β reason + owner β
βββββββββββ¬ββββββββββ
βΌ
contract.render(value, verdict) contract.require(verdict)
"6.9h" | "6.9h (stale 9d)" raises if it can't be backed
| "unknown β source missing"
The six states
Only FRESH permits rendering a bare value. Everything else is a specific
reason the number would be an assertion the data can't back.
| State | Meaning | Renders as |
|---|---|---|
FRESH |
within the source's declared cadence | 6.9h |
STALE |
source exists, older than its own max_age |
6.9h (stale 9d) |
MISSING |
absent, unreadable, or empty | unknown β file not found |
SUSPECT |
present and recent, but the value fails a validity rule | unknown β duration 3.2h below floor |
CONTESTED |
two sources that should agree don't | unknown β contested |
UNKNOWN |
exists but carries no usable timestamp | unknown β no timestamp |
A stale value is still shown, because a labelled stale number is useful and
honest. A missing or suspect one is not shown at all, because there is no
number to label β that's the case where surfaces used to invent a 0.
Failing closed
verdict_from_age() treats an unparseable or absent timestamp as UNKNOWN,
never FRESH. This is the single most important line in the package: at most
prior call sites, an unreadable timestamp meant "assume fine", which is exactly
how a source goes dark without any surface noticing.
Probes never raise, either. An exception while probing is a freshness
answer (MISSING), because a probe that could take down its caller would just
push consumers back to reading raw.
Freshness vs. validity
These fail independently, and vita has been bitten harder by the second.
- Freshness asks when was this written?
- Validity asks is what was written believable?
The Jul-4 garmin reading was written on time and was junk β the watch came off, 5.05h recorded against ~7.5h actually slept β and the gate calc, the sleep-risk scorer, the 19:30 warning builder and an OODA working-memory correction all consumed it as fact. Two false gate warnings went out before a human noticed.
validity.py carries the rules:
sleep_duration_plausibleβ below 4.0h is more likely sensor dropout than a night slept. Deliberately generous: bio-zack logs real 5.5h nights; 4.0h is where "the sensor lost him" becomes the better explanation.sleep_score_presentβ duration without a score is a partial record.coverage_rule(ratio)β an aggregate computed over too little of its window is an artifact. This is the 2026-05-28 case, where missing sync days were averaged in as zeros and a 3-of-7-night average rendered as a 7-night average (4.49h shown against 7.87h actually slept on the nights recorded).
Validity rules only run on otherwise-trustworthy sources β there's no point second-guessing a value already known to be stale.
The registry
registry.py is one declarative table. Adding a source there is the entire
cost of putting a new surface under the contract.
SourceSpec(
id="briefing.engine",
kind="sqlite_max",
max_age=2 * DAY,
target=("data/briefing/briefing.db", "briefing_items", "created_at"),
owner="briefing adapters",
note="dark May-8 -> Jul-7 (~60d) while tiles rendered as live",
)
Two fields carry more weight than they look like:
max_ageis per-source. A view rebuilt nightly and a lab panel refreshed quarterly are both honest at ages that would be alarming for the other. A global default would make the whole surface cry wolf.ownernames what is supposed to keep it fresh. A source owned by "button-only" or "manual" is not broken when it drifts, and the status output says so rather than alarming nightly.
Registered today: memory views (health-snapshot, training-status, goal-progress, identity-snapshot, calendar-travel-context, ceo-progress, relationship-health), engines (briefing, feed, executive loop, proactive queue, stepwise scheduler, capability usage), working memory (reflection.md, identity-state.md, daily scratch), audit instruments (doc-audit, homeostasis predictions), and health data (garmin daily + sleep).
Using it
from freshness import assess, render, require
verdict = assess("view.health-snapshot")
print(render(snapshot["avg_sleep_hours"], verdict, unit="h", fmt="{:.1f}"))
# fresh -> "6.9h"
# stale -> "6.9h (stale 9d)"
# missing -> "unknown β view file absent"
Two render options exist for surfaces with layout constraints:
terse=Truecollapses untrustworthy states to an em-dash, for big-number cards and e-paper. The reason still reaches logs viaverdict.line()β it's dropped from the pixel, not from the record.annotate=Falsedrops the(stale 9d)suffix for split layouts that show the verdict in an adjacent slot. Only pass it when the verdict is displayed elsewhere; dropping the suffix without replacing it turns a stale number back into a fact.
require(verdict) raises StaleSourceError instead of degrading. Most
surfaces should degrade; use require only where acting on a stale number is
worse than not acting β a proactive message that would assert something to
bio-zack, for instance.
The status surface
$ uv run python -m freshness --status
freshness contract: 20 sources, 6 cannot currently back a number
STALE view.relationship-health age= 86d β aged_out_7d [aggregators/relationship_health.py β UNWIRED]
STALE view.ceo-progress age= 79d β aged_out_2d [aggregators/ceo_progress.py β no scheduled rebuild]
STALE garmin.sleep age= 1d β newest sleep is 2026-07-25 (1d back), not last night
STALE view.training-status age= 4h β RWGPS trips synced
STALE view.health-snapshot age= 4h β garmin data updated
unknown view.calendar-travel-context age= ? β not tracked by staleness.json
ok view.goal-progress age= 1d
...
This is the single answer to "which instruments are lying right now". Exit code is 1 when any source is untrustworthy, so it can gate a flow step.
--liars shows only the untrustworthy rows; --json is machine-readable;
--source <id> checks one.
view.relationship-health at 86 days is the canonical exhibit β it read
100/100 on track straight through the 2026-06-07 marital rupture, because
nothing rebuilds it and no consumer honored the freshness signal the detector
was already emitting.
Wired consumers
| Surface | What changed |
|---|---|
E-ink display (epd47_canvas.py) |
sleep card reads 8.3h Β· 2026-07-25 Β· 1d old instead of 8.3h Β· last night; a suspect night renders β; mirror mode won't make an accusation from an untrustworthy source; the exploring agent's source list is generated from live verdicts |
flows/sleep/data_source_health.py |
freshness.* rows join the nightly rollup, so a dark source appears there instead of waiting to be noticed |
GET /api/v1/goals/{id}/progress |
response carries freshness_state / freshness_reason / freshness_age_seconds |
scripts/utils.render_metric |
now delegates to the contract, so there is one code path |
The EPD wiring is the sharpest single example. _load_sleep_last_night() used
to fall back from today's garmin file to yesterday's silently and hand back a
bare dict β so a two-day-old number reached the wall under a "last night"
label. The fallback was always fine; hiding it was the bug.
Honest gaps
- EPD hardware is dark pending a physical power-cycle, so the pixel-level claim is verified against the render path, not against glass.
- The API holds stale bytecode for the
utils.pydelegation until an out-of-band restart.code_fresh.apiflagged this the same night β the verification machinery working β and it was not self-restarted mid-turn, per the self-restart-kill guard. - 20 sources is not all of them. Briefing tiles, X drafts, and the doctor working-memory are not yet consumers.
- The contract makes drift visible; it does not rebuild anything. That's
the write-side sibling (
2026-04-29-view-refresh-cadence-enforcement.md). Two chronically-cold views (ceo-progress,relationship-health) will keep reporting stale until someone owns their rebuild.
Related
- Verification & Anti-Lying Machinery β the broader immune system this belongs to
- E-ink Display β the first consumer
- Memory & Trends β the views the contract guards
- Self-Improvement β where forge 051 was developed