Skip to content

4.8.7 Network Acceptance

The final acceptance workload is network-acceptance-test.ss. It uses production Network/Connection/Stream implementations, real Unix sockets and mutual TLS, actual UCAN authorization, and the shared application-monitor fixture. There are no replacement sockets, production hooks, forced termination or injected exceptions. The current checkpoint records exact build and full-regression evidence and the sign-off status.

4.8.7.1 Current Status

PR review follow-up (2026-09-18): after strict DID validation, context-owned identity normalization, the Network.close worker guard and revocation-stub removal, the 43-module supporting-library regression passed, including all 31 ensemble modules. The full ./build.sh test std/... run completed across 142 modules without a native crash, but reported 14 HTTP server test failures in one module. The other 141 modules had no harness-recorded failures. HTTP source/tests are identical to v0.19-staging; staging was not run separately. See the current checkpoint for commands and failure analysis. This is not a claim that the full stdlib suite passed.

Earlier acceptance checkpoint:

After rebasing onto reviewed v0.19-staging at 3964ba4e and rebuilding from clean artifacts, both verbose and nonverbose ensemble-only runs passed all 30 modules, including the five acceptance cases and both previously crashing paths. The verbose run reported 375 passing named cases. No new crash reproduced in either run.

The earlier full regression and GDB diagnostic crashes remain historical failures, not passes. Their invalid Scheme return/dispatch state has not been traced to an exact cause. The reviewed core adds nullable dotted-receiver safety checks, but these runs alone do not prove which change removed the observed failure. See the current checkpoint for build/rebase details, logs and preserved core evidence. The acceptance work is ready for review on this base; no additional crash fix or claim of exhaustive intermittent-fault elimination is made.

4.8.7.2 Bounded Workload

Each transport runs three persistent linked streams for three explicit connection renewal cycles. Requesters alternate physical initiator, responder, initiator. Each cycle also creates two fixed streams: one drains both writers through FIN and EOF, and the other closes with RESET. Both short-lived streams retire before the next cycle, leaving the three persistent streams live.

Bound Value per transport
Persistent linked streams 3
Renewal cycles 3
Churn streams 6 total, at most 2 concurrently
Maximum live streams 5
Bulk bytes 16 KiB per stream, direction and cycle: 288 KiB total
Churn bytes 48 total
Workload workers 39 tracked readers, writers and renewal callers
DATA frame ceiling 256 bytes
Receive/send rings 1024/2048 bytes
Control payload ceiling 8192 bytes; other control/renewal quotas use defaults
TTL / renewal timeout 120 / 4 seconds
IO timeout 10 seconds
Observation/join cutoff One captured 90-second deadline

Writers submit whole 16 KiB slices, not retries of short successful writes. Readers cycle through chunk sizes 1, 31, 257, 1024 and 4096. Byte offset for stream index 0..2, cycle 1..3 and direction 0..1 is (offset + 17*index + 31*cycle + 97*direction) mod 256; no random seed is needed.

Reader gates create actual full rings and writers waiting on their output CVs. Renewal and stream churn proceed while those persistent writers are backpressured. The gates release only after both connection/stream installations and associated worker/control retirement are observed. Readers then verify every byte. This proves bounded coexistence and progress, not sustained simultaneous throughput or that every churn step overlaps an active round.

At each cycle, synchronized checks verify configured ownership bounds, return to three registry/opening entries, zero completed control charges, returned credit, empty rings after consumption, stable views/handles and one additional renewal ID. Monitor hooks count actual allow callbacks as well as open/close callbacks: reuse and renewal must not repeat admission. Joined shutdown is followed by checks on retained public views, native socket closure, empty jobs/sessions, stable metadata, released rings and usable borrowed capability contexts.

The existing single-write 4 MiB and ten-concurrent 4 MiB E2E cases remain unchanged and run separately in the full regression.

4.8.7.3 Late Ownership

Two additional cases, Unix and TLS, complete one real connection/stream renewal, then hold a verifier during a second renewal after it receives AUTH. Its actual local token and peer-field snapshots are populated. Network closes start while that real capability-context mutex remains held.

The test joins the service thread before releasing the verifier. A separate join observer identifies the verifier’s real completion CV; the connection-cleanup worker must be waiting on that same CV, and the public closer must have reached its wait. Thus a short sleep is not the evidence that shutdown waits. While held, the round is retired but still owns its unchanged snapshots, and worker-done? is false. After release and actual joined close, obsolete round/operation/opening ownership must disappear without changing installed expirations, metadata or IO identity.

This reproduced a retention defect: service could exit before the final owner finished, and shutdown joined without performing its last retirement pass. The repair performs renewal retirement before opening retirement only after a complete owned-worker join barrier. Private joined? reaper arguments avoid rejoining and rethrowing failures already recorded by shutdown. Existing worker/control-release checks remain authoritative; no counter is zeroed to conceal retained ownership. A skipped self-join or incomplete join does not authorize that final pass.

Public callers remove their own waiter records in their finalizers. Network close does not mean every application caller has already finished; the acceptance tests join their application workers before requiring those lists to be empty.

4.8.7.4 Failure Teardown

The shared API fixture retains closer handles, attempts all joins under one finite cleanup deadline, and only then releases borrowed contexts, the store and its Unix directory. If a closer or unknown join failure leaves completion uncertain, these resources remain retained. An ordinary terminated application failure, including raised #f, is not confused with a join timeout.

A dedicated case deliberately holds a real close callback and tracked application worker beyond a 0.1-second cleanup budget. It verifies Timeout and intact borrowed resources/path, then releases gates, joins the actual owners and cleans up manually. It also checks normal fixture cleanup after a known terminated worker raises #f.

Observation/join cutoffs and fixture cleanup budgets are watchdogs, not hard real-time bounds across arbitrary lock acquisition or nonreturning callbacks.

4.8.7.5 Audit Limits

The public facade and current documentation are checked against actual exports and signatures. Internal scheduler, opening, renewal and installation helpers remain outside the facade. Current docs distinguish pre-activation open callbacks from readiness, Unix sidecar ownership, nullable/default arguments, finite lease policy, whole-slice byte IO, independent deadlines and retained failure identity.

One historical handshake candidate, configured seeds, fixed terminated worker handles, errors and public metadata may remain reachable from retained views. Application monitors may retain their own event history. Returned ring buffers may remain in the shared bounded cache; closed TLS views may retain a cached certificate wrapper. These are not claims of zero retained fields or a native allocation census. The tests establish network-owned lifecycle retirement, not RSS reduction or GC collection of every object reachable through a user-retained exception.

Pooling, reconnect, new decoder/waiter budgets, host/address-book work, and exhaustive scheduling permutations are outside the agreed completion scope. A nonreturning provider retains ownership and can delay joined shutdown. Final results and any concrete sign-off blocker belong in the implementation checkpoint, not an expanding test matrix.