js-rigor: check() no longer strips reliability; TTU reliability pins
Bug 34: ArbiterChecks.check destructured { reliability, ...rest } out of
every normal (and binary) check result since the initial commit — the
engine computes reliability faithfully (TTU tupleset.reli * computed.reli,
direct relation reliability) and explain() preserved it, but the public
check() API silently dropped it. explain() kept it, so exposing it in
check() is the intended contract. The destructuring is removed; direct
and TTU checks now return reliability (0.6 / 0.72 in the pins).
Campaign pins added: TTU multi-path fusion (max over intermediates of
min(legs)) with reliability propagation through both persistent and
partial contexts, the maxIntermediates circuit breaker through partial,
and snapshot-restored arbiters evaluating TTU.
This commit is contained in:
@@ -38,7 +38,7 @@ function mkArbiter(opts = {}) {
|
||||
|
||||
describe('Rule-kind × partial-graph parity (rigor)', () => {
|
||||
|
||||
it('FIXED MATRIX: every kind matches between persistent and partial', () => {
|
||||
it('FIXED MATRIX: every kind matches between persistent and partial', async () => {
|
||||
// ---- direct ----
|
||||
{
|
||||
const a = mkArbiter();
|
||||
@@ -385,6 +385,63 @@ describe('Rule-kind × partial-graph parity (rigor)', () => {
|
||||
assert.equal(r.possibility, 1, 'challenge binary satisfied');
|
||||
assert.equal(r.allow, true, 'challenge binary allow');
|
||||
}
|
||||
// ---- TTU multi-path fusion + reliability propagation ----
|
||||
{
|
||||
const a = mkArbiter();
|
||||
a.setRelationConfig('can_read', { type: 'tuple_to_userset', tuplesetRelation: 'owner', computedRelation: 'member_of' });
|
||||
a.setRelationConfig('member_of', { type: 'direct', relation: 'member_of' });
|
||||
a.addRelation('doc:0', 'owner', 'g:0', { possibility: 0.8, reliability: 0.9 });
|
||||
a.addRelation('doc:0', 'owner', 'g:1', { possibility: 0.6 });
|
||||
a.addRelation('u:0', 'member_of', 'g:0', { possibility: 0.7, reliability: 0.8 });
|
||||
a.addRelation('u:0', 'member_of', 'g:1', { possibility: 0.5 });
|
||||
const p = a.check('u:0', 'can_read', 'doc:0');
|
||||
assert.equal(round4(p.possibility), 0.7, 'ttu multi-path fusion persistent');
|
||||
assert.ok(typeof p.reliability === 'number' && p.reliability > 0,
|
||||
`ttu reliability flows through normal check: ${p.reliability}`);
|
||||
assert.ok(Math.abs(p.reliability - 0.72) < 0.01, `ttu reliability = 0.9*0.8, got ${p.reliability}`);
|
||||
a.removeRelation('doc:0', 'owner', 'g:0');
|
||||
a.removeRelation('doc:0', 'owner', 'g:1');
|
||||
a.removeRelation('u:0', 'member_of', 'g:0');
|
||||
a.removeRelation('u:0', 'member_of', 'g:1');
|
||||
const r = a.check('u:0', 'can_read', 'doc:0', {
|
||||
partialGraph: { relations: [
|
||||
{ src: 'doc:0', relation: 'owner', dst: 'g:0', possibility: 0.8, reliability: 0.9 },
|
||||
{ src: 'doc:0', relation: 'owner', dst: 'g:1', possibility: 0.6 },
|
||||
{ src: 'u:0', relation: 'member_of', dst: 'g:0', possibility: 0.7, reliability: 0.8 },
|
||||
{ src: 'u:0', relation: 'member_of', dst: 'g:1', possibility: 0.5 }
|
||||
] }
|
||||
});
|
||||
assert.equal(round4(r.possibility), 0.7, 'ttu multi-path fusion partial');
|
||||
assert.ok(Math.abs(r.reliability - 0.72) < 0.01, `ttu reliability partial, got ${r.reliability}`);
|
||||
}
|
||||
// ---- TTU maxIntermediates circuit breaker through partial ----
|
||||
{
|
||||
const a = mkArbiter();
|
||||
for (let i = 0; i < 25; i++) a.addNode('gx:' + i, 'group');
|
||||
a.setRelationConfig('can_read', { type: 'tuple_to_userset', tuplesetRelation: 'owner', computedRelation: 'member_of', maxIntermediates: 5 });
|
||||
a.setRelationConfig('member_of', { type: 'direct', relation: 'member_of' });
|
||||
const rels = [];
|
||||
for (let i = 0; i < 25; i++) {
|
||||
rels.push({ src: 'doc:0', relation: 'owner', dst: 'gx:' + i, possibility: 0.3 + (i % 10) / 20 });
|
||||
rels.push({ src: 'u:0', relation: 'member_of', dst: 'gx:' + i, possibility: 0.5 });
|
||||
}
|
||||
const r = a.check('u:0', 'can_read', 'doc:0', { partialGraph: { relations: rels } });
|
||||
assert.equal(round4(r.possibility), 0.5, 'ttu circuit breaker picks best of limited intermediates');
|
||||
}
|
||||
// ---- snapshot-restored arbiter evaluates TTU ----
|
||||
{
|
||||
const a = mkArbiter();
|
||||
a.setRelationConfig('can_read', { type: 'tuple_to_userset', tuplesetRelation: 'owner', computedRelation: 'member_of' });
|
||||
a.setRelationConfig('member_of', { type: 'direct', relation: 'member_of' });
|
||||
a.addRelation('doc:0', 'owner', 'g:0', { possibility: 0.8 });
|
||||
a.addRelation('u:0', 'member_of', 'g:0', { possibility: 0.7 });
|
||||
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 p = restored.check('u:0', 'can_read', 'doc:0');
|
||||
assert.equal(round4(p.possibility), 0.7, 'snapshot-restored TTU');
|
||||
}
|
||||
// ---- binary mode agrees with normal at the same threshold ----
|
||||
{
|
||||
const a = mkArbiter();
|
||||
|
||||
Reference in New Issue
Block a user