erlang: Phase 7 capstone — full hot-reload ladder green (+5 eval tests)

This commit is contained in:
2026-05-14 19:29:15 +00:00
parent b5e93df82e
commit 925bbd0d42
5 changed files with 55 additions and 7 deletions

View File

@@ -1,11 +1,11 @@
{
"language": "erlang",
"total_pass": 577,
"total": 577,
"total_pass": 582,
"total": 582,
"suites": [
{"name":"tokenize","pass":62,"total":62,"status":"ok"},
{"name":"parse","pass":52,"total":52,"status":"ok"},
{"name":"eval","pass":380,"total":380,"status":"ok"},
{"name":"eval","pass":385,"total":385,"status":"ok"},
{"name":"runtime","pass":52,"total":52,"status":"ok"},
{"name":"ring","pass":4,"total":4,"status":"ok"},
{"name":"ping-pong","pass":4,"total":4,"status":"ok"},

View File

@@ -1,12 +1,12 @@
# Erlang-on-SX Scoreboard
**Total: 577 / 577 tests passing**
**Total: 582 / 582 tests passing**
| | Suite | Pass | Total |
|---|---|---|---|
| ✅ | tokenize | 62 | 62 |
| ✅ | parse | 52 | 52 |
| ✅ | eval | 380 | 380 |
| ✅ | eval | 385 | 385 |
| ✅ | runtime | 52 | 52 |
| ✅ | ring | 4 | 4 |
| ✅ | ping-pong | 4 | 4 |

View File

@@ -1309,6 +1309,37 @@
hr6:v()")
3)
;; ── Phase 7 capstone: full hot-reload ladder ───────────────────
;; Load v1 → spawn from inside module → load v2 → cross-mod hits v2 →
;; local call inside v1 process still resolves v1 → soft_purge refuses
;; while v1 procs alive → purge kills them.
;;
;; All stages must run in a single erlang-eval-ast call: each call resets
;; the scheduler (er-sched-init!) so cross-call Pid handles would point at
;; reaped processes.
(er-modules-reset!)
(define er-rt-cap-prog "code:load_binary(cap, \"cap.erl\", \"-module(cap). start() -> spawn(fun () -> loop() end). loop() -> receive {ping, From} -> From ! {pong, v1}, loop(); stop -> done end. tag() -> v1.\"), Tag1 = cap:tag(), Pid1 = cap:start(), code:load_binary(cap, \"cap.erl\", \"-module(cap). start() -> spawn(fun () -> loop() end). loop() -> receive {ping, From} -> From ! {pong, v2}, loop(); stop -> done end. tag() -> v2.\"), Tag2 = cap:tag(), _Pid2 = cap:start(), Soft1 = code:soft_purge(cap), Hard = code:purge(cap), Soft2 = code:soft_purge(cap), {Tag1, Tag2, Soft1, Hard, Soft2}")
(define er-rt-cap-result (ev er-rt-cap-prog))
(er-eval-test "capstone v1 tag direct"
(get (nth (get er-rt-cap-result :elements) 0) :name) "v1")
(er-eval-test "capstone v2 tag"
(get (nth (get er-rt-cap-result :elements) 1) :name) "v2")
(er-eval-test "capstone soft_purge while v1 alive = false"
(get (nth (get er-rt-cap-result :elements) 2) :name) "false")
(er-eval-test "capstone hard purge = true"
(get (nth (get er-rt-cap-result :elements) 3) :name) "true")
(er-eval-test "capstone soft_purge clean after hard = true"
(get (nth (get er-rt-cap-result :elements) 4) :name) "true")
(define
er-eval-test-summary
(str "eval " er-eval-test-pass "/" er-eval-test-count))

View File

@@ -1967,6 +1967,21 @@
:else
(er-mk-tuple (list (er-mk-atom "module") mod-arg))))))))))
(define er-env-derived-from?
(fn (env target-env)
(cond
(= env target-env) true
:else
(let ((ks (keys env)) (found-ref (list false)))
(for-each
(fn (i)
(when (not (nth found-ref 0))
(let ((v (get env (nth ks i))))
(when (and (er-fun? v) (= (get v :env) target-env))
(set-nth! found-ref 0 true)))))
(range 0 (len ks)))
(nth found-ref 0)))))
(define er-procs-on-env
(fn (target-env)
(let ((all-keys (keys (er-sched-processes)))
@@ -1977,7 +1992,7 @@
(let ((init-fun (get proc :initial-fun)))
(when (and (not (= init-fun nil))
(er-fun? init-fun)
(= (get init-fun :env) target-env)
(er-env-derived-from? (get init-fun :env) target-env)
(not (= (get proc :state) "dead")))
(append! matches (get proc :pid))))))
(range 0 (len all-keys)))