js-rigor: lossless persistence — validity, decay config, and TTLs survive snapshots
The persistence probe found three silent-loss defects in the snapshot round trip: relation validity labels (finite_sample downgraded to heuristic after save/load!), decay configs, and the value manager's per-relation TTL settings all vanished. The restored arbiter built its indices directly from the condensed graph, whose edge channel carries possibility/reliability/value only. Format version 2 now carries per-relation metadata (validity, decayConfig) and the valueTtls table in the snapshot payload; both the snapshot-access layer and the CondensedGraphIndices build merge the metadata back, so a restored arbiter is lossless end to end. Version 1 buffers are rejected with the existing clean version error. Pinned: a persistence round-trip test asserting validity label, decay config, TTL, and the restored check's validity label. Suites: rigor 207/0, full 809/747/0.
This commit is contained in:
@@ -213,3 +213,33 @@ describe('Security affordances (rigor)', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Persistence losslessness (rigor)', () => {
|
||||
it('FIXED: validity, decay config, and TTLs survive the snapshot round trip', async () => {
|
||||
const a = new Arbiter();
|
||||
a.addNode('u:0', 'user');
|
||||
a.addNode('d:0', 'doc');
|
||||
a.setRelationConfig('can_read', { type: 'direct', relation: 'owner' });
|
||||
a.addRelation('u:0', 'owner', 'd:0', {
|
||||
possibility: 0.8,
|
||||
reliability: 0.42,
|
||||
value: 7,
|
||||
validity: 'finite_sample',
|
||||
decayConfig: { halfLifeMs: 60000 }
|
||||
});
|
||||
a.valueManager.setTTL('owner', 30000);
|
||||
a.enableCondensedSnapshot();
|
||||
const { serializeArbiterSnapshot } = await import('../../src/core/SnapshotBinary.js');
|
||||
const { ArbiterSnapshot } = await import('../../src/core/arbiter/ArbiterSnapshot.js');
|
||||
const restored = ArbiterSnapshot.fromSnapshotBinary(serializeArbiterSnapshot(a), {}, () => new Arbiter());
|
||||
const rel = restored.relationManager.getDirectRelation(restored.resolveNodeId('u:0'), 'owner', restored.resolveNodeId('d:0'));
|
||||
assert.equal(rel.validity, 'finite_sample', 'validity label survives persistence');
|
||||
assert.deepEqual(rel.decayConfig, { halfLifeMs: 60000 }, 'decay config survives persistence');
|
||||
assert.equal(restored.valueManager.getTTL('owner'), 30000, 'per-relation TTL survives persistence');
|
||||
const r = restored.check('u:0', 'can_read', 'd:0', { includeMeta: true });
|
||||
assert.equal(r.validity.label, 'finite_sample', 'restored check carries the persisted label');
|
||||
// and a second restore of the same buffer is byte-stable
|
||||
const restored2 = ArbiterSnapshot.fromSnapshotBinary(serializeArbiterSnapshot(a), {}, () => new Arbiter());
|
||||
assert.equal(restored2.relationManager.getDirectRelation(restored2.resolveNodeId('u:0'), 'owner', restored2.resolveNodeId('d:0')).validity, 'finite_sample');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user