The principle: time is caller-provided (options.now / partialGraph.now);
the wall clock is only the fallback for unpinned callers, never a hidden
decision input. Remaining clock leaks:
- getBlurredValue gained an optional now param threaded to _isValueExpired;
ChainRule (2 sites), MultiHopRule (2 sites), RelationManager (3 sites)
now pass the caller clock. Previously a pinned-clock caller's chain/
multi-hop value TTL used the WALL clock (wall in 2026, pinned T0 in
2001 -> values wrongly expired).
- MultiHopRule's TTL gate used valueFilters.ttl || 24h instead of the
valueManager's per-relation TTL (inconsistent with chain/comparator);
now valueManager.getTTL is the authority, valueFilters.ttl the override.
- QualitativeRelationalComparatorRule decay (_calculatePeriodsElapsed)
and value timestamps used the wall clock, so qualitative possibility
decay ignored the pinned clock; now threaded through _evaluateOperand.
- ValueManager decay internals (getDecayedRelation, _calculateSeparated
Decay, _calculateBlurredValue) accept a now param (background worker
still passes none -> wall clock is correct there).
- PartialGraphContext._addChallengeProof/_addRelation used Date.now()
instead of the context's own this.now (the partial graph's time).
- Arbiter gained an injectable clock (options.clock) driving unpinned
cache-entry freshness in DecisionCache, RuleEvaluator, ChainRule, and
RelationalComparatorRule; DecisionCache explicit clock still wins.
- Collected-value timestamps in DirectRule and RelationalComparatorRule
honor the caller clock.
Pinned-clock chain probe: values fresh at T0, expired at T0+61s, with the
wall clock in 2026. Rigor 251/251, full suite 853/791/0.