From d09ed83fa1e30c5d6fc33bb29a9e09627ace177e Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 09:05:36 +0000 Subject: [PATCH] datalog: cooking-posts canonical demo (Phase 10, 162/162) Adds the canonical Phase 10 example from the plan: "Posts about cooking by people I follow (transitively)." dl-demo-cooking-rules defines reach over the follow graph (recursive transitive closure) and cooking-post-by-network joining reach + authored + (tagged P cooking). 3 new demo tests cover transitive network, direct-only follow, and empty-network cases. --- lib/datalog/demo.sx | 20 ++++++++++++++++++++ lib/datalog/scoreboard.json | 8 ++++---- lib/datalog/scoreboard.md | 4 ++-- lib/datalog/tests/demo.sx | 35 +++++++++++++++++++++++++++++++++++ plans/datalog-on-sx.md | 11 +++++++++++ 5 files changed, 72 insertions(+), 6 deletions(-) diff --git a/lib/datalog/demo.sx b/lib/datalog/demo.sx index 7bbdc3b2..407facd4 100644 --- a/lib/datalog/demo.sx +++ b/lib/datalog/demo.sx @@ -64,6 +64,26 @@ (subgroup-trans X Z <- (subgroup X Y) (subgroup-trans Y Z)) (can-access A R <- (in-group A G) (allowed G R))))) +;; ── Demo 4: cooking-posts (the canonical Phase 10 query) ──────── +;; "Posts about cooking by people I follow (transitively)." +;; Combines federation (follows + transitive reach), authoring, +;; tagging — the rose-ash multi-domain join. +;; +;; EDB: +;; (follows ACTOR-A ACTOR-B) +;; (authored ACTOR POST) +;; (tagged POST TAG) +(define + dl-demo-cooking-rules + (quote + ((reach Me Them <- (follows Me Them)) + (reach Me Them <- (follows Me X) (reach X Them)) + (cooking-post-by-network Me P + <- + (reach Me Author) + (authored Author P) + (tagged P cooking))))) + ;; ── Loader stub ────────────────────────────────────────────────── ;; Wiring to PostgreSQL would replace these helpers with calls into ;; rose-ash's internal HTTP RPC (fetch_data → /internal/data/...). diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index f184d68b..33dd2a77 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,8 +1,8 @@ { "lang": "datalog", - "total_passed": 159, + "total_passed": 162, "total_failed": 0, - "total": 159, + "total": 162, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, @@ -13,7 +13,7 @@ {"name":"negation","passed":10,"failed":0,"total":10}, {"name":"aggregates","passed":13,"failed":0,"total":13}, {"name":"api","passed":9,"failed":0,"total":9}, - {"name":"demo","passed":10,"failed":0,"total":10} + {"name":"demo","passed":13,"failed":0,"total":13} ], - "generated": "2026-05-08T09:02:31+00:00" + "generated": "2026-05-08T09:05:25+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index 7707e42a..ef47d2fd 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,6 +1,6 @@ # datalog scoreboard -**159 / 159 passing** (0 failure(s)). +**162 / 162 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| @@ -13,4 +13,4 @@ | negation | 10 | 10 | ok | | aggregates | 13 | 13 | ok | | api | 9 | 9 | ok | -| demo | 10 | 10 | ok | +| demo | 13 | 13 | ok | diff --git a/lib/datalog/tests/demo.sx b/lib/datalog/tests/demo.sx index d8218266..968da0bd 100644 --- a/lib/datalog/tests/demo.sx +++ b/lib/datalog/tests/demo.sx @@ -179,6 +179,41 @@ (quote (can-access X blog))) (list {:X (quote carol)})) + ;; ── Cooking posts (canonical Phase 10 example) ───────── + (dl-demo-test-set! "cooking posts by network" + (dl-query + (dl-demo-make + (quote + ((follows me alice) (follows alice bob) (follows alice carol) + (authored alice p1) (authored bob p2) + (authored carol p3) (authored carol p4) + (tagged p1 travel) (tagged p2 cooking) + (tagged p3 cooking) (tagged p4 books))) + dl-demo-cooking-rules) + (quote (cooking-post-by-network me P))) + (list {:P (quote p2)} {:P (quote p3)})) + + (dl-demo-test-set! "cooking — direct follow only" + (dl-query + (dl-demo-make + (quote + ((follows me bob) + (authored bob p1) (authored bob p2) + (tagged p1 cooking) (tagged p2 books))) + dl-demo-cooking-rules) + (quote (cooking-post-by-network me P))) + (list {:P (quote p1)})) + + (dl-demo-test-set! "cooking — none in network" + (dl-query + (dl-demo-make + (quote + ((follows me bob) + (authored bob p1) (tagged p1 books))) + dl-demo-cooking-rules) + (quote (cooking-post-by-network me P))) + (list)) + (dl-demo-test-set! "no access without grant" (dl-query (dl-demo-make diff --git a/plans/datalog-on-sx.md b/plans/datalog-on-sx.md index 28f6495e..2d7fca84 100644 --- a/plans/datalog-on-sx.md +++ b/plans/datalog-on-sx.md @@ -243,6 +243,9 @@ large graphs. `(interesting Me P)` joining follows + authored + popular. - **Permissions**: `(member A G)`, `(subgroup C P)`, `(allowed G R)` → `(in-group A G)` over transitive subgroups, `(can-access A R)`. + - **Cooking-posts** (the canonical example): `(reach Me Them)` over + the follow graph, then `(cooking-post-by-network Me P)` joining + reach + authored + `(tagged P cooking)`. - [ ] Loader `dl-load-from-db!` — out of scope for this loop (would need to edit `shared/services/` outside `lib/datalog/`). Programs in `demo.sx` already document the EDB shape expected @@ -270,6 +273,14 @@ large graphs. _Newest first._ +- 2026-05-08 — Phase 10 demo + canonical query. Added the "cooking + posts by people I follow (transitively)" example from the plan: + `dl-demo-cooking-rules` defines `reach` over the follow graph + (recursive transitive closure) and `cooking-post-by-network` that + joins reach with `authored` and `(tagged P cooking)`. 3 demo + tests cover transitive network, direct-only follow, and + empty-network cases. + - 2026-05-08 — Phase 8 extension: `findall L V Goal` aggregate. Bind L to the list of distinct V values for which Goal holds (or the empty list when no matches). Implemented as a one-line case in