fix: standard collected-value shape on the direct fast path + caller-clock timestamps
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.
This commit is contained in:
@@ -177,6 +177,9 @@ export class BaseRule {
|
||||
* @protected
|
||||
*/
|
||||
_createCollectedValue(value, possibility, path, source, metadata = {}) {
|
||||
// Timestamps honor the caller's pinned clock when present; the wall
|
||||
// clock is only the fallback for unpinned callers.
|
||||
const clockNow = (typeof metadata._now === 'number') ? metadata._now : Date.now();
|
||||
return {
|
||||
value: value,
|
||||
possibility: possibility ?? 1.0,
|
||||
@@ -188,7 +191,7 @@ export class BaseRule {
|
||||
step: source.step !== undefined ? source.step : 0
|
||||
},
|
||||
metadata: {
|
||||
timestamp: metadata.timestamp || Date.now(),
|
||||
timestamp: metadata.timestamp || clockNow,
|
||||
reliability: metadata.reliability !== undefined ? metadata.reliability : 1.0,
|
||||
decay: metadata.decay || null,
|
||||
...metadata
|
||||
|
||||
Reference in New Issue
Block a user