Three improvements over the complex-graph crucibles:
1. Anti-vacuity guards (assertRealVerdict): rigor's complexity verdict
PASSES on zero observations — a broken action (missing import, wrong
args shape) silently goes green. Every complexity verdict now asserts
observationCount >= 50, costSource == expected, and calibrated ==
true, so a vacuous verdict is a test failure.
2. Snapshot complexity: serialized snapshot BYTE SIZE is O(n) in graph
size, verified deterministically (build and restore round-trip).
Wall-clock timing at sub-ms scale is pure jitter for the e-process
spread check (verified empirically — buildTime O(n) failed on spread
while buildBytes passed); latency stays covered by benchmark
percentiles.
3. complex-graph-mutation-crucible: MUTATION-FRESHNESS — random edge
removals/additions on community + scale-free graphs, normal/binary
agreement re-checked after EVERY mutation, stale grants and missing
fresh grants are failures. Two real findings during bring-up, both
fixture bugs rather than engine bugs:
- the scale-free generator returned a raw edge COUNT as 'relations'
while other generators returned edge arrays (now null, consistent
with dense-adversarial; the crucible walks the arbiter's store)
- arbiter.relations stores NUMERIC ids, so removals must resolve
string keys to ids before matching (string-key comparison silently
no-oped, looking like a stale grant)
Snapshot read-only semantics documented in the crucible: enableCondensed-
Snapshot flips the engine to read-only permanently, so mutation crucibles
exercise the writable path, and frozen-snapshot properties stay with the
snapshot-parity suites. Rigor 239/239, full suite 841/779/0.
Activates js-rigor's normally-dormant complexity and benchmark verdicts
against the complex-graph generators:
COMPLEXITY (e-process verified, deterministic cost signals):
- direct/chain/ttu lookups declared O(1) in graph size — verified with a
deterministic engine-lookup counter as the cost metric (wall-clock at
sub-ms scale is pure jitter for the spread check); a regression to
linear scans would grow the counter with n and trip the e-process
- union evaluated O(k) in rule count in normal mode vs O(1) in binary
mode (threshold early exit) — declared cost = rule evaluations
BENCHMARK (percentile assertions over auto-collected samples):
- direct/chain/ttu single-check actions stay under p50=0.2ms p95=1.0ms
budgets on the complex graphs
Debugging along the way surfaced two rigor API facts worth pinning:
metric readers receive the raw generated-args ARRAY (fns get the spread
values), and a missing module import silently degrades actions into
'no observations' vacuous verdicts (ReferenceError swallowed by the
runner). Full rigor 237/237.