- Duration literals now accept s/m/h/d/w (was m/h/d/w): 'BEHAVES { ttl 30s }'
is 30s, and 'within 30s' temporal expressions parse.
- Definition fields are REQUIRED by default ('field: type'); 'field: type?'
marks a field optional. addNode enforces presence on insert, getSchema
exposes per-field requiredness, and updateNodeData still validates the
provided fields' types.
- Provider-returned edges are validated against the fact's declared typing:
a value-carrying fact must return { value, possibility } with a value of the
declared type (bare-number shorthand is rejected); a non-value fact must not
carry a value; and every possibility must lie in [0, 1]. Violations throw a
clear provider-authoring error instead of silently injecting malformed edges.
Tests: DSLRuntimeTyping (duration units, required-field enforcement, schema
requiredness, value-type + shape + possibility validation).
Automatically-retrieved facts (balances, sessions, etc.) are now cached with
a time expiry so repeated checks don't re-invoke the underlying data store.
- check(): registered providers cache their normalized edges per
(relation, subject, object) with a TTL; a fresh entry is reused without
re-invoking the provider. Per-check factProviders are one-off observations
and stay cache-transparent (no read, no write).
- TTL resolution: DSL-declared 'BEHAVES { ttl <duration> }' on a fact >
setFactTTL(relation, ms) > policy.providerCacheTTL (default 30s; 0 disables).
- Grammar: facts may now declare a freshness window via
'fact balance(user, amount) BEHAVES { ttl 1h }' (previously BEHAVES only
accepted 'AS edge|transitive|hierarchical|symmetrical_graph'). The runtime
indexes it as the fact's ttlMs.
- registerFact/unregisterFact, graph mutations (add/update/remove node or
relation), and invalidateProviderCache(relation?) keep the cache consistent.
- Injectable clock (default wall clock) drives cache freshness, mirroring the
core's unpinned-clock contract.
Tests: DSLRuntimeCache (reuse within TTL, expiry re-invoke, per-check
override transparency, registerFact invalidation, mutation invalidation,
per-relation/all invalidation, policy default, DSL-declared 1h TTL).
The Evidence DSL (ADR-000) is a thin declarative layer that compiles to
engine rule types. It has zero runtime coupling to the core engine
(DSLCompiler takes an arbiter as a duck-typed argument; the only shared
code was the ip-utils helpers, now local). Extracting it into its own
package keeps the core artifact free of the DSL surface.
- @arbiter/evidence-dsl depends on @arbiter/core (config formats are the
compilation target)
- deep-path exports for the compiler, parser, generator, validation,
and built-in functions (the surface the core's DSL tests consume)
- tests moved alongside; generate-parser script + peggy devDep local
- CI: test on push, publish on v* tags