Automatically-retrieved facts (balances, sessions, etc.) are now cached with
a time expiry so repeated checks don't re-invoke the underlying data store.
- check(): registered providers cache their normalized edges per
(relation, subject, object) with a TTL; a fresh entry is reused without
re-invoking the provider. Per-check factProviders are one-off observations
and stay cache-transparent (no read, no write).
- TTL resolution: DSL-declared 'BEHAVES { ttl <duration> }' on a fact >
setFactTTL(relation, ms) > policy.providerCacheTTL (default 30s; 0 disables).
- Grammar: facts may now declare a freshness window via
'fact balance(user, amount) BEHAVES { ttl 1h }' (previously BEHAVES only
accepted 'AS edge|transitive|hierarchical|symmetrical_graph'). The runtime
indexes it as the fact's ttlMs.
- registerFact/unregisterFact, graph mutations (add/update/remove node or
relation), and invalidateProviderCache(relation?) keep the cache consistent.
- Injectable clock (default wall clock) drives cache freshness, mirroring the
core's unpinned-clock contract.
Tests: DSLRuntimeCache (reuse within TTL, expiry re-invoke, per-check
override transparency, registerFact invalidation, mutation invalidation,
per-relation/all invalidation, policy default, DSL-declared 1h TTL).