relations: Phase 2 reachability + roots/leaves + cycles (engine.sx, kind-parameterized closure) + 24 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m0s

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 11:53:36 +00:00
parent c67aefa211
commit 7a1696490c
7 changed files with 352 additions and 22 deletions

View File

@@ -18,7 +18,7 @@ links. Reuses `lib/datalog/` — does not reimplement the engine.
## Status (rolling)
`bash lib/relations/conformance.sh`**22/22** (Phase 1 complete)
`bash lib/relations/conformance.sh`**46/46** (Phases 12 complete)
## Ground rules
@@ -72,11 +72,11 @@ lib/relations/federation.sx
## Phase 2 — Reachability + cycles
- [ ] recursive reachability rules: `ancestors`, `descendants`, `reachable?(A,B)`
- [x] recursive reachability rules: `ancestors`, `descendants`, `reachable?(A,B)`
(transitive closure over a kind, the acl inheritance shape)
- [ ] `roots` / `leaves` (no parents / no children) for a kind
- [ ] cycle detection: `cycle?(X)``reachable(X, X)`; `acyclic?(db, kind)`
- [ ] `lib/relations/tests/reach.sx` — deep chains, diamonds, disconnected nodes,
- [x] `roots` / `leaves` (no parents / no children) for a kind
- [x] cycle detection: `cycle?(X)``reachable(X, X)`; `acyclic?(db, kind)`
- [x] `lib/relations/tests/reach.sx` — deep chains, diamonds, disconnected nodes,
self-loops, multi-kind isolation
## Phase 3 — Typed relations + path explanation
@@ -100,6 +100,21 @@ lib/relations/federation.sx
## Progress log
- **Phase 2 — reachability + cycles** (46/46). New `engine.sx` is one Datalog
ruleset. Reachability is kind-parameterised — `reach(K,X,Y)` carries the kind as
its first arg so a transitive walk over `parent` never leaks through `reply`
edges (the acl inheritance shape, but closures can't cross kinds). `rnode`
collects touched nodes; `root`/`leaf` use stratified negation over
`has_parent`/`has_child`. Cycles are data, not errors: `cycle?(node,kind)`
`reach(K,node,node)` holds, `acyclic?(kind)` ⇔ no `reach(K,X,X)`. Engine fns:
`relations-descendants/-ancestors/-reachable?/-roots/-leaves/-cycle?/-acyclic?`;
api.sx grew matching `relations/...` current-db wrappers. `relations-rules` and
`relations-pluck` moved from api.sx into engine.sx (engine now loads before api
in conformance.conf). reach.sx covers diamonds, deep chains, disconnected
components, self-loops, c1<->c2 cycles, and multi-kind isolation. acl
convergence: the `reach(X,Y):-edge(X,Y)` / `reach(X,Y):-edge(X,Z),reach(Z,Y)`
closure shape is shared with acl's eff_grant/eff_deny inheritance — flagged, not
extracted (per ground rules).
- **Phase 1 — schema + direct relations** (22/22). `schema.sx`: `rel(Src,Dst,Kind)`
fact constructor + accessors, open kind vocabulary (`parent member reply variant
origin link`), `relations-fact-valid?`/`relations-known-kind?`. `api.sx`: db built