diff --git a/TODO.org b/TODO.org index 7b8e242a..a983ab15 100644 --- a/TODO.org +++ b/TODO.org @@ -1565,11 +1565,12 @@ only by an explicit call. A sentence about the shape of the gate rather than an observed problem: only the daemon sets the variable and it never runs release builds. The fix, if it is ever felt, is a narrower gate. -** NEXT The daemon's "has not called (agent/start ...)" note is unreachable -Decided 2026-09-25: retire the note in the same dead-code sweep. -Unreachable, not merely unexercised: the one state it was true of is closed by the -constructor. Retiring it is the author's call over a lane that merged days ago, so -it is left in place saying a true thing about a state nothing can be in. +** DONE The daemon's "has not called (agent/start ...)" note is unreachable +CLOSED: [2026-09-25] +Retired, with the matching arm of an evaluation's timeout. A running program +either links the agent, whose constructor binds the socket before =main=, or +links none and has its delivery refused; no reply names =(agent/start ...)= as +not yet called. ** DONE The allocation registry CLOSED: [2026-09-13] diff --git a/docs/BUILT.md b/docs/BUILT.md index 930c83da..7703ace3 100644 --- a/docs/BUILT.md +++ b/docs/BUILT.md @@ -7024,9 +7024,8 @@ registry now holds. **When it happens.** At the next frame boundary of a running program. A parked program — one whose `main` has finished — drains its ring when that sleep ends, so the store lands at the top of its next run, ahead of `main`; the run's own startup then computes the initialiser again, which is not a wart but the two events `defparameter` has: an -evaluation assigns, and a re-run re-initialises. A program that has not called `(agent/start ...)` yet installs at its -next `(agent/poll)`, and never if it has none — the reply already says so. A program stopped at a break runs it in the -break loop, like any other evaluation. +evaluation assigns, and a re-run re-initialises. A program stopped at a break runs it in the break loop, like any other +evaluation. **A brand-new `def`** gets its initialiser run too. Its storage comes from `flan_dev_global` and nothing in the host's `.init-globals` names it, so before this a new `(def n i64 (count-them))` came up as `calloc`'s zeroes and stayed diff --git a/lib/dev.ml b/lib/dev.ml index 543e719c..6169b5b2 100644 --- a/lib/dev.ml +++ b/lib/dev.ml @@ -124,7 +124,7 @@ let await ?(ms = 5000) f = (* Whether the program has bound the socket it receives modules on. - Cheap enough to ask on every reply — one [stat] — and asked rather than + Cheap enough to ask before every request — one [stat] — and asked rather than remembered because the answer moves in one direction at a moment this side does not get to see: [agent/start] runs on the program's own thread. *) let agent_bound t = Sys.file_exists t.agent @@ -781,7 +781,7 @@ let refusal ~parked reply = refusal; it is the difference between "queued" and "running", which is a difference only the program can close and only at a moment of its choosing. - Three of them, in the order of how far the module is from being live: + Two of them, in the order of how far the module is from being live: A PARKED program has finished [main] and is asleep in [flan_merged_park]. Its ring is drained whenever that sleep ends — for an expression to run, or @@ -796,16 +796,11 @@ let refusal ~parked reply = not per session, because the reader of a *new* park may not be the reader of the last one. - A RUNNING program that has not bound its agent socket has not called - [(agent/start ...)] yet — it may be about to, ahead of a window that is - still being created, or it may have no such call at all. Either way the - module is in the ring and the ring is drained by [(agent/poll)], so what - can honestly be promised is the poll and not a frame: a program with no - poll in it never installs this, and saying "at its next frame boundary" - would be the reply that made a redefinition look applied when it was not. - - A RUNNING program that has bound it needs no note: the reply already says - queued, and the frame boundary is the next one it reaches. *) + A RUNNING program needs no note: the reply already says queued, and the + frame boundary is the next one it reaches. A running program whose agent + socket is not bound is not a third case: the agent package binds it in a + constructor, before [main], and a program that does not link the package + has nothing to queue a module on, so the delivery is refused instead. *) let install_note t ~parked = if parked then begin let first = not t.park_noted in @@ -821,13 +816,6 @@ let install_note t ~parked = else "queued; installs no later than the parked program's next run") ] end - else if not (agent_bound t) then - [ ":note " - ^ Wire.quote - "queued, but the program has not called (agent/start ...) yet, so \ - this installs when it next reaches an (agent/poll) — and not at \ - all if it never does" - ] else [] (* [pause], when given, is the position of the form to stop at — §9. It rides @@ -1253,21 +1241,6 @@ let eval_expr t ~code ~origin ~pause = the program is stopped at an earlier break and runs \ nothing until that ends. Take a restart or abort in the \ break buffer, and evaluate this again" - (* And a third cause, which is the one a session now reaches - early enough to hit: the program has not bound its agent - socket, so it is still ahead of its own [(agent/start ...)] - — inside whatever it does first, a window being created — - and asking whether it calls [(agent/poll)] would send the - reader to look at a loop it has not got to yet. Said only - where it is a fact about *this* program: the socket is - missing, which is a stat, not a guess. *) - else if not (agent_bound t) then - error - "the program has not called (agent/start ...) yet, so \ - nothing has run the expression. It is queued and will run \ - at the program's first (agent/poll); this reply cannot \ - carry its value, so evaluate it again once the program is \ - up" else error "the program did not reach a frame boundary; is it calling \ diff --git a/test/programs/dev-noagent-running.flan b/test/programs/dev-noagent-running.flan index 0883332a..1834441c 100644 --- a/test/programs/dev-noagent-running.flan +++ b/test/programs/dev-noagent-running.flan @@ -7,12 +7,10 @@ ;;;; hand a module to and no socket to fall back on, so the daemon refuses the ;;;; delivery and says which socket it could not reach. ;;;; -;;;; That is the honest answer for it. The sentence [install_note] keeps for a -;;;; running program with no socket — queued, installs at its next -;;;; (agent/poll) — was true of a program that *links* the agent and has not -;;;; reached its (agent/start ...) yet, because there the ring is reachable -;;;; in-process while the socket is not yet bound. The package's constructor -;;;; binds before main now, so that window is gone; see TODO.org, "(agent/start) takes no argument, and binds before main". +;;;; That is the honest answer for it. A program that *links* the agent has its +;;;; socket bound by the package's constructor before main, so a running +;;;; program with no socket is always this one; see TODO.org, "(agent/start) +;;;; takes no argument, and binds before main". ;;;; ;;;; So: no (import agent ...) anywhere, and a loop that outlasts the test. (defn step [] i64 7)