The reliability gap found last round was invisible to every parity mirror
(they compared possibility only). Hardened the existing campaigns so the
mirrors carry reliability too:
- batch-order-parity: batch ops carry reliability; the mirror tracks
last-write-wins reliability and the crucible asserts engine reliability
parity (mirror corrected: add-on-existing preserves reliability, it does
not reset it).
- rule-kind-partial-parity: the TTU differential property now generates
per-edge reliabilities and asserts the winning intermediate's
reliability (tupleset.reli * computed.reli); a new chain reliability
differential property does the same for 2-step chains.
- snapshot-quantization-parity: edges carry deterministic reliabilities and
the round-trip pins the codec's reliability channel (product-aware
tolerance: chain reliability multiplies two quantized inputs).
- model-based-graph: the reference model tracks reliability per tuple and
checks it alongside possibility for direct and chain queries.
The model crucible immediately caught a real bug: the direct-check fast
path returned the relation's reliability on a DENIED decision (possibility
0), while the rule-collection path zeroes it — denied results leaked
reliability. Both fast-path branches (direct match and threshold_not_met)
now report reliability 0 when the decision is denied.
Systemic reliability gap found by the probe sweep: the compiled evaluation
paths never emitted the reliability the engine computes.
- Compiled _evaluateDirect omitted the relation's reliability, and the
chain/multi_hop rules hardcoded reliability: 1.0 — so check() results
reported 1.0 for any rule whose decision came through a chain, multi_hop,
union, intersection, exclusion, or defeasible combination.
- The chain and multi_hop traversals now track per-path reliability (product
of edge reliabilities) and report the winning path's value; the compiled
and fallback logical operators (union/intersection/exclusion, direct_list
fast path, early exits) report the selected child's reliability
(max/min child or OWA trace index; exclusion multiplies both legs), and
normal-mode defeasible combines base x requires x defeater reliabilities.
- The checker's logical fast path dropped collectedValues from union/
intersection/exclusion results; it now passes them through.
- MultiHopRule.valueManager was read off relationManager where the real
arbiter keeps it on the arbiter — collectValues: true on a multi_hop rule
with a value-carrying edge crashed the evaluation (error result, silent
denial). Now resolved at the arbiter level with a relationManager
fallback for stubs.
Campaign pins: reliability per kind (chain/multi_hop product, union/intersection
selected child, exclusion/defeasible product), and multi_hop value collection
through persistent and partial contexts.
updateRelationsBatch previously pre-sorted ops remove->modify->add, which
changed the final state whenever one tuple was touched by mixed kinds:
[add, remove] left the tuple present, [modify, add, modify] ended with
the middle value. Now ops apply strictly in the given order via the
dedup-aware _addRelationInternal (in-place last-write-wins) with upfront
validation, post-batch PLTC edge updates, and per-relation arbiter-level
cache invalidation.
batch-order-parity.test.js pins the contract with an in-order mirror
(modify-of-missing is a silent no-op).