feat: duration seconds; required fields; type-validated insertions/updates/retrievals
CI / publish (push) Successful in 9s
CI / test (push) Successful in 19s

- 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).
This commit is contained in:
John Dvorak
2026-08-03 16:00:49 -07:00
parent aa38fbfd8c
commit 9111c4b20d
8 changed files with 856 additions and 707 deletions
+6 -6
View File
@@ -14,8 +14,8 @@ import { Arbiter } from '@arbiter/core';
import { DSLRuntime } from '../src/runtime/DSLRuntime.js';
const BASE_DSL = `
definition Employee { id: string }
definition Doc { id: string }
definition Employee { id: string? }
definition Doc { id: string? }
fact *owns(user: Employee, doc: Doc)
evidence can_read(user: Employee, doc: Doc) { owns(user, doc) }
`;
@@ -102,8 +102,8 @@ describe('DSLRuntime provider-result caching', () => {
it('invalidateProviderCache() clears all or per relation', async () => {
const dsl = `
definition Employee { id: string }
definition Doc { id: string }
definition Employee { id: string? }
definition Doc { id: string? }
fact *owns(user: Employee, doc: Doc)
fact *banned(user: Employee)
evidence can_read(user: Employee, doc: Doc) { owns(user, doc) }
@@ -151,8 +151,8 @@ describe('DSLRuntime provider-result caching', () => {
it('uses the DSL-declared fact TTL (BEHAVES { ttl X })', async () => {
const dsl = `
definition Employee { id: string }
definition Doc { id: string }
definition Employee { id: string? }
definition Doc { id: string? }
fact *balance(user: Employee, amount: number) BEHAVES { ttl 1h }
evidence can_spend(user: Employee, doc: Doc) { balance(user, 1) }
`;