js-rigor: OWA fusion hardened; reliabilityWeighting, shorthand children, cache key

Probe sweep of the OWA surfaces found three real defects:

- reliabilityWeighting was a silent no-op everywhere: every implementation
  scaled possibilities by metas[i].reliability, but no child meta ever
  carried a reliability field (the compiled direct omitted it and the
  DirectRule handler omitted it too), so the weighting was always x1.0.
  All weighting branches now use the tracked child reliabilities, and the
  DirectRule handler + its meta now carry the relation's reliability.
- The compiled union and the direct_list fast path had no
  reliabilityWeighting branch at all; both now apply it.
- Shorthand children ({ relation: 'editor' }) dispatch to the direct
  handler but carry no type, so _getRuleResultCacheKey derived the generic
  'rule' suffix for every shorthand child of a logical rule — the first
  child's cached result was served for all of them (the fallback path
  returned the owner's 0.8 for the editor). The key derivation now matches
  the shorthand dispatch. The RuleEvaluator also treats shorthand operands
  as direct rules instead of unknown_rule_type on the non-compiled path.

New pins: an OWA differential property (custom weights, max/min/average
aggregators, reliabilityWeighting, compiled path) and a multi_hop
pathAggregation=owa fixed pin with reliability propagation.
This commit is contained in:
John Dvorak
2026-08-02 08:14:39 -07:00
parent 7c465b64f4
commit fb258035f9
5 changed files with 151 additions and 9 deletions
+9 -2
View File
@@ -984,6 +984,9 @@ export class LogicalOperators extends BaseRule {
inputCount: possibilities.length,
bilatticeAnalysis: epistemicAnalysis
});
} else if (unionConfig.reliabilityWeighting) {
const weighted = possibilities.map((poss, i) => poss * (reliabilities[i] ?? 1.0));
result = OWAFusion.fuseWithMeta(weighted, metas, unionOWAWeights, unionConfig.aggregator || 'max', true, owaTraceOptions);
} else if (unionOWAWeights.some(w => w > 0)) {
Arbiter.DEBUG && Arbiter.log('union using OWA evidential fusion', {
aggregator: unionConfig.aggregator || 'max',
@@ -1148,7 +1151,7 @@ export class LogicalOperators extends BaseRule {
let result;
if (intersectionConfig.reliabilityWeighting) {
const reliabilityWeightedPossibilities = possibilities.map((poss, i) => poss * (metas[i]?.reliability || 1.0));
const reliabilityWeightedPossibilities = possibilities.map((poss, i) => poss * (reliabilities[i] ?? 1.0));
result = OWAFusion.fuseWithMeta(reliabilityWeightedPossibilities, metas, finalWeights, defaultMode, true, owaTraceOptions);
} else {
result = OWAFusion.fuseWithMeta(possibilities, metas, finalWeights, defaultMode, true, owaTraceOptions);
@@ -1279,7 +1282,11 @@ export class LogicalOperators extends BaseRule {
});
if (exclusionConfig.reliabilityWeighting) {
const reliabilityWeightedPossibilities = possibilities.map((poss, i) => poss * (metas[i]?.reliability || 1.0));
const legReliabilities = [
a.reliability !== undefined ? a.reliability : 1.0,
b.reliability !== undefined ? b.reliability : 1.0
];
const reliabilityWeightedPossibilities = possibilities.map((poss, i) => poss * (legReliabilities[i] ?? 1.0));
result = OWAFusion.fuseWithMeta(reliabilityWeightedPossibilities, metas, exclusionOWAWeights, exclusionConfig.aggregator || 'min', true, owaTraceOptions);
} else {
result = OWAFusion.fuseWithMeta(possibilities, metas, exclusionOWAWeights, exclusionConfig.aggregator || 'min', true, owaTraceOptions);