Commit Graph

6 Commits

Author SHA1 Message Date
John Dvorak ed34df4474 feat: intermediate chain condition steps, graph-version cache invalidation, rolling-hash chain keys; fix vacuous rigor invariants
CI / benchmark (push) Successful in 48s
CI / test (push) Successful in 5m26s
CI / publish (push) Has been skipped
Chain intermediates (rule-based reachability):
- ChainRule: a condition step ({ rule, conditionStep }) at an INTERMEDIATE
  position is now EXPANDED from the current node — the rule's base edges'
  destinations, filtered by its defeaters/requirements — and traversal
  continues from each discovered node. Adds _expandRuleFromSrc / direct /
  logical(union/intersection) / defeasible / nested-chain expansion.
- RuleEvaluator: _subjectIsObject flag for unary predicate calls whose subject
  entity IS the object parameter (trusted(other) inside peer_trusted(user,
  other)); previously only subject-var unary calls (_subjectAsObject) were
  handled, so object-var unary defeaters never fired.

Graph-version cache invalidation:
- Arbiter gains a monotonic _graphVersion, incremented on every relation
  mutation. ChainRule result cache, RuleEvaluator rule-result cache, and
  DecisionCache rule cache now stamp entries with the graph version and treat
  any mismatch as a miss — graph mutations can no longer serve stale
  chain/authorization results.

Rolling-hash cache keys:
- UnifiedKeyManager.createChainKey now builds a 53-bit rolling hash (dual
  FNV-1a lanes, exact for ints/floats/strings/nested configs) instead of
  JSON.stringify — no string allocation or serialization on the chain-cache
  hot path. Composite keys stay structured strings because the direct-check
  cache pattern-invalidates by relation ID.

Rigor invariant migration (correctness):
- All 43 rigor test files' throw-based invariants ({ error, errorMessage } =>
  !error && !errorMessage) never saw fn throws — vacuous. Migrated to
  ({ actual }) => actual !== undefined, which fails on any thrown violation
  while passing legitimate null-skips. The migration immediately surfaced
  two latent bugs, now fixed:
    * node-manager/graph-indices skip paths returned bare undefined (falsy
      sentinel) — return { skipped: true }.
    * complex-graph-values-crucible expiry section rewrote values equal to the
      mutation loop's last write; the engine (by design) keeps the old
      timestamp on same-value rewrites so the pre-expiry grant never
      materialized. Now writes guaranteed-different values.
2026-08-03 13:26:42 -07:00
John Dvorak 4da3158c63 feat: ChainRule condition steps — rule-based final hops for chains
CI / publish (push) Has been skipped
CI / test (push) Successful in 5m43s
CI / benchmark (push) Successful in 35s
A chain step of the form { rule: <config>, conditionStep: true } is a
condition-gated hop instead of an edge traversal. It is valid only as the
FINAL step: the object is known, so the engine verifies the referenced rule
at (intermediate, object) for each current path. Enables a chain's object-side
hop to reference a defeasible/logical evidence (e.g.
member_of(user,*g){ gated(g,doc) } where gated is WHEN/UNLESS).

- RuleEvaluator wires the ChainRule with itself so condition steps can
  evaluate sub-rules recursively.
- ChainRule constructor accepts the ruleEvaluator; the traversal loop handles
  a final condition step (min-combined possibility, reliability product,
  threshold respect). Non-final condition steps return condition_step_not_final.
- The rule config is part of the chain cache key (JSON.stringify of steps).

Tests: chain-condition-step (grant/deny/missing-edge/non-final/parallel-max).
2026-08-03 12:00:16 -07:00
John Dvorak f446750ff3 refactor: extract Evidence DSL to @arbiter/evidence-dsl package
CI / test (push) Successful in 5m23s
CI / benchmark (push) Successful in 47s
CI / publish (push) Has been skipped
The Evidence DSL (ADR-000) compiles a natural DSL into core rule
configurations — it is a separate concern from the engine. The AST had
zero runtime coupling to the core (DSLCompiler takes the arbiter as a
duck-typed argument; ip-utils were the only shared code, now local to
the DSL package). This extraction removes the DSL surface from the core
artifact entirely:

- src/ast/ (748K, ~60 files) moved to @arbiter/evidence-dsl@1.0.0
- ip-utils moved with it (only the DSL consumed them)
- generate-parser script + peggy devDep moved to the DSL package
- the 8 DSL-consuming tests now import from @arbiter/evidence-dsl
  (deep-path exports: DSLCompiler, parser/*, generator/*, validation/*,
  interpreter/*)
- package.json gains the devDependency, drops build:ast/generate:parser

Tarball: AST-free. Rigor 251/251, full suite 838/776/0.
2026-08-03 09:17:33 -07:00
John Dvorak 257c52ea91 tests: migrate Date.now patching to the pinned-clock parameter
The now parameter (and partialGraph.now) replaced the need for global
Date.now patching in tests. The ttl-expiry parity campaign's module-scope
patch and the relational-comparator Time-Based Decay tests' before/after
patches now pass the clock explicitly through check options — no global
mutation, no restore-order fragility, and the pinned-clock cache bypass
keeps every evaluation honest. No stale references to the removed
compiled evaluator or useCompiled option remain in the test suite.
2026-08-02 11:03:10 -07:00
John Dvorak f0a310fd7c tests: harden wall-clock smoke bounds against parallel-load spikes
The full suite intermittently failed (pass counts 725-735, fail 0-1) under
parallel node --test execution. The reachability integration test asserted
a single-shot 100ms quick-failure bound and big-graph-optimized a 1s load
bound — both are regression smoke checks that can blow on a GC pause or
CPU contention spike while other files' campaigns run concurrently.

Both now re-measure once before failing, keeping the tight regression
signal while eliminating load-induced flakes. Full suite is now stable at
735 pass / 0 fail / 62 skipped across repeated runs.
2026-07-31 20:02:50 -07:00
John Dvorak 717ae1031e initial commit: @arbiter/core authorization engine with js-rigor hardening
Zanzibar-style authorization graph engine (direct/chain/TTU/defeasible/
binary modes, condensed snapshots, value relations) with 39 rigor test
campaigns. Includes fixes for snapshot binary writer/reader format
mismatch (snapshot-of-snapshot corruption), possibility write-boundary
validation, empty-graph snapshot serialization, relation lookup cache
direction collision, config-redefinition cache invalidation, binary
threshold semantics, defeasible compiled routing, and comparator
reason whitelisting.
2026-07-31 13:44:06 -07:00