Part of #364 (D107 temporal clocks). Gates WP-T.1. Lands as a design amendment to temporal_clocks_design.md §7.1 (and k_layers_design.md / the profile refresher design), reviewed by Codex, before any WP-T.1 code.
Context
D107 makes "current" the full interval-containment predicate facts_current already uses (ingested_at <= E, not invalidated, valid_from absent or <= E, valid_until absent or > E) on every current read. Entity profiles and K pages are cached renderings; today they deliberately admit only open-ended facts because a future cap would make their input hash expire as wall time passes (profile_refresher.py:835). D107 §7.1 introduces a durable fact_expiry_schedule that regenerates an artifact when the earliest future activation or expiry among its inputs passes, with the boundary instant as E.
What the spike must decide (Codex round 5, major 6)
- Dependency tracking for not-yet-active facts: a fact starting in 2030 is excluded by the predicate today and so is not an artifact input — how does its activation get scheduled for the artifacts that will include it (route by entity/page membership, not by current inputs)?
- Transactional schedule maintenance: schedule rows updated in the same transaction as any change to a fact boundary or to the routing relation (entity merges, K page membership), D12-idempotent keys.
- Downtime: drain and coalesce all boundaries that passed while the sweep was down; regenerate once with the current instant as
E, not once per missed boundary.
- Staleness that reads cannot fix: the read-time predicate protects live fact reads, not already-rendered profile text or a static K page. Either give cached artifacts a checked
valid_through / stale state that prevents presenting them as current when the refresh is late, or disclose staleness through the D49 envelope (freshness) and document the guarantee honestly.
- Cost bounds: how many artifacts a single boundary can invalidate (hub entities), and batching.
Acceptance
A state with a future end is current today and its profile refreshes when the end passes, including after a restart with several boundaries missed; a fact starting in the future appears in its profile when it starts; a late sweep never serves an expired fact as current without disclosure.
🤖 Generated with Claude Code
Part of #364 (D107 temporal clocks). Gates WP-T.1. Lands as a design amendment to
temporal_clocks_design.md§7.1 (andk_layers_design.md/ the profile refresher design), reviewed by Codex, before any WP-T.1 code.Context
D107 makes "current" the full interval-containment predicate
facts_currentalready uses (ingested_at <= E, not invalidated,valid_fromabsent or<= E,valid_untilabsent or> E) on every current read. Entity profiles and K pages are cached renderings; today they deliberately admit only open-ended facts because a future cap would make their input hash expire as wall time passes (profile_refresher.py:835). D107 §7.1 introduces a durablefact_expiry_schedulethat regenerates an artifact when the earliest future activation or expiry among its inputs passes, with the boundary instant asE.What the spike must decide (Codex round 5, major 6)
E, not once per missed boundary.valid_through/ stale state that prevents presenting them as current when the refresh is late, or disclose staleness through the D49 envelope (freshness) and document the guarantee honestly.Acceptance
A state with a future end is current today and its profile refreshes when the end passes, including after a restart with several boundaries missed; a fact starting in the future appears in its profile when it starts; a late sweep never serves an expired fact as current without disclosure.
🤖 Generated with Claude Code