Two remaining clock/shape inconsistencies from the audit:
1. The direct fast path emitted a bare collected-value object
{value, source, relation, userKey, objectKey} — no possibility, no
path, no metadata. Value consumers (comparators, chains) rely on the
self-describing shape the rule paths emit. The fast path now emits
the standard shape (value/possibility/path/source/metadata), matching
DirectRule's existing _createCollectedValue contract.
2. Collected-value timestamps fell back to the WALL clock (Date.now())
even for pinned-clock callers in BaseRule._createCollectedValue,
ChainRule, and TupleToUsersetRule. The metadata timestamp now honors
options.now when pinned (changed_last_at wins, then pinned now, then
wall clock). ValueContext's collectedAt remains metadata-only.
Pinned by ttl-contract.test.js: the fast-path collected value carries
the full shape and its timestamp honors the pinned clock. Rigor 251/251,
full suite 853/791/0.
Three related findings from the nervous-item audit:
1. TTL contract pinned (ttl-contract.test.js + README): TTL is a
VALUE-FRESHNESS gate, not an access-expiry mechanism. Direct grants
are timeless; expired values deny comparators and drop from collected
values. The direct fast path collected values WITHOUT the TTL gate
(comparators skipped expired relations, the direct path did not) —
now gated identically.
2. ChainRule cache served pinned-clock callers (ChainRule.js): a chain
result captured at one time (with then-fresh values) was served to
callers asking about another time. The chain cache now bypasses
reads AND writes when options.now is pinned, matching the rule-result
cache contract.
3. Decision caches bundled stale values (AuthorizationChecker.js):
the direct-check cache stored collectedValues alongside the timeless
decision; an unpinned caller past wall-clock expiry got the stale
value. Value-carrying results are now never cached (the decision is
timeless, the values are not). The rule-result cache is unchanged —
it serves snapshots under explicit write-invalidation (its own
contract, asserted by cache-invalidation tests).
Rigor 250/250, full suite 852/790/0.