mod: Ext 19 — end-to-end triage pipeline (capstone), 390/390
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 41s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 41s
mod/triage-pipeline domain r reports actor composes domain-policy decision → explanation → AP activity → wire into one bundle. Integration test runs the whole federated path across 5 modules (decide → wire → peer → trust-gated apply), confirming the module-by-module subsystem composes end to end. +15 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ PRELOADS=(
|
||||
lib/mod/wire.sx
|
||||
lib/mod/activity.sx
|
||||
lib/mod/policies.sx
|
||||
lib/mod/pipeline.sx
|
||||
lib/mod/lifecycle.sx
|
||||
lib/mod/audit.sx
|
||||
lib/mod/api.sx
|
||||
@@ -55,4 +56,5 @@ SUITES=(
|
||||
"activity:lib/mod/tests/activity.sx:(mod-activity-tests-run!)"
|
||||
"policies:lib/mod/tests/policies.sx:(mod-policies-tests-run!)"
|
||||
"defrule:lib/mod/tests/defrule.sx:(mod-defrule-tests-run!)"
|
||||
"pipeline:lib/mod/tests/pipeline.sx:(mod-pipeline-tests-run!)"
|
||||
)
|
||||
|
||||
18
lib/mod/pipeline.sx
Normal file
18
lib/mod/pipeline.sx
Normal file
@@ -0,0 +1,18 @@
|
||||
;; lib/mod/pipeline.sx — end-to-end triage orchestration.
|
||||
;;
|
||||
;; A single entry point that runs a report through the subsystem and returns the
|
||||
;; full artifact bundle: the decision (under the report's domain policy), a
|
||||
;; human-readable explanation, an ActivityPub-shaped event for the bus, and the
|
||||
;; wire line for federated peers. Composes policies (Ext 17), explain (Ext 3),
|
||||
;; activity (Ext 16) and wire (Ext 14) — the modules are independent, this is just
|
||||
;; the convenience that wires them together for the common "process a report" path.
|
||||
|
||||
(define
|
||||
mod/triage-pipeline
|
||||
(fn
|
||||
(domain r reports actor)
|
||||
(let ((d (mod/decide-in domain r reports))) {:activity (mod/decision->activity d actor) :action (get d :action) :wire (mod/decision->wire d) :rule (get d :rule) :decision d :explanation (mod/explain d)})))
|
||||
|
||||
(define mod/pipeline-action (fn (p) (get p :action)))
|
||||
(define mod/pipeline-activity (fn (p) (get p :activity)))
|
||||
(define mod/pipeline-wire (fn (p) (get p :wire)))
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"lang": "mod",
|
||||
"total_passed": 375,
|
||||
"total_passed": 390,
|
||||
"total_failed": 0,
|
||||
"total": 375,
|
||||
"total": 390,
|
||||
"suites": [
|
||||
{"name":"decide","passed":31,"failed":0,"total":31},
|
||||
{"name":"audit","passed":29,"failed":0,"total":29},
|
||||
@@ -23,7 +23,8 @@
|
||||
{"name":"disjunction","passed":10,"failed":0,"total":10},
|
||||
{"name":"activity","passed":17,"failed":0,"total":17},
|
||||
{"name":"policies","passed":14,"failed":0,"total":14},
|
||||
{"name":"defrule","passed":11,"failed":0,"total":11}
|
||||
{"name":"defrule","passed":11,"failed":0,"total":11},
|
||||
{"name":"pipeline","passed":15,"failed":0,"total":15}
|
||||
],
|
||||
"generated": "2026-06-06T19:36:45+00:00"
|
||||
"generated": "2026-06-06T19:40:03+00:00"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# mod scoreboard
|
||||
|
||||
**375 / 375 passing** (0 failure(s)).
|
||||
**390 / 390 passing** (0 failure(s)).
|
||||
|
||||
| Suite | Passed | Total | Status |
|
||||
|-------|--------|-------|--------|
|
||||
@@ -24,3 +24,4 @@
|
||||
| activity | 17 | 17 | ok |
|
||||
| policies | 14 | 14 | ok |
|
||||
| defrule | 11 | 11 | ok |
|
||||
| pipeline | 15 | 15 | ok |
|
||||
|
||||
112
lib/mod/tests/pipeline.sx
Normal file
112
lib/mod/tests/pipeline.sx
Normal file
@@ -0,0 +1,112 @@
|
||||
;; lib/mod/tests/pipeline.sx — Ext 19: end-to-end triage orchestration.
|
||||
|
||||
(define mod-pp-count 0)
|
||||
(define mod-pp-pass 0)
|
||||
(define mod-pp-fail 0)
|
||||
(define mod-pp-failures (list))
|
||||
|
||||
(define
|
||||
mod-pp-test!
|
||||
(fn
|
||||
(name got expected)
|
||||
(begin
|
||||
(set! mod-pp-count (+ mod-pp-count 1))
|
||||
(if
|
||||
(= got expected)
|
||||
(set! mod-pp-pass (+ mod-pp-pass 1))
|
||||
(begin
|
||||
(set! mod-pp-fail (+ mod-pp-fail 1))
|
||||
(append!
|
||||
mod-pp-failures
|
||||
(str name "\n expected: " expected "\n got: " got)))))))
|
||||
|
||||
(mod/policies-reset!)
|
||||
(mod/register-policy!
|
||||
"market"
|
||||
(mod/ruleset
|
||||
(mod/defrule "market-spam-remove" :remove (list :classification "spam"))
|
||||
(mod/defrule "default-keep" :keep)))
|
||||
|
||||
;; ── spam in the market domain: full bundle ──
|
||||
|
||||
(define mod-pp-spam (mod/mk-report "r1" "u" "bob" "this is spam"))
|
||||
(define
|
||||
mod-pp
|
||||
(mod/triage-pipeline "market" mod-pp-spam (list mod-pp-spam) "inst.example"))
|
||||
|
||||
(mod-pp-test!
|
||||
"pipeline action (market policy → remove)"
|
||||
(mod/pipeline-action mod-pp)
|
||||
"remove")
|
||||
(mod-pp-test! "pipeline rule" (get mod-pp :rule) "market-spam-remove")
|
||||
(mod-pp-test!
|
||||
"pipeline explanation mentions the action"
|
||||
(mod/str-contains? (get mod-pp :explanation) "remove")
|
||||
true)
|
||||
(mod-pp-test!
|
||||
"pipeline activity is Delete (remove)"
|
||||
(get (mod/pipeline-activity mod-pp) :type)
|
||||
"Delete")
|
||||
(mod-pp-test!
|
||||
"pipeline activity object is the report"
|
||||
(get (mod/pipeline-activity mod-pp) :object)
|
||||
"r1")
|
||||
(mod-pp-test!
|
||||
"pipeline wire round-trips to the same action"
|
||||
(get (mod/wire->decision (mod/pipeline-wire mod-pp)) :action)
|
||||
"remove")
|
||||
|
||||
;; ── same report, blog domain (default) → hide, Flag ──
|
||||
|
||||
(define
|
||||
mod-pp-blog
|
||||
(mod/triage-pipeline "blog" mod-pp-spam (list mod-pp-spam) "inst.example"))
|
||||
(mod-pp-test!
|
||||
"blog default policy → hide"
|
||||
(mod/pipeline-action mod-pp-blog)
|
||||
"hide")
|
||||
(mod-pp-test!
|
||||
"blog activity is Flag"
|
||||
(get (mod/pipeline-activity mod-pp-blog) :type)
|
||||
"Flag")
|
||||
|
||||
;; ── clean report: keep, no activity, explanation says (none) ──
|
||||
|
||||
(define mod-pp-clean (mod/mk-report "r2" "u" "eve" "a fine post"))
|
||||
(define
|
||||
mod-pp-k
|
||||
(mod/triage-pipeline
|
||||
"market"
|
||||
mod-pp-clean
|
||||
(list mod-pp-clean)
|
||||
"inst.example"))
|
||||
(mod-pp-test! "clean → keep" (mod/pipeline-action mod-pp-k) "keep")
|
||||
(mod-pp-test! "keep → no activity" (mod/pipeline-activity mod-pp-k) nil)
|
||||
(mod-pp-test!
|
||||
"keep explanation says no evidence"
|
||||
(mod/str-contains? (get mod-pp-k :explanation) "Evidence: (none)")
|
||||
true)
|
||||
(mod-pp-test!
|
||||
"keep wire still round-trips"
|
||||
(get (mod/wire->decision (mod/pipeline-wire mod-pp-k)) :rule)
|
||||
"default-keep")
|
||||
|
||||
;; ── federated handoff: market decision crosses to a peer, trust-gated ──
|
||||
|
||||
(mod/fed-reset!)
|
||||
(define mod-pp-peer-dec (mod/wire->decision (mod/pipeline-wire mod-pp)))
|
||||
(mod-pp-test!
|
||||
"untrusted peer: market decision is advisory"
|
||||
(get (mod/fed-receive-decision "peerX" mod-pp-peer-dec) :applied)
|
||||
false)
|
||||
(mod/grant-trust "peerY" :mod)
|
||||
(mod-pp-test!
|
||||
"trusted peer: market decision applies"
|
||||
(get (mod/fed-receive-decision "peerY" mod-pp-peer-dec) :applied)
|
||||
true)
|
||||
(mod-pp-test!
|
||||
"applied action is remove"
|
||||
(get (mod/fed-applied-action "r1") :action)
|
||||
"remove")
|
||||
|
||||
(define mod-pipeline-tests-run! (fn () {:failures mod-pp-failures :total mod-pp-count :passed mod-pp-pass :failed mod-pp-fail}))
|
||||
@@ -16,7 +16,7 @@ federation extension.
|
||||
|
||||
## Status (rolling)
|
||||
|
||||
`bash lib/mod/conformance.sh` → **375/375** (roadmap + 18 extensions complete)
|
||||
`bash lib/mod/conformance.sh` → **390/390** (roadmap + 19 extensions complete)
|
||||
|
||||
## Ground rules
|
||||
|
||||
@@ -147,6 +147,12 @@ lib/mod/fed.sx
|
||||
derivation goal-by-goal with `[proved]`/`[unproved]` marks and unification
|
||||
bindings. E.g. `Report rc: escalate (rule: repeated-escalate)` … `[proved]
|
||||
report(rc, B, S), report_count(S, N), N >= 3 {B=ann, N=3, S=dave}`.
|
||||
- [x] **Ext 19 — end-to-end triage pipeline** (`lib/mod/pipeline.sx`, +15).
|
||||
`mod/triage-pipeline domain r reports actor` runs a report through domain-policy
|
||||
decision → explanation → AP activity → wire, returning the full bundle. The test
|
||||
is a genuine integration across 5 modules including a federated handoff (market
|
||||
decision → wire → peer → trust-gated apply). The capstone that proves the
|
||||
independently-built modules compose.
|
||||
- [x] **Ext 18 — ergonomic defrule / ruleset** (`lib/mod/defrule.sx`, +11). The
|
||||
roadmap's `(defrule …)` surface, done with `&rest` variadics (no macro needed —
|
||||
conditions are already plain data): `mod/defrule` collects trailing conditions,
|
||||
@@ -234,6 +240,14 @@ lib/mod/fed.sx
|
||||
|
||||
## Progress log
|
||||
|
||||
- **Ext 19 — end-to-end triage pipeline, 390/390** (+15). Capstone: one
|
||||
orchestration call composes domain policy + decide + explain + activity + wire,
|
||||
and the integration test runs the whole federated path (decide in a domain →
|
||||
wire → peer → trust-gated apply) across 5 modules. Confirms the subsystem — built
|
||||
module-by-module — actually composes end to end. mod-sx now spans schema → policy
|
||||
DSL (boolean algebra + count/score/reporters/burst) → engine + proofs → audit →
|
||||
lifecycle → SLA → federation (trust/wire/AP) → analytics (trace/whatif/lint/batch)
|
||||
→ domain policies → pipeline, all on the green lib/prolog substrate, 390 tests.
|
||||
- **Ext 18 — ergonomic defrule / ruleset, 375/375** (+11). Closes the roadmap's
|
||||
original `defrule` surface. `fn` supports `&rest` here, and conditions evaluate
|
||||
to plain data, so no macro is needed — variadic functions give the ergonomics
|
||||
|
||||
Reference in New Issue
Block a user