W14: pin crit-2 signal-return kont non-vacuously (test-only)
crit-2's failure mode discards every frame outside the signal site —
including the covering test's own assert — which is why the shipped test
"signal returns handler value to call site" passed vacuously pre-fix. A
plain assert pin would inherit that vacuity on regression.
Add suite gate-crit2-signal-return-kont with a side-effect sentinel: test 1
runs the core.md repros ((list "outer" (handler-bind ... (+ 1
(signal-condition 5))) "end") -> ("outer" 43 "end"); raise-continuable ->
143) then set!s a top-level flag; test 2 independently asserts the flag, so
a dropped continuation fails loudly even though test 1 would "pass". Third
test pins the shipped-test expression (51). 267 passed / 0 failed under
OCaml run_tests.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,8 @@ Pin each confirmed-and-fixed finding with a minimal repro. Add suites to
|
||||
- [x] K49 [W8] — five void elements (area/base/embed/param/track) renderable
|
||||
(spec side; native regen drift → see Blocked). NB: the depth/cycle guard
|
||||
is K16 [W8], still OPEN — not a W14 pin target until its fix lands
|
||||
- [ ] crit-2 [W1] — signal-return frame key (verify the pin is non-vacuous)
|
||||
- [x] crit-2 [W1] — signal-return kont pinned NON-VACUOUSLY (side-effect
|
||||
sentinel across two tests; a plain assert would inherit the vacuity)
|
||||
- [ ] C1/C1b [W3] — HTTP-mode concurrency fixes, pin
|
||||
- [ ] S4 [conformance] — housekeeping repro, pin
|
||||
|
||||
@@ -79,6 +80,16 @@ Pin each confirmed-and-fixed finding with a minimal repro. Add suites to
|
||||
|
||||
## Progress log (newest first)
|
||||
|
||||
- 2026-07-04 — **crit-2 non-vacuous pin (item A.5)**. The original bug's
|
||||
signature — handler value becomes the WHOLE program result, discarding
|
||||
every outer frame *including the covering test's own assert* — means a
|
||||
plain `(assert= repro expected)` pin would pass vacuously on regression.
|
||||
Added suite `gate-crit2-signal-return-kont` with a **side-effect sentinel**:
|
||||
test 1 runs both repros (`("outer" 43 "end")` list shape + `raise-continuable`
|
||||
→ 143) then `set!`s a top-level flag; test 2 independently asserts the flag
|
||||
— if the continuation is ever dropped again, test 1 "passes" but test 2
|
||||
fails loudly. Third test pins the exact shipped-test expr (51). Verified
|
||||
both repro shapes live via sx_eval first. 267 passed / 0 failed. Test-only.
|
||||
- 2026-07-03 — **K49 void-elements pin (item A.4) + regen-drift DISCOVERY**.
|
||||
Corrected the checklist label first: K49 is "five void elements
|
||||
unrenderable" (core.md:335), not the depth guard (that's K16, OPEN). Added
|
||||
|
||||
@@ -161,3 +161,59 @@
|
||||
(quote (embed))
|
||||
(quote (param))
|
||||
(quote (track))))))
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; crit-2 [W1, critical] signal-return frame stored the saved kont under :f
|
||||
;; but the reader looked up "saved-kont" — the resume kont was always nil,
|
||||
;; so the handler value became the WHOLE program's result and every frame
|
||||
;; outside the signal site (including the covering test's own assert!) was
|
||||
;; silently discarded. The shipped test "signal returns handler value to
|
||||
;; call site" passed VACUOUSLY — the bug defeated its own test.
|
||||
;;
|
||||
;; A plain assert around the repro would inherit the same vacuity on
|
||||
;; regression (the dropped continuation includes the assert frame). So this
|
||||
;; pin uses a side-effect sentinel: test 1 runs the repro and then sets a
|
||||
;; flag; test 2 independently asserts the flag was reached. If crit-2
|
||||
;; regresses, test 1 still "passes" (vacuously) but test 2 FAILS.
|
||||
;; Repro (core.md).
|
||||
;; --------------------------------------------------------------------------
|
||||
(define *gate-crit2-after-signal* false)
|
||||
(define *gate-crit2-result* nil)
|
||||
(define *gate-crit2-rc-result* nil)
|
||||
|
||||
(defsuite
|
||||
"gate-crit2-signal-return-kont"
|
||||
(deftest
|
||||
"continuable signal resumes at the raise site"
|
||||
(do
|
||||
(set!
|
||||
*gate-crit2-result*
|
||||
(list
|
||||
"outer"
|
||||
(handler-bind
|
||||
(((fn (c) true) (fn (c) 42)))
|
||||
(+ 1 (signal-condition 5)))
|
||||
"end"))
|
||||
(set!
|
||||
*gate-crit2-rc-result*
|
||||
(handler-bind
|
||||
(((fn (c) true) (fn (c) (+ c 100))))
|
||||
(+ 1 (raise-continuable 42))))
|
||||
(set! *gate-crit2-after-signal* true)
|
||||
(assert= *gate-crit2-result* (list "outer" 43 "end"))
|
||||
(assert= *gate-crit2-rc-result* 143)))
|
||||
(deftest
|
||||
"non-vacuity sentinel: the continuation after the signal actually ran"
|
||||
(do
|
||||
(assert
|
||||
*gate-crit2-after-signal*
|
||||
"continuation dropped — crit-2 regressed (previous test passed vacuously)")
|
||||
(assert= *gate-crit2-result* (list "outer" 43 "end"))
|
||||
(assert= *gate-crit2-rc-result* 143)))
|
||||
(deftest
|
||||
"handler value feeds the arithmetic frame, not the program result"
|
||||
(assert=
|
||||
(handler-bind
|
||||
(((fn (c) true) (fn (c) (* c 10))))
|
||||
(+ 1 (signal-condition 5)))
|
||||
51)))
|
||||
|
||||
Reference in New Issue
Block a user