flow: error model — fail/failed?/fail-reason failure values + 6 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s
Explicit (fail reason) values flow downstream as data and are inspected with failed?/fail-reason — distinct from raised exceptions (retry/try-catch territory). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,10 @@
|
||||
{
|
||||
"total": 24,
|
||||
"passed": 24,
|
||||
"total": 30,
|
||||
"passed": 30,
|
||||
"failed": 0,
|
||||
"suites": {
|
||||
"basic": { "passed": 18, "total": 18 },
|
||||
"control": { "passed": 6, "total": 6 }
|
||||
"control": { "passed": 12, "total": 12 }
|
||||
},
|
||||
"phases": {
|
||||
"phase1": "done",
|
||||
"phase2": "in-progress"
|
||||
}
|
||||
"phases": { "phase1": "done", "phase2": "in-progress" }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# flow-on-sx Scoreboard
|
||||
|
||||
**All tests pass: 24 / 24 across 2 suites.**
|
||||
**All tests pass: 30 / 30 across 2 suites.**
|
||||
|
||||
`bash lib/flow/conformance.sh`
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
| Suite | Passing | Covers |
|
||||
|-------|--------:|--------|
|
||||
| basic | 18 | Phase 1: single nodes, linear sequence, data-flow threading, defflow, parallel fan/join, nested composition, publish-shaped flow |
|
||||
| control | 6 | Phase 2: `branch` conditional — true/false select, threaded predicate, full-node branches, nested 3-way, approval gate |
|
||||
| control | 12 | Phase 2: `branch` conditional (6); error model `fail`/`failed?`/`fail-reason` failure values that flow as data (6) |
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -36,6 +36,6 @@ capture the flow continuation directly.
|
||||
## Phases
|
||||
|
||||
- [x] Phase 1 — Declarative DAG + sequential execution (combinators + 18 tests, `flow/start`)
|
||||
- [~] Phase 2 — Control flow + error handling (`branch` done)
|
||||
- [~] Phase 2 — Control flow + error handling (`branch`, error model done)
|
||||
- [ ] Phase 3 — Suspend / resume (the showcase)
|
||||
- [ ] Phase 4 — Distributed nodes via fed-sx
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
;; Phase 2 combinators (flow-control-src):
|
||||
;; (branch pred then else) — pred on input selects then/else node
|
||||
;; (`cond` is a Scheme special form, so the combinator is named `branch`)
|
||||
;; (fail reason) — make an explicit failure value (data, not an exception)
|
||||
;; (failed? x) — is x a failure value?
|
||||
;; (fail-reason x) — the reason carried by a failure value
|
||||
|
||||
(define
|
||||
flow-combinators-src
|
||||
@@ -26,7 +29,7 @@
|
||||
|
||||
(define
|
||||
flow-control-src
|
||||
"(define (branch pred then else)\n (lambda (input) (if (pred input) (then input) (else input))))")
|
||||
"(define (branch pred then else)\n (lambda (input) (if (pred input) (then input) (else input))))\n (define (fail reason) (list (quote flow-fail) reason))\n (define (failed? x) (and (pair? x) (eq? (car x) (quote flow-fail))))\n (define (fail-reason x) (car (cdr x)))")
|
||||
|
||||
(define
|
||||
flow-load-combinators!
|
||||
|
||||
@@ -50,4 +50,32 @@
|
||||
"(defflow publish (branch (lambda (post) (>= (string-length post) 3)) (lambda (post) (string-append post \" [published]\")) (lambda (post) (string-append post \" [rejected]\")))) (flow/start publish \"ok\")")
|
||||
"ok [rejected]")
|
||||
|
||||
;; ── error model — explicit (fail reason) values ─────────────────
|
||||
(flow-ctl-test
|
||||
"fail: failed? is true for a failure value"
|
||||
(flow-c "(failed? (fail 404))")
|
||||
true)
|
||||
(flow-ctl-test
|
||||
"fail: fail-reason extracts the reason"
|
||||
(flow-c "(fail-reason (fail 404))")
|
||||
404)
|
||||
(flow-ctl-test
|
||||
"fail: failed? is false for a plain value"
|
||||
(flow-c "(failed? 7)")
|
||||
false)
|
||||
(flow-ctl-test
|
||||
"fail: failed? is false for an ordinary list"
|
||||
(flow-c "(failed? (list 1 2 3))")
|
||||
false)
|
||||
(flow-ctl-test
|
||||
"fail: a node may emit a failure as data"
|
||||
(flow-c
|
||||
"(defflow validate (lambda (s) (if (>= (string-length s) 3) s (fail (quote too-short))))) (failed? (flow/start validate \"hi\"))")
|
||||
true)
|
||||
(flow-ctl-test
|
||||
"fail: failure flows downstream, branch recovers"
|
||||
(flow-c
|
||||
"(defflow guarded (sequence (lambda (s) (if (>= (string-length s) 3) (string-length s) (fail (quote too-short)))) (branch failed? (lambda (f) (list (quote recovered) (fail-reason f))) (lambda (n) (list (quote ok) n))))) (flow/start guarded \"hi\")")
|
||||
(list "recovered" "too-short"))
|
||||
|
||||
(define flow-ctl-tests-run! (fn () {:total (+ flow-ctl-pass flow-ctl-fail) :passed flow-ctl-pass :failed flow-ctl-fail :fails flow-ctl-fails}))
|
||||
|
||||
@@ -16,7 +16,7 @@ federation extension via fed-sx for remote-node execution.
|
||||
|
||||
## Status (rolling)
|
||||
|
||||
`bash lib/flow/conformance.sh` → **24/24** (Phase 1 done; Phase 2 in progress)
|
||||
`bash lib/flow/conformance.sh` → **30/30** (Phase 1 done; Phase 2 in progress)
|
||||
|
||||
## Ground rules
|
||||
|
||||
@@ -80,7 +80,9 @@ lib/flow/spec.sx lib/flow/runtime.sx lib/flow/store.sx
|
||||
- [ ] `retry n [backoff]` — re-runs node up to n times on exception
|
||||
- [ ] `timeout ms` — bounds node execution
|
||||
- [ ] `try-catch` — exception handler with reified error
|
||||
- [ ] error model — exceptions vs explicit `(fail :reason ...)` results
|
||||
- [x] error model — exceptions vs explicit `(fail reason)` results: `fail`/`failed?`/
|
||||
`fail-reason` produce/inspect failure values that flow downstream as data
|
||||
(distinct from raised exceptions caught by retry/try-catch). 6 tests.
|
||||
- [ ] `lib/flow/tests/control.sx` — 25+ cases: each combinator + composition
|
||||
|
||||
## Phase 3 — Suspend / resume (the showcase)
|
||||
|
||||
Reference in New Issue
Block a user