diff --git a/lib/host/tests/blog.sx b/lib/host/tests/blog.sx index 1fb7dc0c..e4cfc35f 100644 --- a/lib/host/tests/blog.sx +++ b/lib/host/tests/blog.sx @@ -6,14 +6,19 @@ (define host-bl-pass 0) (define host-bl-fail 0) (define host-bl-fails (list)) -(define - host-bl-test - (fn (name actual expected) - (if (= actual expected) - (set! host-bl-pass (+ host-bl-pass 1)) - (begin - (set! host-bl-fail (+ host-bl-fail 1)) - (append! host-bl-fails {:name name :actual actual :expected expected}))))) +;; R3: the check thunks `actual` and evaluates it under guard, so a test whose actual RAISES is +;; RECORDED as a failure (with the error) instead of vanishing (the loader skips a raising top-level +;; form). Native exceptions still escape guard — those already fail loud via conformance's error grep. +(define host-bl--check + (fn (name thunk expected) + (let ((actual (guard (e (true (list :__raised (str e)))) (thunk)))) + (if (= actual expected) + (set! host-bl-pass (+ host-bl-pass 1)) + (begin + (set! host-bl-fail (+ host-bl-fail 1)) + (append! host-bl-fails {:name name :actual actual :expected expected})))))) +(defmacro host-bl-test (name actual expected) + (quasiquote (host-bl--check (unquote name) (fn () (unquote actual)) (unquote expected)))) (define host-bl-req (fn (target) (dream-request "GET" target {} ""))) (define host-bl-app (host/make-app (list host/feed-routes host/blog-routes))) @@ -1591,6 +1596,18 @@ (set! host/blog--mint-ticket host-bl-h5-mint-was) (set! host/blog--shop-base host-bl-h5-shop-was) +;; ── R3: a test whose actual-expr RAISES must be COUNTED as a failure, not silently vanish ── +;; The loader skips a raising top-level form, so an eager `actual` that raises disappears from the +;; tally (a red test can look green). host-bl-test must thunk `actual` + evaluate it under guard. +(define host-bl-r3-fail-before host-bl-fail) +(host-bl-test "R3-probe (deliberate SX raise — should be recorded)" (raise "r3-boom") 42) +(define host-bl-r3-delta (- host-bl-fail host-bl-r3-fail-before)) +(when (= host-bl-r3-delta 1) ;; fixed: it was recorded → un-pollute the tally + (begin + (set! host-bl-fail (- host-bl-fail 1)) + (set! host-bl-fails (filter (fn (f) (not (starts-with? (get f :name) "R3-probe"))) host-bl-fails)))) +(host-bl-test "R3: a raising test is counted as a failure (not silently skipped)" host-bl-r3-delta 1) + (define host-bl-tests-run! (fn () diff --git a/plans/business-logic-fed-flows.md b/plans/business-logic-fed-flows.md index 63aeb2fd..24d48ed6 100644 --- a/plans/business-logic-fed-flows.md +++ b/plans/business-logic-fed-flows.md @@ -334,6 +334,20 @@ covers everything until a DAG's cost/latency/placement forces the substrate. activities), so business logic can change state, which federates, which triggers more flows. ## Progress log (newest first) +- 2026-07-03 — MINI-PASS R1-R3 + a correcting finding. R1 DONE (per-offering atomic stock: buy holds + a 2nd pool "offering:", cap=:cap field ∞-if-unset; the store's product stock, atomic + durable; + 259 tests). FINDING (see [[project_host_handler_mutex]]): lib/host http-listen holds ONE per-peer + mutex across the WHOLE handler run (persist IO + the outbound http-request), so there is ZERO + intra-peer handler concurrency — the read-check-write "races" fixed in H3/H5/R1/R2 are NOT + exploitable today (the "10 concurrent buys → 1 seat" test proved the mutex serializes, not that + append-expect beat a race). The atomic-pool work keeps INDEPENDENT value (durable authority + surviving edge-wipes; H5 fixes a real seat LEAK; H6 durable dedup is real at-least-once redelivery), + and it FUTURE-PROOFS for when the mutex is narrowed for throughput. R2 (outbox→stream) DEFERRED — + its stated "no lost deliveries under a race" rationale was masked by the mutex; fold it into the + throughput work. NEW REGISTER ITEM: "narrow the handler mutex" is the real concurrency task — a + handler holds the peer's mutex during a 100s-of-ms cross-domain http-request, blocking the whole + peer; the multi-co-op throughput future forces it, and THAT is when the masked races become real. + R3 (test runner counts a raising test as a failure, not a silent skip) proceeding — independent value. - 2026-07-03 — HARDENING PASS H1-H7 DONE (TDD, failing test first, all 7) + deployed + live-verified. H1 internal endpoints HMAC-gated (x-int-sig of the TARGET; unsigned /ticket|/order|/person → 403 — closed the live capacity-bypass). H2 admin ops (new-film/new-showing/offering-*/add-poll/new-event)