host: enrich the adapter seam to be substrate-agnostic (review fixes)
After review, the seam was only synchronous-complete; the durable/celery-sx runners couldn't plug in cleanly. Additive fixes (pipeline unchanged): (1) :status branch in run-binding — 'done' dispatches effects, 'suspended' records the flow + :resume (a durable runner holds it; completion re-enters as a new activity via pump), 'failed' records + :error for retry/dead-letter. (2) richer runner env — :ctx (per-activity, via engine :ctx-of) + injected :effects (external-read interfaces, e.g. a deterministic fetch_followers). (3) dedup by content :id — a cycle is caught by identity, not just the depth guard. (4) behavior/pump — drain transport.deliver for inbound (peer activities + async runner completions), sharing one trace so dedup spans the batch. behavior 9/9 (+ suspended/failed/dedup/env/pump); full host conformance 580/580. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -64,6 +64,52 @@
|
||||
(and (> (len (get tr :emitted)) 1) (<= (len (get tr :emitted)) 10)))
|
||||
true)
|
||||
|
||||
;; ── status branch: a SUSPENDED runner is recorded (no effects yet); a FAILED one too ──
|
||||
(define bs-triggers {:register! (fn (s d h) nil) :match (fn (a) (if (= (get a :verb) "wait") (list {:dag "w"}) (list)))})
|
||||
(define bs-sus-runner {:run (fn (dag env) {:status "suspended" :resume "morning"})})
|
||||
(define bs-sus-engine (behavior/make-engine {:triggers bs-triggers :runner bs-sus-runner :transport be-transport :driver be-driver}))
|
||||
(host-be-test "a suspended runner is recorded (+ :resume), no effects dispatched (durable path)"
|
||||
(let ((tr (behavior/process bs-sus-engine {:verb "wait" :actor "a"})))
|
||||
(list (len (get tr :suspended)) (len (get tr :effects)) (get (first (get tr :suspended)) :resume)))
|
||||
(list 1 0 "morning"))
|
||||
(define bs-fail-runner {:run (fn (dag env) {:status "failed" :error "boom"})})
|
||||
(define bs-fail-engine (behavior/make-engine {:triggers bs-triggers :runner bs-fail-runner :transport be-transport :driver be-driver}))
|
||||
(host-be-test "a failed runner is recorded (+ :error) for retry/dead-letter"
|
||||
(let ((tr (behavior/process bs-fail-engine {:verb "wait" :actor "a"})))
|
||||
(list (len (get tr :failed)) (len (get tr :effects)) (get (first (get tr :failed)) :error)))
|
||||
(list 1 0 "boom"))
|
||||
|
||||
;; ── dedup: the same activity (by content :id) is processed ONCE even if re-emitted ──
|
||||
(define bd-triggers {:register! (fn (s d h) nil) :match (fn (a) (if (= (get a :verb) "x") (list {:dag "d"}) (list)))})
|
||||
(define bd-runner {:run (fn (dag env) {:status "done" :effects (list {:kind "re"})})})
|
||||
(define bd-driver {:dispatch (fn (eff) (list {:verb "x" :id "same-id" :actor "a"}))}) ;; re-emits the SAME id
|
||||
(define bd-engine (behavior/make-engine {:triggers bd-triggers :runner bd-runner :transport be-transport :driver bd-driver}))
|
||||
(host-be-test "dedup — the same activity (by :id) processes once (a cycle caught by identity)"
|
||||
(let ((tr (behavior/process bd-engine {:verb "x" :id "same-id" :actor "a"})))
|
||||
(list (len (get tr :emitted)) (len (get tr :ran))))
|
||||
(list 1 1))
|
||||
|
||||
;; ── env: the runner receives the injected :effects (external reads) + per-activity :ctx ──
|
||||
(define benv-runner
|
||||
{:run (fn (dag env) {:status "done"
|
||||
:effects (list {:kind "saw" :ctx (get (get env :ctx) :state)
|
||||
:ff (not (nil? (get (get env :effects) :fetch-followers)))})})})
|
||||
(define benv-engine (behavior/make-engine
|
||||
{:triggers bs-triggers :runner benv-runner :transport be-transport :driver be-driver
|
||||
:effects {:fetch-followers (fn (x) (list 1 2 3))} :ctx-of (fn (a) {:state "loaded"})}))
|
||||
(host-be-test "the runner env carries injected :effects + per-activity :ctx"
|
||||
(let ((eff (first (get (behavior/process benv-engine {:verb "wait" :actor "a"}) :effects))))
|
||||
(list (get eff :ctx) (get eff :ff)))
|
||||
(list "loaded" true))
|
||||
|
||||
;; ── pump: drain transport.deliver → process each inbound activity (peers / async completions) ──
|
||||
(define bp-transport {:emit (fn (a) nil) :deliver (fn () (list {:verb "publish" :actor "a"} {:verb "publish" :actor "b"}))})
|
||||
(define bp-engine (behavior/make-engine {:triggers be-triggers :runner be-runner :transport bp-transport :driver be-driver}))
|
||||
(host-be-test "pump drains transport.deliver → processes each inbound activity"
|
||||
(let ((tr (behavior/pump bp-engine)))
|
||||
(list (len (get tr :emitted)) (len (get tr :ran)) (len (get tr :effects))))
|
||||
(list 2 2 2))
|
||||
|
||||
(define host-be-tests-run!
|
||||
(fn ()
|
||||
{:total (+ host-be-pass host-be-fail)
|
||||
|
||||
Reference in New Issue
Block a user