Cut the prose the sweep of #48 found restated or false
Mirror / push (push) Successful in 8s
Test / lint (pull_request) Successful in 24s
Test / test (18) (pull_request) Successful in 32s
Test / test (20) (pull_request) Successful in 31s
Test / test (22) (pull_request) Successful in 33s
Test / test (24) (pull_request) Successful in 32s
Test / test (26) (pull_request) Successful in 31s

This commit is contained in:
2026-09-28 21:44:54 +02:00
parent 242eb30ab3
commit de572803a0
7 changed files with 32 additions and 42 deletions
+11 -23
View File
@@ -508,10 +508,7 @@ rule and an index of the titles below.
- **`close` means the session is over, and a drop the loop will retry is `disconnected`.**
Maintainer's call, 2026-08-31: without the split, an application that opens a replacement client on
`close` ends up holding two binds on one account. `teardown()` picks the event by
`LinkLife.retrying()`, and `end()` stops the session before tearing down, so every deliberate
shutdown emits `close`. A retry that opens a socket and then loses it is attached again through
`attach()`, which is why a second drop emits again.
`close` ends up holding two binds on one account, which goal 4 forbids.
- **An answer belongs to the link the message arrived on; a receipt does not.** Maintainer's call,
2026-09-01. Rejected: answering on the new link, which succeeds and reports `{}` for a response
@@ -541,9 +538,7 @@ rule and an index of the titles below.
gives up on the operator whose provisioning lands a minute later; the backoff is what bounds the
rate goal 4 cares about. The attempts before the first link report nothing, because the session
running one has not reached the application: `disconnected` would have no listener and `close`
would be a lie. Its wait is the one retry timer that is not `unref()`'d, for the reason
`LinkLife`'s hold is not — it is awaited with no other handle, so a process whose only work is
`client()` would exit unbound.
would be a lie.
- **`connectTimeout` defaults to 10 s, bounds the whole connect including the TLS handshake, and
`false` is the one way to turn it off.** Maintainer's call, 2026-09-20, serving goal 5: a connect
@@ -739,9 +734,7 @@ rule and an index of the titles below.
the one spelling on the public surface. The hold is bounded by `responseTimeout` rather than an
option of its own — that is already the answer to how long one request may wait — and its clock
starts when the send is issued rather than when it first finds the link down, so one budget covers
every hold a single call makes. That timer is the one here that is not `unref()`'d: a held request
is awaited with the socket already destroyed, so an unref'd one lets a process whose only remaining
work is that send exit without settling it.
every hold a single call makes.
- **A send queued for a send-window slot is bounded by the caller's `signal`, and by nothing else.**
Maintainer's call, 2026-09-06, from a review of PR #71: the hold above observes the signal and the
@@ -760,19 +753,14 @@ rule and an index of the titles below.
an abort while held for a link already gives. The drain half needs nothing: `close({ signal })` already hands the signal to
`window.idle()`, and `unbind()` taking none is the shape README states.
- **`LinkLife` decides whether a link can carry a request, and a bind is what makes it one.**
Maintainer's call, 2026-09-01: `attach()` marks the session attached the moment a socket is
handed over, one round trip before the bind is answered, so gating on that let a send arriving in
that window go out unbound and come back `ESME_RINVBNDSTS`. `LinkLife` is told what happened and
never reads back into the session: a collaborator that has to ask does not own its decision, which
is how the first cut ended up answering the same question two different ways at admit and at
release. Every other collaborator reads whether the link lives from it and keeps no copy: five
copies held in step by statement order were what the 2026-09-28 comprehension runs ranked hardest.
`ReconnectLoop.halted` is the loop's own, for its timer, because `client()` also runs a loop with
no session behind it for `fromStart`; a session's loop is stopped by `Session.stop()` alone.
The retry in `requestPastDrain()` asks `link.awaitsNextLink()` rather than `canCarry()`, which also
reads the socket: a loop condition the link does not gate on spins against a link that admits it
straight back.
- **One owner decides whether a link can carry a request, and a bind is what makes it one.**
Maintainer's call, 2026-09-01, extended 2026-09-28; goal 1, since a send on a link not yet bound
comes back `ESME_RINVBNDSTS`. `LinkLife` is told what happened and never reads back into the
session; every other collaborator reads it and keeps no copy. Rejected: gating on the socket being
attached, which admits a send one round trip before the bind is answered, and collaborators that
ask the session, which answered the same question two ways at admit and at release.
`ReconnectLoop.halted` is the one other flag, because `client()` also runs a loop with no session
behind it for `fromStart`; a session's loop is stopped by `Session.stop()` alone.
## Internals and tests