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.
README: purpose-first (possibility not boolean, caller owns evidence/time),
install, verified quick start, concepts (result shape, overlays, temporal
context), API table, development commands, design notes.
benchmark: scripts/benchmark.js on @tenere/benchmark-lib — eight contours
(direct/union/denied/meta/overlay/binary checks, snapshot build/restore),
committed .rigor-baseline.json, exit 1 on high-severity regressions.
CI: benchmark job compares on push (continue-on-error), re-saves baseline
and uploads it as an artifact on tags; publish now depends on benchmark
passing as well as test.