js-rigor: possibilistic validity layer (Cella FVN labels, conflict mass, validification)
Adds an epistemic validity layer in the spirit of the zig-contour fusion
spec: every check result now carries a validity block {label, operator,
regime, sources, conflictMass, validifiedPossibility, nonMaxitive}.
- Relations accept a validity label (default heuristic = unlabeled input).
- Labels propagate through fusion: identity/max preserve the weakest
source label (max is already valid under arbitrary dependence); min
(conjunctive: intersection, chain, TTU, multi_hop, parent) is
approximate at best, surfaces the conflict mass (1 - possibility) that
was previously dropped, and exposes the arbitrary-regime validification
min(1, K*gamma); product-style operators (exclusion, defeasible) and
interior OWA averaging are always heuristic, with nonMaxitive flagged.
- Reliability and validity are now explicitly distinct: reliability stays
the scalar confidence adaptation; validity tracks the epistemic label.
- The hottest paths attach a shared frozen default block instead of
allocating (perf A/B shows no regression: ~300k ops/s direct both ways).
- Pre-existing fixes surfaced while wiring: the array-form logical config
dropped top-level aggregator/owaWeights (average union compiled as max),
and _createStandardResult dropped unknown fields (validity never
survived rule results).
New campaign validity-parity.test.js pins the label taxonomy, conflict
mass, validification, weakest-propagation, and the reliability/validity
separation. Suites: rigor 203/0, full 803/741/0.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { buildValidity, normalizeValidity, mergeValidity, DEFAULT_VALIDITY } from '../core/validity.js';
|
||||
import { Arbiter } from '../core/Arbiter.js';
|
||||
import { RuleEvaluator } from './RuleEvaluator.js';
|
||||
import { RuleCollector } from './RuleCollector.js';
|
||||
@@ -162,6 +163,9 @@ export class AuthorizationChecker {
|
||||
} else {
|
||||
result = {
|
||||
possibility: directRel.possibility,
|
||||
validity: directRel.validity !== undefined
|
||||
? buildValidity('identity', [effectiveRelation], [normalizeValidity(directRel.validity)], 1, directRel.possibility)
|
||||
: DEFAULT_VALIDITY,
|
||||
// A denied decision (possibility 0) must not leak the
|
||||
// relation's reliability — the rule-collection path zeroes it.
|
||||
reliability: directRel.possibility > 0
|
||||
@@ -344,6 +348,7 @@ export class AuthorizationChecker {
|
||||
const finalResult = {
|
||||
possibility: resPossibility || 0,
|
||||
reliability: res.reliability !== undefined ? res.reliability : 1.0,
|
||||
validity: res.validity || DEFAULT_VALIDITY,
|
||||
...(collectValues && res.collectedValues && Array.isArray(res.collectedValues) && { collectedValues: res.collectedValues }),
|
||||
...(includeMeta && {
|
||||
meta: {
|
||||
@@ -373,6 +378,8 @@ export class AuthorizationChecker {
|
||||
let bestDenyReliability = 0;
|
||||
let bestAllow = null;
|
||||
let bestDeny = null;
|
||||
let bestAllowValidity = null;
|
||||
let ruleValidityBlocks = [];
|
||||
let reason = undefined;
|
||||
let allRuleResults = shouldTrackEvaluation ? [] : null;
|
||||
let allCollectedValues = collectValues ? [] : null; // Collect values from all evaluated rules
|
||||
@@ -457,7 +464,9 @@ export class AuthorizationChecker {
|
||||
maxAllow = resAllowPossibility;
|
||||
bestAllow = resMeta;
|
||||
bestAllowReliability = res.reliability !== undefined ? res.reliability : 1.0;
|
||||
bestAllowValidity = res.validity || null;
|
||||
}
|
||||
if (res.validity) ruleValidityBlocks.push(res.validity);
|
||||
|
||||
if (resDenyPossibility > maxDeny) {
|
||||
maxDeny = resDenyPossibility;
|
||||
@@ -543,9 +552,21 @@ export class AuthorizationChecker {
|
||||
const remediation = maxAllow === 0
|
||||
? buildRemediation(remediationOptions.length > 0 ? { status: 'required', options: remediationOptions } : null, { status: 'required' })
|
||||
: null;
|
||||
const result = {
|
||||
// Possibilistic validity of the decision: the winning rule's block when
|
||||
// a single rule drove it, otherwise the weakest-merge of all
|
||||
// contributors (a heuristic/banned contributor downgrades the whole).
|
||||
let finalValidity = DEFAULT_VALIDITY;
|
||||
if (ruleValidityBlocks.length === 1) {
|
||||
finalValidity = ruleValidityBlocks[0];
|
||||
} else if (ruleValidityBlocks.length > 1) {
|
||||
finalValidity = mergeValidity(ruleValidityBlocks);
|
||||
} else if (maxAllow > 0 && bestAllowValidity) {
|
||||
finalValidity = bestAllowValidity;
|
||||
}
|
||||
const result = {
|
||||
possibility: maxAllow,
|
||||
reliability: maxAllow > 0 ? bestAllowReliability : maxDeny > 0 ? bestDenyReliability : 0,
|
||||
validity: finalValidity,
|
||||
...(includeMeta && {
|
||||
meta: {
|
||||
allow: bestAllow,
|
||||
|
||||
Reference in New Issue
Block a user