mod: Ext 14 — decision wire format for federation transport, 323/323
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
mod/decision->wire emits a versioned pipe-delimited line (MOD1|r1|hide|spam-hide); mod/wire->decision parses it back (mod/wire-valid? guards). split-char built over slice/len (loaded env has no split). Integration test runs the full federated path: serialize → wire → deserialize → fed-receive-decision trust-gating (untrusted→advisory, trusted→applied). +16 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ PRELOADS=(
|
||||
lib/mod/batch.sx
|
||||
lib/mod/temporal.sx
|
||||
lib/mod/sla.sx
|
||||
lib/mod/wire.sx
|
||||
lib/mod/lifecycle.sx
|
||||
lib/mod/audit.sx
|
||||
lib/mod/api.sx
|
||||
@@ -46,4 +47,5 @@ SUITES=(
|
||||
"batch:lib/mod/tests/batch.sx:(mod-batch-tests-run!)"
|
||||
"temporal:lib/mod/tests/temporal.sx:(mod-temporal-tests-run!)"
|
||||
"sla:lib/mod/tests/sla.sx:(mod-sla-tests-run!)"
|
||||
"wire:lib/mod/tests/wire.sx:(mod-wire-tests-run!)"
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"lang": "mod",
|
||||
"total_passed": 307,
|
||||
"total_passed": 323,
|
||||
"total_failed": 0,
|
||||
"total": 307,
|
||||
"total": 323,
|
||||
"suites": [
|
||||
{"name":"decide","passed":31,"failed":0,"total":31},
|
||||
{"name":"audit","passed":29,"failed":0,"total":29},
|
||||
@@ -18,7 +18,8 @@
|
||||
{"name":"whatif","passed":13,"failed":0,"total":13},
|
||||
{"name":"batch","passed":17,"failed":0,"total":17},
|
||||
{"name":"temporal","passed":15,"failed":0,"total":15},
|
||||
{"name":"sla","passed":15,"failed":0,"total":15}
|
||||
{"name":"sla","passed":15,"failed":0,"total":15},
|
||||
{"name":"wire","passed":16,"failed":0,"total":16}
|
||||
],
|
||||
"generated": "2026-06-06T19:08:06+00:00"
|
||||
"generated": "2026-06-06T19:16:49+00:00"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# mod scoreboard
|
||||
|
||||
**307 / 307 passing** (0 failure(s)).
|
||||
**323 / 323 passing** (0 failure(s)).
|
||||
|
||||
| Suite | Passed | Total | Status |
|
||||
|-------|--------|-------|--------|
|
||||
@@ -19,3 +19,4 @@
|
||||
| batch | 17 | 17 | ok |
|
||||
| temporal | 15 | 15 | ok |
|
||||
| sla | 15 | 15 | ok |
|
||||
| wire | 16 | 16 | ok |
|
||||
|
||||
96
lib/mod/tests/wire.sx
Normal file
96
lib/mod/tests/wire.sx
Normal file
@@ -0,0 +1,96 @@
|
||||
;; lib/mod/tests/wire.sx — Ext 14: decision wire format + federated transport.
|
||||
|
||||
(define mod-w-count 0)
|
||||
(define mod-w-pass 0)
|
||||
(define mod-w-fail 0)
|
||||
(define mod-w-failures (list))
|
||||
|
||||
(define
|
||||
mod-w-test!
|
||||
(fn
|
||||
(name got expected)
|
||||
(begin
|
||||
(set! mod-w-count (+ mod-w-count 1))
|
||||
(if
|
||||
(= got expected)
|
||||
(set! mod-w-pass (+ mod-w-pass 1))
|
||||
(begin
|
||||
(set! mod-w-fail (+ mod-w-fail 1))
|
||||
(append!
|
||||
mod-w-failures
|
||||
(str name "\n expected: " expected "\n got: " got)))))))
|
||||
|
||||
;; ── split-char ──
|
||||
|
||||
(mod-w-test! "split on pipe" (mod/split-char "a|b|c" "|") (list "a" "b" "c"))
|
||||
(mod-w-test! "split single field" (mod/split-char "abc" "|") (list "abc"))
|
||||
(mod-w-test!
|
||||
"split four fields"
|
||||
(len (mod/split-char "MOD1|r1|hide|spam-hide" "|"))
|
||||
4)
|
||||
|
||||
;; ── serialize ──
|
||||
|
||||
(define
|
||||
mod-w-dec
|
||||
(mod/decide-report
|
||||
(mod/mk-report "r1" "a" "bob" "this is spam")
|
||||
(list (mod/mk-report "r1" "a" "bob" "this is spam"))
|
||||
mod/default-rules))
|
||||
(define mod-w-line (mod/decision->wire mod-w-dec))
|
||||
|
||||
(mod-w-test!
|
||||
"wire is versioned + delimited"
|
||||
mod-w-line
|
||||
"MOD1|r1|hide|spam-hide")
|
||||
(mod-w-test!
|
||||
"wire-valid? accepts well-formed"
|
||||
(mod/wire-valid? mod-w-line)
|
||||
true)
|
||||
(mod-w-test!
|
||||
"wire-valid? rejects junk"
|
||||
(mod/wire-valid? "not a wire line")
|
||||
false)
|
||||
(mod-w-test!
|
||||
"wire-valid? rejects wrong version"
|
||||
(mod/wire-valid? "MOD9|r1|hide|x")
|
||||
false)
|
||||
|
||||
;; ── round-trip ──
|
||||
|
||||
(define mod-w-back (mod/wire->decision mod-w-line))
|
||||
(mod-w-test! "round-trip report-id" (get mod-w-back :report-id) "r1")
|
||||
(mod-w-test! "round-trip action" (get mod-w-back :action) "hide")
|
||||
(mod-w-test! "round-trip rule" (get mod-w-back :rule) "spam-hide")
|
||||
(mod-w-test! "round-trip tags :wire" (get mod-w-back :wire) true)
|
||||
(mod-w-test! "malformed → nil" (mod/wire->decision "garbage") nil)
|
||||
|
||||
;; ── full federated transport: serialize → wire → deserialize → trust-gate ──
|
||||
|
||||
(mod/fed-reset!)
|
||||
(define mod-w-peer-dec (mod/wire->decision mod-w-line))
|
||||
|
||||
;; untrusted peer: decision is advisory, not applied
|
||||
(define mod-w-recv1 (mod/fed-receive-decision "peerX" mod-w-peer-dec))
|
||||
(mod-w-test!
|
||||
"wired decision from untrusted peer → advisory"
|
||||
(get mod-w-recv1 :applied)
|
||||
false)
|
||||
(mod-w-test!
|
||||
"untrusted wired decision not applied locally"
|
||||
(mod/fed-applied-action "r1")
|
||||
nil)
|
||||
|
||||
;; trusted peer: decision binds locally
|
||||
(mod/grant-trust "peerY" :mod)
|
||||
(define mod-w-recv2 (mod/fed-receive-decision "peerY" mod-w-peer-dec))
|
||||
(mod-w-test!
|
||||
"wired decision from trusted peer → applied"
|
||||
(get mod-w-recv2 :applied)
|
||||
true)
|
||||
(mod-w-test!
|
||||
"trusted wired decision binds locally"
|
||||
(get (mod/fed-applied-action "r1") :action)
|
||||
"hide")
|
||||
|
||||
(define mod-wire-tests-run! (fn () {:failures mod-w-failures :total mod-w-count :passed mod-w-pass :failed mod-w-fail}))
|
||||
55
lib/mod/wire.sx
Normal file
55
lib/mod/wire.sx
Normal file
@@ -0,0 +1,55 @@
|
||||
;; lib/mod/wire.sx — portable decision wire format for federation transport.
|
||||
;;
|
||||
;; fed.sx shares decisions as in-memory dicts and leaves mod/fed-send! as the
|
||||
;; transport seam. This is the bytes that cross it: a versioned, pipe-delimited
|
||||
;; line encoding the verdict a peer needs (report id, action, rule) — enough to
|
||||
;; trust-gate and apply/advise, without shipping the whole proof tree. The
|
||||
;; loaded env has no string split, so split is built over slice/len.
|
||||
|
||||
(define
|
||||
mod/split-loop
|
||||
(fn
|
||||
(s ch n start pos acc)
|
||||
(if
|
||||
(= pos n)
|
||||
(append acc (list (slice s start n)))
|
||||
(if
|
||||
(= (slice s pos (+ pos 1)) ch)
|
||||
(mod/split-loop
|
||||
s
|
||||
ch
|
||||
n
|
||||
(+ pos 1)
|
||||
(+ pos 1)
|
||||
(append acc (list (slice s start pos))))
|
||||
(mod/split-loop s ch n start (+ pos 1) acc)))))
|
||||
|
||||
(define
|
||||
mod/split-char
|
||||
(fn (s ch) (mod/split-loop s ch (len s) 0 0 (list))))
|
||||
|
||||
(define
|
||||
mod/decision->wire
|
||||
(fn
|
||||
(d)
|
||||
(str "MOD1|" (get d :report-id) "|" (get d :action) "|" (get d :rule))))
|
||||
|
||||
(define
|
||||
mod/wire-valid?
|
||||
(fn
|
||||
(w)
|
||||
(let
|
||||
((parts (mod/split-char w "|")))
|
||||
(if
|
||||
(= (len parts) 4)
|
||||
(= (nth parts 0) "MOD1")
|
||||
false))))
|
||||
|
||||
(define
|
||||
mod/wire->decision
|
||||
(fn
|
||||
(w)
|
||||
(if
|
||||
(mod/wire-valid? w)
|
||||
(let ((parts (mod/split-char w "|"))) {:action (nth parts 2) :wire true :rule (nth parts 3) :report-id (nth parts 1)})
|
||||
nil)))
|
||||
Reference in New Issue
Block a user