# RelaySwarm full documentation context > Generated from maintained Markdown. Source package 0.4.4; release and deployment evidence is recorded in docs/STATUS.md. Canonical repository: https://github.com/forgesworn/relayswarm. Main-branch documentation can correct released documentation. Historical spike evidence is indexed separately in llms.txt. Regenerate with `npm run docs:generate`; do not edit this file by hand. --- Source: [README.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/README.md) # RelaySwarm Experimental peer-assisted HLS video delivery using WebRTC data channels and Nostr relays for peer discovery and signalling. A separate native proof of concept uses HyperDHT and Noise for installed Node applications. **Status:** [v0.4.4 is the prepared experimental prerelease](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.4). Cached schema-3 media can combine a bounded peer fraction with origin pieces even when a whole-object peer estimate is late. Waiting for unavailable known-VOD main media requires a live same-key fetch lease from a contributor; live and unknown playlists retain their bounded coordination. Its opt-in sustainable peer waits preserve origin-recovery time within a segment's duration; its matching WASM core takes only requested upload ranges across the byte-copy boundary. Longer physical-phone continuity remains open. It integrates holder recovery with the Rust/WASM core, accepted connection and verified-media observations, bounded cancellation/draining and relay recovery. JavaScript/WASM and native core downloads have separate checksums. Native real-time transport remains experimental. MIT licensed, Node 22.13+; CI uses Node 24. The npm registry is unpublished. Production acceptance remains incomplete. The dated [pilot evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) records earlier controlled trials and their open sustained-operation, physical-device, difficult-network and measured-benefit gates. This release does not deploy or qualify that pilot. See the [delivery requirements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) and [current source evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Installation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) · [hls.js integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md) · [API reference](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md) · [Evidence and remaining work](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) · [FAQ](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FAQ.md) · [AI index](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms.txt) · [Full AI context](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms-full.txt) ## Try it Install ffmpeg with libx264 for synthetic media, then: ```sh git clone --branch v0.4.4 --depth 1 https://github.com/forgesworn/relayswarm.git cd relayswarm npm ci npm run demo ``` Open `http://localhost:8787`. The server generates two live H.264/AAC renditions, keeps its publisher key in Node and signs commitments derived from the local playlists. The player starts origin-only. Uploading requires the viewer's explicit opt-in; controls include upload limits, quality selection, an origin-only kill switch and a local JSON receipt download. To use existing media: ```sh npm run demo -- --media-dir /path/to/hls --manifest master.m3u8 ``` See [the field-test guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md) for the supported HLS subset, HTTPS access from separate devices and receipt interpretation. Synthetic media requires ffmpeg; serving an existing directory does not. v0.2.1 includes a **broadcaster**: live RTMP-to-HLS ingest, persistent publisher identity, cumulative viewer upload allowances, measured peer choice and authenticated operator controls. Optional RTMPS forwarding can send the source to an external platform independently of RelaySwarm delivery. These features are in v0.2.1 and absent from the immutable v0.1.0 downloads. The [production feature guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) also describes wider media, delegation, admission, durable budgets/reports and native fallback. See [broadcasting](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md), [operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md) and [container setup](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md). ## Install the library The release supplies an installable tarball, a standalone browser ESM bundle, the optional WASM module and SHA-256 checksums. Apple and Android core assets are described in the [packaging guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/CORE-PACKAGING.md): ```sh npm install https://github.com/forgesworn/relayswarm/releases/download/v0.3.0/relayswarm-0.3.0.tgz ``` ```js import { createHlsSwarm } from 'relayswarm/hls-swarm'; import { createHlsPublisher } from 'relayswarm/hls-publisher'; // Node only ``` The host supplies hls.js. Install it separately for a host-page integration; the source demo includes it as a runtime dependency. The release bundle includes the browser loader's runtime dependencies. Pinned Git installation and bundle usage are in [Getting started](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md). ## What it does | Path | Transfer and integrity | Signalling | |---|---|---| | Original CLI, `poc.mjs` | werift WebRTC; SHA-256 supplied by the sending peer detects transport corruption | Signed **plaintext SDP** on Nostr relays | | Browser loader, `relayswarm/hls-swarm` | Native WebRTC; shadow compares with origin bytes, peer-first verifies stream-author-signed segment commitments | Pairwise NIP-44-encrypted signals, session wire version 3 | | Native CLI, `native-poc.mjs` | HyperDHT/Noise; receiver enforces an independently expected digest and size | Pairwise NIP-44-encrypted one-shot dial authorisation, session wire version 3 | The browser loader has three modes: - **Off:** origin-only HLS, without swarm sockets, publications or peer connections. - **Shadow:** origin bytes play as usual; sampled peer transfers measure potential delivery and add data traffic. Uploading defaults to off. - **Peer-first:** a bounded peer attempt precedes the normal HTTP loader. Signatures, exact media context, size and SHA-256 must verify before bytes reach hls.js. Startup, thin buffers, missing peers and failed deadlines use origin. Benefits can differ substantially between viewers. Peer-first requires a trusted signed kind-30311 stream event with the experimental `["relayswarm", "redistribute", "1"]` tag and an expiring commitment signed by that author or a host-trusted, author-scoped delegate. Kinds 24170/24171/24172 and this authorisation tag are experimental assignments, not an accepted RelaySwarm NIP or a stable interoperability guarantee. ## Why use Nostr for rendezvous? Peers still need infrastructure to discover one another. [P2P Media Loader uses WebTorrent-compatible trackers](https://github.com/Novage/p2p-media-loader/blob/main/FAQ.md#what-is-tracker). RelaySwarm instead uses application-selected Nostr relays for presence and signals, then sends media over the direct peer connection. [NIP-53](https://github.com/nostr-protocol/nips/blob/master/53.md) kind-30311 events can list relays. A host can reuse that selection, but this library does not automatically read relay/STUN policy from them: the host passes `streamEvent`, `swarmId`, `relays` and `iceServers` explicitly. The HTTP origin remains responsible for initial media availability and fallback. ```mermaid flowchart TB O[HTTP origin and publisher] R[Application-selected Nostr relays] A[Viewer A] B[Viewer B] A -. presence and encrypted signals .-> R B -. presence and encrypted signals .-> R O -->|HLS and signed commitments| A O -->|HLS fallback| B A <-->|verified media over WebRTC| B ``` Other approaches and the narrow comparison are in [Landscape](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/LANDSCAPE.md). [RelaySwarmKit](https://github.com/forgesworn/relayswarm-kit) is a separate Swift signalling/transport project. Kit v0.6.0 adopts the released Rust core and supports session version 3, signed schemas 1/2/3 and explicit piece transfers. Its public SDK received verified author/delegate HLS bytes from two production browser peers and rejected corruption, signature tampering and revocation. That measured macOS arm64/Chrome loopback journey and its boundaries are in the [protocol draft](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NIP-DRAFT.md); physical-device and NAT acceptance remain open. These are libraries; running a ForgeSworn-hosted service is not required. Applications choose their HLS origin, signalling relays and network policy. The interoperability fixtures use temporary loopback servers and close them after each run. Historical pilot deployments are separate, dated evidence. ## Evidence The [release-main CI run](https://github.com/forgesworn/relayswarm/actions/runs/38233694634) passed all seven standard jobs: the publisher/player playback regression, shadow and peer-first Chrome harnesses, native tests on Linux/macOS/Windows, and public-relay transport tests. The [twelve-viewer loopback soak](https://github.com/forgesworn/relayswarm/actions/runs/38231951028/attempts/2) used three arrival waves and a 180 s final measurement window. Peers supplied 923 of 1,343 fragment loads (68.7%); all twelve viewers and the baseline had zero stalls or fatal errors. Corruption was rejected, sampled resources stayed within limits and shutdown released resources. Two viewers used origin throughout. Media loads avoided exclude signalling, commitments and protocol overhead; they are not net connection-data savings. The two-rendition playback regression covers quality switches, forward/backward seeks, shared-file byte ranges, a timestamp reset, relay loss/recovery, receive-only behaviour, the kill switch and downloaded receipts. [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) separates this evidence from remaining field gates; [spike results](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/RESULTS.md) retain dated historical measurements. Earlier CLI/browser and limited cross-NAT runs do not validate the new loader on physical phones or a broad range of internet networks. ## Commands | Command | Purpose and prerequisites | |---|---| | `npm run demo` | Publisher/player; ffmpeg for synthetic media | | `npm run check` | JavaScript syntax | | `npm run check:docs` | Documentation links, AI index structure and generated-context freshness | | `npm run docs:generate` | Regenerate `llms-full.txt` from maintained Markdown | | `npm run test:swarm` | Browser-loader and hardening unit tests | | `npm run test:publisher` | Publisher context/range and demo HTTP/relay tests | | `npm run broadcast:install` | Fetch the platform-pinned MediaMTX test router | | `npm run broadcast` | Unreleased live ingest launcher; FFmpeg, H.264/AAC input | | `npm run test:broadcast` | Real ingest/reconnect/forwarding plus control guards; FFmpeg/OpenSSL | | `npm run test:broadcast:browser` | Real-time two-quality Chrome playback; installed router and FFmpeg | | `npm run test:operator` | Actual Chrome allowance, remote policy and reporting controls | | `npm run test:media-browser` | Actual fMP4/ABR, audio/AES/mixed-codec and low-latency-part Chrome journeys | | `npm run native:fetch -- --help` | Installed native client with verified HTTP fallback | | `npm run test:native` | Local relay and local HyperDHT bootstrap; no external network | | `npm run test:playback` | Two-rendition real Chrome regression; Chrome and ffmpeg | | `npm run test:playback:resume` | Trusted Resume click, decoded media and fresh consent; Chrome and ffmpeg | | `npm run test:browser -- --mode shadow` | Live HLS Chrome harness; Chrome and ffmpeg | | `npm run test:browser -- --mode peer-first` | Authenticated peer-first harness; Chrome and ffmpeg | | `npm test` / `npm run poc` | Original WebRTC PoC/fan-out against public Nostr relays | | `npm run poc:native` | Native PoC against public relays and DHT bootstrap nodes | | `npm run audit` | Dependency audit at the high-severity threshold | Use `--chrome /path/to/chrome` for either browser test, or set `CHROME_PATH`. The optional twelve-viewer CI soak is enabled by a manual workflow dispatch with `soak=true`. Public-relay failures can reflect relay policy or availability. ## Privacy and limits Swarm keys are ephemeral and separate from social identities. Participation is pseudonymous: relays see metadata and connecting addresses, and connected peers can learn one another's network addresses. NIP-44 hides signal bodies, not those observations. The original CLI still exposes its SDP to relays. Origin-only mode avoids swarm participation; the origin still receives normal HLS requests. Upload consent and publisher redistribution permission are separate requirements. The optional [shared upload allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md) uses explicit Nostr sign-in or a host website account to coordinate media reservations across devices. Its private service can associate those devices; linking both identities also reveals their association to that service. Stable account identities and grants stay out of swarm traffic and receipts. Sign-in never enables uploading or reporting. The [current pilot](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) offers Nostr sign-in; integrating websites supply their own authenticated account resolver. The browser defaults to Google's public STUN server unless the host supplies `iceServers`; the native path uses HyperDHT bootstrap/routing nodes instead. No managed TURN or super-peer service is supplied. Hosts can pass TURN ICE credentials through `iceServers`. For browser HLS, blocking peers or relays leaves the normal origin loader as fallback. The native CLI reports failure; the installed native client adds verified HTTP fallback. The swarm provides neither durable storage nor availability after every source disappears. Still outstanding: physical-phone and varied-NAT trials, sustained operation, broad internet scheduling/cost evidence, a full Sybil suite, an accepted NIP and physical/public-NAT independent-client acceptance. Actual fMP4/adaptive-quality and wider-media fixtures are recorded separately from physical acceptance. See [Threat model](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/THREAT-MODEL.md) and [the field gates](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md). ## Documentation and AI readers The canonical public repository is [`forgesworn/relayswarm`](https://github.com/forgesworn/relayswarm). [`llms.txt`](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms.txt) is a short index with direct Markdown links; [`llms-full.txt`](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms-full.txt) is generated from the maintained guides. Published code is pinned at `v0.3.0`; documentation on `main` can include later corrections. [Maintaining the docs](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/MAINTAINING-DOCS.md) explains regeneration and publication checks. Release assets are never replaced after publication. [Changelog](https://raw.githubusercontent.com/forgesworn/relayswarm/main/CHANGELOG.md) records release and documentation changes. [MIT licence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/LICENSE). --- Source: [INTEGRATION.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md) # Integrating the hls.js swarm in a host page [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Installation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) · [API reference](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md) · [Release evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) `src/browser/hls-swarm.mjs` adds peer-assisted delivery to an hls.js player. In **shadow mode** it changes nothing the viewer sees: every fragment still comes from the origin, and the swarm only measures what peer delivery would have achieved. That is the mode to deploy first. The module is browser ESM with a direct runtime dependency on `nostr-tools`. The published [v0.2.1 GitHub prerelease](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.1) supplies an installable tarball and a standalone bundle containing the browser runtime dependencies. The host supplies hls.js. The npm registry is unpublished; [Getting started](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) gives exact asset and pinned-Git commands. v0.2.1 adds the [production feature work](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md); those additions are absent from v0.1.0 assets and retain separate delivery/acceptance gates. The host selects a trusted stream event, shared swarm id, relay policy and ICE servers. This module does not perform Nostr stream discovery or automatically extract relay/STUN policy from a kind-30311 event. ## Attaching This host-page snippet assumes the application provides `eventId`, `manifestUrl` and the `video` element. Replace the example relay with your own tested endpoint. The metrics callback below logs locally; the library does not submit analytics automatically. ```js import Hls from "hls.js"; import { createHlsSwarm } from "relayswarm/hls-swarm"; const swarm = createHlsSwarm({ swarmId: `stage-${eventId}`, // same string for every viewer of one stream relays: ["wss://relay.example"], // 1-8; the deployment's own relay first mode: "shadow", // "shadow" | "peer-first" | "off" originFallbackMs: 1500, // "in time" means within this of the load starting shadowSampleRate: 0.25, // race this share of fragments (see Cost) onMetrics: (metrics) => console.log(metrics), }); const hls = new Hls(); swarm.attach(hls); // attach BEFORE loadSource hls.loadSource(manifestUrl); hls.attachMedia(video); // later, or when the kill switch says off swarm.stop(); ``` An invalid supported configuration or unsupported browser yields a swarm whose `metrics().mode` is `"off"` and whose `metrics().disabledReason` says why (`invalid-swarm-id`, `invalid-relays`, `invalid-mode`, `mode-off`, `invalid-stream-authorisation`, `missing-commitment-provider`, `invalid-limits`, `no-webcrypto`, `no-webrtc`, `no-websocket`). A disabled swarm leaves the player untouched, so the host page can attach unconditionally. `attach()` replaces `hls.config.fLoader` with a wrapper around the loader that was configured, and `stop()` puts the original back, closes every peer connection and relay socket, drops held segments and emits one final `onMetrics`. Requires a secure context (https, or localhost) for WebCrypto. For a same-identity admission renewal, `updateTicket(ticket)` replaces only this viewer's opaque ticket and schedules a bounded presence announcement. Established links, the loader, held segments, counters and upload reservations remain intact. It returns `true` for an accepted ticket (including an unchanged one), or `false` for an invalid ticket or stopped, disabled or ungated swarm. The host must validate its own credential's issuer, swarm, epoch and expiry before calling it, and retain expiry checks around asynchronous admission and upload reservations. It does not validate an opaque credential, extend policy authority or restore upload consent. Publisher, policy or peer-configuration changes still require reconfiguration. If an upload arrives during that peer's changed-ticket admission check, it joins the pending bounded check. Only an accepted decision permits media or an upload reservation. Rejection, timeout or shutdown prevents delivery. A successful decision is not cached as permission for later upload requests. ## Options | Option | Default | What it does | |---|---|---| | `swarmId` | required | Groups viewers of one stream. 8-128 characters. | | `relays` | required | 1-8 relay URLs (`wss://`, or `ws://` on loopback). | | `mode` | `"shadow"` | `"off"` disables; `"peer-first"` requires a signed stream authorisation and commitment provider. | | `secretKey` | fresh per viewer | Ephemeral signing key for presence and signalling. Never the viewer's own identity. | | `originFallbackMs` | `1500` | The in-time budget a peer delivery is measured against, and peer-first's ordinary wait. | | `maxPeerWaitMs` | `5000` | Peer-first may wait past `originFallbackMs`, up to this, only while recent peer timing projects the segment needs it and the playback buffer covers the wait with `originReserveMs` to spare. | | `originReserveMs` | `2000` | Minimum buffered playback reserved for origin recovery; measured p90 HTTP time can increase it. Multi-holder origin tails retain that same per-load reserve and its absolute recovery deadline. An empty buffer goes directly to origin. | | `sustainablePeerWait` | `false` | Opt-in: also cap the initial peer wait and every extension by the fragment/part duration minus measured p90 whole-object origin time with a 25% and 100 ms recovery margin. Substantial origin ranges update this estimate after scaling by their actual byte count. Unknown origin timing or duration leaves no serial peer wait. This limits repeated failed waits from consuming more playback than each segment adds. Independent cached/late-HAVE races keep their window beside immediate HTTP. | | `warmAhead` | `false` | Experimental peer-first option, requiring `serve: true`: use the same player's next two parsed, unencrypted, whole main-media fragments for bounded speculative loading. A warmed object promoted to genuine demand frees the sole speculative slot. Existing demand/range limits are unchanged. Verified future objects share the held cache; at most three distinct cached/in-flight objects and 24 MiB of warm data plus all reservations fit within `maxHeldBytes`. Fresh cache permission may wait only within actual buffer headroom, up to 25 ms, before ordinary source recovery proceeds independently. | | `startupBufferTarget` | `null` | Experimental one-shot startup buffer for peer-first serving: a synchronous function returns the current player's fresh raw HLS target time in seconds, or `null` when its ownership/epoch is invalid. Hold the first main-fragment callback until verified contiguous upcoming media covers that target and measured origin-recovery headroom. The first held body shares the existing three-object/24 MiB budget and original eight-second/parent deadline. Works with `warmAhead: false` to stop speculative fetching after startup. It never pauses, plays, seeks or changes the room clock; bounded failure reports a loader error instead of releasing unsafe media. | | `startupBufferCommit` | `null` | Optional async host hook, requiring `startupBufferTarget`, called once with frozen `{ signal }` after verified reservoir readiness and before releasing HLS callbacks. The host may acknowledge a new room start here. The original startup deadline and resource limits continue; cancellation ignores late settlement. Fresh target, authority, context and resident coverage are checked again afterwards. The SDK never creates or reanchors the room clock. | | `uploadPacing` | `false` | Experimental canonical-piece upload refill deferral: one FIFO waiter per link, at most `min(maxUploadPeers, maxPeers)` waiters, and a fixed 250 ms queue deadline. The existing per-second rate, twice-rate burst, session allowance and wire remain unchanged. Whole-object deficits still refuse immediately. Queue rows contain identity and numeric geometry; held bytes and current host permission are checked after waiting. | | `latePeerRace` | `false` | Experimental peer-first option requiring `zeroBudgetPeerRace`: permit the first peer arm of still-running whole-main-fragment HTTP with no prior peer plan to use a newly accepted, current exact-HAVE holder. Warm work needs a genuine consumer or an owned pending startup-buffer dependency. Genuine demand keeps its earliest demand window; startup dependencies keep the original HTTP-entry window and first startup deadline. Both retain `min(lateWindowMs, 4000)`, arming plus `min(maxPeerWaitMs, 2500)`, and the known original HTTP load deadline. Same HTTP request/timers, fresh authority and current immutable identity; no retries or extra GET. Dormant watchers share `maxConcurrentRaces`; lifecycle changes retire them. Numeric `latePeerRace` metrics do not create delivery credit. | | `lateWindowMs` | `6000` | How long a race keeps asking peers before it counts as missed. | | `maxPeers` | `6` | Connections in and out. The demo selects four explicitly. | | `maxDialsInFlight` / `dialTimeoutMs` | `2` / `12000` | Simultaneous outbound dials and setup deadline. | | `maxUploadPeers` | `4` | Distinct peers served in any 30 s. | | `maxUploadBytesPerSecond` | `1250000` | Upload token bucket. Bytes a receiver's cancel kept from being sent return to it. | | `maxUploadBytesPerSession` | unlimited | Optional non-negative safe integer, including zero. Reserves full accepted media payloads; interrupted transfers do not refund the allowance. | | `reserveUploadBytes` | none | Optional async `(bytes, {signal}) => boolean` host reservation before serving; refusal/error/timeout stops the send. Use for persistent cross-tab budgets. | | `serveOnCellular` | `false` | With `false`, detected cellular or `saveData` connections neither upload nor fetch peer media. Detection is advisory and does not identify every metered connection. | | `serve` | `false` | Set `true` only after the viewer opts into uploading. With `false`, the viewer is receive-only: it takes from peers but never uploads or advertises what it holds. Use it where the connection type cannot be read (Safari), so a phone on cellular is never asked to upload. | | `ticket` | none | An opaque string (up to 2 KB) this viewer presents in its presence and in every offer and answer, typically a short-lived credential the origin signed for this viewer's swarm key. | | `admit` | none | `(pubkey, ticket) => boolean \| Promise`. With it set, a viewer never dials, answers or follows a referral to a peer it has not admitted, so its address (carried in the SDP) only reaches ticket holders. The host is called again before each dial and SDP publication, including retries and referrals; it must check expiry. A third argument provides an operation-specific abort `signal`, cancelled on its deadline or swarm stop. At most 16 checks run concurrently and each has a 3 s deadline. | | `shadowSampleRate` | `0.25` | Share of fragments raced. | | `streamEvent` / `getCommitment` | required for peer-first | Signed kind-30311 stream event and `(context, { signal }) => signedCommitment`. See below. | | `delegation` / `revokedDelegationIds` / `delegationRevocations` | none / empty | Explicit author-signed scope and current host revocation view for delegated commitments. | | `maxConcurrentRaces` | `24` | Maximum retained shadow races. | | `admissionTimeoutMs` | `3000` | Deadline for a host admission check. | | `swarmParts` | `false` | Include low-latency HLS parts. Parts are small; leave off. | | `maxHeldSegments` / `maxHeldBytes` | `12` / 64 MiB | What a viewer keeps to serve others. | | `maxSegmentBytes` | 16 MiB | Maximum accepted/retained segment payload. | | `minLinkLifeMs` / `idleEvictMs` / `evictionCooldownMs` | `15000` / `20000` / `10000` | Minimum link lifetime, bidirectional idle threshold and rotation cooldown. | | `retryFloorMs` / `retryCeilingMs` / `maxRetriesPerPeer` | `4000` / `45000` / `3` | Refusal retry bounds and retry attempts per peer. | | `maxReferrals` | `2` | Maximum referrals offered after a refusal. | | `reannounceDebounceMs` / `minReannounceGapMs` | `4000` / `12000` | Bound capacity-change presence announcements. | | `presenceIntervalMs` | `20000` | Presence heartbeat, jittered 30%. | | `metricsIntervalMs` | `10000` | How often `onMetrics` fires. | | `onPeerDelivery` | none | Optional `({ connection, bytes }) => void` observation for each accepted, verified peer-first media contribution. `connection` is the actual `RTCPeerConnection`; `bytes` is the positive media payload byte count. A single-holder delivery fires once with its whole payload; a multi-holder delivery fires once per contributing connection with only its first-verified-copy bytes, excluding origin and duplicate pieces. It fires only after the complete verified object is accepted for the player. Aggregate peer-first counters are updated first, then all contributions are observed immediately before the player's success callback. Host exceptions and rejected promises are ignored without changing playback or other observations. It does not fire for protocol traffic, shadow measurement, origin fallback, corrupt/rejected media, an incomplete multi-holder object or loads aborted, stopped or too late for the peer-first handoff. | | `iceServers` | one public STUN | Host-provided STUN/TURN configuration captured at swarm creation. Browser TURN credentials are disclosed to the client; no managed TURN deployment is supplied. The demo/broadcaster accepts a private `--ice-config FILE` or a separate optional [renewal adapter](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#optional-turn-credential-renewal) that replaces demo swarms. | | `iceTransportPolicy` | `"all"` | `"all"` or `"relay"`, captured at creation and passed to every native connection. `"relay"` restricts peer ICE to relayed candidates; it never retries with `"all"`. Usable TURN configuration is required for peer connectivity. This does not select TLS, change consent or extend a peer deadline; origin fallback remains available. | | `coreWasm` | unset | Experimental and opt-in. Peer-first only: the Rust core's commitment verifier, peer selection, neighbour discovery and peer link protocol, `src/browser/relayswarm-core.wasm`, as a URL, its bytes or a compiled `WebAssembly.Module`. Serve the file as `application/wasm`; a page with a Content Security Policy needs `'wasm-unsafe-eval'` in `script-src`. The relay session starts once the module has loaded or failed, after at most 2 seconds; fragments loaded meanwhile go to origin. JavaScript decides until the module loads, and for the rest of the session if it fails to load or traps; a trap closes the links the module ran, and later links are JavaScript. A rejection from the module stands. See `core` in the metrics. | | `transferWorkerUrl` | unset | Experimental opt-in with peer-first, `coreWasm` and `multiHolder`. Explicit URL of a separately bundled companion worker from the same SDK revision. It warms asynchronously from the already compiled module and runs the same Rust schema-3 transfer facade off the main thread. While warming, after worker failure or at resource limits, those loads use HTTP; no silent large synchronous transfer retry. Existing absolute deadlines and complete-object credit checks remain. [Packaging, bounds and lifecycle](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/TRANSFER-WORKER.md). | | `multiHolder` | `false` | Experimental; needs `coreWasm`. A schema 3 segment (signed with the publisher's `pieceCommitments`) is fetched from several holders at once by piece range, with an HTTP `Range` fetch from origin for any tail the peers are projected to miss; a holder that proves fast once idle takes back pieces origin has not yet sent, and the first verified copy wins; every piece is verified against the commitment before the segment is delivered. A holder that stays silent or whose flow cannot finish its range in time is abandoned early, by the single-holder rules, and its pieces move to the other sources; unlike the single-holder path, a flow that stops after its first byte is also checked every 250 ms rather than left to its timeout. Used only with holders whose presence advertises object framing 2, and the viewer advertises it only while every one of its links runs in the core. Ranged origin requests go through the player's own fragment loader with `rangeStart` and `rangeEnd` set, as for an `EXT-X-BYTERANGE` segment, so headers and credentials from hls.js `xhrSetup`, `fetchSetup` or a custom loader apply. A body that is not exactly the range (a server that ignored `Range` and sent the whole segment) is discarded, and a refused range sends the segment to the whole-segment origin load. After one such answer the origin (scheme, host and port) is not asked for ranges again in that session, and its segments take the single-holder path. A ranged upload is charged by the bytes it sends. | | `zeroBudgetPeerRace` | `false` | Experimental opt-in with `coreWasm` and `multiHolder`. When buffered playback leaves no safe peer wait, start normal whole-segment HTTP immediately and race a schema 3 object already advertised in a connected framing 2 holder's HAVE at load entry. The Rust transfer requires the optional peer-only capability: no origin lane or origin estimate exists inside that transfer. Cold holders get bounded calibration; verified progress refills pending ranges, each piece and the whole object hash must match. Candidates remain inside the initial snapshot and current HAVE. Older modules safely decline this arm while HTTP continues. No new neighbour search or ranged HTTP request is added. Key hashing and commitment verification never delay HTTP. The first complete verified peer object or normal HTTP response wins; losing callbacks are suppressed. Peer work stops at `maxPeerWaitMs`. Existing upload rate/session limits apply to each bounded request. Progressive hls.js delivery skips this race; unexpected nonempty HTTP progress locks the load to HTTP. Accepted peer bytes alone do not establish network savings. | | `lateHaveRace` | `false` | Experimental opt-in alongside `zeroBudgetPeerRace`. When no entry-snapshot HAVE matches, observe actual matching HAVE only on the accepted, eligible framing 2 connections captured at load entry. Normal whole HTTP already runs. The first qualifying holder snapshot starts at most one existing peer-only arm; key hashing, HAVE observation, metadata and transfer all share the original `maxPeerWaitMs` deadline. FETCH, new or replaced connections and withdrawn HAVE do not qualify. No new discovery, dial, HTTP request, origin range or deadline extension is added. HTTP success, exposed progressive data, abort and stop cancel observation and peer work under the same ownership rules. This can use overlapping source downloads; it does not guarantee throughput, continuity or network savings. | | `maxHoldersPerObject` | `3` | Holders per segment under `multiHolder`, 1 to 8. Provisional: not yet set from a replayed field trace. | | `abrIgnorePeers` | `false` | Peer-first. Keeps a peer-delivered fragment out of the hls.js bandwidth and first-byte estimates, so automatic quality follows the origin path; otherwise the time a peer delivery took, including any wait for a holder, is sampled as if it were an origin download. The loader skips the estimator's samples only while hls.js dispatches `FRAG_LOADED` and `FRAG_BUFFERED` for that fragment, and puts hls.js back on `stop()`. The one sample it cannot withhold is the first-byte sample hls.js's own timer takes when a load has waited past half a segment with no byte, the check that can switch quality down mid-load. A fragment fetched under `multiHolder` counts as peer-delivered even when origin sent part of it. `metrics().segments.abrPeerSamplesWithheld` counts the skipped samples. Needs the default hls.js ABR controller; with another one it does nothing. | | `traceRequests` | `0` | Rows kept for `trace()`, 0 to 32,768, oldest dropped first: loads, eligibility decisions, peer and origin requests and multi-holder scheduler calls, enough to replay a transfer offline. For field runs that need a replayable input; it is not part of `metrics()`, so a receipt must take `trace()` itself. | | `segmentKey` | URL pathname | Maps a fragment URL to the key peers index by. Must agree across viewers, so strip per-viewer query strings and CDN tokens. | | `RTCPeerConnectionImpl` / `WebSocketImpl` / `WorkerImpl` | globals | Constructor injection points for tests; the worker remains explicitly configured through `transferWorkerUrl`. | The pending glare-reuse correction keeps the existing lower-public-key offer when both peers dial simultaneously. The yielding peer may adopt only its still-pending outgoing connection for the winning admitted offer. Native operations are serialised and old negotiation/channel callbacks are fenced; the same capacity slot and original absolute `dialTimeoutMs` deadline remain. The host admission check runs again before rollback, after asynchronous rollback immediately before remote SDP, and before answer publication. These checks share the existing dial deadline and bounded admission policy. Established, failed or unsupported native states are not reused; failure retains normal origin fallback. Recent admitted offer IDs are retained privately up to 256 entries per swarm; active incoming duplicates do not allocate or restart a timer. Incoming distinct requests still supersede pending incoming connections. Wire version, public options and existing limits stay unchanged. The correction has passed 121 unit tests; native rollback/SCTP and Internet renewal remain unproved. See the [current checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint). ## Cost, and what to tell viewers Shadow mode downloads a raced fragment **twice**: once from the origin for the player, once from a peer to measure. That is the price of measuring with no playback risk. Keep `shadowSampleRate` low enough that the extra data is acceptable (0.25 gives a useful sample), and leave `serveOnCellular` false. Contribution is off by default. Say plainly that `serve: true` redistributes media, and obtain the viewer's opt-in before enabling it. Cellular detection is advisory: browsers can omit connection information, so it cannot replace consent. Receive-only still discovers peers and exposes its address to them; `mode: "off"` or `stop()` provides origin-only playback. ## Metrics `onPeerDelivery` and `peerConnections()` are included from v0.4.0. The immutable v0.3.0 release assets do not include them. The opt-in `zeroBudgetPeerRace` and measured origin-recovery reserve below are later main-branch additions; consume a commit that contains those changes. `peerConnections()` returns a fresh array of the actual `RTCPeerConnection` objects for accepted, active peer links. Pending offers, dials, glare negotiations and closed/disconnected links are excluded. It returns an empty array after `stop()`. Changing the returned array does not change the swarm's membership. Use this snapshot to draw connected peers; observing native constructors also sees negotiations that never become peers. Connection references are deliberately separate from serialisable `metrics()` data. `peerConnectionDetails()` is a later main-branch addition. It returns fresh `{ connection, pubkey }` records for the same accepted links. `pubkey` is the remote peer's ephemeral signalling key, explicitly associated with that native connection. Neither array order nor a local connection counter identifies a remote peer. The records disappear on link closure or `stop()`, and changing a record cannot change membership. This read-only projection adds no wire traffic. Keep native references local; a room participant's claim to a signalling key remains a self-report unless the application establishes its own binding. Use `onPeerDelivery` to attribute verified video to its contributing connections. For a multi-holder delivery, each connection is observed once with the bytes its pieces contributed to the completed object. The first verified copy of each piece wins; duplicate or origin-winning pieces add no peer credit. All contributions sum to the increase in `bytes.peerFirst`. An incomplete or rejected object emits no observation even if some pieces verified. Aggregate counters include the whole delivery before its first observation runs. Keep connection references in local maps rather than serialising them into receipts. The callback provides no URL, peer key, SDP or payload buffer, and does not add a network request or change a deadline. It observes bytes accepted for the player, not the segment currently playing from its buffer. Browser RTC byte statistics include connection and protocol messages and must not be presented as verified video delivery. Likewise, the `payload` outcome in `peerRequestDiagnostics` precedes hash verification and is not an alternative to this callback. `segments.zeroBudgetPeerRaces` counts matching cached-HAVE race attempts; `zeroBudgetPeerRaceWins` counts only complete peer objects accepted by the player. With `lateHaveRace`, the zero-budget `have-after-wait` eligibility row records actual later HAVE admission while HTTP runs; it is not a serial origin wait. Verified pieces of an origin-winning or incomplete object add no accepted peer bytes and emit no delivery callback. `stop()` cancels the peer arm while pending normal HTTP continues for playback; loader `abort()` or `destroy()` cancels both arms. Run `npm run test:cached-peer-race:browser` ([fixture](https://raw.githubusercontent.com/forgesworn/relayswarm/main/test/zero-budget-peer-race-native-browser.mjs)) for two native browser contexts exchanging a signed six-MiB object, both winners, one HTTP request per load, partial HTTP cancellation and connection reuse. It is a loopback integration proof; the deployment's media/network acceptance remains separate. `onMetrics(metrics)` and `metrics()` return a version-2 snapshot: `v`, `swarmId`, `mode`, `disabledReason`, `stopped`, `pubkey` (the ephemeral swarm key, not an identity), `uptimeMs`, `serving`, plus: - `peers`: `connected`, `dialling`, `dialsStarted`, `dialsAccepted`, `dialsFailed`, `dialsTimedOut`, `dialsRejected`, `offersAccepted`, `offersRefused`, `linksOpened`, `linksClosed`, `banned`, `candidatePairs` (counts keyed `local/remote` candidate type, the NAT outcome: `host/host`, `srflx/srflx`, `relay/...`, `unknown`). - `signalling`: `samples`, `medianMs`, `p90Ms` from offer sent to channel open. `signalling.clock` holds local age-window counts: `aheadRejected` (swarm events dated more than 30 s ahead), `staleRejected` (older than the 60 s window, including relay history), `maxAheadSeconds`, and `signalSamples` with `signalAgeMedianSeconds` from at most 64 recent live signals that decrypted and validated. A median far from zero suggests this device's clock differs from its peers'; it is relay delay plus skew in whole seconds, not a clock measurement. No identities. `signalling.clock.origin` is `{ samples, offsetSeconds }` from the HTTP `Date` (plus `Age`, when present) of up to 16 recent origin fragment loads, timed at first byte, as origin minus this device; positive means the origin is ahead. It needs a readable `Date`: same-origin, or `Access-Control-Expose-Headers: Date`; otherwise `samples` stays 0 and `offsetSeconds` is null. `Date` has one-second resolution and delay only lowers a sample, so `offsetSeconds` is the largest recent sample, rounded. It is a diagnostic, not a clock correction. Without a session the session fields are null and `origin` is still reported. - `segments`: `originLoaded`, `raced`, `noPeers`, `sampledOut`, `skipped`, `aborted`, `peerInTime`, `peerLate`, `peerMiss`, `peerCorrupt`, `peerUnverified`, `inTimeShare`, `sampledInTimeShare`, `observedInTimeShare`, `sampledInTimeByteShare`, `observedInTimeByteShare`, `peerFirstLoaded`, `originFallbacks`, `peerSkippedLate`, `peerProjectedLate`, `peerWaitExtended`, `peerAbandoned`, `peerNoFit`, `peerUntestedTrial`, `peerUntestedTrialLoaded`, `commitmentRequests`, `commitmentRejected`, `commitmentUnavailable`, `peerFirstShare`, `peerFirstByteShare`, `peerLatencyMedianMs`, `peerLatencyP90Ms`, `originLatencyMedianMs`. - `bytes`: `fromOrigin`, `fromPeers`, `peerFirst`, `uploaded`, `uploadsServed`, `uploadsRefused`, `uploadsCancelled`, `uploadCancelledBytes`, `held`, `uploadRemaining` (null when unlimited), `uploadExhausted`. `uploadsCancelled` counts responses this viewer stopped early because the receiver cancelled them; `uploadCancelledBytes` is the part of `uploaded` that was therefore not sent. Those bytes return to the per-second upload rate; the session allowance and any host reservation already charged are not refunded. - `peers.deliveryMeasurements`: bounded measurements for active links, including completion time, payload rate and failures. - `relays`: `connected`, `presenceSent`, `signalsSent`, `published`, `rejected`, `rejectedTimestamp` (the `rejected` frames whose message mentions a timestamp), `sinceDropped` (events dropped only by the subscription `since` filter, unverified and so unauthenticated; a device clock ahead of its peers raises it), `publishErrors`. - `errors`: `total` and `byStage`. A module named by `coreWasm` that fails to load or traps counts once under `core`. - `core`: `state` (`off`, `loading`, `ready` or `failed`), `verifier` (`wasm` or `js`, whichever decides the next commitment), `selection` (`wasm` or `js`, whichever chooses peers), `discovery` (`wasm` or `js`, whichever runs neighbour discovery), `links` (`wasm` and `js`: how many links each opened; links opened before the module loads are JavaScript), `fallbacks` (traps that handed the core's work to JavaScript) and `decided` (`wasm` and `js`: how many commitments each verifier decided). Selection moves to the core when it loads only if no peer has been chosen yet, and back to a fresh JavaScript selection, without link history, after a trap. Discovery moves to the core only while it holds no context, hint or window, and after a trap to a fresh JavaScript instance that keeps its counters. `multiHolder` reports whether framing 2 is advertised (`enabled`) and counts `transfers`, `delivered`, `late` (planned past the deadline even with origin), `failed`, `bans`, `abandoned` (holders dropped early as silent or too slow), the bytes each source was first to verify (`peerBytes`, `originBytes`), the bytes received that verified nothing new, such as the slower copy of a piece sent by both a holder and origin (`unusedBytes`), `originRanges`, and `originRangesIgnored`, the origins that answered a range with something else (each once). `originRangeOutcomes` contains fixed counters for `payload`, `invalid-request`, `wrong-size`, `error`, `timeout`, `abort` and `exception`, so an origin tail cancelled by the library differs from an HTTP failure or ignored range. Counters saturate and snapshots own their copies. Optional bounded origin trace rows also include a numeric `httpStatus`; no error text or URL is added. `timings` gives p50 and p90 over the last 128 delivered transfers of their duration, their slowest single request and their request count. Peer byte totals elsewhere count only a transfer's peer share. An additive metrics-v2 field. - `config`: the effective settings, so a receipt says what produced it. Snapshots contain no IP addresses, user agent or long-term key, but the ephemeral public key can correlate a receipt with public swarm activity. Keep receipts local unless the viewer explicitly agrees to reporting. The current demo's optional reporting endpoint accepts a numeric summary rather than this full snapshot; see [operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md). `peerEligibilityDiagnostics` is an additive local version-2 snapshot field in the current source. Its fixed reason `counters` survive eviction from the 64-record ring; `capacity` and `dropped` describe that ring. Each row contains elapsed `atMs`, numeric `cc` and `level` (null when unavailable), the already computed initial `budgetMs`, `reason` and `matchingHave` (boolean or null). `no-budget` records HAVE as **null/unobserved**: the loader does not compute a segment key or inspect peer availability to populate this diagnostic. The original origin fallback may still compute its normal key afterwards. Positive-budget reasons distinguish `no-have-no-wait`, `no-have-wait`, `wait-no-longer-eligible`, `wait-aborted`, `wait-expired`, `have-at-entry` and `have-after-wait`; `aborted-before-eligibility` means cancellation after the existing key computation, before the HAVE decision. `projected-late` means recent peer timing projected that the delivery could not fit before the buffer limit (see [peer-first loading](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#authenticated-peer-first-loading)); such a row adds `projection`: `stage` (`entry`, before availability, or `commitment`, after), `transferMs`, `holderWaitMs`, `roomMs`, `firstByteMs` and `rateBytesPerSecond`, each a number or null. Wait expiry/cancellation also leaves HAVE null rather than claiming it was still absent. One load can produce both a wait-entry and a wait-outcome row: counters count decisions, not distinct segments. Budget is the initial allowance, not remaining request time. Rows contain no segment keys, hashes, URLs, peer public keys or addresses. Rows for decisions made after the key computation and link inspection (every positive-budget reason except `aborted-before-eligibility`; never `no-budget`) also carry four sorted arrays of at most eight holder labels: `holders` (links serving this rendition now), `haveHolders` (links whose HAVE contains the demanded key now), `staleHolders` (the serving links that neighbour discovery treats as stale for this rendition, see below) and `heldMissHolders` (the links recorded as a held miss on this decision, see below; empty until the load ends, then filled on the decision's last row). The first three are read after the decision and change no decision, timer or deadline; if reading them fails the row is still written with the arrays null. The `have-at-entry` row of a load that was granted an untested-holder trial (see [peer-first loading](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#authenticated-peer-first-loading)) also carries `trial: true` and the `projection` detail of the later late stage (the commitment detail when both stages were late); no other row has a `trial` field. A holder label is a positive integer that this instance assigns to each remote peer when it first becomes a link, in first-link order, kept across connection replacement in a map of at most 64 peers (oldest evicted; `0` means unknown). It is a local counter, not a key or address: it is never derived from a key and never sent to a peer, placed in presence or signalling, or added to the numeric operator report. A full local receipt can still join the label to the ephemeral public key through `peers.deliveryMeasurements[].holder`, which the snapshot already exposes with that key, so treat rows with the same consent as the rest of the receipt. Each row also carries `budgetGeometry`: the calculation's final `currentTime`, `bufferedEnd`, `playableEnd`, `fragmentStart` (seconds), computed `originReserveMs`, and `uncappedMs`, the buffered playback less that reserve before `originFallbackMs` caps it. These are the values consumed by the original calculation, without additional media or context getter reads. Finite signed values are retained; unavailable or nonfinite values are null. The fixed `source` is `buffer`, `no-media`, `no-buffer`, `error` or `unobserved`; `positionSource` is `part`, `fragment` or null. Non-buffer sources leave the numeric fields null. With `sustainablePeerWait` enabled, the geometry additionally includes `durationMs`, `originRecoveryMs` and `sustainableMs`. These explain the separate per-segment cap; `uncappedMs` continues to describe only the buffer calculation. Unknown duration or origin recovery is null and permits no serial peer wait. Wait outcomes retain their original geometry, rather than sampling the later buffer. Each row and returned snapshot owns a copy. These values explain the initial budget calculation, not donor availability or remaining request time. They remain readable after stop and use the existing local/reporting-consent boundary; they add no requests, authority checks or deadline changes. These observations do not establish the cause of a failed peer transfer. `peerRequestDiagnostics` records the outcome of each peer-first transport request, after peer selection. Its fixed counters distinguish `payload`, `none`, `timeout`, `abort`, `abandoned`, `closed`, `busy` and `send-error`. At most 64 rows are retained; `dropped` counts evicted rows. Rows contain elapsed `atMs`, the same page-local connection `id` as transport diagnostics, numeric `cc` and `level`, the deadline's `remainingMs` at selection (after any extension), the actual request `timeoutMs`, request `elapsedMs`, `expectedBytes`, `receivedBytes`, `firstByteMs` (request to first payload chunk), `metadataReceived`, `draining`, a fixed `closeReason` or null, and `holder`, the local label (see above) of the link the request went to. `abandoned` is a request the loader gave up as unable to finish in time. Unavailable numeric values are null. A `payload` means the transport assembled bytes; signature, size, hash, expiry and final loader-deadline checks still decide whether playback accepts them. Each logical request contributes one outcome. A timeout or abort may leave an ordered reliable channel draining late bytes; those bytes and its later EOF do not contribute another outcome or turn that request into a delivered segment. This field does not count eligibility decisions or commitment failures before selection, and shadow-mode requests are outside its scope. `uploadRefusalDiagnostics.counters` classifies the existing upload refusal branches: `admission`, `not-held`, `not-serving`, `banned`, `session-allowance`, `peer-limit`, `rate-limit`, `reservation-refused` and `reservation-inactive`. These count local decisions, not wire delivery or remote receipt. Both fields are local metrics, contain no media keys, URLs, peer public keys or addresses (the eligibility and request rows carry only the local holder label described above), and are excluded from automatic numeric reporting. They add no network traffic, timers, retries, upload permission or deadline changes. Returned snapshots own their copies, and retained outcomes remain readable after stop. `admissionDiagnostics.calls` counts actual host `admit` callback invocations at the fixed sites `presence`, `dialStart`, `offerBeforeSend`, `offerIncoming`, `answerIncoming`, `glareBeforeRollback`, `glareAfterRollback`, `answerBeforeSend`, `upload`, `refresh` and `other`. Coalesced waiters and operations cancelled before the callback starts add no call. A callback that refuses or throws still counts. Counters saturate at `Number.MAX_SAFE_INTEGER`; snapshots own their copies. These local counters contain no credentials or identities, add no requests and are excluded from automatic reports. They do not cache admission or establish which server budget, network condition or peer caused a failed request. Deployed source `f393abf` includes `transportDiagnostics` within metrics version 2. It contains fixed-enum `counters`, a ring of at most 64 `records`, `capacity` and an eviction `dropped` count. Records contain a page-local, per-swarm numeric connection `id` (0 when no PC is allocated/correlated), elapsed milliseconds in `atMs`, and fixed `event`/ `detail` values for gathering, native states, signalling stages and close reasons. Unreadable native state uses the fixed `unknown` classification. Local-description records may add `candidates` (count only, capped at 256) and `candidatesCapped`; they contain no addresses, SDP, peer keys or request IDs. `signal-send` means local signalling acceptance, not relay delivery or remote receipt. The ring and counters remain readable after `stop()`; native listeners are detached when their dial/link ends. No automatic reporting, signalling change or connectivity fix is implied. Keep this diagnostic receipt local under the same reporting-consent boundary as other metrics. The two ordinary cross-machine short checks retained actual supersession, post-SDP dial timeout and established- link request-timeout stages; their [public summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-ordinary-cross-machine-20261014.json) is evidence of observation, not a connectivity repair. Numeric IDs do not identify the remote role. Union sampled records by `(id, atMs, event, detail)` within each swarm instance; never sum repeated ring snapshots as new events. A request-timeout close identifies the branch, not the request start, available budget or reason bytes missed it. The pending correction adds fixed `negotiation` / `glare-yield` observations for adoption of a pending outgoing connection. Its numeric connection ID remains the same: this is neither a new native construction nor a completed link. Superseded negotiation callbacks cannot label the adopted connection's later description as an earlier offer. Existing close reasons and reporting consent remain unchanged; this event does not prove successful native rollback or media. `inTimeShare` remains conditional on having peers. `sampledInTimeShare` includes sampled fragments with no peers; its byte equivalent weights by fragment size. The `observed` shares divide verified in-time samples by all origin-loaded fragments/bytes and are lower bounds when sampling is below 1. Use sampled coverage alongside `noPeers` and `candidatePairs` when assessing reachability. In peer-first mode, `bytes.peerFirst` counts verified bytes actually delivered to hls.js instead of starting an origin fragment request; `originFallbacks` counts loads delegated to the original loader. Shadow coverage fields are null in peer-first mode. `bytes.uploaded` counts payloads accepted for serving after the upload token bucket, any host reservation callback, and the subsequent live-state checks. Pending or refused host reservations never increment it. Session capacity is reserved internally before awaiting that callback, so concurrent requests cannot overspend; an accepted reservation remains charged if the link closes before serving. Consequently `uploadRemaining` can include charges absent from `uploaded`. An interrupted accepted transfer can send less than its counted payload; signalling and protocol overhead are excluded. These counters are not wire metering or acknowledged delivery, and durable host-ledger spend may exceed accepted serving totals. The session allowance is additive within metrics version 2. Exhaustion withdraws media availability and stops serving while receiving remains available. The library counts one swarm instance; a host recreating instances must retain accepted totals. The demo uses an origin-wide Web Lock and storage reservation across Apply, rejoin, publisher refresh, reloads and tabs. Consent is never persisted. Storage failure disables uploading; an explicit viewer reset or increase can change the quota. Peer-first ranks eligible advertised media by measured completion time, payload rate and failure history. Healthy measured peers take priority over fast refusals. A cold route gets the remaining time minus 25 ms for each of up to two alternatives that also pass the selector's measured deadline-fit check; excluded alternatives reserve no time. This reserves quick retries while allowing an unknown route to complete and acquire a measurement. A known delivery gets headroom within the original peer deadline, rather than an equal share of it. Attempts remain serial and capped by `maxPeers` and the original deadline. A timed-out or cancelled request resolves promptly for origin fallback. On a known ordered, fully reliable channel, the link stays busy while discarding that response up to a matching validated EOF, or a refusal before metadata. Only then can another request use the channel. The receiver also sends `cancel`; a holder that honours it stops adding binary data and queues EOF behind the bytes already sent, including when it is waiting for the channel's buffer-low event, or refuses before metadata. Holders without `cancel` send the response in full. A holder queues more of a response only while at most 128 KiB is waiting to be sent on the channel, so chunks queued before a cancel arrives still flow. The existing drain limit closes an incomplete response; host stop and admission withdrawal close immediately. Schema 3 multi-holder peer requests verify progress in batches of at most four canonical pieces and 512 KiB; a canonical piece larger than that is requested alone. The remaining pieces stay queued for that holder, so a later abandoned request preserves earlier verified pieces. Origin keeps its contiguous HTTP ranges. Multi-holder planning keeps each connection's first-byte delay separate from its payload flow and from HTTP service time. The model retained between objects keeps up to 16 samples per connection for 30 seconds; its rate needs at least 32 KiB and 300 ms after the first byte. Substantial HTTP ranges (at least half the object and 32 KiB) refresh the rendition's whole-object recovery estimate, scaled by bytes; tiny tails do not become whole-object latency samples. A stale or pessimistic multi-holder estimate can receive one demand-bound refresh per connection every ten seconds, only when that connection already advertises the requested object. The first request is explicitly limited to one canonical piece, independently of another connection's fast rate, while origin starts the remainder. Fresh verified probe data can unlock ordinary bounded requests within the existing deadline. An accepted short-flow refresh can discard an older pessimistic rate without creating a rate below the 300 ms floor; subsequent unknown-rate demands keep the one-piece initial limit. A newer unsuccessful attempt removes that useful-delivery allowance. Older WASM modules without the optional bounded-probe capability skip these probe sources safely and retain origin and ordinary measured holders. No background media fetch or additional timer is added. Run `npm run test:core-link:browser` for native Chrome loopback coverage of a cancelled six-MiB ranged response and a subsequent hash-checked range on the same reliable connection. Fresh-origin coordination is bounded by safe buffered playback and measured HTTP fallback time. hls.js owns quality selection. These mechanisms do not prove optimal internet scheduling or net savings. For an eligible already-advertised framing-2 object, schema-3 mixed admission does not require the whole object to fit a peer-only forecast. After verifying the commitment, the bounded piece planner may assign a smaller peer fraction and obtain the rest from origin. Closed, busy, banned, stale or non-range holders do not gain this exception. An unavailable range path or valid schema 1/2 still uses the whole-object projection; all existing deadlines and verification remain in force. This does not force peer traffic when an already-running normal HTTP/cache response wins a cached-peer race. When a peer-first viewer's current rendition has no linked serving neighbour or matching HAVE, bounded local discovery can replace one old idle unsuitable link to seek an admitted peer advertising an exact requested key. Signed presence HAVE and serving hints remain untrusted; the existing fresh admission checks precede SDP, and commitments and payload hashes still authenticate media. The existing peer, outgoing-dial and admission-check limits remain unchanged. Victim selection protects active receiving, draining and queued/active uploads, minimum link life, bidirectional idle time, the shared rotation cooldown and useful sibling audio/video neighbours. At least one established link remains. Among the links that rotation could already drop (not mid-transfer, not banned, at least `minLinkLifeMs` old and idle for `idleEvictMs`), both this victim choice and the idle rotation for an incoming offer now go in tier order before idle time. Tier 0 (unhelpful) is a non-serving remote that is not a consumer. Tier 1 (serving) is a remote that is serving. Tier 2 (consumer) is a non-serving remote when this viewer is serving, if that remote announced, in a contribution message within two `presenceIntervalMs`, a rendition this viewer plays within 30 s: it plays what this viewer can give it, though it may not have asked yet. The lowest tier goes first, and idle longest within it. A discovery replacement still leaves out the links useful to an active context before it orders the rest. This is an ordering, not an exemption. If the link to a consumer is the only eligible link it is dropped exactly as before, so a receiver that never asks still cannot hold a slot indefinitely, and the ordering does not make discovery run when no candidate hints a demanded key. Rotation cadence, the number of rotations, `minLinkLifeMs`, `idleEvictMs` and `evictionCooldownMs` are unchanged. Each link keeps, for at most eight renditions, when the remote last announced each one, serving or not; this is local state and no message changes. `peers.evictedUnhelpful`, `evictedServing` and `evictedConsumer` count offer evictions by the victim's tier, `neighbourDiscovery.counters.victimUnhelpful`, `victimServing` and `victimConsumer` count discovery replacements, and `peers.evicted` still counts every eviction. Held-miss charging and the untested-holder trial below govern the single-holder whole-object path. Schema-3 multi-holder loads retain the core piece scheduler; their accepted, first-verified peer contributors clear holder history. An all-origin assembly does not renew a peer replacement or become a peer timing or ABR sample. Neither path changes the signed-media acceptance checks. A serving link normally counts as a neighbour for its rendition even before it holds any segment, which keeps discovery off. Each load that reached the HAVE check is decided once, when it ends. If a verified segment came from a link, that link's history is dropped and no other link is changed. If the load went to origin, only the links that were judged are charged, with a miss called a held miss. These are the serving links that were asked and did not deliver a verified segment in time (the request was abandoned, timed out or failed, or the payload arrived after the deadline), and, when no link could fit the time left (`peerNoFit`), the serving links that held the key and whose own timing estimate did not fit. A decline made on swarm-wide estimates or on the buffer charges no holder: a `projected-late` decision while some link held the key, or a request skipped because no recent transfer could finish. A link that was never asked is left alone. When no link held the key, every serving link takes a miss, as before: at a `wait-expired` outcome (or a `wait-aborted` outcome that the deadline timer itself caused, which keeps its row reason) and at an entry-stage `projected-late` decision. Holding the key at entry or after the wait no longer clears a link by itself. Four misses on distinct segments, "distinct" meaning a different key from the last missed key (consecutive keys), at least ten seconds after the first, make the link stale for that context: it no longer meets the context and is no longer protected as a useful neighbour, so discovery may seek a peer hinting the exact demanded key and may replace it. The count is kept per `main` or `audio` context, only from loads that reached the HAVE check (zero-budget, aborted-before-eligibility and no-longer-eligible loads neither count nor reset). A load that is aborted by the caller (an hls.js abort) or by `stop()`, an unavailable, rejected or expired commitment do not count. A corrupt payload is never charged to the link that sent it: that link is banned and closed, and the size and digest check is made first even when the deadline has passed, though another holder asked by a later step of the same load can still be charged. A payload that would have verified but arrives after the deadline goes to origin and charges the link that was asked. A link's history is dropped only when a verified segment from that link reaches this viewer's loader in time, when the link closes, when the rendition changes, or when the context sees no demand for 30 seconds. A stale link is still asked for any segment it does hold. The thresholds are internal constants, not options, and the wait, deadlines, HTTP fallback, `maxPeers`, the single 15-second window, the rotation cooldown and every upload limit are unchanged. In a full neighbourhood the allowance still bounds this to one replacement per context generation until a verified delivery or the twenty-second re-arm below renews it, so a replacement that is also never ahead or never delivers leaves the viewer on origin for that rendition between attempts. The additive `neighbourDiscovery.counters.staleHolder` counts attempts that began because every serving link was stale; `staleBlocked` counts loads where a fresh eligible candidate hinted a demanded key for such a context but a bound (spent allowance, no room or victim, no outgoing slot, an attempt in flight) began no attempt; `heldMiss` counts one per link and demanded key for a held miss. `unmetNoHint` counts, at most once per candidate search, a current unmet context for which no fresh candidate hinted a demanded key, and `unmetIneligible` one for which fresh candidates did but every one was ineligible (cooldown, retries, already dialling); neither changes the search. They count only contexts that also pass discovery's existing room, reservation or victim condition, so an unmet context with no room and no victim is not counted, and they count per context, so one search can count a context and still return a candidate for another. All are local counts in the local snapshot, are not added to the numeric operator report, and do not show that delivery improved. A stale link's HAVE does not count: a link that still advertises a demanded key but is stale for that context neither keeps the context met nor is protected as a useful neighbour. A link that is not stale still counts through its HAVE, as before. Discovery retains at most two requested keys for each selected `main` and `audio` context, 64 candidate hints of at most eight hashes, and one opportunity with an absolute maximum of 15 seconds. Quality changes invalidate only that media type, including zero-budget loads; those loads add no key hashing or HAVE lookup. A refused attempt may reuse its single vacancy before that same deadline. The reservation and scoped victim reconnect suppression then expire even if loads continue. An accepted commitment/hash-verified delivery for the exact selected context generation renews its one-replacement allowance; PC-open, HAVE, sibling progress and inactivity do not. Without a delivery, a spent allowance also renews once at least twenty seconds (an internal constant, `neighbourDiscovery.replacementRearmMs`) after it was spent, if the context is still current and every link serving its rendition is stale or none serves it; `neighbourDiscovery.counters.rearmed` counts these. That allows at most one replacement per twenty seconds per context. The single 15-second window, one attempt at a time, the rotation cooldown, `maxPeers` and ticket gating still apply, so two contexts that re-arm together do not rotate links in quick succession. Per-piece origin fallback remains unchanged. A still-current discovery offer can include the exact demanded `requestedKey` inside its existing pairwise NIP-44 payload, alongside the truthful peer count. After fresh incoming admission, a full recipient may apply the existing idle rotation policy when it currently holds that exact key and serving is allowed. The same cooldown, link lifetime, idle, transfer, reserved-slot and keep-one guards apply. The digest is untrusted advice, not upload or media authority; it is not echoed in presence or rejections. Older peers ignore this optional wire-version-3 field and retain their existing full-recipient behaviour. This offers a bounded chance to reach a peer during that interval. A permanently full or misleading remote can still refuse; after expiry and refill the unchanged unmet episode cannot force another eviction. It does not guarantee all-rendition connectivity or establish the cause of previously missed field delivery. `neighbourDiscovery` metrics contain bounded counts and remaining time, not keys, tickets or remote identities, under the existing reporting consent. ## Authenticated peer-first loading The runnable publisher/player example and the Node-only `relayswarm/hls-publisher` helper are documented in [`docs/FIELD-TEST.md`](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md). The helper signs only contexts present in its own local playlists, including exact byte ranges and discontinuities; its supported HLS subset is deliberately limited. ```js const swarm = createHlsSwarm({ swarmId, relays, mode: "peer-first", streamEvent: signedLiveEvent, getCommitment: (context, { signal }) => fetch(commitmentUrl(context), { signal }).then((response) => response.json()), serve: viewerHasOptedIntoUploading, originFallbackMs: 1500, }); ``` The host obtains a kind-30311 event from its trusted stream discovery flow. The event must have a valid signature and the experimental tag `["relayswarm", "redistribute", "1"]`. This opts the publisher into peer redistribution. These assignments are a RelaySwarm contract, not an accepted NIP or an interoperability claim. The commitment is a Nostr event of experimental kind 24172, signed by the same author or a trusted scoped delegate, tagged `x` with the swarm id and `e` with the exact stream event id. Its content is the exact output of `commitmentContent(fields)` exported by `relayswarm/segment-commitment`. Fixed field order and the `relayswarm-segment-v1` domain bind the signature to this use: ```js commitmentContent({ streamEventId: signedLiveEvent.id, swarmId, key, // SHA-256 of swarmId + "\n" + segmentKey + byte range rendition: "0", // String(context.frag.level) sequence: 123, // context.frag.sn discontinuity: 0, // context.frag.cc, default 0 part: null, // context.part.index, otherwise null sha256, // digest of the exact media bytes size, // exact byte count, within maxSegmentBytes expiresAt, // Unix seconds, future and at most five minutes away }); ``` The default segment key is the URL pathname; a byte-range request adds `#start-end`, matching the loader context. Publisher and viewer must agree on this mapping. A commitment older than two minutes, a different stream, rendition, discontinuity, sequence or part, an expired commitment, or a signature from an unauthorised key is rejected. Author-scoped delegation and the host's current revocation view are supported; see [delegated signing](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md#signing-and-discovery). Signature validation, peer discovery, transfer and SHA-256 verification must all finish within the loader's wait. The ordinary wait is `originFallbackMs`, shortened with a thin playback buffer so that `originReserveMs` of playback remains for origin loading. Startup, an empty buffer, or a fragment with neither advertised availability nor an eligible contributor goes directly to origin. The loader projects each delivery from recent peer timing on any link: the median time to first byte, the upper-quartile payload rate after first byte measured over the latest part of recent transfers (completed, timed out or abandoned; flows of at least three first-byte times decide once two exist), and, when no holder has the segment yet, this viewer's median origin time for the rendition less however long an announced origin fetch has run. The buffer limit is the buffered playback less the origin reserve, at most `maxPeerWaitMs`, and the wait never passes it. A projection that fits may extend the wait to cover it with a quarter to spare; one that overruns the room by no more than a quarter, or rests on evidence older than 15 s, waits to the limit; one that overruns by more, or whose holder wait leaves no time for a first byte, goes to origin at once (`peerProjectedLate`). `peerWaitExtended` counts extensions. Without evidence the ordinary wait applies. An individual wait can fit the current buffer while repeated misses still drain it: for example, a 2.5 s peer wait followed by a 1.3 s HTTP recovery takes longer than a two-second segment adds. The opt-in `sustainablePeerWait: true` also limits both the initial wait and every extension, including multi-holder transfers, to `max(0, duration * 1000 - (p90OriginMs * 1.25 + 100))`. For a two-second segment and 1,300 ms measured HTTP, that cap is 275 ms. The existing buffer-safe reserve and configured caps still apply. Before whole-object origin service has been measured, HTTP starts immediately; `originReserveMs` is not treated as an observed recovery time. Substantial origin ranges can supply that measurement after byte scaling. Missing or invalid duration also permits no serial wait. Parts use their own duration. This admission rule cannot guarantee smooth playback when later origin, peer or decoder performance changes. A zero result can still use `zeroBudgetPeerRace`, whose independent peer timer runs alongside immediate normal HTTP and retains its configured window. The loader also goes to origin without asking a peer when the time left to the limit is less than the fastest of its last 16 completed transfers at least as large as the segment would need, or less than a recent first byte (`peerSkippedLate`), and when no link with the segment could fit (`peerNoFit`). Once a link is chosen, the wait may grow to cover that link's own estimate, within the limit. A request is abandoned, and the load goes to origin, when it can no longer finish by the deadline on generous assumptions: without a first byte, after three recent first-byte times (at least 250 ms) and once even an immediate first byte at the best recent rate would be late; with data flowing, from two first-byte times in, when neither double its latest rate nor the best recent rate would finish in time. `peerAbandoned` counts these. The holder is asked to stop and returns the unsent bytes to its per-second rate. A holder that has never been asked gets one request. The projection rests on one pool of timing evidence for the whole viewer, so a single slow holder's partial transfers can make every decision late, including the decision about a holder that has not been tried. When the entry or the commitment projection would send a load to origin as `projected-late`, some link held the key at entry (the load is not coordinated), and the room to the buffer limit is longer than the median first byte, the loader looks for an untested holder: an open, free, unbanned link whose HAVE holds the key, that has no recorded attempt, and that is not stale for the load's context. If there is one, the load waits to the buffer limit as a nearly fitting projection does, and its first request goes to that link if it still qualifies at that moment (the first in link order, since an untested link has no observation to rank by), otherwise to the ordinary choice. `peerUntestedTrial` counts the request and `peerUntestedTrialLoaded` a request that returned a segment verified against its commitment. For that decision no `projected-late` row is written and `peerProjectedLate` is not counted. A load gets at most one trial and a link is untested only until its first recorded attempt, so it gets at most one in its life. A stale link, a busy or banned one, and a coordinated load get none. The rest of the attempt is unchanged: the pre-request checks above still send a load to origin (`peerSkippedLate`), the attempt is abandoned on its own progress, a link that was asked and did not deliver is charged as a held miss, and later requests in the same load use the ordinary choice. There is no completion-rate condition. The option considered was to allow a trial only when the median completed transfer time fits the room, but a receiver whose only evidence is partial transfers has no completed transfer to take a median of, so that condition would not apply in the case the trial is for. The safeguards are the existing ones: the buffer limit, the pre-request first-byte and fastest-completion checks, and abandonment on the attempt's own progress. This gives an untested holder one chance. It does not make a segment fit a room shorter than a relayed transfer needs, and a load with less room than that still goes to origin. For a recorded main-rendition segment, the loader waits only if an eligible same-rendition contributor has a live FETCH lease for that exact key. Known VOD means `context.frag.type === "main"` and the exact demanded integer level's `hls.levels[level].details.live === false`; `currentLevel` is not consulted. Bare serving presence or rendezvous rank is insufficient because the contributor may be behind this viewer's VOD prefetch frontier. Live and unknown playlists retain bounded receive-only/rendezvous coordination for synchronous segment release. Alternate audio remains unknown here because its level indexes a different track family. The loader requests its signed commitment while waiting for availability. It verifies the commitment after availability arrives, before requesting peer bytes. Both operations share the loader's deadline. An eligible wait may make one commitment request even if availability never arrives. A failed commitment request still falls back to origin, without a commitment retry. If peer work fails or exceeds its budget, the original loader starts and owns its usual HTTP retries and errors. Invalid peer bytes are discarded and the peer is banned. Init segments and, by default, low-latency parts use the original loader directly. `abort()`, `destroy()` and `stop()` cancel pending peer work; stopping also immediately releases a waiting load to its original loader. No late peer completion can invoke a second success callback. Peer success updates the statistics object retained by hls.js, including loaded bytes and timestamps. Aborting a pending peer load invokes `onAbort` once; destroying it cancels without a completion callback. The playback regression checks these behaviours alongside ranges, seeks and discontinuities. ## The kill switch The host page owns the mode. Read it from your own stage status or config (`off` / `shadow` / `peer-first`), create the swarm accordingly, and when a live change flips it to `off`, call `stop()`. After `stop()` the player is exactly as it would have been without the module, and a new swarm can be created later if the switch flips back. Nothing in the module reaches back to the host to decide its own mode. ## Known limits - **Limited peer-first scheduling.** Each load asks one available peer at a time within a fixed deadline. Origin seeders can contribute substantially without receiving any peer-first segments themselves; per-viewer benefits are uneven. Fresh media coordination and measured deadlines are implemented; internet-scale scheduling, released independent-client interop and physical mobile/NAT measurements remain open. See the production delivery checklist. - **Bounded peer resources.** A link queues at most four uploads, rejects empty or excessive chunks and has a 3 s backpressure deadline. These bounds limit particular attacks; they do not prove resistance to every Sybil or resource-exhaustion attack. - **Rotation is narrow on purpose.** A peer at `maxPeers` rotates a link out only for a caller that has no peers at all, only when it would still keep one of its own, at most one per `evictionCooldownMs`, and never a link that is mid-transfer or younger than `minLinkLifeMs`. Rotating for anyone who asked was measured to cost late joiners more than it won, because an evicted peer re-dials at once and displaces a third. Among the links it may drop it takes the lowest tier first, so a link to a receiver that plays what it can give goes last, not never. Other refusals carry a `retryAfterMs` and up to two referrals instead. `peers.evicted`, `peers.evictionsUnavailable`, `peers.retriesScheduled`, `peers.referralsFollowed`, `offersRefused` and `segments.noPeers` show what is happening, and `segments.firstPeerSegmentAtMs` says how long a viewer waited before the swarm was any use to it. - **Hard NATs.** Symmetric NAT and some VPN egresses will not connect with STUN alone. A host can supply TURN credentials through `iceServers`; no managed TURN or super-peer service is supplied. When peer connection fails, viewers play from the origin. - **Relays.** Presence is one event per viewer per 20 s plus two events per connection. Point at a relay you control; a public relay may rate-limit. Sessions subscribe to swarm-wide presence and only their own recipient-tagged signals. Relay frames must match a live subscription before signature work and dispatch; reconnect restores both subscriptions. ## Experimental peer supply hint With `coreWasm` in peer-first mode, opt in with `peerSupplyHint: true`. `metrics().playerHint` and optional `onPlayerHint(rows)` report one advisory `PlayerHint` row per hls.js level at the next demanded segment's sequence and discontinuity. Without the option the field, callbacks and trace rows are absent. The adapter never assigns a player level. A host may use a hint only as a tie-breaker between two levels its **origin-only** estimate can sustain; keep `abrIgnorePeers: true` when evaluating that estimate. Never force a level from peer capacity or treat the hint as a bandwidth sample. Each row carries `rendition`, `level`, `sequence`, `eligibleHolders`, `projectedMs`, `sizeEstimate`, `sizeEstimateSource` and `knowledge: "linked-have"`. The projection is milliseconds from the observation, using the core scheduler, current peer budget and holder limit; origin joins when the peer plan would be late. Size comes from the previous verified commitment or origin load for that rendition, falling back to playlist bitrate times segment duration. The source is labelled `observed` or `playlist-bitrate` (null if neither is available). Origin timing comes from that rendition's earlier origin loads, falling back to this viewer's measured origin rate across renditions. These are estimates for the next segment, not knowledge of its signed size. Unknown size or unavailable sources yield `projectedMs: null`; an unloaded playlist has `sequence: null`. Cold peers retain the scheduler's 32 KiB/s floor. Only open, idle, unbanned, non-stale framing-2 links advertising the segment's HAVE count. The count can exceed `maxHoldersPerObject`, which limits the plan. Discovery still keeps one context per media type, for the playing rendition. Other rendition supply is limited to already linked holders advertising HAVE; the option fetches no playlists or commitments, starts no target discovery, and prepares no switch. An unavailable core produces no hints. Whole segments only; LL-HLS parts produce no new hint. This is experimental in-process and loopback behaviour, with no field or physical-device acceptance yet. `traceRequests` records replayable `playerHint` inputs and commands for `scripts/trace-report.mjs`. --- Source: [CHANGELOG.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/CHANGELOG.md) # RelaySwarm changelog ## Unreleased - Replace UniFFI with a versioned C ABI, thin JNI Kotlin facade and direct C-import Swift facade. Public records, enums, objects and functions retain their existing shapes; Android packages no longer require JNA. - Add experimental `lateHaveRace`, disabled by default. With a zero-budget cached race, normal whole HTTP starts immediately while existing accepted connections may advertise an exact HAVE within the original deadline. Freeze one holder snapshot and run at most one existing peer-only arm; FETCH, new connections and withdrawn HAVE do not qualify. HTTP wins, progressive exposure and cancellation retain their existing ownership. No origin range, discovery request, dial or deadline extension is added. - Add explicit originless `peerOnly` Rust transfers for the zero-budget cached arm. Pending pieces refill after verified calibration; no fast whole-HTTP estimate, invented origin lane or ignored origin command can strand them. The independent HTTP arm, initial cached identity, hashes, hard deadline and existing per-range upload limits remain. Older modules safely decline the optional mode without retiring healthy mixed transfers. The failed native whole-object fallback control remains recorded; final performance and playback qualification use the unchanged acceptance gates. - Add opt-in `transferWorkerUrl`: warm one explicitly packaged worker from the already compiled core, then run the shared Rust schema-3 transfer facade off the main thread. Startup, resource limits and genuine worker failure retain HTTP; late/cancelled replies cannot credit peer delivery. Existing synchronous/native APIs remain compatible. The companion is a separate release asset and `relayswarm/transfer-worker` bundler entry. - Keep multi-holder first-byte and post-first-byte flow measurements per connection, separately from HTTP service timing. Substantial ranged HTTP loads refresh byte-scaled, rendition-specific origin recovery estimates. - Allow demand-bound recovery of a pessimistic or stale holder estimate with an explicit one-piece probe, at most once per connection every ten seconds. Other routes' bandwidth cannot expand that probe. Fresh verified data can unlock ordinary bounded requests; unsuccessful later attempts remove the allowance to continue useful short-flow delivery. The retained rate still needs at least 300 ms and 32 KiB of flow evidence. - Use a measured lane's own first-byte time before the shared silence fallback. Preserve existing native transfer signatures; older WASM modules skip sources requiring the optional bounded-probe capability safely. - Retain the speed-optimised SHA-256 path while keeping the remaining module size-optimised. Device playback and net network benefit remain separate acceptance gates. - Republish broadcast rendition playlists when a directory watch reports the encoder's playlist rename, keeping the 250 ms interval as the fallback. Measured publication delay fell from a 135 ms mean to 6 ms. Closing the pipeline during a publication no longer waits for another interval. - Let allowance operations that queue behind an in-flight write share the next durable write. Operations still apply and settle in arrival order, a refused operation leaves no trace, cancellation is checked as before, and no acceptance, refusal or read is returned before a write it may depend on completes; concurrent reservations completed about four times faster in the measured profile. - Reduce hot-path work, measured in [Performance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PERFORMANCE.md): - Remember proved Schnorr signatures in both commitment verifiers, keyed by the recomputed event hash, public key and signature. The unchanged stream event, delegation and revocations are no longer re-proved per segment; every other check still runs on every call. - Copy a received peer object once across the WebAssembly boundary and reserve a commitment-expected receive size once. The link frame format is unchanged. - Compile the core's SHA-256 at `opt-level = 3`, halving multi-holder piece and object hashing time for about 0.7 KB more gzip module. - Derive each peer's NIP-44 conversation key once per session. - Add `RelayPool` `readyOnFirstRelay`; the installed native client uses it so one stalled relay no longer spends its peer deadline, and overlaps the DHT bootstrap with Nostr discovery. - Receive native objects into one buffer of the trusted size, hashing as bytes arrive. - Copy and hash origin segments in the loader only when a sampled comparison or serving needs them, and cache the core discovery's candidate list until a hint or clear changes it. - Join identical in-flight commitment requests instead of refusing them at the concurrency limit; each joined request is still checked against a catalogue and file read after it arrived. Read media playlists concurrently, and reuse the previous parse when every playlist is byte-identical (never for `EXT-X-SKIP` deltas). Add the `commitmentJoins` publisher counter. - Make account-allowance validation linear in its bounded state. - Serve the demo page assets compressed with ETag revalidation; other routes keep `no-store`. Serialise demo relay fan-out frames once. - Add `npm run bench:hot-paths` for local before/after comparisons. ## v0.4.4 (24 October 2026) Prepared experimental library prerelease following [v0.4.3](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.3). Sustained physical-device continuity and net network benefit remain open. - Let eligible already-advertised, framing-2 schema-3 media reach the bounded mixed piece planner even when the whole-object peer estimate is late. The planner can take a small verified peer fraction and load the remainder from origin. Schemas 1/2 retain their whole-object timing check. Integrity, sustainable deadlines, origin reserve and the estimator's 300 ms flow floor remain unchanged; no Rust/WASM rebuild or wire change is required. - Require a live same-key FETCH lease from a fresh same-rendition serving contributor before waiting for unavailable recorded main-rendition media. The exact demanded rendition must explicitly report VOD; live, unknown and alternate-audio contexts retain bounded rendezvous coordination. Bare serving presence and key rank no longer hold a known-VOD prefetch leader. - Retain real-WASM regressions and the previous-source failing control. Paired with separate website clock/first-frame fixes, a physical Pixel/M4 candidate passed a bounded 45.5-second original-4K window: 6,553,600 verified peer bytes, zero reported post-first-frame stalls and zero dropped frames. Earlier longer-window seek/loop interruptions remain recorded; sustained continuity and net network benefit remain open. ## v0.4.3 (24 October 2026) Prepared experimental library prerelease following [v0.4.2](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.2). Physical iPhone/iPad and Android/Vanadium continuity, public NAT, sustained distributed playback and net benefit remain unverified. No service is deployed. - Add opt-in `sustainablePeerWait`: bound serial peer waits and all extensions by each fragment/part's duration minus measured whole-origin recovery with a 25% and 100 ms margin. Existing buffer reserves remain in force; the independent cached-peer race still runs alongside immediate HTTP. - Pass only requested range bytes into the WASM upload path when the matching core supports it. Previously each small range copied the entire held object into WASM before slicing. The peer wire protocol and upload charging remain unchanged; older committed cores retain the existing whole-object ABI. - Retain the historical v0.4.2 failed cached-race CI attempts. Local loader regressions establish the new wait bound, not physical-phone playback. - Make the native cached-peer race fixture wait for framing-2 presence from the accepted peer as well as its cached-object advertisement. A controlled delayed heartbeat proves that a connected channel with HAVE is insufficient. Retain failing-load traces and eligibility diagnostics in CI receipts. ## v0.4.2 (24 October 2026) Experimental library prerelease following [v0.4.1](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.1). No service is deployed; R70 distributed retention, TURN renewal, physical-device, public-NAT and sustained acceptance remain open. See [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). - Let uploads arriving during a changed-ticket admission check join its bounded online decision before spending allowance or sending media. Previously the remembered old ticket could cause the live link to close. Rejection, timeout, stop and channel closure still prevent delivery; later uploads check online again. - Expose accepted peer identities and connection references through `peerConnectionDetails()` so observers can distinguish retention from replacement. - Retain a native Chrome/WASM ticket-renewal receipt in CI. Three rotations on both sides retain the exact connection while delivering four verified 256 KiB objects; later revocation sends zero peer bytes. This is synthetic loopback protocol evidence, not distributed field acceptance. - Exclude local native real-time build output from the JavaScript tarball. ## v0.4.1 (24 October 2026) Experimental library prerelease following [v0.4.0](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.0). No service is deployed; physical-device, public-NAT and distributed field acceptance remain open. See [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). - Preserve the measured per-load HTTP recovery reserve when a multi-holder deadline moves unfinished pieces to origin. Retain bounded, URL-free range outcome counters so aborts, timeouts and incorrect response sizes are distinct. - Add opt-in `zeroBudgetPeerRace`: start the normal HTTP request immediately and race only an already advertised cached schema-3 object. Only a complete verified winner reaches the player; stopping the swarm leaves pending HTTP running, while loader cancellation stops both arms. Defaults are unchanged. - Retain a native Chrome cached-race receipt in CI, proving both winners and reuse of the same connection with synthetic protocol data on loopback. - Apply accepted-contributor holder recovery to both normal peer-first loads and cached races; all-origin and unsuccessful peer work remain neutral. ## v0.4.0 (24 October 2026) The old JavaScript field qualifier R70 passed 15 of 16 gates at `20693ea`; in-place link renewal failed. This integration with the current core is not field-qualified. High-quality delivery margin and sustained acceptance remain open. See [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). - Count a linked holder that was asked for a segment and did not deliver it in time as a miss. Previously a holder whose HAVE held the key was treated as ahead and cleared, so one that was ahead but too slow was never stale and kept neighbour discovery off. Each single-holder load is decided once, when it ends. A verified delivery clears only the link it came from. A load that goes to origin charges only the links that were judged: those that were asked and did not deliver in time, and at `peerNoFit` those whose own estimate did not fit. Declines made on swarm-wide estimates or the buffer charge no holder, and every serving link takes a miss only when no link held the key. A stale link's HAVE no longer keeps a context met or the link protected as a victim. Loader aborts, `stop()`, commitment failures and integrity failures record nothing against the link concerned. The thresholds (four misses on distinct segments over at least ten seconds) are unchanged. - Let a spent replacement re-arm once, at most every twenty seconds per context, when no verified peer delivery has happened since it was spent and every link serving that rendition is stale or none serves it. The 15-second discovery window, one attempt at a time, the eviction cooldown, `maxPeers` and ticket gating are unchanged. The interval is an internal constant, not an option. - Add local diagnostics: `neighbourDiscovery.counters.heldMiss` and `rearmed`, `neighbourDiscovery.replacementRearmMs`, and `heldMissHolders` on the eligibility rows that carry holder labels. They sit in the local snapshot and are not part of the numeric operator report. - Give a linked holder that holds the demanded key but has never been asked one request when the viewer's shared projection is late. One slow holder's partial transfers set the projected rate for every link, so a later holder could be declined unasked. Only when some link held the key at entry, the room exceeds the median first byte and the holder is open, free, unbanned and not stale. At most one trial per load and per link; the pre-request checks, abandonment and held-miss charging apply as before. There is no completion-rate condition, because a receiver whose only evidence is partial transfers has no completed transfer to measure. This is one chance, not a promise that the segment fits. - Order rotation victims by tier before idle time: a non-serving remote that is not a consumer, then a serving remote, then a non-serving remote that announced a rendition this serving viewer plays. This is an ordering of links rotation could already drop, not an exemption, so a consumer link is still dropped when it is the only eligible one. Rotation cadence, `minLinkLifeMs`, `idleEvictMs`, `evictionCooldownMs` and the wire messages are unchanged. - Add local diagnostics: `segments.peerUntestedTrial` and `peerUntestedTrialLoaded`, `peers.evictedUnhelpful`, `evictedServing` and `evictedConsumer`, `neighbourDiscovery.counters.victimUnhelpful`, `victimServing`, `victimConsumer`, `unmetNoHint` and `unmetIneligible`, and `trial: true` on the eligibility row of a granted trial. They sit in the local snapshot and are not part of the numeric operator report. - The late-arrival projection, deadlines, abandonment, bounded peer work, admission and HTTP fallback are unchanged. - Expose accepted native connections with `peerConnections()` and attribute first-verified accepted media through `onPeerDelivery`, including multi-holder contributions. Wire/control traffic and unsuccessful media receive no credit. - Preserve partially verified scheduler progress when origin has reserved the tail, and keep reliable channels alive while cancelled responses drain. - Start a reconnecting pool on its first healthy relay and replay only current presence to later relays; pending sockets and retries retain bounded ownership. - Carry the holder re-arm state, trial selection and diagnostics through Rust, WASM and generated native bindings. Keep the existing framing and signed-media schemas; update the matching binary and bindings together. - Include the native real-time source integration added after v0.3.0, with guarded backend preparation and bounded TURN teardown. Native core packages do not provide that separate WebRTC transport. ## v0.3.0 (24 October 2026) Experimental shared-core release. JavaScript/WASM, Apple and Android downloads have source metadata and checksum manifests. The native package retains its local-path Swift dependency; RelaySwarmKit adoption and field acceptance remain open. Session wire version 3 and metrics version 2 are unchanged. - Add opt-in advisory peer supply hints through Rust, WASM, the browser loader and UniFFI; report known HAVE supply without forcing player quality. - Report receipt rendition-switch costs and holder observations in the trace reporter, and pin deadline and gated-viewer test ordering. - Measure signature verification size and Chrome call cost; keep core verification, with no production verifier switch. - Add tag-gated native release packaging, actual SwiftPM checksums and exact source/hash verification, plus a reproducible JavaScript/WASM asset builder. - Exclude native build directories from JavaScript package tarballs. - Add `core/relayswarm-proto`, a Rust port of signed segment commitment, scoped delegation and revocation verification (schemas 1 and 2; schema 3 below). It performs no I/O and builds for WebAssembly. The browser loader uses it only with `coreWasm` (below); the native path does not use it. - Add 120 shared vectors generated from the JavaScript verifier (`core/vectors/commitments.json`). The Rust and JavaScript test suites both check them, and a new CI job runs both with the Rust lint and WebAssembly build. - Port the browser data-channel protocol (`peer-link.mjs`) to `relayswarm_proto::link`, a state machine with no I/O. 48 traces recorded from the real `PeerLink` check its events and state step by step. - Port peer selection and neighbour discovery to `relayswarm_proto::selection` and `relayswarm_proto::discovery`. Seeded random and scripted operation sequences from the JavaScript check every output and state after each step. - Add the opt-in `coreWasm` loader option: peer-first viewers verify segment commitments with the Rust core compiled to WebAssembly (`src/browser/relayswarm-core.wasm`, then 200,458 bytes, 87,373 gzip). The JavaScript verifier decides until it loads, and for the rest of the session if it fails to load or traps. A new metrics field, `core`, reports which verifier decided. The demo serves the module, uses it, and allows `'wasm-unsafe-eval'` in its Content Security Policy. - With `coreWasm`, peer selection also runs in the Rust core: each swarm binds it when the module loads, provided no peer has been chosen yet. A trap anywhere in the module hands both selection and verification to JavaScript, and selection starts again without link history. The module is now 227,541 bytes (94,900 gzip). `core.selection` in the metrics reports which one chooses peers. - With `coreWasm`, links opened once the module is ready run the peer link protocol in the Rust core (`src/browser/core-peer-link.mjs` keeps the channel, timer and callbacks). All 48 committed link traces match through the module. A trap closes the links it ran, and later links are JavaScript. `core.links` counts links of each kind. The module is now 274,837 bytes (112,644 gzip). `npm run test:swarm:core` runs the loader hardening suite with every peer-first fixture on the module. - With `coreWasm`, neighbour discovery also runs in the Rust core (`src/browser/core-discovery.mjs` keeps one object per context, window and attempt, as the swarm compares them by identity). Each swarm binds it when the module loads, provided discovery holds no context, hint or window yet. The seeded and scripted discovery sequences match through the module. A trap hands discovery to a fresh JavaScript instance that keeps the counters. `core.discovery` in the metrics reports which one runs. The module is now 315,803 bytes (122,029 gzip). - With `coreWasm`, the relay session starts once the module has loaded or failed, waiting at most 2 seconds; the relay connection opens meanwhile. Fragments loaded during the wait go to origin and leave discovery empty, so discovery, selection and links start in the module. One CI viewer had kept discovery in JavaScript after hints arrived before the module loaded. - Experimental commitment schema 3 (`relayswarm-segment-v3`): schema 2 plus `pieceSize` and one SHA-256 per piece, at most 64 pieces. Both verifiers accept it and `commitmentPieceSize` is exported; 19 new shared vectors (139 in all). - Add piece-range requests (framing 2, `"p"` on `want` and `meta`) to the Rust link, and `relayswarm_proto::scheduler`, which plans one schema 3 object across up to three holders with origin for a late tail and runs the transfer with per-piece verification. The loader uses both only with `multiHolder` (below); the holder and lookahead defaults are provisional. - Add the publisher option `pieceCommitments` and the demo flag `--piece-commitments` (both off by default): exact-playlist contexts are signed as schema 3 instead of schema 2, with piece digests from the same read pass. Schema 3 replaces schema 2 rather than being published beside it, so v0.2.1 and RelaySwarmKit v0.5.0 receivers load those segments from origin. - Add the experimental loader option `multiHolder` (with `coreWasm`): a schema 3 segment comes from up to `maxHoldersPerObject` framing 2 holders at once by piece range, run by the core's scheduler, with ranged HTTP fetches from origin for a late tail and for pieces still outstanding at the deadline. Presence carries `obj: 2` only while every link runs in the core. Off by default. A ranged upload is charged against upload allowances and `reserveUploadBytes` by the bytes it sends, not the whole segment. - Under `multiHolder`, abandon a silent or too-slow holder early, by the single-holder rules, and move its pieces, instead of waiting for the deadline; counted as `core.multiHolder.abandoned`. Unlike the single-holder path, a flow that stops after its first byte is also rechecked every 250 ms. - Under `multiHolder`, load ranged origin pieces through the player's own fragment loader, so headers and credentials from `xhrSetup`, `fetchSetup` or a custom loader apply; a body that is not exactly the range is discarded. - Under `multiHolder`, a holder whose first request proves it fast takes back pieces origin has not yet delivered, as many as it can finish before origin is projected to, leaving busy holders their share; the first verified copy wins and origin's request keeps running. Before, untested holders got one trial piece each and origin the rest in one request, and nothing moved that work back: over RelaySwarmKit's data channels, with 8 MB and origin at 300 bytes per ms, 60 of 62 pieces came from origin in 27.9 s against a 10 s deadline. `core.multiHolder.peerBytes` and `originBytes` now count the bytes each source was first to verify, and the new `unusedBytes` counts received bytes that verified nothing new. - Under `multiHolder`, stop asking an origin for ranges once it has answered one with something else, and send its later segments down the single-holder path for the session; counted as `core.multiHolder.originRangesIgnored`. A loader downloads the whole body before the length check can reject it, and a failed origin piece fails the transfer, so without this every such segment came from origin twice. Cloudflare Stream answered a probe for a segment range with the whole segment (200); Apple's, Mux's and Unified Streaming's test streams answered 206. - Add the loader option `traceRequests` (off by default) and `trace()`: a bounded ring of loads, eligibility decisions, peer and origin requests and every multi-holder scheduler call with its inputs and commands. A test replays a recorded transfer through the module and gets the same commands. The Chrome harness takes `--trace N` and stores each viewer's trace. - Add `scripts/trace-report.mjs`, which replays saved traces against the module and summarises holder use, origin share, request timing and buffer ahead, with an optional what-if over other holder limits (an estimate that ignores shared uplinks). - Document commitment schema 3, object framing 2 and the presence `obj` field in `docs/NIP-DRAFT.md`. - The demo player takes `multiHolder=1` and `trace=N` page URL parameters and keeps the latest scheduler traces in its receipt, which `scripts/trace-report.mjs` reads. - `abrIgnorePeers` (off by default) keeps peer-delivered fragments out of the hls.js bandwidth and first-byte estimates; without it the time a peer delivery took, holder waits included, is sampled as origin throughput. The demo takes it as `abrIgnorePeers=1`, and its receipt records hls.js's bandwidth estimate with each fragment. - The Rust verifier now rejects a commitment whose content omits `part`, as the JavaScript one does (a new shared vector, 140 in all). Under `multiHolder`, an untested holder is planned with the shared first-byte time rather than none, origin stays live once peers verify its pieces, requests stopped because the segment is done or another holder won count as aborts rather than abandonments, and a closed link's last result no longer leaves an entry in the core's peer selection. - Add `core/relayswarm-ffi`, a UniFFI facade over the Rust core for Swift and Kotlin: the commitment verifiers (JSON in and out), the schema 3 piece helpers, the multi-holder transfer scheduler, the peer link protocol, peer selection and neighbour discovery. `npm run test:ffi:swift` and `npm run test:ffi:kotlin` check all 140 vectors, all 48 recorded link traces, a transfer, a piece range exchange and the seeded selection and discovery sequences through generated bindings, and CI runs both. `npm run build:ffi:apple` packages it as a Swift package with an arm64 XCFramework for iPhone, the iOS simulator and macOS (iOS 16, macOS 14); `npm run test:ffi:apple` runs the same checks against the package on macOS and in an iPhone simulator, and links it for iPhone. RelaySwarmKit does not use it yet. `npm run build:ffi:android` packages it as an Android library (AAR) for arm64-v8a, armeabi-v7a and x86_64, API 26 and later; `npm run test:ffi:android` builds an app against it with the Android Gradle plugin, and the same checks pass on an API 35 arm64 emulator. ## v0.2.1 (21 October 2026) Experimental [GitHub prerelease](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.1) of the source from [PR 9](https://github.com/forgesworn/relayswarm/pull/9), following v0.2.0. Field acceptance remains open: the sustained 7,200 s run, the 3 MB both-quality shared-cap lifecycle and Safari 17.6 desktop are RED, and physical-device, difficult-network and downloaded-release gates have not passed. The prerelease was published by owner decision with those open. See [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). - Add local holder labels to the peer diagnostics. Labels are session-local counters, not keys, and are for local diagnostics only. - Stop a linked holder that is never ahead from suppressing neighbour discovery, so such a holder is no longer treated as enough; bounded peer work, deadlines and HTTP fallback are unchanged. - Field results on this source (21 October 2026, desktop and relay-only scope): the fourteen-role short qualifier passed 16 of 16 gates for the first time, and Firefox 152.0.6 and Safari 26.6.2 desktop journeys passed. The sustained 7,200 s run and the 3 MB both-quality shared-cap lifecycle are RED and open, and Safari 17.6 desktop is RED. Physical devices, hard NAT and a separate network are not tested. See [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint). ## v0.2.0 (21 October 2026) Experimental [GitHub prerelease](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.0) adding the supervised broadcaster and production feature work to v0.1.0. Field acceptance remains open: the fourteen-role qualifier is RED (R65 passed 14 of 16 gates), and the sustained, natural-expiry, physical-device, difficult-network, measured-benefit and downloaded-release gates have not passed. The pilot runs `5f2ece0`; this release also includes the later loader clock-skew diagnostics. See [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). - Report swarm events rejected by the age window, and the age of recent live signals, in `signalling.clock`, with an origin `Date` offset estimate (`clock.origin`) and `relays.sinceDropped` / `relays.rejectedTimestamp` counters (additive within metrics version 2). Local counts only; acceptance rules and wire format are unchanged. - Set app and waiting-listener HTTP keep-alive to 130 seconds so Caddy's default 120-second upstream pool retires them first. The 128-connection cap and ten-second request/header deadlines remain. A real 121-second regression verifies original-socket reuse, exact replies and prompt close/handover; distributed repair remains unproved. - Negotiate a coherent policy/public-session response so the example player needs one renewal GET instead of two. Legacy servers retain parallel reads; malformed advertised snapshots fail closed. Expiry, early OFF, admission and consent rules remain unchanged; field repair is unproved. - Discover bounded rendition neighbours when existing peer slots do not offer the current media context, using signed advisory presence and existing peer, admission, consent and retry limits. - Preserve useful time for a cold peer attempt instead of equally dividing its deadline across unmeasured alternatives. Total deadlines, measured-peer allocation, verification and fallback remain unchanged. - Expose the broadcaster's existing per-socket-address request allowance through `--admission-per-address-requests` (1–10,000, default 600). Other admission limits remain unchanged; field acceptance is separate. - Reclaim settled TURN viewer entries after their credential cache expires or initial issuance fails. Fresh credentials and unresolved issuance keep their slots; the viewer, request, issuer and rate limits remain unchanged. - Retain renewed admission tickets while peer retry or connection limits delay their next validation, without replacing a newer pending ticket when older work settles. - Measure account authority against the signed issuer lifetime and conservative elapsed time, so small device/server clock differences do not reject a valid challenge. Keep the original grant/delegation limits, rollback revocation and server proof checks; issue all challenge timestamps from one clock sample. - Add an explicit Resume playback action to rebuild suspended media from the origin, preserve errors/spend and require fresh Apply/upload consent before peer contribution. Explain disabled reporting when the server has it off. - Retain an abandoned response on known ordered, reliable peer channels only until its validated response boundary or the existing drain timeout. Origin fallback stays prompt; late payload is discarded before connection reuse. Wire framing, playback deadlines and signed media verification are unchanged. - Add redacted TURN lease provenance and conservative monotonic response timing for lifecycle measurement, retaining cached leases without moving their anchors. A passive debug getter exposes only epoch, ordinal and timestamp; it does not check or grant credential freshness. - Add optional `issued`/`tls-tcp` TURN URL projection to the demo and broadcaster credential adapter. Explicit secure TCP is retained; only transport-unspecified secure URLs gain a TCP selection. Raw leases, expiry and upload consent remain bounded. This is configuration support, not selected-path or field proof. - Add explicit `all`/`relay` ICE transport policy to the swarm, demo and broadcaster, defaulting to `all`. Relay-only does not force TLS or establish a delivery repair; changed demo policy requires fresh viewer Apply and consent. - Refuse redundant stop IPC after a broadcaster worker's first force request or drain witness, preserving its original cleanup proof and deadlines. - Expose the broadcaster's per-socket-address admission ticket limit through `--admission-per-address-tickets` (1–120, default 12), without changing other admission limits or establishing multi-viewer acceptance. - Keep a live process-group wrapper for broadcaster worker shutdown, using its original private IPC channel instead of signalling a reaped leader's numeric PID. Preserve output, inner exit status and the existing dirty recovery fence. - Added complete live-playlist blocking reload across compatible renditions, with bounded waits, disconnect/shutdown cleanup, directory replacement revalidation and snapshot-consistent HEAD/range responses. - Filter unrelated named file events from playlist reload watches while retaining authorisation coverage, directory replacement checks and bounded revalidation. - Reuse the pending browser connection when simultaneous offers require it to yield, with fresh admission checks, fenced callbacks and its original dial deadline. Native browser and Internet qualification remain separate gates. - Added an optional durable account upload allowance supporting Nostr sign-in, host website accounts, explicit linking and short-lived page authority. Account actions preserve cumulative charges and require fresh upload consent. - Added bounded numeric peer-eligibility observations to distinguish deadline and availability decisions without changing peer selection or its budgets. Records retain the original buffer geometry; the broadcast fixture observes existing request timings with explicit pending and missing measurements. - Separated in-flight upload quota from accepted-upload metrics so a pending or refused host reservation cannot be archived as an uploaded payload. - Added fresh live-media coordination, measured fallback reserves and actual fMP4/adaptive, audio, AES-128, mixed-codec and low-latency-part journeys. - Added exact schema 2 media commitments, scoped signing delegation/revocation and linked signed NIP-53 advertisements without changing stable authorisation. - Added bounded admission, persistent cross-tab upload budgets, idempotent durable reports and two-lease worker supervision with tested crash cleanup. - Added an installed native client with verified HTTP fallback, acknowledged connection readiness and an absolute completion deadline. Native presence discovery accepts valid cached announcements without widening signal replay. - Upgraded and published RelaySwarmKit v0.5.0; its public SDK passes author, delegate, corruption and revocation journeys against the actual browser sender. - Added one bounded origin-only media repair, cancellation and timeout handling; fatal records and spent upload allowance remain in the receipt. - Fixed Windows hash-cache deduplication, malformed relay-filter crashes, discovery eviction, worker descendant cleanup and pending-write queue bounds. - Fixed expired host callbacks leaving HTTP requests outstanding, and added bounded native discovery when relays replay no ephemeral presence history. - Reproduced and repaired a nonfatal live-playback stall after an interrupted quality switch and a new media continuity. A fresh live window and ten seconds without decoded-frame progress permit the existing single origin repair; cancellation, allowance usage and original errors remain preserved. - Made playback checks prove each rendition's peer delivery before seeking, and added physical iPhone targeting and scoped Safari-window focus to the acceptance harness. - Added bounded numeric control-request diagnostics, private STUN/TURN browser configuration and failed-TLS-startup cleanup. - Fixed demo, broadcaster and probe commands silently doing nothing when launched through an absolute filesystem alias. Imports still leave their commands stopped. - Fixed the single VOD repair repeating a video-only prefix after a later fragment introduced audio. It waits for media reattachment before resuming at the validated failing fragment; original errors and allowance remain. - Made container public code readable and directories traversable when a build context uses private modes, while retaining private state permissions. ### Earlier 0.2.0 broadcaster work (12 October 2026) The earlier intermittent hosted MSE failure and physical-device, separate-network, sustained-operation and external-platform acceptance remain open. - Added a supervised H.264/AAC broadcast bridge with two HLS renditions, continuous sequence numbers, source recovery and independent RTMPS forwarding. - Added private persistent publisher identity, bounded hash/signature caches, cumulative viewer media upload allowances and measured peer selection. - Added authenticated operator status/policy and explicitly opted-in bounded numeric reporting; fixed cancelled HTTP media response cleanup. - Added a host-scoped trusted Nostr stream adapter and an isolated container pilot package, with real transport/browser checks and documented acceptance gaps. - Included the broadcaster/demo runtime dependencies in production installs and excluded local IDE metadata and private state from the package. - Refreshed the documentation for the GitHub distribution and measured browser/native capabilities; separated planned work and historical observations. - Added a documentation index, getting-started guide, module API reference and release evidence/status page. - Reworked `llms.txt` with direct public Markdown links, added generated `llms-full.txt`, and added documentation freshness/link checks. - Corrected RelaySwarmKit compatibility, phone validation, network-policy and measurement-cost claims; normalised repository metadata and discovery keywords. ## v0.1.0 — 12 October 2026 First [experimental GitHub release](https://github.com/forgesworn/relayswarm/releases/tag/v0.1.0), commit `3e480e19dfe4d675f14bcb2968f3dc4926fbca25`. - Original Nostr-signalled WebRTC CLI and separate native HyperDHT/Noise journey. - Browser shadow and bounded peer-first HLS loading with author-signed commitments. - Admission, connection/transfer bounds, consent defaults, rotation/referrals, lifecycle hardening and restored loader statistics/abort semantics. - Local HLS publisher/player with exact-context signing, upload controls, origin-only kill switch, local receipts and controlled HTTPS trial configuration. - Real Chrome regressions, native OS matrix, public-relay tests and an optional twelve-viewer soak; [evidence and remaining work](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). - Installable package tarball, standalone browser ESM bundle and checksums. The npm registry remains unpublished. This release is a proof of concept. --- Source: [docs/README.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) # RelaySwarm documentation RelaySwarm is an experimental peer-assisted HLS library and transfer proof of concept. The [published v0.2.1 prerelease](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.1) adds broadcaster and production features to the earlier v0.1.0 release. The repository and GitHub release are the public distribution surfaces; the npm registry is unpublished. The operated [HTTPS pilot](https://relayswarm.forgesworn.dev) is a controlled trial, with its measured scope and acceptance gaps in [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). | Task | Read | |---|---| | Understand the project and transport choices | [Project overview](https://raw.githubusercontent.com/forgesworn/relayswarm/main/README.md) | | Install the package, browser bundle or source demo | [Getting started](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) | | Attach the loader, configure consent/admission, read metrics | [hls.js integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md) | | Move schema-3 Rust transfer work into an explicitly packaged worker | [Transfer worker](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/TRANSFER-WORKER.md) | | Find module exports and publisher/session methods | [API reference](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md) | | Review current production implementation and acceptance | [Production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md), [delivery checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) | | Continue the agreed production work as another agent | [Goals and agent handover](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/AGENT-GOALS.md) | | Implement compatible session and commitment messages | [Protocol draft](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NIP-DRAFT.md) | | Carry opaque deadline-sensitive datagrams with supplied ICE | [Experimental real-time transport](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/REALTIME-TRANSPORT.md) | | Run a trial on separate devices and interpret receipts | [Publisher/player field test](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md) | | Force HLS peer traffic through Spry TURN and inspect the qualification gates | [Spry interoperability](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/interop/spry-turn.md) | | Ingest a live broadcast or add optional RTMPS forwarding | [Broadcasting](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md) | | Operate private state, remote policy and opt-in reports | [Operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md) | | Share an upload allowance across devices using Nostr or website accounts | [Shared upload allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md) | | Deploy beside existing services with private ingest | [Container pilot](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md) | | Understand HyperDHT/Noise and native authorisation | [Native transport](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NATIVE-TRANSPORT.md) | | Review integrity, privacy and resource boundaries | [Threat model](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/THREAT-MODEL.md) | | Separate tested, released and outstanding capabilities | [Evidence and remaining work](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) | | Answer common questions and compare other projects | [FAQ](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FAQ.md), [Landscape](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/LANDSCAPE.md) | | Compare core and imported signature verification costs | [Signature budget](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/CORE-SIGNATURE-BUDGET.md) | | Review measured hot-path costs and performance follow-ups | [Performance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PERFORMANCE.md) | | Inspect dated measurements and reproduction commands | [Spike results](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/RESULTS.md) | | Prepare native binary assets without releasing | [Core packaging](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/CORE-PACKAGING.md) | | Follow release and documentation changes | [Changelog](https://raw.githubusercontent.com/forgesworn/relayswarm/main/CHANGELOG.md) | | Maintain AI entry points and check links | [Maintaining the docs](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/MAINTAINING-DOCS.md) | For AI readers, start with the [raw `llms.txt` index](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms.txt). The [generated full context](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms-full.txt) collects maintained guides with absolute links. Historical spike code and receipts remain separate so a dated experiment is not mistaken for current release behaviour. Local coding agents should read [AGENTS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/AGENTS.md). --- Source: [docs/GETTING-STARTED.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) # Getting started with RelaySwarm [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [API](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md) · [hls.js integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md) These installation instructions target the prepared experimental [v0.4.4 GitHub prerelease](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.4). Confirm that tag and its checksum-listed assets have been published before using these pinned commands; a prepared version is not a verified download. Node 22.13+ is required; CI runs Node 24. `npm install relayswarm` is not the documented distribution path: the npm registry is unpublished. ## Install for a host application ```sh npm install https://github.com/forgesworn/relayswarm/releases/download/v0.4.4/relayswarm-0.4.4.tgz npm install hls.js ``` ```js import Hls from 'hls.js'; import { createHlsSwarm } from 'relayswarm/hls-swarm'; ``` The host owns stream discovery, trusted publisher selection, network policy, viewer consent, page lifecycle and the commitment endpoint. The full attach, stop and peer-first contract is in [INTEGRATION.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md). Browser peer participation requires HTTPS or a loopback secure context, WebCrypto, WebRTC data channels and WebSocket. Native HLS alone does not attach this hls.js loader. A Git dependency can also be pinned to the versioned release tag: ```sh npm install 'git+https://github.com/forgesworn/relayswarm.git#v0.4.4' ``` ## Use the standalone browser bundle Download [`relayswarm-hls-swarm-0.4.4.mjs`](https://github.com/forgesworn/relayswarm/releases/download/v0.4.4/relayswarm-hls-swarm-0.4.4.mjs) and serve it from your own application: ```js import { createHlsSwarm } from './relayswarm-hls-swarm-0.4.4.mjs'; ``` The bundle contains the loader's runtime dependencies; hls.js remains the host's dependency. Prefer vendoring the verified file to relying on GitHub release-download URLs as a JavaScript CDN. The separate publisher helper uses Node filesystem/crypto APIs and does not belong in a browser bundle. The release's [`SHA256SUMS`](https://github.com/forgesworn/relayswarm/releases/download/v0.4.4/SHA256SUMS) covers the tarball, browser bundle, WASM module and JavaScript build metadata. Download those four files and the manifest into one directory and verify: ```sh shasum -a 256 -c SHA256SUMS ``` ## Use the optional shared core Download [`relayswarm-core-0.4.4.wasm`](https://github.com/forgesworn/relayswarm/releases/download/v0.4.4/relayswarm-core-0.4.4.wasm) and serve it beside the browser bundle with `Content-Type: application/wasm`. Pass its URL through `coreWasm`; enable experimental `multiHolder` and `peerSupplyHint` only when the host intends to use them. A Content Security Policy must permit WebAssembly compilation, for example with `'wasm-unsafe-eval'` in `script-src`. See [Integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md) for fallback, feature requirements and the advisory hint callback. The tarball also contains the committed module under `src/browser/`. ## Use the native core assets The [v0.4.4 release](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.4) includes `relayswarm-core.xcframework.zip`, its `.checksum`, `relayswarm-core-swift-bindings.zip` and `relayswarm-core.aar`. Download the platform's `SHA256SUMS-apple` or `SHA256SUMS-android` and every file listed in it, then run `shasum -a 256 -c SHA256SUMS-apple` (or the Android manifest). Native metadata identifies the same tagged source as the JavaScript metadata. Extract both Apple archives beside one another to use the local-path Swift package; its minimums are iOS 16 and macOS 14, arm64 only. The AAR requires Android API 26+ and Kotlin 2.2+; JNA is not required. See [Native core packaging](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/CORE-PACKAGING.md) for the complete dependency, build and verification contract. These are core bindings, with no native WebRTC adapter or client application. RelaySwarmKit v0.6.0 separately consumes the v0.3.0 core; its existing WebRTC transport remains macOS arm64 only. ## Run the source demo ```sh git clone --branch v0.4.4 --depth 1 https://github.com/forgesworn/relayswarm.git cd relayswarm npm ci npm run demo ``` Open `http://localhost:8787`. Synthetic live media requires ffmpeg with libx264. Existing media does not require ffmpeg: ```sh npm run demo -- --media-dir /path/to/hls --manifest master.m3u8 ``` Keep uploading off until a viewer opts in. The published demo is intended for controlled trials; current source adds bounded ticket admission. See [FIELD-TEST.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md) for supported playlist features, TLS/reverse-proxy setup, relay/ICE choices and baseline/swarm receipts. Current source adds the broadcaster workflow; it is absent from v0.1.0. See [Broadcasting](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md) for live input and optional independent RTMPS forwarding. ## Run the transfer proofs From a source checkout after `npm ci`: ```sh npm run poc # WebRTC CLI, public Nostr relays npm run poc:native # HyperDHT CLI, public relays and DHT npm run test:native # deterministic local relay and DHT ``` The original WebRTC CLI publishes signed plaintext SDP and uses the seeder's own digest; it is a transport proof, not the browser peer-first integrity contract. The native journey must obtain expected object identity from a trusted source in a real application. Its CLI has no automatic HTTP fallback. See [Native transport](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NATIVE-TRANSPORT.md) for those boundaries. ## Troubleshooting | Symptom | Check | |---|---| | Synthetic demo fails to start | `ffmpeg -version`; build must include libx264, or supply existing media | | Remote page remains origin-only | Use device-trusted HTTPS; plain LAN HTTP lacks browser WebCrypto | | No peer-first fragments | Opted-in seeder availability, shared swarm/context, trusted signed event and a working commitment endpoint; startup uses origin | | No direct connection across networks | Relay/ICE policy and NAT reachability; hosts may supply TURN credentials, but managed TURN and super-peers are absent | | `metrics().mode` is `off` | Inspect `disabledReason`; see integration options and validation | | Public-relay test fails | Re-run before treating policy/availability changes as a code regression | Current evidence and remaining device/network gates are in [STATUS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). ## Development source The published commands above install v0.4.4. Later development lands on `main`, a mutable reference; its [production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) and [delivery requirements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) have separate evidence. For the latest source: ```sh git clone --depth 1 https://github.com/forgesworn/relayswarm.git cd relayswarm npm ci npm run demo ``` Both v0.4.4 and current development source include the installed native executable, verified HTTP fallback and wider-media tests: ```sh npm run native:fetch -- --help npm run test:media-browser npm run test:media-recovery # actual corrupt-media repair/cancel/deadline journeys npm run test:interop npm run test:interop:kit # published SDK API, not the historical adapter npm run test:interop:kit -- --pieces # schema-3, two browser holders, released core ``` The historical adapter fixture requires macOS arm64 and read-only authenticated `gh` access to its pinned public sources. The current SDK fixture uses published Kit v0.6.0 in `../relayswarm-kit` (or `RELAYSWARM_KIT_DIR`) and requires Swift 6, macOS arm64, Chrome and ffmpeg. Its verified transfer and acceptance boundaries are in the [interop guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/interop/README.md). --- Source: [docs/API.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md) # RelaySwarm API reference [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Installation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) · [hls.js integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md) This describes current source, including additions after the experimental v0.4.0 source snapshot. Package version `0.4.0`, session wire version `3`, segment-commitment schemas `1`/`2`/`3` (3 experimental) and metrics snapshot version `2` are different version numbers. Source exports and protocol fields are not a stable interoperability promise; immutable release assets retain the API they were built with. ## Module entry points | Import | Environment | Main exports | |---|---|---| | `relayswarm` | Node or a browser bundler | `RelayPool`, `RelaySwarmSession`, `validTicket`, `RELAYSWARM_VERSION`, `KIND_PRESENCE`, `KIND_SIGNAL`, `SWARM_TAG` | | `relayswarm/hls-swarm` | Browser with hls.js | `createHlsSwarm`, `HLS_SWARM_METRICS_VERSION`, `rotationCandidate`, `retryAfterFor`, `readRefusal` | | `relayswarm/transfer-worker` | Dedicated module-worker or bundler entry | `createCoreTransferWorkerRuntime`; installs the companion handler when loaded in a dedicated worker. See [packaging and lifecycle](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/TRANSFER-WORKER.md). | | `relayswarm/segment-commitment` | Browser or Node | `commitmentContent`, `commitmentPieceSize`, `delegationContent`, `revocationContent`, `validStreamAuthorisation`, `verifyCommitmentDelegation`, `segmentMediaContext`, `verifySegmentCommitment`, `KIND_SEGMENT_COMMITMENT`, `KIND_COMMITMENT_DELEGATION`, `KIND_COMMITMENT_REVOCATION` | | `relayswarm/hls-publisher` | Node only | `createHlsPublisher`, `PublisherError` | | `relayswarm/publisher-state` | Node only | `loadPublisherState`, `publisherManifestPath`, `publisherSwarmId`, `publisherStreamEvent`, `validatePublisherStreamEvent`, `createCommitmentDelegation`, `createCommitmentRevocation` | | `relayswarm/stream-discovery` | Browser or Node | `resolveTrustedStream`, `discoverTrustedStreams`, `StreamDiscoveryError` | | `relayswarm/broadcast-pipeline` | Node with FFmpeg | `startBroadcastPipeline`, `broadcastEncoderArgs`, `broadcastForwardArgs` | | `relayswarm/native-client` | Installed Node application | `validateNativeDescriptor`, `fetchNativeObject`, `createNativeObjectSeeder` | | `relayswarm/publisher-advertisement` | Node or a browser bundler | `createPublisherAdvertisement`, `verifyPublisherAdvertisement` | | `relayswarm/account-upload-budget` | Node on supported local POSIX storage | `createAccountUploadBudget`, `AccountBudgetError`, `accountBudgetError` | | `relayswarm/realtime-peer` | Browser; injected connection in tests | `RealtimeDatagramLink`, `RealtimePeer`, `REALTIME_TRANSPORT`, `REALTIME_CHANNEL` | | `relayswarm/realtime-werift-build` | Node build tool | `realtimeWeriftPlugin`, `weriftRealtimeRevision` | | `relayswarm/package.json` | Package metadata | Name, version and declared dependencies | The wildcard export also permits source subpaths such as `relayswarm/src/native-journey.mjs`. These are implementation paths, not additional stable named entry points. Do not import HyperDHT, Node filesystem or Buffer-based object-transfer modules into an ordinary browser page. ## Relay sessions `RelayPool.connect()` with `reconnect: true` becomes ready on the first usable relay while the other initial attempts and bounded retries remain owned by the pool. Without reconnect it waits for all initial attempts and reports an all-failed connection error, unless `readyOnFirstRelay: true` makes it ready on the first usable relay; it then still reports the all-failed error, and a slower relay joins when it opens, with no retry. The installed native client uses this so one stalled relay cannot spend its whole peer deadline. `close()` cancels attempts, waiters and retries. `onRelayOpen(handler)` supplies a publish function scoped to that newly opened socket; it becomes inert after the socket or pool closes. An active `RelaySwarmSession` retains one copied signed presence and replays it only to a newly opened or reconnected relay while it remains inside the session's age window. Existing sockets receive no replay broadcast. Signals and SDP are never cached or replayed. Expiry or `close()` clears the retained presence; `close()` also unregisters the relay-open handler. ## Browser loader `createHlsSwarm(options)` returns `{ attach(hls), updateTicket(ticket), stop(), metrics(), peerConnections(), peerConnectionDetails(), trace() }`. `attach` wraps `hls.config.fLoader`; call it before `loadSource`. `stop` is the origin-only kill switch and closes connections, cancels pending work, releases held bytes and restores the original loader. Create a new swarm to participate again. Uploading defaults to off; `mode` defaults to `shadow`. `peerConnections()` returns a fresh array of the actual `RTCPeerConnection` references for accepted, active links. It excludes pending dials, offers, glare negotiations and closed/disconnected links; `stop()` leaves it empty. Mutating the returned array cannot alter the swarm. Keep native references local to the host; serialisable metrics contain no connection objects. The later main-branch `peerConnectionDetails()` returns fresh `{ connection, pubkey }` records for those same accepted links. Each native connection is bound to its remote ephemeral signalling key, without an array ordering assumption. Records cannot mutate membership and disappear when the link closes or the swarm stops. It creates no new network messages. The opt-in `zeroBudgetPeerRace: true` races an already advertised cached schema 3 object against immediately started normal HTTP when no safe peer wait remains. It requires `coreWasm`/`multiHolder` framing eligibility and the optional peer-only transfer capability. The Rust piece planner has no origin lane in this mode, adding no ranged HTTP or invented origin estimate; only eligible cached peers can refill its pending ranges. Candidates stay inside the initial cached snapshot and current HAVE. Existing rate and session limits apply to every bounded request. Older modules decline the peer arm safely; only a complete verified peer winner counts as peer media. Normal HTTP never waits for metadata; stopping the swarm cancels its peer arm while that pending HTTP request continues. Progressive hls.js loads skip the race. See the [options and lifecycle contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#options). The additional experimental `lateHaveRace: true` observes actual matching HAVE on those connections accepted at load entry when no initial cached snapshot matches. HTTP starts immediately. At most one later holder snapshot starts the existing peer-only arm; hashing, observation, metadata and delivery must all fit the original `maxPeerWaitMs`. FETCH, new or replaced connections and stale availability cannot supply it. HTTP wins and exposed progressive data cancel the arm. The default entry-snapshot behaviour is unchanged; verified peer credit alone does not establish network savings or continuity. The opt-in `sustainablePeerWait: true` additionally bounds serial peer waits and multi-holder extensions by each fragment/part's duration minus measured whole-origin recovery time with a 25% and 100 ms margin. The ordinary buffer reserve remains in force. Unknown origin recovery, unknown duration or no spare duration starts HTTP immediately; an enabled cached/late-HAVE race retains its independent window. This is an admission bound, not a smooth-playback guarantee. The unreleased experimental `warmAhead: true` option requires peer-first and explicit `serve: true`. It observes this player's actual parsed main-media fragments, loads at most the next two, and keeps one speculative whole-object HTTP arm in flight. Existing demanded whole/range request limits still apply; this is not a two-request global HTTP limit. Demand starts immediately and joins already-running exact-object work instead of downloading it again. That work becomes genuine demand and frees the single speculative slot, so the following object can load concurrently. The combined cache and in-flight set remains bounded to three distinct objects and 24 MiB; all in-flight reservations reduce the existing held-cache budget together. This option alone adds no startup gate, pause, hidden player, clock offset or automatic seek. The separate unreleased `startupBufferTarget` option defaults to `null`. A host may supply a synchronous function returning its fresh raw HLS target time in seconds. Return `null` when the player, room epoch or playback intent is no longer current. This enables a one-shot buffer before the first genuine main fragment reaches HLS demuxing. The original attached media element and pending trusted play request remain owned by the host. The first held body and verified upcoming fragments share the same three-object, 24 MiB reservoir. Before first HTTP, the host must admit the worst-case 24 MiB reservation against its existing held budget; a smaller available budget fails explicitly. The original first response is handed to HLS unchanged and is not retained as an extra shared-cache seed; its reservation is released. Release requires a contiguous verified interval covering the fresh target plus at least the origin reserve or measured p90 whole-origin recovery with its 25% and 100 ms margin, whichever is greater. The original eight-second and parent load deadlines remain upper bounds. Invalid ownership, insufficient capacity or expiration fails the loader explicitly; it does not release stale media or renew the deadline on automatic HLS retries. A separate new adapter may start again after an explicit user retry. The optional `startupBufferCommit` function defaults to `null` and requires `startupBufferTarget`. It runs once after the encoded reservoir passes the readiness checks, before held callbacks or consumed-media credit reach HLS. Its frozen argument contains only the original startup `AbortSignal`; it may return a promise. For example, a host can prepare a new room locally at zero, publish its start after verified media is ready, and await acknowledgement. An existing room must retain its advancing clock. The original eight-second/parent deadline and held reservations remain in force while the host acknowledges. Cancellation retires the operation; late resolution or rejection cannot release media. A current hook failure reports `commit-refused`. After success, the loader repeats fresh target, authority, context, parsed-fragment and resident-coverage checks. Insufficient headroom does not recall the hook or extend the deadline. The hook establishes encoded reservoir readiness, not decoded frames or accepted playback. The SDK itself does not publish, start, pause or reanchor any room. The signal also ends after successful HLS handoff. A host must detach its pending-acknowledgement listener once acknowledged, so normal operation cleanup does not cancel an established room. The final authority verdict and HLS callback share one synchronous turn; success cleanup follows actual delivery. With `warmAhead: false`, startup may preload the parsed upcoming fragments and retain them for genuine consumption, then stops speculative fetching. Peer consumption credit is deferred until the corresponding genuine callback is released. `metrics().startupBuffer` distinguishes buffering, release, failure and cancellation and reports reservoir use, target and recovery headroom. It does not establish decoded playback, shared-clock accuracy or device acceptance. The separate unreleased `latePeerRace: true` option defaults to false and requires peer-first plus `zeroBudgetPeerRace`. When a whole main-fragment HTTP request began without any peer plan, its first peer arm may use a newly accepted framing-2 connection advertising that exact object. Ordinary speculation cannot arm it: a warm object needs a genuine hls.js consumer. The window starts at that earliest genuine demand, including promotion before the inner loader is ready. An existing or expired peer plan is never renewed. HTTP starts immediately and keeps its original request and network timers. The peer arm ends by the earliest of four seconds from genuine demand, `lateWindowMs`, 2.5 seconds from arming, `maxPeerWaitMs`, and the known original HTTP load deadline. Unknown load deadlines and progressive delivery retain the ordinary path. Fresh admission, signed authority, exact immutable context and current connection identity gate peer work and final delivery. Nonempty HTTP progress locks the response to HTTP. Only one complete authorised result can win; this creates no second HTTP request or playback-clock adjustment. Dormant metadata and active cached races share `maxConcurrentRaces`. Pause, end, epoch/rendition/ticket change, abort, stop and original HTTP termination retire the watcher. `metrics().latePeerRace` exposes entered, armed, won, expired, retired and refused counts plus at most 64 numeric timing records. Waiting and arming create no peer credit. Existing load-entry `lateHaveRace` membership remains unchanged when this separate option is off. When startup buffering is explicitly enabled, its required parsed future fragments may instead carry a `startup-buffer-dependency` role while the real first HLS terminal remains owned and pending. This leaves `genuineAt` unset; the future object has not been consumed by HLS. Its existing HTTP-entry window, peer-arm limit, parent deadline and original first startup deadline all apply. The startup abort signal retires the role immediately on release or cancellation. Steady speculative work receives no such role, and accepted-byte counters still wait for the actual HLS callback. Verified peer reception updates physical link usefulness independently from player consumption. Fast short transfers keep an unknown rate below the unchanged 300 ms observation floor; no rate is invented. Discovery delivery, consumed bytes and external delivery notifications still require actual player acceptance. This avoids using deferred playback credit as a prerequisite for the next startup transfer. Future bytes need a current signed commitment and matching SHA-256 before entering the shared held cache. At most three warm references and 24 MiB of warm data/reservations fit inside the existing `maxHeldBytes` budget. The warm map references the held buffer; delivery to hls.js receives a transfer-safe copy. Normal player/decoder memory and transient demand buffers remain separate. Speculation expires after eight seconds. Promotion retires that speculation-only timer; the already-running parent's timeout still runs from its original start. A parent error or timeout settles the genuine demand through its original callback, without an implicit fresh request or reset deadline. Pause, unrelated seek, ticket change, rendition change and stop clear speculative state; unrelated work yields to a new demanded position. Gap, ranged, encrypted and alternate-audio fragments retain the ordinary loader path. Seeks inside the existing appended buffer retain current and future work, including shared-clock alignment. An unbuffered target also retains already-tracked work when it falls inside an exact warm fragment's finite media interval in the active rendition scope. This covers initial alignment into a next object before its append; it creates no new request. Targets outside both the playable buffer and tracked warm intervals still clear speculative state. Normal hls.js abort handling and the next actual demand continue to prune unrelated contexts. Before the first append, the last genuine parsed-demand interval can also retain its unchanged same-scope next window after HTTP has already completed. Its normalised identity and finite interval are snapshots, distinct from an active request. Changed parsed next metadata, invalid/new demand, unsuccessful termination, clear and stop retire that record. This creates no work, extends no deadline and does not change permission or byte accounting. Every demand reuse checks the host's current commitment/delegation/revocation view. Only actual buffer beyond the normal origin recovery reserve permits waiting for that check, capped at 25 ms. Unknown/empty headroom starts the ordinary source immediately; otherwise source recovery starts when this small budget expires. The first authorised cache result or source result wins and cancels the other arm. Refusal leaves source recovery running. Thus buffered, promptly authorised cache reuse avoids another HTTP request, while underflow recovery can make another request; actual traffic remains counted. Stopping does not wait for an unresponsive cache provider. Exhausting upload allowance also clears warm references and reservations. `metrics().warmAhead` reports `verifiedBytes`, `verifiedPeerBytes`, `consumedPeerBytes`, `localReuseBytes`, active speculative work, promoted demand, tracked objects, cache bytes and aggregate reservations. Raw peer reception is recorded once; `bytes.peerFirst` and `onPeerDelivery` receive speculative peer credit only when real hls.js demand consumes it. Local reuse does not create network bytes. These source tests do not establish sustained cold-cache 4K, a public TURN route, network savings or physical-device continuity. Multi-holder admission reserves its candidate links synchronously before asynchronous worker creation. Other download selectors respect those leases. Only warm work may wait once for an already-captured candidate to become free, within its original peer window and speculation lifetime; its existing HTTP arm continues. Abort, failure and settlement release ownership. This does not add a request, admit another peer or extend a playback recovery deadline. The unreleased `uploadPacing: true` option is disabled by default. Canonical piece ranges can wait in one global FIFO for the existing token bucket to refill: at most one waiter per link, `min(maxUploadPeers, maxPeers)` waiters overall, and a fixed 250 ms absolute queue deadline. A delayed event loop expires overdue work instead of granting it. Rate and twice-rate burst caps stay unchanged; unsupported whole-object requests still refuse immediately. Queue rows retain no bulk media buffer. Current held data, host admission, serving policy and allowance are rechecked before delivery; the final lookup follows every host await. An owned rate reservation is refunded once when nothing is submitted. Explicit host refusal releases its session reservation; accepted or unknown host outcomes retain conservative session billing. The existing provider callback exposes no remote request cancellation signal. Remote CANCEL therefore cannot immediately end this short refill wait: the unchanged Core/JavaScript framing suppresses late output and returns unsent rate capacity, while accepted session/host reservations stay charged. Local stop or link closure cancels immediately. `metrics().uploadPacing` reports queued work, reserved rate bytes, grants/refusals/expiry/cancellation and total and maximum deferred queue milliseconds (including time behind the head). Observed expiry can exceed 250 ms when the event loop is delayed; the grant deadline stays fixed. Host-policy time and payload time are not queue time. `metrics().peerAdmission` reports held link leases and bounded waiter outcomes. Neither waiting nor reservation creates peer delivery credit or rate evidence. The unreleased opt-in `transferWorkerUrl` warms one explicitly packaged companion worker asynchronously after `coreWasm` loads. With `multiHolder`, schema-3 verification and planning use the same Rust transfer facade in that worker. Configured loads use HTTP during warm-up or after failure, without a large synchronous transfer retry. Queue/object limits and late-reply fences preserve the ordinary origin path and accepted-only peer observations. `loadCore(...).module` exposes the already compiled module for this use; the worker fetches no second copy. See the [worker integration guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/TRANSFER-WORKER.md) for the companion bundle, resource bounds, metrics and asynchronous low-level API. For eligible already-HAVE framing-2 holders, a verified schema-3 commitment can enter mixed piece planning without passing a whole-object peer forecast. The planner may use only a bounded peer fraction alongside origin pieces; valid schemas 1/2 retain their whole-object projection. Waiting for unavailable known-VOD main media requires a live same-key FETCH lease from a fresh serving contributor. VOD is read from the exact demanded main level's `details.live === false`; live, unknown and alternate-audio contexts retain their bounded coordination. The current player level does not override the demand's level. These changes preserve the estimator floor, integrity checks and existing deadline/reserve bounds; the committed core module is unchanged. `trace()` returns `{ v: 1, capacity, dropped, rows }`, the rows kept under `traceRequests` (none by default): each peer-first load, eligibility decision, peer request and origin request (whole or ranged), joined by a load ID, and each multi-holder scheduler call with its inputs and the commands it returned, so a recorded transfer replays against the module offline. Times are whole milliseconds from the swarm's creation; holders are session labels, not keys. It is kept out of `metrics()`, which receipts snapshot repeatedly. `node scripts/trace-report.mjs file.json...` summarises saved traces (from a harness receipt, a demo field receipt, a bare trace or a list of any of them): it replays every transfer against the committed module and reports a mismatch, then gives holders offered and used, bytes by holder rank, origin and redundant shares, slack at finish, request timing and buffer ahead of the playhead. `--what-if 1,2,3` replays transfers with other holder limits against each holder's measured timing; it ignores shared uplinks, so it is an estimate of whether fewer holders would do, not evidence for more. `updateTicket(ticket)` refreshes this viewer's bounded opaque admission ticket without rebuilding connections, the loader or upload accounting. It returns `true` for an accepted ticket, including the current ticket, and `false` for an invalid ticket or stopped, disabled or ungated swarm. The host must first validate the credential's identity and expiry. Remote admission checks before SDP and media serving remain required; this method grants no new authority and does not restore consent. Use a new swarm when the publisher, policy or peer configuration changes. The complete options, callback contract, metrics and peer-first validation are in [INTEGRATION.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md). The host must honour upload consent and pass a trusted signed stream event. The optional discovery adapter below resolves events under an explicit host policy; the loader itself opens no discovery query. The peer loader updates hls.js's retained statistics object and sends one `onAbort` callback for an aborted pending peer load. `destroy` cancels without reporting a completed load. The optional `onPeerDelivery({ connection, bytes })` callback attributes verified peer-first media to its actual `RTCPeerConnection`. A single-holder delivery fires once with its whole payload. A multi-holder delivery fires once per contributing connection with only its first-verified-copy piece bytes; origin-winning and duplicate pieces are excluded. `bytes` is a positive media payload byte count, and all observations for an object sum to its increase in `bytes.peerFirst`. The complete object must be accepted for the player first; verified pieces of an incomplete or rejected object emit nothing. It runs after all aggregate counters change and immediately before the player's success callback. Observer exceptions and rejected promises cannot cause fallback, prevent playback or suppress other contributions. Protocol traffic, shadow measurements, origin fallback, failed verification and aborted or late deliveries do not fire it. Connection references stay local to the host; the callback supplies no URL, peer identity, SDP or media buffer. See the [callback contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#metrics). The rotation/refusal helpers are exported for the loader's policy and tests; most hosts only need `createHlsSwarm` and `HLS_SWARM_METRICS_VERSION`. ## Shared account upload allowance `createAccountUploadBudget(options)` supplies the private durable reservation ledger. Its `identity`, `authorize`, `inspectGrant`, `reserve`, `renew` and `revokeGrant` methods are trusted server operations, not a public authentication interface. Await `ready()` before use and `close()` during shutdown. The required `statePath` has the private filesystem requirements described in the [account allowance guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md). The example HTTP integration is `startDemoServer({accountBudget: {...}})`. Omitting `accountBudget` omits the service. Configure `statePath` and optionally `resolveWebsiteAccount(request, {signal})`, which must resolve the host's authenticated session to `{issuer, subject}`. Nostr proof verification is supplied by the example; website authentication belongs to the host. Neither method enables uploading, resets spend or enrols other devices automatically. Defaults are `defaultLimit: 100000000`, `grantTtlSeconds: 120` and `delegationTtlSeconds: 10800`. Limits accept zero through 10¹² bytes; grants accept 30–300 seconds; delegation accepts the grant duration through 86,400 seconds. Account, identity, grant, replay-operation and pending-write bounds refuse excess work rather than evicting recorded spend. The HTTP adapter also bounds challenges, active requests and authentication time. This is a serial, durable payload ledger; no high-volume capacity or physical wire metering is claimed. The same-origin POST routes under `/account-budget/` use a private versioned proof contract and short-lived page-bound grants. Keep them behind HTTPS and the configured origin; do not expose the trusted ledger methods directly or accept viewer-supplied account subjects as authentication. The session descriptor contains supported methods, bounds and fixed endpoint paths only. ## Example policy and session renewal The source demo advertises `deliveryPolicySession: "inline-v1"` with `deliveryPolicyEndpoint: "/delivery-policy.json?session=1"`. Its GET response contains the existing policy fields plus `session`, built synchronously from the same public descriptor used by `/session.json`, after operator readiness. The bare policy URL and operator routes retain their existing response shapes. The opt-in route uses exact buffered JSON, `Content-Length` and `no-store`. The example client uses one request for an advertised inline snapshot and two parallel requests for legacy descriptors. It applies observed OFF first, then validates the session and prepares admission under the existing five-second issuance lifetime. Missing or incompatible advertised data fails closed without a legacy retry. The two-second cadence, three-pending cap and consent rules are unchanged. `startDemoServer({policySessionSnapshot: false})` selects the legacy contract programmatically; it has no CLI or viewer switch. This reduces renewal requests and does not establish field reliability. See [operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md#policy-and-viewer-consent). ## ICE transport policy The core swarm and `startDemoServer` accept `iceTransportPolicy: "all" | "relay"`, default `"all"`. Both demo and broadcaster CLIs expose `--ice-transport-policy all|relay`. Invalid values are rejected before host state or services start. A demo policy change stops peers and requires fresh Apply and upload consent; an absent legacy descriptor means `"all"`. Relay-only is an explicit operator privacy/compatibility choice, not a TLS selection or a proved transfer repair. It never downgrades to `"all"`; if usable relay connectivity is unavailable, playback retains its existing origin fallback. ## Optional demo TURN renewal `startDemoServer({turnCredentials: {url: 'https://issuer.example/turn'}})` enables the demo's bounded, per-viewer credential adapter. Omit it for the existing static/default ICE path; it is mutually exclusive with `iceServers`. The demo and broadcaster CLIs expose the same choice as `--turn-credentials-url`. The [field guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#optional-turn-credential-renewal) describes the issuer response, limits, cookie and consent behaviour. The descriptor in `/session.json` contains only the fixed same-origin endpoint contract. This integration replaces demo swarms when accepted credential material changes. An identical cached reply preserves the original lease and peers and schedules a bounded retry; it does not extend expiry or increment the refresh counter. The core `createHlsSwarm({iceServers})` option remains a configuration captured when the swarm is created; no seamless ICE-restart API is added. ### Optional TLS-over-TCP URL projection Set `turnCredentials.urlProjection: "tls-tcp"` (default `"issued"`) or use `--turn-url-projection tls-tcp` together with `--turn-credentials-url`. This operator selection is independent of `iceTransportPolicy`. Invalid choices or CLI TLS projection without an issuer are rejected before private reads/state. The default session descriptor stays unchanged; explicit selection adds only `urlProjection: "tls-tcp"` to its TURN descriptor. The adapter retains the raw issued URLs and lease in its private cache. In its response it preserves explicit `turns:host[:port]?transport=tcp`, appends `?transport=tcp` only to a valid transport-unspecified `turns:host[:port]`, and excludes plain `turn:` and explicit UDP. Hostname, port, credentials and original expiry/refresh boundaries are preserved. Empty/invalid projections refuse peer configuration without unrestricted retry; origin fallback remains. The client independently requires explicit secure TCP URLs. A selection change fences old pending work, stops peers and withdraws upload until fresh Apply. This is application-selected configuration, distinguishable from the original issuer response. [RFC5928 section3](https://www.rfc-editor.org/rfc/rfc5928.html#section-3) defines user/application transport preferences; [RFC7350 section4.6](https://www.rfc-editor.org/rfc/rfc7350.html#section-4.6) allows TLS or DTLS for unspecified `turns:`. Explicit TCP narrows that selection; it does not prove issuer/server compatibility. The selected URI is then resolved unchanged under [RFC7065](https://www.rfc-editor.org/rfc/rfc7065.html#section-3.1) and supplied as [WebRTC ICE configuration](https://www.w3.org/TR/webrtc/#dom-rtciceserver). TLS describes the client-to-TURN hop, not every relay-to-peer hop. Actual selected transport and verified payload still require measurement; no delivery repair, cost or field qualification follows from this option. ## Node HLS publisher ```js import { createHlsPublisher } from 'relayswarm/hls-publisher'; const publisher = await createHlsPublisher({ mediaDir: '/path/to/hls', manifest: 'master.m3u8', }); ``` | Option | Default | Meaning | |---|---|---| | `mediaDir` | required | Real local directory containing the supported playlists/media | | `manifest` | `master.m3u8` | Entry playlist, relative to that directory | | `secretKey` | fresh ephemeral key | Publisher's 32-byte Nostr signing key; keep server-side | | `streamEvent` | fresh signed event | Restore a valid authorisation signed by this key and bound to this manifest | | `swarmId` | derived from signed stream event id | Shared id, 8–128 characters | | `now` | `Date.now` | Clock returning milliseconds; useful for deterministic tests | | `maxConcurrent` | `8` | Simultaneous signing work, configurable from 1 to 64 | | `maxCacheEntries` | `512` | Entries in each bounded hash/commitment cache, configurable from 1 to 4,096 | | `allowEncryptedMedia` | `false` | Explicit AES-128 ciphertext publication; local keys remain HTTP-only | | `pieceCommitments` | `false` | Experimental: sign exact-playlist contexts as schema 3 (one SHA-256 per piece) instead of schema 2. v0.2.1 and RelaySwarmKit v0.5.0 receivers reject schema 3; Kit v0.6.0 has an explicit schema-3 piece API | | `commitmentSecretKey` / `delegation` | author key / none | Author-scoped delegated commitment signing; an externally authored event permits operation without the author secret | | `revokedDelegationIds` / `delegationRevocations` | empty arrays | Host-trusted current revocation view; no automatic global lookup | `commitment` accepts `playlist`, `mediaType` and `part` for schema 2 exact media identity. Use `segmentMediaContext(context)` to derive the playlist, type and encryption from hls.js. `advertisement({manifestUrl, relays, status, starts, previousEvent, allowLoopback})` creates full linked live metadata; delegate-only publishers must supply an externally author-signed `event`. See [production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) and the [protocol draft](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NIP-DRAFT.md) for scope and compatibility. The returned object contains: - `swarmId`: selected swarm identifier. - `streamEvent`: signed kind-30311 event with a `d` tag and the experimental redistribution authorisation; this is not a stream-discovery service. - `manifestPath`: published path under `/media/`. - `await media(path)`: resolves a currently listed media path to its contained real local filename. It does not serve HTTP itself. - `await commitment(context)`: signs a kind-24172 commitment derived from a matching playlist record and the exact bytes on disk. - `await playlistSnapshot(path, {fresh = false})`: returns a copied playlist buffer, its canonical file, presentation paths and media-playlist texts from the bounded authorised catalogue. `fresh` settles any earlier shared refresh before starting or joining the next one; it supports watch-before-read HTTP handling without exposing media or encryption-key bodies. - `getMetrics()`: request, cache, streamed hashing, signing, renewal, eviction, changed-read, bounded playlist-retry and concurrency counters. `commitmentJoins` counts requests that joined an identical one already in flight; joined requests take no concurrency slot and are each checked against a catalogue and file read after they arrived. A playlist rejected by the byte/stat change guard gets one fresh full-catalogue retry; invalid data and changed segment bytes still reject. These counters do not measure network delivery. Commitment input is `{ path, level, sequence, discontinuity, rangeStart?, rangeEnd?, part? }`. The path is the published `/media/...` path; level is the hls.js rendition index, and sequence/discontinuity match its fragment. Omit both range fields for whole segments; otherwise use a start-inclusive, end-exclusive range. Only a null/absent `part` is supported. Callers do not choose the digest, size, author or expiry. Contexts absent from the current playlist are rejected. The signed expiry is 60 seconds after the publisher clock. `PublisherError` carries an HTTP-style `status` for expected validation/capacity errors. Filesystem failures can also occur; a public server should mask internal paths as the demo does. Catalogue/signing bounds and the exact supported HLS subset are in [FIELD-TEST.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#publish-your-own-media). ## Example origin HTTP playlists `startDemoServer` supports blocking reload of compatible complete live media playlists with target durations from one to three seconds. Its `blockingPlaylistReload` option defaults to `true`; setting it to `false` retains conventional playlist polling. Capability advertising is presentation-wide: unsupported parts, delta, ended or mixed presentations do not receive a partial blocking-reload promise. Raw pipeline files and media bytes are unchanged. Direct directory watches cover every currently authorised playlist basename, including the master and other renditions, and the directory's own rename. Named temporary files and media segments do not invalidate playlist snapshots. Changes to filename coverage require a fresh read within the existing three revalidation limit. On Windows, shallow watches of immediate parents also observe playlist-directory moves and ignore unrelated siblings and named metadata events. Missing filenames or unknown event types fail closed. If a presentation requires more than 41 watched directories, it retains its original bytes without added blocking capability. Arbitrary ancestor-tree moves are outside this coverage. A valid `_HLS_msn` request waits for a fresh authorised playlist containing that sequence or a later one. Requests for sequences already removed return the latest full playlist. Malformed directives and excessive future sequences are rejected; ended playlists ignore sequence and part directives. Blocking has a deadline of three initial target durations, cancellation on disconnect/shutdown and a 24-waiter limit within the existing 32-media-request ceiling. It does not change the loader's peer budget, origin reserve, segment durations or playback holdback. See the [HLS blocking-reload draft contract](https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-22#section-6.2.5.2). The focused suite includes actual HTTP publication, capacity, timeout, abort and shutdown checks. One injected headless Chrome loopback pair passed both qualities and producer-restart sharing with this option enabled and disabled. The [paired results](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/blocking-playlist-reload-paired-browser-20261014.json) retain recoverable 503 errors seen only with the option enabled; reliability improvement, ordinary public and physical acceptance remain unproved. `demo.playlistReloadMetrics()` exposes the policy, waiter limit, current blocked requests/watchers and numeric start, release, abort, timeout, watcher-error and rejection counts. These counters do not prove browser use or media delivery. ## Private publisher state `await loadPublisherState(path, { manifest = 'master.m3u8', swarmId?, now? })` returns `{ secretKey, streamEvent, swarmId }` to spread into `createHlsPublisher`. The parent must be an existing owner-controlled directory; the state must be a private regular 0600 file with one link. Creation publishes one complete identity atomically, including concurrent callers. Invalid state, identity, manifest or explicit swarm mismatches fail without overwriting it. This helper requires POSIX file permissions; Windows ACL storage is not implemented and fails before file access. This file contains the signing secret. Keep it on the server and preserve it across orderly restarts. Without this opt-in, the publisher remains ephemeral. The other exports are validation/construction helpers; they do not manage backups or key rotation. See [operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md). ## Trusted stream adapter `resolveTrustedStream(event, policy)` returns a descriptor or `null`. `policy` requires `trustedAuthors` (at most 64 hex public keys), `allowedMediaOrigins` (at most 32 exact HTTPS origins), `swarmId`, and 1–8 host-selected `relays`. `iceServers` defaults to an empty list, avoiding event-selected network services; `allowLoopback: true` permits local HTTP/WS fixtures. Invalid host configuration throws `TypeError`. The adapter verifies the signed kind-30311 event, bounded size, one address identifier, live status, streaming URL, time bounds and experimental redistribution authorisation. Event-advertised relays never replace the host's policy. A descriptor contains `{ manifestUrl, streamEvent, swarmId, relays, iceServers, config }`. `config` starts with `serve: false`; the host supplies mode, commitment provider and consent separately. `await discoverTrustedStreams({ ...policy, query, signal?, timeoutMs?, maxEvents?, maxResults?, maxTotalBytes? })` calls the host's `query({ filters, relays, signal })`, accepting an array or asynchronous iterable. Defaults are 5 s, 256 events, 32 results and 2 MiB total; per-event size is capped at 16 KiB. The latest signed address update is selected before live filtering, so an ended update suppresses an older live event. Equal timestamps select the lowest event id. Floods, cancellation and timeout throw `StreamDiscoveryError`, including `EVENT_LIMIT`, `ABORTED` and `TIMEOUT`. This helper owns no sockets or fetches. The host query must close its resources on cancellation. The host must still enforce allowed origins on redirects and playlist assets, distinguish swarms for different streams, and establish publisher trust. The demo's minimal authorisation event does not advertise a complete discoverable NIP-53 broadcast. ## Broadcast pipeline `await startBroadcastPipeline({ input, mediaDir, ffmpeg?, forwardUrl?, allowInsecureLoopbackForward?, retryFloorMs?, retryCeilingMs?, publicationIntervalMs?, retainGenerations?, generationGraceMs? })` returns `{ mediaDir, manifest, metrics(), ready({ timeoutMs? }), close() }`. Rendition playlists are republished when a directory watch on the current generation reports the encoder's playlist rename; `publicationIntervalMs` (250) is the fallback interval where watching is unavailable or an event is missed, and `close()` does not wait for it. Default input is the local RTSP live path; `mediaDir` is required and must be a dedicated owner-controlled directory. The pipeline holds an exclusive lock until close. Unclean process termination needs operator lock recovery. Supported inputs are RTSP, RTMP, RTMPS and SRT. Use plaintext inputs on a private network or secure their transport separately. RTSPS is rejected because TLS verification through that demuxer differs between supported FFmpeg versions. FFmpeg creates 360p/700 kbps and 720p/2,500 kbps H.264 video with AAC audio, 30 fps, 2 s full MPEG-TS segments and a 12-segment live window. Both source tracks are required. Independent input readers supervise HLS and optional forwarding; retries default to 1–15 s, bounded to at most 60 s. Forwarding requires RTMPS with explicit certificate/hostname verification and a 15 s output I/O timeout. Plaintext loopback forwarding is an explicit test option. RTMPS requires a DNS hostname and a verified TLS implementation: the supervisor accepts FFmpeg 5 or newer with GnuTLS, or FFmpeg 8 or newer with OpenSSL, after a bounded capability check. Earlier OpenSSL implementations do not check hostnames. Stable playlist URLs retain continuous media sequence numbers and advance discontinuity after a complete published generation. New generation URLs prevent media aliasing; pruning protects media referenced by stable playlists. `ready` defaults to a 120 s deadline; zero waits until source or shutdown. `close` is idempotent. Metrics describe processes/publications and never include upstream credentials; a running forward process is not platform acceptance. The HLS worker also exposes a bounded numeric progress snapshot (frames, fps, encoding speed, output time and sample timestamp) for actual host measurements. `broadcastEncoderArgs(input, runDirectory, { startNumber = 0 })` and `broadcastForwardArgs(input, output, options?)` construct argument arrays without a shell. They do not create directories or launch processes. The caller must enforce the same FFmpeg TLS prerequisites when launching these arrays directly. The supervisor derives the next encoder start number from published playlists. See [broadcast setup](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md) and [container deployment](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md). ## Segment commitments `commitmentContent(fields)` returns canonical JSON with the domain `relayswarm-segment-v1`, schema `v: 1` and fixed field order. It serialises fields; it does not sign an event or validate media bytes. `commitmentPieceSize(size)` returns the piece size that experimental schema 3 (`v: 3`, `relayswarm-segment-v3`) requires: at least 64 KiB, at most 64 pieces per segment, rounded up to a multiple of 16 KiB. Schema 3 adds `pieceSize` and one lowercase SHA-256 per piece in `pieces` to schema 2. The verifier accepts it; the publisher signs it only with `pieceCommitments: true`. The loader fetches and verifies pieces from several holders only with `multiHolder` (see `INTEGRATION.md`). `validStreamAuthorisation(event)` checks the signed kind-30311 event, a `d` tag, bounded event size and the exact redistribution tag. `verifySegmentCommitment(event, { streamEvent, swarmId, key, context, maxSegmentBytes }, at = Date.now())` returns the verified fields or `null`. It verifies the signer, tags, canonical content, timestamp/expiry and exact fragment identity. The caller must separately hash and size-check received media. `context` uses hls.js's `{ frag, part? }` shape, not publisher input. See [the signed contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#authenticated-peer-first-loading) for every field and timestamp constraint. ## Relay pool and session ```js import { RelayPool, RelaySwarmSession } from 'relayswarm'; const pool = new RelayPool(['wss://relay.example'], { reconnect: true }); const session = new RelaySwarmSession({ pool, swarmId: 'example-stream' }); try { await pool.connect(); session.start(); // Register handlers and publish presence/signals for your transport. } finally { session.close(); pool.close(); } ``` This illustrates lifetime management; `relay.example` is a placeholder. `new RelayPool(urls, options)` requires 1–8 `wss://` relay URLs (`ws://` is allowed on loopback). Options are `label`, `WebSocketImpl`, `connectTimeoutMs` (8,000), `reconnect` (false), `reconnectMaxMs` (30,000) and `readyOnFirstRelay` (false). Methods: - `await connect()`, `close()`. - `subscribe(filter)` → subscription id; `unsubscribe(id)` sends CLOSE. - `onEvent(handler)` / `onReject(handler)` → unsubscribe callback. - `publish(signedEvent)` sends to connected relays; it is not a delivery receipt. Live subscription ids and filters are checked before signature validation and dispatch. Reconnect mode restores active subscriptions. `new RelaySwarmSession({ pool, swarmId, secretKey?, maxEventAgeSeconds? })` uses a fresh ephemeral key by default; maximum event age defaults to 120 s. `pubkey` is the session key. Methods: - `start()` / `close()` manage a presence subscription and recipient-filtered signal subscription; closing the session does not close its shared pool. - `onPresence`, `onSignal`, `onError` register handlers and return unsubscribe callbacks. - `announcePresence({ role, transports?, have?, open?, ticket? })` returns the signed event. Capabilities are `{ type, publicKey, obj? }`; `have` contains digests. Experimental `obj` is the object framing version, an integer 1 to 15 (absent means 1); received presence keeps a valid `obj` and drops any other. Session wire version 3 is unchanged, and v0.2.1 peers ignore the field. - `sendSignal(toPubkey, { type, transport, requestId, payload? })` returns a signed NIP-44-encrypted event addressed to that session key. - `waitForPresence(predicate, timeoutMs?)` / `waitForSignal(predicate, timeoutMs?)` resolve matching `{ from, event, payload }`; default deadline 15 s. - `clockDiagnostics()` returns local counts `{ aheadRejected, staleRejected, maxAheadSeconds, signalSamples, signalAgeMedianSeconds }`: swarm events outside the age window, and arrival age of up to 64 recent signals that decrypted and validated. Acceptance rules are unchanged. `validTicket(ticket)` validates the opaque ticket's shape/size, not permission, signature, identity or expiry. Host admission policy supplies those decisions. ## Native transfer primitives From `relayswarm/src/native-dht-transport.mjs`, `NativeDhtTransport` exposes `ready`, `listen`, `authorize`, `connect` and `close`, plus its Noise `publicKey`. Authorisation binds one remote Noise key and Nostr key to request id, digest, size and lifetime. The default limits are 256 pending authorisations, 16 incoming connections, 15 s connection setup and 30 s transfer lifetime. See [the native protocol](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NATIVE-TRANSPORT.md) for the security boundary. `runNativeJourney({ relayUrls, bootstrap?, bytes?, WebSocketImpl?, timeoutMs?, log? })` from `relayswarm/src/native-journey.mjs` starts two peers, transfers and verifies an object, returns its measurement summary and closes resources. It is a test/CLI orchestration helper, not a long-lived native HLS scheduler. `relayswarm/src/object-transfer.mjs` exports `sha256Hex`, `encodeFrame`, `decodeFrames`, `serveAuthorizedObject`, `requestObject`, `FRAME` and `DEFAULT_MAX_OBJECT_BYTES` (256 MiB). These Buffer/stream primitives enforce the supplied object identity and frame bounds; trusted digest discovery, durable storage and application origin fallback remain outside them. ## Installed native client `fetchNativeObject(descriptor, options)` returns `{bytes, receipt}` only after independent size/digest verification. A version-1 descriptor requires `swarmId`, `sha256`, `size`, `relayUrls`, `trustedSeeders` and optionally `originUrl`. HTTPS/WSS are required; `allowLoopback: true` permits HTTP/WS solely for loopback tests. The host supplies `bootstrap`, optional cancellation, `peerTimeoutMs` (default 10,000), `timeoutMs` (30,000) and `maxObjectBytes` (at most 256 MiB). A failed peer attempt automatically uses the configured trusted origin; redirects and substituted content are refused. `createNativeObjectSeeder({bytes, swarmId, relayUrls, bootstrap, secretKey, originUrl, allowLoopback, timeoutMs})` returns `{descriptor, close}`. Serving requires an explicit application call. Descriptors from untrusted seeders cannot establish provenance. `validateNativeDescriptor` validates the same policy without opening network resources. Clients subscribe before announcing receive-only native presence (`open: false`, empty `have`). Seeders coalesce replies globally with a minimum one-second publication gap and cancel the pending timer on close. This permits discovery without ephemeral history replay. Presence discloses the temporary Nostr/native public-key link but never authorises a dial or implies an inbound service. The installed `relayswarm-native` executable accepts `--descriptor`, `--output`, repeated `--bootstrap`, `--peer-timeout` and `--allow-loopback`. It requires Node and atomically creates a new verified output without replacing an existing path. `npm run native:fetch -- --help` shows usage. ## Experimental PlayerHint command The browser loader accepts `peerSupplyHint: true` with `coreWasm` in peer-first mode and optional `onPlayerHint(rows)`. It exposes the same rows in `metrics().playerHint`; the field is absent when disabled. See the [host contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#experimental-peer-supply-hint) for row fields, unknown estimates and the restriction to tie-breaking between levels the origin already sustains. No hls.js level is assigned by this adapter. `loadCore(...).playerHint(supply)` returns `{ t: "playerHint", rendition, eligibleHolders, projectedMs }` or null if the core is unavailable. Supply contains `rendition`, `size` (nullable estimate), `peers` (`[id, firstByteMs, bytesPerMs]`), `origin` (`[firstByteMs, bytesPerMs]`, both null if unknown), `sharedFirstByteMs`, `sharedRate`, `availableMs` and `maxHolders`. Times are durations in milliseconds; the projection is not a wall-clock finish timestamp. The host filters eligible HAVE holders before the call. The function does no I/O and reserves no pieces. The native facade exposes `player_hint(PlayerSupply) -> PlayerCommand::PlayerHint`, with `PlayerSupplyHint { rendition, eligible_holders, projected_ms }`. `PlayerSupply` uses typed `PeerTiming`, optional origin `Timing`, shared `Timing`, optional size, available milliseconds and maximum holders. Swift and Kotlin use their platform naming conventions. Native hosts retain origin-sustainability checks and the same eligibility filters. Discovery remains one context per media type; other rendition counts reflect linked HAVE advertisements only. This API is experimental and has no field acceptance evidence. --- Source: [docs/STATUS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) # RelaySwarm evidence and remaining work [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Field-test guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md) · [Changelog](https://raw.githubusercontent.com/forgesworn/relayswarm/main/CHANGELOG.md) Checkpoint: 24 October 2026. The prepared experimental shared-core prerelease is [v0.4.4](https://github.com/forgesworn/relayswarm/releases/tag/v0.4.4). The [changelog](https://raw.githubusercontent.com/forgesworn/relayswarm/main/CHANGELOG.md#v044-24-october-2026) records its source changes; the [installation guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) describes JavaScript/WASM and native downloads and checksum verification. The npm registry is unpublished. Earlier release and pilot evidence below retains its date and source. ## Measured startup and recording wrap (26 October 2026) The paired site at `a0db0e63`, using SDK `bea813a`, passed real 60-second and 330-second full-4K runs on two fresh visible M4 Chrome contexts. Browser HTTP caching was disabled; CDN state was not asserted cold. Both viewers had zero post-first-frame stalls and dropped frames. The separate whole-window 0.75-second sync audit passed; maximum drift in the long run was 0.343 and 0.116 seconds. Actual programme rollover and CC0-to-CC1 transitions were followed by over 61 seconds of clean periodic samples. This used startup-only buffering with steady `warmAhead` disabled; it does not qualify steady speculation. The first room prepared verified media locally before publishing its start; the later viewer joined the advancing epoch. Accepted peer shares were 11.08%/19.72% in the short run and 12.02%/6.65% in the long run. The unchanged harness qualifies its selected receiver, not every viewer above 10%. Peer share is not net HTTP saving, wire cost or a competitor comparison. Both viewers used native host-to-host UDP on one Mac; physical iPhone, public-NAT and independently operated public TURN acceptance remain separate. The [privacy-safe measurement summary](https://github.com/forgesworn/forgesworn.dev/blob/main/docs/evidence/prepared-room-4k-20261026.json) records source and raw-receipt hashes, protocol scope and per-viewer results. Earlier failures below remain historical evidence rather than the latest startup-only qualification result. Release assets remain version 0.4.4; these opt-in source changes are not substituted into existing release files. ## Unreleased per-connection timing and bounded recovery (25 October 2026) An M4 comparison with steady speculation disabled still had one 0.88-second startup interruption; its other viewer had none. Both received useful peer media, but the interrupted viewer failed the shared-clock audit. Its first freshly aligned position left 0.68 seconds of buffered media while the next whole-fragment source request took 1.73 seconds. No peer wait or subsequent clock seek caused that underflow. The experimental, default-null `startupBufferTarget` contract therefore holds the first encoded callback until verified upcoming media covers a fresh host target plus measured recovery headroom, within the existing reservoir and deadlines. This is unreleased work; at that stage real continuity, shared-clock and physical-device acceptance remained pending. The first startup-buffer M4 run kept one viewer playing for 73 seconds with zero waits or dropped frames and at most 0.283 seconds of room drift. The other viewer never presented a frame: a required future HTTP request could not use a peer accepted after load entry, and its first verified short peer transfer did not establish link usefulness until player consumption. That formed a startup dependency cycle. The media gate remained RED and overall sync was unqualified. The follow-up changes distinguish owned startup-buffer dependencies and verified transport usefulness from actual HLS consumption, with the original memory, rate and deadline limits. Fresh real playback qualification was still required before the later results above. The next M4 run failed before the first viewer presented a frame; a second viewer never joined. All three contiguous bodies (18.27 MB) completed, but the first room's clock had advanced before media preparation. At the last coverage check, the verified tail provided 2.388 seconds ahead of the target against 3.076 seconds of measured recovery headroom. The original eight-second startup deadline expired. This remains RED, with no observation samples and unqualified sync. Follow-up work adds an optional bounded host acknowledgement hook so a new room can prepare before publishing its start, without reanchoring an existing room or changing the media acceptance gates. Real playback was still pending before the later results above. The experimental `warmAhead` option is disabled by default. Signed-commitment loader tests using actual hls.js 1.7.3 parsed Fragment objects cover future object verification, exact-demand reuse/coalescing, current-authority refusal, cache/reservation limits, cancellation and the untouched default path. Its speculative map shares the existing held byte budget, and local reuse is reported separately from accepted peer payload. Sustained cold-cache 4K, useful peer contribution, shared-clock behaviour and physical iPhone acceptance require fresh browser/device measurements before enabling it in a deployment. An initial 60-second public-4K candidate run remained RED despite local cache reuse. Promoting an in-flight warm object to actual demand now frees the speculative slot for its successor, with aggregate reservations and an independent buffer-bounded source recovery path. These causal source fixes still require another unchanged cold-cache playback comparison. The subsequent M4 comparison also remained RED. Its trace identified an in-buffer clock alignment cancelling needed loads, and promoted current requests still using the eight-second speculative cap. Source regressions now retain useful work for buffered seeks and preserve the original parent's deadline/error callback on promotion. A subsequent 60.269-second M4 run retained both peer-assisted players with no dropped frames, but remained strictly RED: buffered shared-clock seeks produced one 13 ms and one 39 ms wait. Accepted peer shares were 14.5% and 16.9%. Partial-inclusive HTTP bodies were 5.61% and 7.27% below accepted media bytes; this is not a matched origin-only comparison, wire savings or production/device acceptance. The trace showed initial alignment using a manifest-time target about two seconds behind the room clock. The SDK now also retains an exact already-tracked, same-scope warm interval when a seek enters it before append. Real parsed-fragment regressions cover verified/in-flight reuse and invalid or unrelated seek cancellation. This paired SDK/site startup-alignment candidate subsequently passed a 60-second continuity gate with no stalls/drops and 16.1% receiver peer contribution. The unchanged 330-second gate remained RED with early interruptions, despite 82.2% receiver peer contribution. The short pass does not establish close room synchronisation or physical-phone acceptance. Its startup trace also showed a seek inside the completed genuine first fragment, before append, discarding a verified next object and downloading its full body again. Source regressions now retain only that last genuine fragment's unchanged parsed next window, retiring it on incompatible metadata, unsuccessful termination or lifecycle changes. This additional fix remains unmeasured. The longer trace also exposed concurrent asynchronous worker admissions selecting the same free-looking link, followed by token-bucket refusal during piece upload. High-level source regressions now reserve link ownership before the worker await and permit only bounded warm contention waiting. The new default-off `uploadPacing` option defers canonical-piece refill in a bounded 250 ms FIFO without increasing rate, burst or quota. Tests exercise actual committed-Core worker/provider contracts and unchanged cancellation framing; they do not establish smooth full-track playback or close room synchronisation. The subsequent 60-second M4 candidate with these retention, admission and pacing changes remained RED on continuity and whole-window synchronisation: one viewer had two waits totalling 2.49 seconds and seven dropped frames; the other had none. Accepted peer shares were approximately 36% and 1.9%. Pacing reported no refusal or expiry. The trace instead showed a needed HTTP object starting before a peer connected, then continuing through an underflow while that peer completed the same object. Its exact HAVE arrival was not captured. A newly implemented, default-off `latePeerRace` permits only a first peer arm for such genuine demand, with fresh authority and the original HTTP left running. Source tests cover late accepted exact-HAVE adoption, bounded windows, stale context and cancellation; actual playback and synchronisation with this option remain unmeasured. No wire-savings, public-NAT, production or physical-device pass is claimed. Cold-cache physical diagnostics exposed two distinct timing errors: a holder's completion rate already included startup, yet the piece planner also added a viewer-wide first-byte delay from another connection; HTTP service timing could borrow that peer delay too. Large ranged origin loads did not refresh the earlier whole-origin estimate. The working source now keeps per-connection startup and qualifying payload flow separately, uses HTTP service timing independently, and scales substantial HTTP ranges by their actual bytes for rendition-specific recovery estimates. A pessimistic or stale connection may get one explicit canonical-piece probe per ten seconds on a real matching HAVE demand. Origin starts the remainder immediately. Another route's fast rate cannot enlarge the probe; only fresh verified data can unlock ordinary bounded requests. Accepted short-flow recovery can discard an older pessimistic rate without creating a retained rate below the 300 ms/32 KiB observation floor. A newer unsuccessful request invalidates that useful-delivery allowance. The optional WASM capability is additive, with safe origin/known-holder fallback for older modules and unchanged existing native start signatures. SHA-256 uses the throughput-oriented optimisation override; the remaining core retains its size-oriented release profile. These source changes are unreleased. Focused tests cover actual verified small fractions, origin-winning cancellation, corrupt and late probes, old-module compatibility, per-lane silence and replay of the bounded-probe inputs. The matching Rust workspace passes. The complete real-WASM loader sweep passes 315 tests with one expected JavaScript-prototype-only skip; the protocol/ABI/source-stamp suite passes all 46 checks. Initial fixture failures are retained: two quiet-peer controls needed explicitly unknown startup, one new test accidentally terminated its transfer through an origin failure, and the loader replay needed the new start input. The repeated-contribution fixture now verifies a 65,536-byte piece in 750 ms against its unchanged 800 ms deadline before testing later useful fractions; its whole-object projection remains late. Its integrity and byte-accounting assertions remain. Cold-cache sustained contribution, complete device playback continuity and net network benefit remain open field gates. ## Cached mixed admission and fetch-backed waits (24 October 2026) A fresh slow partial-flow estimate could reject an entire large object before the schema-3 mixed planner ran, although a contributor held the requested media and could supply a smaller useful fraction. Eligible already-HAVE framing-2 holders now reach that planner after commitment verification. The planner, sustainable deadline and origin reserve still bound peer work; valid schemas 1/2 retain their whole-object projection. The 300 ms estimator floor, integrity verifier, wire and committed WASM bytes are unchanged. For known-VOD main media, an unavailable object is waited for only while a fresh same-rendition serving contributor advertises a live FETCH lease for that exact key. A contributor behind a recorded-media prefetch leader no longer causes a wait merely by serving or ranking ahead. VOD is the exact demanded main level's explicit `details.live === false`, rather than `currentLevel`; live, unknown, alternate-audio and invalid-level contexts retain the previous bounded coordination. A lying or expired lease cannot move the deadline. Twenty focused real-WASM checks cover repeated mixed delivery after an actual slow partial flow, both valid legacy schemas, missing/wrong/expired leases, valid availability, a bounded lying lease, live/unknown compatibility and exact-level/track-family classification. The same corrected fixture on the previous `6f63fb2` source fails the mixed-admission and missing-lease controls. Test channels model native reliable/ordered SCTP and allow losing EOF frames to drain before the next eligible demand. The initial candidate's complete WASM loader sweep passed 301 tests with one expected JavaScript-prototype-only skip (302 total). Syntax and authored/generated documentation checks passed. The first parallel JavaScript loader sweep had four timed holder-accounting failures; the same four passed on both previous and candidate source in quiet isolation without changing their assertions. Its complete serial JavaScript loader rerun then passed all 370 tests with zero failures in 125.875 seconds. The initial hosted broadcast fixture exposed a synchronous live-release race: donor HAVE arrived 29–58 ms after the consumer's decision, while the first candidate admitted waits only after observing FETCH. The recorded-media scope above preserves the prior live coordination and the unchanged strict peer playback assertion; that failed initial attempt remains recorded. Physical candidate checks used original 2160p HLS on Pixel/Vanadium and an M4 browser, actual Nostr signalling and the owner's existing Archy Spry TLS service with private expiring credentials. Selected DTLS fingerprints and native data-channel byte counts establish the paired transport. With separate website clock/first-frame fixes, the final staged 45.5-second window passed: both decoded 3842×2160, Pixel accepted 6,553,600 verified peer bytes, M4 recorded 7,602,176 uploaded media bytes, and both reported zero post-first-frame stalls and zero dropped frames. This is bounded physical application evidence. An earlier 100-second run accepted 24,739,840 peer bytes but retained clock-seek and recording-loop interruptions; those failures remain recorded. Some ordinary HTTP responses were served from browser cache, so accepted origin media bytes are not wire traffic or net network savings. Cold-follower and default-buffer observations remain distinct from cached and tiered trials. Phone privacy settings and the existing service were preserved; profiles stayed private. Sustained continuity and net network benefit remain open. A later cold-consumer window verified each HTTP response's network/cache classification but delivered only about 245 KiB of peer media: its usable native link arrived about 67 seconds into the 100-second observation. That qualification remains failed and reliable cold discovery remains open. ## Sustainable peer waits and range-sized WASM uploads (24 October 2026) The opt-in `sustainablePeerWait` bounds serial peer waits and multi-holder extensions by the requested fragment/part duration minus measured p90 whole-origin recovery with a 25% and 100 ms margin. A two-second segment with a 1,300 ms measured origin load leaves 275 ms for serial peer work. The independent cached-peer race retains its window alongside immediate HTTP. Existing buffer reserves, integrity checks and defaults remain intact. The matching WASM upload ABI accepts only the requested range. Previously a 512 KiB ranged upload could first copy a roughly 6 MiB held object into the module and clone it before slicing. This removes that repeated whole-object input work without changing peer messages, range validation or upload charges. It is not a measured throughput, CPU-time or smooth-playback claim. The focused Node loader sweep passed 32 tests covering the new measured deadline, complete verified cached-peer contribution, cancellation and the existing origin-recovery reserve. It uses real committed WASM and simulated browser connections. The combined `npm run test:swarm:core` sweep against the rebuilt module passed 291 tests, with one expected skip and zero failures (292 total). That skip patches JavaScript selection's prototype, which the WASM selection path does not use. The protocol/ABI suite passed 42 tests; 13 Rust range tests also passed. The actual WASM allocation regression sends the same 6 MiB object in 16 ranges: boundary input falls from 96 MiB with the legacy ABI to 6 MiB with the new ABI. This is a byte-copy measurement using synthetic links, not a device or streaming throughput comparison. These checks do not establish actual iPhone/iPad, Pixel/Vanadium, varied-NAT or sustained distributed continuity. The v0.4.2 failed hosted-browser attempts below remain historical RED. ## Admission-renewal overlap release (24 October 2026) v0.4.2 also exposes accepted peer connection identities with `peerConnectionDetails()` for distinguishing retained links from replacements. No service or pilot deployment is part of this library prerelease. A media request arriving during a peer's changed-ticket admission check could close the live link: the upload checked the old ticket while the new ticket already owned the per-peer check. Uploads now join that bounded online decision before reserving allowance or sending media. Rejection, timeout and shutdown still prevent delivery; subsequent requests check authority online again. `npm run test:ticket-renewal:browser` exercises two independent Chrome contexts, local Nostr signalling, real HTTP admission, native SCTP and the committed WASM core. Three ticket rotations on each side retain the exact accepted connection, peer identity, loader, held bytes, host upload opt-in and spent allowance. One real admission response is held while media is requested: no bytes or quota are spent before acceptance. Four verified 256 KiB loads use the retained connection; later online revocation sends zero peer bytes and the loader falls back to HTTP. The JavaScript and WASM hardening regressions also cover refusal, timeout and late acceptance after stop or channel closure. See the [source and local evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/core-ticket-renewal-20261024.json). This is a synthetic-byte loopback protocol check. R70 remains RED: its retained diagnosis attributed the lost link to far-end neighbour replacement during the renewal observation window. Distributed retention, TURN renewal, physical devices, public NAT and sustained playback remain open. ## Cached-peer race release (24 October 2026) v0.4.1 includes the opt-in `zeroBudgetPeerRace` loader option. It starts the normal HTTP request immediately and races only an object already advertised by an eligible cached schema-3 peer. A complete verified winner owns delivery; progressive loads skip the race. Stopping the swarm leaves pending HTTP running, while loader cancellation stops both arms. The default remains off. The multi-holder origin tail also retains the measured per-load recovery reserve, with bounded range-outcome diagnostics. The native Chrome fixture checks both winners, exact verified bytes, one whole HTTP request per load and reuse of the same connection. It uses two contexts on one machine with synthetic protocol data. Accepted peer bytes do not prove net savings: an aborted HTTP arm may already have transferred bytes. No public service or pilot is deployed. The field and device gates below remain open; publishing these libraries does not close them. ### Cached-peer fixture readiness correction (24 October 2026) The [v0.4.2 tag workflow](https://github.com/forgesworn/relayswarm/actions/runs/40100436726) failed the HTTP-before-key-hash assertion on both attempts. Those historical failures remain RED; the later renewal and broadcast steps were skipped. An instrumented local run reproduced the assertion on the first receiver load: the native channel advertised all three objects, but no cached-peer race ran. An incoming connection can deliver HAVE before the holder's next presence supplies its framing-2 capability. The ordinary zero-budget HTTP fallback then legitimately hashes its accounting key before starting the HTTP loader. Current main's fixture requires framing-2 presence from the accepted peer's identity as well as connected/HAVE readiness. It withholds actual signed presence frames while allowing real SDP and native SCTP through, asserts that HAVE alone is insufficient, then releases those unchanged frames and runs the original three-load assertions. The old readiness predicate fails this control; the corrected fixture passes two verified 6 MiB peer wins, one HTTP win and same-connection reuse. Failures now retain the offending load, HTTP/hash order, eligibility diagnostics and loader trace. See the [local evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/cached-race-readiness-20261024.json). This changes test readiness, not the loader, wire protocol, core or immutable v0.4.2 release assets. The original CI logs lack per-load diagnostics, so their missing prerequisite cannot be read back directly from those logs. ## Integrated library release (24 October 2026) v0.4.0 integrates holder recovery with Rust/WASM/native discovery, accepted connection snapshots and verified-media observations, partial-progress retention, reliable-channel cancellation draining and first-healthy-relay recovery. Native real-time source support added after v0.3.0 is included. No public service or pilot deployment is part of this library release. Operators choose media, relays, upload consent and transport policy. The old JavaScript R70 qualifier at `20693ea` passed 15 of 16 gates: in-place renewal failed, with a thin high-quality delivery margin. Those historical results are retained. The integrated source has not rerun that distributed profile. Physical devices, public NAT, sustained quality and net benefit remain unproved; local/CI regressions do not close those gates. ## Shared-core release checkpoint (24 October 2026) PRs [14](https://github.com/forgesworn/relayswarm/pull/14), [15](https://github.com/forgesworn/relayswarm/pull/15), [16](https://github.com/forgesworn/relayswarm/pull/16), [17](https://github.com/forgesworn/relayswarm/pull/17), [18](https://github.com/forgesworn/relayswarm/pull/18) and [19](https://github.com/forgesworn/relayswarm/pull/19) merged after their required CI jobs passed. Integration also advances the peer link's wall clock with the loader's virtual clock in the deadline regression; both pinned outcomes pass without loosening byte accounting or deadline assertions. The hint regression holds commitment delivery until its idle-HAVE snapshot has been observed, so key-resolution timing cannot make the holder busy first. Native packaging's [dispatch dry run](https://github.com/forgesworn/relayswarm/actions/runs/40051822407) built and verified both platforms on its packaging PR source; attachment was skipped. Release downloads carry the actual tagged source commit in their metadata. The packaging guide describes exact-source verification; a dry run is not tagged-release or physical-device evidence. The core, multi-holder path and peer supply hint remain opt-in. The hint is advisory and reports known HAVE supply. Signature checks remain in the core following the [measured comparison](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/CORE-SIGNATURE-BUDGET.md). The scheduler keeps the 32 KiB/s floor and three-holder default. RelaySwarmKit v0.6.0 adopts the released core for verification, framing and explicit schema-3 scheduling. A separate native application and physical-device/public-NAT acceptance remain open. Publishing the libraries does not deploy or qualify a pilot. ## Swift core adoption (24 October 2026) [Kit v0.6.0](https://github.com/forgesworn/relayswarm-kit/releases/tag/v0.6.0) consumes the v0.3.0 XCFramework by URL/checksum and retains its unedited UniFFI wrapper and exact 140 verifier vectors and 48 link traces. Swift retains the application's author/admission gates, exclusive channel ownership, timers, cancellation and host-supplied origin policy. Native buffered amount and low-water callbacks pace opt-in uploads; no synthetic empty queue is used. The 54-test Kit suite passes with one opt-in public-relay test skipped. It includes a real 3 MiB ranged upload over multiple native queue windows, corrupt holder bans, exact origin ranges, final trust checks and joined cancellation. The current-SDK Chrome fixture covers both schema-2 whole-object reception and schema-3 two-holder assembly. Author/delegate cases deliver verified generated H.264/AAC fMP4 bytes. Corruption, signature tampering and both pre-request and in-flight revocation return zero media. No Swift wire adapter is used. The piece fixture labels its controlled timing estimates; they are not measured network rates. CI pins the SDK source and retains receipts with source hashes. This is macOS arm64/Chrome loopback evidence. It does not prove physical Apple devices, public NAT, sustained field quality or net hosting benefit. Kit's transport binary remains macOS arm64 only despite the core's iOS slices. RelaySwarm and Kit are libraries and require no ForgeSworn-hosted backend. Applications supply their own media, relays and policy. Test fixtures are temporary loopback listeners; no public pilot is required or deployed here. ## Experimental core supply hint, 24 October 2026 The next-source loader has an opt-in `peerSupplyHint` advisory command through WASM and UniFFI. It reports eligible linked HAVE holders and estimated peer-plus-origin completion duration per rendition's next segment, without assigning a player level. Hosts may use it only to break ties between origin-sustainable levels. Discovery retains one playing context per media type; target-rendition preparation is not implemented. Unknown sizes or timing remain explicit. Shared Rust/WASM replay and loader on/off tests exercise the contract; physical devices, public NAT and field acceptance remain open. See [integration details](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#experimental-peer-supply-hint). ## Silent-holder deadline classification, 24 October 2026 The silent-holder regression now pins two timer orders using virtual time. The loader registers its floor timer before issuing link requests. At an integer clock time it cancels the silent request at the floor (`abort`). With a fractional start, the link truncates its remaining duration separately from the transfer's floored absolute deadline; the link can time out one millisecond earlier (`timeout`). Both paths preserve verified delivery, origin fallback, source accounting and zero early-abandonment charges. Origin take-back adds verified deliveries and re-arms the transfer timer as work moves. Those extra callbacks can change timer registration phases under host load; the relative frequency of either ending is not a scheduler invariant. The two deadline contracts are unchanged. The regression asserts the request outcome and trace ordering/timestamps for each phase, advancing `Date.now()` with `performance.now()` and timers so the core link and loader share the controlled clock. This is an in-process clock/ordering check, not a field timing or physical-device result. ## Current delivery checkpoint Checkpoint: 21 October 2026. [PR 9](https://github.com/forgesworn/relayswarm/pull/9) merged as `1d54538`, which is published as experimental prerelease [v0.2.1](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.1) and deployed to the pilot. Its loader change is `140c256`: it adds local holder labels to the peer diagnostics (`368b860`) and stops a linked holder that is never ahead from suppressing neighbour discovery. Most field results below were measured on the `140c256` deployment of the same loader; P06 at 6 MB and the short qualifiers R67 and R68 ran on the deployed `1d54538`. v0.2.1 is released by owner decision while field acceptance remains open: Item 5, P06, Safari 17.6 and v0.2.1's own short qualifier R68 are RED. **Passed on this source.** - All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/39529800310) succeeded. Attempt 2 reran only the hls.js playback job, after the runner's Chrome install hit an apt 403 before any test step. - Fresh consumption of the exact committed source (not downloaded release assets) passed with 286 package members. The served client is 787,462 bytes. The release merge commit `1d54538` passed its own fresh consumption with 287 members (one added evidence file) and builds the same client. - Guarded deployment to the pilot passed its independent deployment review. After P07 the pilot app was `38eb5c2d`, started 02:59:29 UTC. The release merge commit `1d54538` was then deployed through the same guarded cycle and passed its own independent deployment review: the pilot app is `ce410033`, started 14:56:56 UTC, with reporting and forwarding off. Its runtime differs from `140c256` only in the `package.json` and `package-lock.json` version fields, and it serves the same client. - P05 reporting lifecycle passed, with natural expiry after 303,923 ms. P07 parent-crash recovery passed, with an independent native review. - **Fourteen-role short qualifier R66 is GREEN, 16 of 16 gates**, including `each4BothQualityPeer` and `all8ActuallyUploaded`. This is the first green fourteen-role qualifier. It ran 302.823 s with contributors at 1,250,000 B/s, relay-only TURN over TLS/TCP and no VPN tunnel carrying the default route. It passed `each4BothQualityPeer` by one high-quality peer segment (receiver-1 received exactly one after switching to high), so it is a narrow pass, not repeatable evidence. R68 on the deployed v0.2.1 did not repeat it (below). - Desktop installed-browser journeys passed for Firefox 152.0.6 on one Mac and Safari 26.6.2 on another (all six checkpoints each: verified receive, quality and seek, explicit upload, reload retains usage without consent, origin-only kill). The Safari 26.6.2 pass is the first Safari pass. Scope is macOS arm64 desktop with one dedicated 1,800 s finite source and three owned Chrome 155 actors per browser; it is not physical-device, hard-NAT or separate-network evidence. - Finite-source cleanup reviews for the P06 and desktop sources passed. **Matched wire and cost (R66, 302 s window, two origin-only baseline roles).** Receivers used 31.5% less origin traffic than their matched baselines (185.9 MB against 271.2 MB, model error about ±4%). The origin served about 226 MB less than all-origin delivery. TURN runs on a separate host, which carried about 319 MB egress (280 to 365 MB, endpoint-side estimate) and about 323 MB ingress, so total egress across both hosts rose by roughly 85 to 100 MB. Marginal cost on the hosts' plans is not determined because the plan terms are not recorded. Nostr signalling bytes were not separable. **RED or open.** - **Item 5, the sustained 7,200 s run (22 churn events, natural TURN expiry and renewal), is RED and stopped by decision.** R37 failed at the first churn event on a harness assertion about retained renewals, which was fixed. R38 failed after 640,110 ms of measurement on a harness race: `rejoin()` read the page 7 ms after clicking Start, before the page applied its settings (diagnosis confidence high). A fix that waits for the applied state, as the setup path does, is prepared but has not run. The long run requires a GREEN matching short qualifier on the deployed source, and none exists on `1d54538`. R67 stopped at controller binding before any browser started, because the harness preparation still pinned the 0.2.0 `package-lock.json` hash: a harness defect with no product evidence. R68 is RED (next item). The 7,200 s run has not completed on any source. - **The fourteen-role short qualifier on the deployed v0.2.1 (R68) is RED, 15 of 16 gates.** It completed 303.088 s of measurement. `each4BothQualityPeer` failed because receiver-1 and receiver-2, which switch from low to high quality about 150 s in, then received no high-quality segment from a peer: every high transfer was declined as projected to arrive late or missed its deadline, and the origin served their high phase. The runtime is identical to R66's apart from the version fields. An independent diagnosis (high confidence on the mechanism, low on the trigger) found a product mechanism with a one-segment margin, tipped over by origin media fetches 1.5 to 2 times slower than in R66. The late-arrival projection uses the viewer's own origin latency as the holder wait, so each origin fallback raises the next estimate; there is no back-off; high-quality segments of about 670 KB over the relay are abandoned at the deadline; and a spent neighbour replacement resets only after a verified high-quality segment. Verified peer bytes were 138.6 MB, against 225.9 MB in R66. These are findings, not fixes. R68 was not re-run, by decision. - **P06, the 3 MB both-quality shared-cap lifecycle, is RED and open** (`RED_HIGH_QUALITY_NO_VERIFIED_COMPLETION_BEFORE_SHARED_CAP_REFUSAL`, the same class as the a416f7e third run). Low-quality verified peer media reached the receiver (216,952 B at 9.75 s). Three 720p reservations (659,128, 673,604 and 659,692 B) were accepted and charged, but none completed as verified peer media within the receiver's buffer-safe wait on the relay path (about 255 KB/s on the best link). The fourth (661,948 B) was refused as exhausted at 2,625,232 of 3,000,000 B, and the only high-quality holder stopped. The shared allowance behaved as documented in [Account upload budget](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md): the client reserves its full payload before sending, and an accepted reservation stays charged after cancellation. This is a design limitation under relay throughput, one high-quality holder and a 3 MB cap, not a recorded product defect. It is recorded RED and open. The owner then raised the starting allowance to 6 MB for one run on the deployed `1d54538`: high-quality peer media from the shared account completed (seven of eight 720p reservations verified, 4,689,096 B), but the lifecycle stayed RED at natural exhaustion (`RED_LOCAL_SESSION_CAP_BELOW_SEGMENT_NO_ACCOUNT_REFUSAL`). Each uploading page takes the smaller of its local allowance and the account's remaining allowance when uploading is applied, and refuses locally once a segment exceeds its own remainder, so the account never received the request it would have refused. A different cap cannot reach that stage; P06 is stopped by decision. - **Safari 17.6 on the desktop is RED.** No verified peer download within 45 s and no selected ICE candidate pair was recorded; every fragment came from the origin. The cause is not determined and the journey was not retried. - Physical iPhone (unavailable), physical Android and device Safari or Firefox (these need the owner), hard NAT and a separate network (these need another network) remain open and unverified. npm publication is out of scope. - Release: v0.2.1 is published as an experimental prerelease by owner decision while field acceptance remains open: Item 5, P06, Safari 17.6 and the v0.2.1 short qualifier R68 are RED. See [Release verification](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#release-verification). Run-by-run evidence is in [Goals and agent handover](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/AGENT-GOALS.md). See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/140c256-current-delivery-checkpoint-20261021.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Previous checkpoint: 20 October 2026 (5f2ece0) Checkpoint: 20 October 2026. The pilot runs `5f2ece0bc8e0a78e9a7eca5c56f5ca9141df4669`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/39384666332), fresh consumption of 284 package members, guarded deployment and its independent review passed, followed by reporting lifecycle acceptance (P05) and parent-crash recovery (P07 r5). The fourteen-role qualifier is RED from R62 to R65: R65 completed its 300-second measurement with 14 of 16 gates, failing `each4BothQualityPeer` and `all8ActuallyUploaded`. A one-link probe through the pilot's TURN service, with no qualifier load, moved high-quality segments at 3 to 4 Mbit/s over TLS; UDP relay addresses were no faster and lost more. Run-by-run evidence is in [Goals and agent handover](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/AGENT-GOALS.md). Earlier checkpoint: 19 October 2026. The pilot runs `3f706a9bc4a895d17345be26b77006cf13093c46`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/39169937465), fresh consumption of 280 package members and guarded deployment passed. The 773,458-byte browser client is unchanged. Nostr allowances are enabled; the host-supplied account API is implemented, with no website resolver configured. Reporting and forwarding remain off. **Durable reporting acceptance passed.** A real browser remained silent before opt-in, sent an accepted report after trusted user input, and handled duplicate reports idempotently. A same-volume restart preserved the report and policy; the report then expired naturally after 304.105 seconds. No clock or retention override was used. Reporting was restored to off, and browser and finite-source cleanup passed independent review. This closes the current P05 reporting check; it does not qualify the remaining load or device requirements. **Crash-recovery acceptance remains RED.** The latest test passed the parent-only crash, strict writer audit, guarded marker recovery and server restart. Publisher state, all four permanent leases and the original restart policy were preserved. Browser playback did not recover: six playlist HTTP 502 responses exhausted hls.js's retry budget before the server became healthy. The fatal network error remains in the receipt. No post-restart decoded progress was proved. Owned browser and verification-source cleanup passed; the failed acceptance window was not extended. An existing browser regression also reproduces the failure against the unchanged source with a 35-second HTTP 503 outage: playback stays at the same frame count after service returns. The retry correction and a separately reproduced origin-only admission-epoch correction are being verified. The specific reason the actual crash test lost its current swarm report remains unproved. See the [latest recovery checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3f706a9-parent-crash-recovery-checkpoint-20261019.json). The fourteen-viewer short qualifier has not passed. R55 stopped during setup; the earlier R54 both-quality peer-coverage failure remains unresolved on the current field configuration. The two-hour/churn/TURN-expiry run remains ineligible. After an earlier outage, a bounded M4 connection check at 23:15 UTC on 18 October succeeded. Fresh resource and runtime checks remain required; other work must keep running. P01–P12 source surfaces are implemented; production acceptance and release remain incomplete. The remaining work is crash/restart acceptance, matching short and sustained qualification, both-quality shared-budget lifecycle, browser/device/network coverage, matched bandwidth benefit and final release checks. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3f706a9-current-delivery-checkpoint-20261019.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical a02d5ec checkpoint Checkpoint: 18 October 2026. The experimental pilot runs `a02d5ec4d5408c8c196e0c259d07c7fc68e965d6`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/39160708033), fresh consumption of 278 package members and guarded HTTPS deployment passed. The 773,458-byte browser client matched its image. Private state, permanent leases and the independent proxy were preserved. Nostr account allowances are enabled; the authenticated host-supplied account API is implemented. Reporting and forwarding remain off. **The short qualifier remains unproved.** R55 stopped during setup at its sixth browser navigation, before any measurement. Its six acquired contexts and owned source, processes and temporary files passed independent cleanup review. This supplies no fourteen-viewer or 300-second qualification. M4 subsequently became unreachable from this Mac, so distributed checks remain pending while other work continues. **Durable reporting acceptance also remains RED.** A later single-browser test ran for 85.580 s. Playback progressed and the server enabled reporting, but the browser refused the changed telemetry setting at the unchanged policy revision. The reporting opt-in control stayed disabled and no report request was sent. Restart durability and natural five-minute expiry were not reached. Reporting was restored to off; full browser and finite-source cleanup passed independent review. The server's persisted policy revision needs to include startup telemetry changes; the browser's conflict and consent checks remain required. The source correction persists the telemetry setting and advances its policy revision before serving a changed setting. Focused operator and bundled-client regressions pass, including migration, malformed-state preservation and consent ([local results](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/operator-policy-revision-20261018.json)). CI, deployment and the reporting acceptance rerun remain pending for that fix. P01–P12 source surfaces are implemented; production acceptance and release remain incomplete. Matching short qualification, two-hour/churn/natural expiry, both-quality account lifecycle, durable reports and crash recovery, browser/device/network breadth, matched wire/cost benefit and final release/download checks remain open. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/a02d5ec-current-delivery-checkpoint-20261018.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical 3515d5b delivery checkpoint Checkpoint: 18 October 2026. The experimental pilot runs exact `3515d5b0acad4d18811ed08e4d9f7648781e55cf`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/39157143848), fresh consumption of 277 package members and guarded HTTPS deployment passed. The 773,254-byte browser client matched its image. Private state, permanent leases and the independent proxy were preserved. Nostr account allowances are enabled; the authenticated host-supplied account API is implemented. Reporting and forwarding remain off. **R54 remains RED after 303.647 s of measurement.** Fifteen of sixteen gates passed: all fourteen viewers progressed video and audio, all eight contributors uploaded, both qualities decoded, and consent, resources, in-place renewal and all admission checks passed. The requirement for every receiver to obtain verified peer media at both qualities failed: receiver 2 had no measured LOW peer bytes; receiver 3 had no measured HIGH peer bytes. The successful elapsed window does not supply strict qualification. The two-hour run remains ineligible. The deployed demo explicitly selects four neighbours; the SDK default stays six. Provider observations recorded zero admission refusals and a peak of 731 calls per aligned minute against the selected 900-request address budget. This is a healthy measured run, not proof of six-neighbour capacity or the individual effect of replay dropping versus the changed profile. The original fourteen-viewer, eight-contributor, every-receiver both-quality and resource requirements remain unchanged. The complete receiver request tails reconcile with all cumulative outcome counters. Receiver 2 made no LOW request, with 88 `no-have-no-wait` observations. Receiver 3 recorded 34 HIGH timeouts, 27 with partial bodies; its only HIGH completion occurred before measurement. Upload refusals were exclusively token-bucket rate refusals. These observations do not identify a specific network, queue, CPU or receiver-to-uploader cause. All fourteen contexts and the owned processes, profiles, stages and finite source passed independent cleanup review. The public pilot, router and proxy remain running intentionally. Other work on the Macs remains untouched. A later local correction lets an admitted discovery caller advise the exact requested key to a full serving peer. It permits the same bounded idle replacement when the peer holds that key, without changing admission, consent, rotation or connection limits. A two-swarm regression fails on the original source and passes after the correction; malformed advice and serving withdrawal during admission are refused. All 196 combined loader, discovery and receiver tests pass. This is separate from R54: neither its precise cause nor a field repair is established. The correction still requires CI and deployment. P01–P12 source surfaces are implemented; production acceptance and release remain incomplete. Matching short qualification, two-hour/churn/natural expiry, both-quality account lifecycle, durable reports and crash recovery, browser/device/network breadth, matched wire/cost benefit and final release/download checks remain open. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3515d5b-current-delivery-checkpoint-20261018.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical c0f337d delivery checkpoint Checkpoint: 18 October 2026. The experimental pilot runs exact `c0f337d0fe0439c64b05aed847e9d49ee4350e15`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/39152159082), fresh consumption of 276 package members and guarded HTTPS deployment passed. The 772,551-byte client matched its image. The selected relay-only TLS/TCP TURN configuration and admission budgets remain unchanged. Nostr account allowances are enabled; the authenticated host-supplied account API is implemented. Reporting and forwarding remain off. Private state, permanent leases and the independent proxy were preserved. **Neither field run passed.** R52 stopped after 156.325 s when its resource monitor rejected a timestamp as future. All fourteen viewers had progressed video and audio; this partial run grants no full qualification. A separate controlled regression reproduced fractional-versus-integer millisecond comparison failure. The corrected monitor passes eight checks while retaining the original freshness limits; the failing R52 clock values were not retained, so this does not establish its exact cause. R53, with the corrected monitor, stopped after 17.135 s of measurement on admission refusal. Browser records contain twelve HTTP 429 responses, with no public-observer unknown or capacity overflow. Provider counters show 900 accepted admission calls, then twelve refusals and a return to successful responses. This supports exhaustion of the configured 900-per-address 60-second budget; the server error body and exact bucket state were not retained. Both runs passed independent finite-source and browser cleanup. The full short qualifier has not passed, so the two-hour run remains ineligible. R52's new diagnostics recorded partial bytes in 84 of 94 HIGH receiver timeouts. LOW requests completed more often. Transport assembly, verified playback acceptance and wire costs remain separate; these observations do not establish a network cause or a performance repair. The local candidate drops already-seen offers before redundant host admission work, while retaining the checks after pending admission completes. It adds eleven fixed local counters for actual host callback sites. The settled-replay regression fails before the correction and passes afterwards; sixteen focused and all 194 combined loader, discovery and receiver tests pass. This does not establish how often R53 replayed offers or demonstrate a field repair. The local candidate selects four demo neighbours rather than the SDK default six. This is an explicit configuration change awaiting CI, deployment and field checks. The same fourteen-viewer, eight-contributor, every-receiver both-quality and resource requirements remain in force. It does not establish six-neighbour capacity or guarantee an admission-rate reduction. P01–P12 source surfaces are implemented; production acceptance and release remain incomplete. Both-quality account lifecycle, durable reporting, crash recovery, natural expiry/churn, browser/device/network breadth, matched wire/cost benefit and final release/download checks remain open. Other work on the Macs must keep running. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/c0f337d-current-delivery-checkpoint-20261018.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical 2911ea5 delivery checkpoint Checkpoint: 18 October 2026. The experimental pilot runs exact `2911ea55f1bd21335a979df8a3fd38ed83cc6bee`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/39148186931), fresh consumption of 275 package members and guarded HTTPS deployment passed. The 769,958-byte client matched its image. Relay-only ICE, TLS/TCP TURN, admission 32 and the selected 900-request address budget remain configured. Nostr account allowances are enabled; the authenticated host-supplied account API is implemented. Reporting and forwarding remain off. Private state, permanent leases and the independent proxy were preserved. **R51 remains RED after 306.350 s.** All fourteen roles progressed video and audio, all eight contributors uploaded, and in-place renewal, admission, reconciliation, recovery and resource checks passed. Only the requirement that each receiver obtain verified peer media at both qualities failed: receivers 1 and 2 obtained both; receiver 3 obtained only LOW; receiver 4 only HIGH. All owned contexts, processes, profiles, tunnels and the finite source passed independent cleanup review. Cleanup does not change the failed verdict. The matching short qualifier has not passed, so the two-hour run is ineligible. Receiver 3 saw positive HAVE and valid commitments without completing HIGH peer delivery. Its observed wait-to-HAVE median was 651 ms, leaving at most 849 ms of the initial 1,500 ms budget before further work. Receiver 4 recorded 80 LOW decisions with no eligible neighbour; its bounded replacement dial was rejected. Precise transfer/refusal and network causes remain unproved. Later local source changes add bounded request-outcome and upload-refusal diagnostics and correct a separate allocation inconsistency: alternatives already excluded by the selector's measured deadline-fit rule reserve no time from a cold peer. A controlled 670 kB delivery at 1,470 ms fails before the correction and passes afterwards within the unchanged 1,500 ms deadline. All 187 combined loader, discovery and receiver tests pass. These changes are not deployed or field-qualified at this checkpoint and do not prove an R51 fix. The P01–P12 source surfaces are implemented; production acceptance and the 0.2.0 release remain incomplete. Both-quality account lifecycle, durable reporting, crash recovery, natural expiry/churn, browser/device breadth, difficult networks, matched wire/cost benefit and downloaded-release checks remain open at their declared evidence gates. Other work on the Macs must keep running; the test resource limits remain unchanged. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/2911ea5-current-delivery-checkpoint-20261018.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical 44b21d6 delivery checkpoint Checkpoint: 16 October 2026. The experimental pilot runs exact `44b21d69dd924fea648c2dc214df02dafa8e690c`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38859102559), fresh consumption of 273 package members and guarded deployment passed. Normal HTTPS matched the 769,303-byte client to the candidate image and read both fresh playlists. Relay-only ICE, TLS/TCP TURN projection, admission 32 and the explicitly selected 900-request address budget are deployed. The default request budget remains 600 and the global capacity 2,048. Private publisher/account state, permanent lease identities and the independent EE proxy were preserved. Reporting and forwarding remain off. Verification-source cleanup and a fresh independent server review passed; actual source exit 255 is retained. Bounded rendition-neighbour discovery and cold-peer deadline allocation are deployed. The latter preserves useful time for an unmeasured peer while keeping the existing total deadline and bounded alternatives. Its original-source regression fails; five focused checks and all 160 swarm tests pass. These local checks do not establish the cause or repair of an earlier field failure. **R30 remains RED, with 36,188 ms measured.** All fourteen roles started; setup observed 64 connected links and 1,323,896 verified peer bytes globally. The failing contributor recorded an unplanned origin-only interval lasting 82 ms before peer-first recovered. Recovery does not satisfy uninterrupted authority. The same page recorded a session request taking 5,146 ms; retained network observations include a five-second cancellation without headers and later connection-pool delay. Their timing fits expiry before a subsequent renewal completed, but exact clock/request joins and the downstream cause remain unproved. Final admission coverage, reconciliation and caller-abort recovery checks passed. All fourteen contexts, owned processes, profiles, tunnels and the finite source passed independent cleanup review. The defined P01–P12 feature surfaces are implemented. Nostr and an authenticated host-supplied account API are supported; the Nostr-only pilot is valid. Prior account API, focused LOW lifecycle, native iOS Simulator and Internet TURN component passes retain their original revisions and limits. The historical full-window R28 still failed both-quality coverage for two receivers; R29 stopped at 117.240 s. Neither is a matching successful qualifier for this build. The matched-cost comparison remains inconclusive; payload counters do not establish wire or bill savings. No matching full 300 s, 7,200 s/22-churn or natural expiry acceptance exists. The longer run is ineligible until the short qualifier and its cleanup pass. Physical/browser breadth, difficult networks, matched wire/cost benefit and final release/download acceptance remain open. PR 8 remains open; v0.1.0 is published and 0.2.0 remains the source candidate. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/44b21d6-current-delivery-checkpoint-20261016.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical afbf052 delivery checkpoint Checkpoint: 16 October 2026. The experimental pilot runs exact `afbf052df93d6b4902703dddb4b5987ec6119e6e`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38821621670), fresh consumption of 271 package members and guarded HTTPS deployment passed. The 762,188-byte browser client remains byte-identical to 18bb; the runtime change reclaims settled TURN viewer entries after lease expiry or failed initial issuance. Fresh leases and unresolved issuance retain their slots. Two original-source regressions fail; the corrected service passes 16 tests, and 49 combined TURN checks pass. Private state, permanent account/publisher leases and the independent EE proxy were preserved. The temporary verification source was removed, retaining its actual exit 255; independent cleanup passed. The defined P01–P12 feature surfaces are implemented. Both Nostr and an authenticated host-supplied account API are supported; the Nostr-only pilot is valid. Prior account API, focused LOW lifecycle, native iOS Simulator and Internet TURN component passes retain their original source and scope. The 18bb Internet cohort remains historical component evidence for this source. **R20 remains RED, with 0 ms measured.** All fourteen contexts were acquired, and all twelve intended peer participants had peer-first mode and available TURN in their latest preflight snapshots. Subsequent control failures stopped setup: 37 admission verifies returned HTTP 429 before cleanup, 38 finally, and two requests failed. Delayed session bodies align with policy expiry and an OFF session for receiver 3; a separate HTTP 200 verify body did not complete before its three-second abort. Policy-expiry attribution is a supported timing inference, not an exact cancellation-hook join. All fourteen contexts and owned processes/profiles/stages/source passed independent cleanup review. Offline replay of the unchanged admission counter reproduces exactly 600 accepted requests and 37 address-budget refusals from 637 calls in one window. Caddy presents one backend socket address; forwarded IP headers are not trusted. This exposes the shared 600-per-minute address budget, while the global budget remains 2,048. Adding startup spacing alone does not establish a repair: even optimistic timing counterfactuals retain refusals. The source candidate exposes operator configuration of the existing address-request limit: 16 CLI checks and four admission tests pass, default 600 is retained, and a measured-cohort pilot setting of 900 is planned. New configuration CI, deployment and field evidence remain required. A separate idle control-path check completed 48 ordinary HTTP/1.1 requests across both Macs, server public HTTPS and server loopback. All returned 200; maximum observed body times were 1.9/11.7/0.9/2.0 ms respectively. These fresh connections do not reproduce the loaded browser delays or establish a cause. No matching full 300 s, 7,200 s/22-churn or natural expiry acceptance exists. Physical/browser breadth, difficult networks, matched wire/cost benefit and immutable release/download acceptance remain open. PR 8 remains open; v0.1.0 is published and 0.2.0 remains the source candidate. R13–R20 retain their original RED verdicts and declared contracts. Automatic surviving-guardian worker drain is implemented; guardian/host catastrophe requires inspection. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/afbf052-current-delivery-checkpoint-20261016.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical a416f7e delivery checkpoint The experimental pilot runs exact `a416f7e1ee2d73acc6535b313baac018f2baab8a`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38775128822) and fresh offline consumption of 269 exact-source package members passed. The installed CLI, eleven imports, durable ledger and native/HTTP fallback pass. The consumer resolves the declared production dependency ranges; the separate standalone ESM is bound to the root lock. Normal HTTPS attestation matched the 761,854-byte client, SHA-256 `570f12f862e9d8609c8d8f207abbc5a22346f4ed7fde0d099fc256244507d671`, from image `sha256:cf44c19870338976f0a0bfd6e1bc22ca177f54ca6b6d4418bbafc5755349bcda`. Relay-only ICE, TLS/TCP TURN selection, admission 32 and Nostr account budgets are configured; reporting and forwarding are off. Private state, permanent leases and the independent EE proxy survived deployment. Verification-source cleanup passed all five guards, retaining actual exit **255**. The selected account scope is **Nostr plus an authenticated host-supplied resolver API**. No named external website or human-wallet integration is a required feature; the Nostr-only pilot is valid. The public cross-Mac account API trial passed the shared cap, overlapping client reservations, replay, conflict, reopen and grant fencing with a disposable owner. Client overlap does not prove simultaneous server arrival. Its final limit was zero/spent 100; the disposable ledger row is intentionally retained. The focused LOW browser lifecycle passed all seven component gates in **74.412 s**: one verified low fragment/213,756 bytes and a real M1 production reservation; actual reload with a new page key, retained local/shared spend and upload still off after reconnect; fresh trusted Apply followed by a new 206,424-byte reservation; M4 active serving-state Disconnect; and LAST UI 10 MB/reset:false Settings with no subsequent fixture resume. All four contexts, exchanges, CDP, endpoint profiles and source cleanup passed. The final real zero-cap/logout retained spent 1,901,244 and cleared owned key buffers. This is not high-quality delivery, identified in-flight cancellation or the original both-quality/exhaustion acceptance. That original 3 MB trial remains RED: both donors accepted serving, but no high fragment completed verification before natural shared-cap refusal. Its later lifecycle gates were unmeasured. Native iOS 26.5 Simulator Safari passed trusted Start, Home/return and Resume, with advancing video clock/pixels and frame deltas 59/61, zero fatal/native/page errors and upload/report consents off. Cleanup and all 38 pre-existing Simulator states passed independent review. Return was still playing (`paused: false`), so the physical stopped-video fault was **not reproduced**. Physical-device, audible-audio, public-peer and enabled-upload-withdrawal acceptance remain separate. The original 4+10 R10 capacity attempt remains RED at 33 observed processes against M1's unchanged cap of 32, before measurement; its original M4 receipt-read failure and later fenced recovery remain separate. The new 3+11 R12 attempt started all fourteen roles but measured only **97.691 s** before an observed runtime admission refusal. Resource/shared-reader gates and all owned cleanup passed; the underlying cause is unproved. The source now retains a bounded replacement admission ticket and validates it before a new dial, preserving later candidates across earlier validation. The original source failed the maintained cooldown-renewal regression; the corrected source passed all 12 focused regressions and all 137 swarm tests. This local correction has no new CI or deployment proof and has not been established as the R12 cause. No matching 300 s or 7,200 s/22-churn acceptance exists. Historical 533 short public/Internet passes below retain their exact revision and do not become new a416 cohorts. See the [current checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/a416f7e-current-delivery-checkpoint-20261015.json) for exact evidence hashes. The full [P01–P12 requirements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist) and 37-review-item scope remain open: complete both-quality/shared-budget and physical/browser coverage, difficult networks, natural expiry, matching capacity and sustained/churn operation, matched wire/cost benefit and immutable release acceptance. PR 8 remains open; v0.1.0 is the published prerelease and 0.2.0 the source candidate. No completed separate 37-row ledger is claimed. ## Historical 5334091 delivery checkpoint The experimental pilot runs exact `53340911d3bb973fb392c1bad1f8f72aec2aa8bd`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38741613596) and fresh offline consumption of 267 exact-source package members passed. Guarded deployment served the 759,084-byte client, SHA-256 `ca2d08ad1c4c2459658d5a2d0a6e045bf5ff7b464491b0bd49180ca1cacdd6f0`, from image `sha256:9d911f23d618cc5f78f79b5817a119f6b38439938a356f60a717763258d787a4`. Relay-only ICE, TLS/TCP selection, admission 32 and Nostr account allowances remain configured; website authentication, reporting and forwarding are off. The ordinary public check passed all three original application gates over 60.034 s, independently replayed from retained samples. The receiver verified one low and one high fragment, 868,936 bytes total, or 5.8896% of its measured encoded media payload. All four players had zero observed fatal/native media errors or stalls. Twelve requests were accepted for serving; only two verified completions were proved. The other ten causes remain unknown. This is neither sustained reliability, a matched baseline benefit nor wire/cost savings. All owned cleanup passed. The separate genuine Internet TURN diagnostic passed 90.043 s/40 verified fragments; its first local lease was shortened to 60 s against real 3,600 s credentials, so natural expiry remains unproved. The latest fourteen-role attempt stopped after 24.522 s at the unchanged M1 32-process limit, with three players started and no measurement window. Its original M4 cleanup-receipt read failed; subsequent fenced recovery proved endpoint/profile cleanup, archived the owned stage and removed it after fresh absence checks. Original browser-context closure remains unknown. No matching 300 s capacity qualifier or two-hour/22-churn result exists. The cross-Mac account API diagnostic failed before reservations: M4 received a valid challenge but measured 30.016 s against the client's strict 30 s upper bound. A final zero-cap/spent-zero policy was observed; missing-token revocation remains unknown, while both actors exited and cleared their owned key buffers. The unreleased source corrects issuer-relative lifetime measurement without extending grant/delegation limits, and provides explicit media recovery after background suspension. Local regressions and a trusted-click Chrome check pass. The latter reloads media, proves decoded video/audio progress, retains errors and spend, and leaves both consents off; explicit Apply rejoins receive-only. This synthetic pause/reload check does not reproduce the physical Safari failure. These checks remain separate from deployment, real owner/website authentication, upload enforcement and iPhone acceptance. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/5334091-public-and-account-checkpoint-20261015.json). The complete [P01–P12 requirements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist) remain open, including sustained sharing, physical/Safari and hard-NAT checks, natural expiry, shared-account field acceptance, matched wire/cost evidence and immutable release/download checks. PR 8 remains open; v0.1.0 is still the only published prerelease. Historical failures below retain their original scope. ## Historical 3e52294 delivery checkpoint The experimental pilot runs exact `3e52294c2e1f44ab9cbed13adf43e94e995f1e2d`. All nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38701249959) and fresh offline consumption of 262 exact-source package members passed. The installed CLI/native HTTP fallback, durable ledger and rebuilt standalone ESM checks retain their own scope; hosted browser checks are injected headless loopback evidence, not ordinary public or physical acceptance. Guarded deployment and normal HTTPS attestation passed. The image is `sha256:2e20d5dd2eb96f7505d03c3b018565e5756d27941b1ea5c5396d1206c95751ea`; the served client is 757,269 bytes, SHA-256 `b561859c7b1b5167a5843d41569d0309915773a1c8dc91f7b1732cf138c35882`. The attestation matched image/client/identity and read two fresh HLS playlists. Exact deployed options are `--ice-transport-policy relay`, `--turn-url-projection tls-tcp` and `--admission-per-address-tickets 32`, alongside the existing server-owned issuer. Nostr account allowances are enabled; the website account resolver remains unconfigured. Reporting and forwarding stay off. Private state and permanent lease/token identities survived the orderly drain; account JSON atomic replacement is allowed. The temporary source was removed under all five cleanup-v2 guards, retaining its actual exit code **255**. Admission 32 is configuration evidence, not fourteen-role capacity acceptance. The separate `selected-send-and-resolved-transport-v1` Internet renewal cohort passed 90.031 s/88 samples: 40 verified fragments/4,631,756 bytes, including 23 fragments/2,656,252 bytes after the renewed transport boundary. Independent replay also passes the unchanged original strict state machine on this same cohort (initial 7.298 s, boundary 40.059 s, final 90.031 s). Two local isolated headless Chrome pages used prepared synthetic HLS/local rendezvous and genuine Internet TURN. Three genuine issuances had 3,600 s leases; the first local lease was shortened to 60 s. The rebuilt 127,516-byte diagnostic candidate is distinct from the exact standalone ESM. All seven worker/six supervisor cleanup flags and fresh three-group/scratch absence checks passed. This is not a journey against the deployed pilot, natural expiry or exact ingress attribution. Earlier intermittent timeouts remain unexplained; no product repair or browser bug is inferred, and previous RED cohorts remain RED. **Ordinary public peer delivery remains RED.** The latest 60.038 s measured four-role journey passed frame/audio decoding at both requested qualities and contribution, with no fatal/native media errors or stalls. The receiver verified zero peer fragments/bytes. Seven matching-HAVE requests reached valid metadata and partial payload, but no EOF was observed before channel closure; six product timeout closures and one abort were recorded separately. Their exact native-to- product reason correlation and underlying send-queue/network cause remain unproved. Donors accepted 633,184 low and 2,685,768 high bytes for serving; these are not completed network delivery. All four contexts, both CDP connections, owned worker/group/helper, endpoint resources/stages and source cleanup passed. The actual source exit was 255. M1 peaked at 39 processes under this check's 64-process cap; this does not qualify the long scenario's 32-process cap. The [public result summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3e52294-ordinary-public-20261015.json) retains exact evidence hashes and limits. Earlier preparation refusals, native monitor failures and historical exact-54 delivery/cleanup failures remain separate retained results. Exact retained provenance is in `deployment-3e52294-directional-proof-bound-20261015/ROOT-DEPLOYMENT-EVIDENCE-MANIFEST.json`, `existing-turn-renewal-3e52294-directional-r5-run-20261015` and `public-cross-hls-eligibility-3e52294-seventh-root-20261015` under `artifacts/`. Deployment, forced-renewal cohort and ordinary public delivery are separate proof classes. The full [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist) and 37-review-item scope remain open; no separate completed 37-row ledger is claimed. Ordinary public peer delivery, complete physical/Safari journeys, hard NAT, website resolver integration, natural expiry/reconnection, cross-device budget field evidence, fourteen-role capacity, 7,200 s/22-churn operation, matched wire/cost benefit and immutable release/download acceptance remain outstanding. v0.1.0 remains the published release; 0.2.0 is the source candidate. Package 0.2.0, session wire 3, commitment schemas 1/2 and metrics 2 are distinct. The original CLI signs plaintext SDP; the browser loader uses pairwise NIP-44 signalling. Deployment does not close final production or release acceptance. ## Connection reuse and lease observations included in 5334091 The branch adds bounded draining of an abandoned response on known ordered, fully reliable peer channels. The request still resolves promptly; the link remains busy until a validated terminal response or the existing drain timeout. Signed verification, wire framing and playback/fallback deadlines are unchanged. Redacted TURN lease provenance and a passive three-scalar getter support later natural-renewal observation without fetching credentials or granting freshness. All 170 focused maintained-source checks pass, including 12 new framing/drain cases and 33 lease-observation cases, with guarded cleanup and fresh worker-group absence. The [source-check summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/peer-link-response-drain-source-checks-20261015.json) retains exact file hashes. The later 5334091 CI, deployment and short ordinary public pass are recorded above. They do not establish causal improvement over the unchanged historical 3e failure or natural expiry from pure witnesses. ## Historical implementation and delivery checkpoints The following dated results retain their original source, topology, failures and limits. Their statements about then-current deployment or pending options do not describe the current pilot above. Later passes do not rewrite a RED. The optional TURN adapter now supports explicit `issued`/`tls-tcp` URL selection. It keeps the raw issued lease and expiry, selects TCP only for secure URLs whose transport was unspecified, and independently checks the projected client response. Selection changes require fresh Apply/upload consent. Invalid refreshed descriptors revoke the prior policy immediately, including at the same unexpired clock. Twenty-nine credential/service tests passed. The first focused run remained RED at two new initial-state assertions that misread the disabled optional adapter's availability flag. A test-only correction checks actual peer authority and the initially disabled Start button; all 52 demo-client tests then passed in 7.942 s. Runtime bytes were unchanged between runs, and all recorded outer cleanup checks passed within the original bounds. The [TURN URL checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/turn-url-projection-checks-20261015.json) retains both scopes. This option has no Internet allocation, deployment or public delivery qualification yet. The swarm, demo and broadcaster now expose explicit `all`/`relay` ICE candidate policy, defaulting to `all`. A changed policy stops peers, clears upload consent and fences an Apply awaiting old admission. Fourteen focused tests, syntax for 142 modules and documentation checks passed in 7.219 s within the unchanged 40/60 s guard. All five recorded outer cleanup checks passed. The [ICE policy checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/ice-transport-policy-checks-20261015.json) records that local scope. Relay-only does not force TLS or prove a delivery repair; the option has not been deployed or publicly qualified. Exact `e7330694dbcd7a16d5ac305dbde74f95162fbdc7` subsequently passed all nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38699590666) and fresh consumption of all 261 committed package members. Its hosted loopback broadcast receipt verified five peer loads/2,695,920 bytes across four checkpoints, including 842,804 bytes after restart. The two contributors each recorded one buffer stall and one console 404 was retained. These results predate the TURN URL selection above and do not establish ordinary public or physical acceptance. The latest worker shutdown correction refuses further TERM/KILL IPC after its first force request or an accepted drain witness. Two regressions reproduce EPIPE with the preceding source; all 21 focused lease/controller tests pass with the correction. The 6.645 s guarded run retained the original time and resource bounds, with all five recorded outer cleanup checks passing. Syntax for 142 modules passed separately. The earlier combined local suite remains RED: a 6 s playlist fixture timeout preceded the original 40 s work cutoff, and initial group absence failed. The confirmed remaining task TLS probe was subsequently stopped after fresh exact identity and fixture checks; its absence and group absence were then proved. This later recovery does not change the original result. The [stop-message correction checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/worker-stop-send-fence-checks-20261015.json) records the separate scopes; the focused pass is not a full-suite pass. Exact `f3eeef340213a009f7986f1d8d69073e7e0edda1` passed fresh 259-member package consumption. Its [CI run](https://github.com/forgesworn/relayswarm/actions/runs/38691157253) passed eight required jobs and failed the RTMPS capability guard's orderly close with `worker-group-probe` / `unknown`; the later broadcast browser step did not run. That hosted failure's cause remains unproved. Corrected-source CI and fresh package consumption subsequently passed on exact `91423b2e7eb1576f67265b64208023d565f8c5f8`: all nine required [jobs](https://github.com/forgesworn/relayswarm/actions/runs/38694780028) passed, and the clean consumer verified 260 package members. Its hosted loopback broadcast check verified six peer loads/3,298,836 bytes across four checkpoints, including 756,888 bytes after restart. Those results predate the new ICE option; they do not establish ordinary public delivery or final production acceptance. The broadcaster exposes `--admission-per-address-tickets` (1–120, default 12) for the existing per-socket-address quota. Viewers behind a proxy can share that address. The focused admission and broadcaster checks passed all 33 tests, with syntax for 142 modules, in a 28.445 s guarded run. Other quotas and ticket expiry retain their defaults. This option has not been deployed or qualified with fourteen viewers. Exact `54da3840a6a057d2112945b3b465704a030aac32` passed all nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38663487490), fresh 258-member package consumption and the complete 90.006 s forced-early Internet TURN renewal check. The receiver verified 40 fragments/4,632,696 bytes, including 23 fragments/2,654,936 bytes after the renewed transport boundary. Real credentials lasted 3,600 seconds; the first local lease was conservatively shortened to 60 seconds. This does not prove natural expiry or prolonged load. The experimental pilot now runs exact 54 with server-owned credentials from the existing TURN service. Normal HTTPS attestation matched the live client to the image and read both fresh HLS playlists. Identity and permanent leases matched; private budget files were retained across the orderly drain. The account JSON inode changed during an atomic write. The temporary source was stopped and removed with its actual exit code 255 retained. The subsequent ordinary four-role public check remains RED after 60.072 s. Playback and accepted contribution passed; the receiver verified zero peer loads/bytes at both qualities. Five matching-have opportunities reached five commitment requests and five request timeouts. Donor counters record accepted serves, not completed wire delivery. The original M4 cleanup failed its strict full-command comparison. Its same-read witness retained the Python launcher to runtime command-name change; later original-birth/group absence and owned-stage removal passed without signals. All task-owned actors and the finite source were then absent. No request-timeout cause or cleanup repair is claimed. A later response-phase diagnostic stopped before measurement when the unchanged 0.5 s ownership process probe timed out. It provides no new peer result. The M4 endpoint's ten cleanup flags passed with the direct kernel runtime; its original controller assertion remains separate from later actor/stage absence and source removal proof. A further diagnostic reached 50.513 s of the required 60 s before the unchanged 0.5 s group-membership probe timed out. Its application gates remain unmeasured; all original endpoint and outer cleanup checks passed. Three receiver responses had matching metadata but no matching EOF when JavaScript entered channel close: two had no chunks and one had 114,688 of 204,356 declared bytes. Product timeout, abort and channel-error counters are separate observations; native channel ordinals were not joined to product request reasons. This narrows the observed phase to incomplete responses without establishing a cause or a passing run. The [pilot and acceptance checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/pilot-turn-acceptance-20261015.json) records these separate scopes. Ordinary sharing, Safari/physical devices, natural expiry, sustained/churn, matched wire/cost and immutable release gates remain open. Earlier RED results remain unchanged. ## Historical correction checkpoint The broadcaster guardian now keeps a live wrapper as each worker's process-group leader. It commands that wrapper through its original IPC channel, avoiding TERM/KILL against a numeric group after the leader has been reaped. Unknown IPC or cleanup evidence retains the dirty fence. The four worker slots, 1,500 ms force timer and 5,000 ms drain deadline are unchanged; each occupied slot adds one Node wrapper. The reviewed source passed syntax for 142 modules and a combined publisher and broadcast-guard run: 305 passes, two platform skips and no failures or cancellations. Real-process cases cover parent termination, redirected descendants, exact 128 KiB output and inner exit code 19, followed by lease handoff. The 28.521 s run retained 27 resource samples, peaking at 1,293,959,168 bytes/22 processes with at least 40% free memory. Worker/group/birth and probe reaping passed; detached test-group and scratch absence are outside that outer guard's proof. The later exact-54 CI, package and pilot results are recorded above. The [worker correction checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/worker-live-group-checks-20261015.json) records the exact source and retained evidence. Natural TURN expiry, ordinary public peer delivery, Safari/physical journeys, sustained operation, immutable publication and final production acceptance remain open. ## Earlier watcher correction checkpoint The follow-up watcher correction filters named temporary/media-file events, covers all authorised playlist names and case aliases, and revalidates changed filename coverage within the unchanged three-pass bound. The native-client test fixture also closes acquired resources on partial setup failure. Native tests now emit TAP failure details; the real directory-replacement test retains a bounded categorical trace if it fails. Neither instrumentation identifies the earlier hosted failures' causes. One serial local qualification first reproduced the new noise regression's 503 against exact-1b watcher code, then passed syntax for 141 modules, all 29 native tests and 269 publisher tests with two platform skips. There were no corrected suite failures or cancellations. The outer run took 27.375 s within the original 40/60 s guard; 26 resource samples peaked at 1,368,113,152 bytes/20 processes with at least 47% free memory. Worker/group/birth and probe reaping passed. This does not establish detached-group/scratch absence, native Windows qualification or any remaining field gate. The [local correction checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/playlist-filter-and-native-fixture-checks-20261015.json) records the exact source and retained manifest. Exact `274cd4dd193047ddd606fa22cdfee2fe1b22e309` subsequently passed all nine required jobs in [CI 38659745211](https://github.com/forgesworn/relayswarm/actions/runs/38659745211) and fresh offline consumption of all 256 committed package members. That result predates the worker-wrapper correction above and does not qualify it. Exact `1b096a060abf5bc9bdadb320fa32243048522985` remains unreleased. [CI 38657013063](https://github.com/forgesworn/relayswarm/actions/runs/38657013063) finished with six required jobs passing, Windows failing the directory-replacement publisher test, macOS cancelled during native tests, and dependent live-relay checks skipped. Windows passed all 121 swarm tests; its publisher result was 222 passes, one failure and 43 platform skips. The macOS log records a failed HTTP-fallback test before cancellation, without a retained assertion or final test totals. Neither failure's native event chronology is established. Fresh offline consumption of exact 1b passes all 254 committed package members, the eleven imports, installed CLI/demo, durable ledger replay, separate-process native transfer/HTTP fallback and standalone browser ESM. The unpublished 1,150,413-byte tarball has SHA-256 `870580a268b7a32143341146f079a1bff550274a5edd0dccbbc5ae91c712f99d`; the 124,612-byte standalone ESM has SHA-256 `13291cbb1727d85144ddce6a4a2c49c0c2f0bc27e25bb54c2a7cf06fb22fb043`. The independent audit is retained in `artifacts/clean-consumer-1b096a0-diagnostics-preparation-20261014/analysis`. The instrumented real Chrome collision test on exact 1b remains RED. Both connections completed their offer/answer operations, including the yielding connection's rollback, but stayed in ICE checking until their original dial deadlines. Neither channel opened. The retained post-failure snapshot identifies these states without establishing the cause or its exact instant. No settings were changed. All worker/supervisor cleanup flags passed; audit: `artifacts/native-chrome-glare-1b096a0-run-20261015/analysis`. The subsequent R5 check used the existing Internet TURN service and the exact 1b standalone bundle. It remains RED at the initial transport prerequisite: each endpoint retained 36 selected relay/TLS candidate-pair rows with known zero received bytes. Missing selected-pair references remain unknown. Seventeen complete peer fragments/1,981,896 bytes were verified before credential rotation; that media does not establish the required positive counters on the selected pair. Three real credential issuances succeeded and the donor accepted its new lease, with two lifetime connections per page and no constructor refusal. The test stopped at the missing prerequisite, so post-renewal media was not assessed. Consent and nondecreasing spend were retained. All seven worker and six supervisor cleanup flags passed within the unchanged time/resource bounds. The independent audit is retained in `artifacts/existing-turn-renewal-1b096a0-r5-run-20261015/analysis`. No browser defect, server quota or product renewal cause is established. The [public checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/internet-renewal-and-ci-checkpoint-20261015.json) records these exact-source outcomes and retained audit hashes. The following earlier checkpoints retain their original scope; they do not qualify the later source or reclassify these failures. Exact `cf479ebd7bd42df3a08a0fba6bc2ed0fb6f42b44` completed all nine required jobs in [CI 38651823241](https://github.com/forgesworn/relayswarm/actions/runs/38651823241), including Windows, both HLS modes and the media/broadcast journey. The optional twelve-viewer soak was skipped. The retained broadcast receipt passes all four original checkpoints with six verified peer fragments/3,249,204 bytes, including post-restart high sequence 9/discontinuity 1 at 738,464 bytes. Peer deadlines and the 2,000 ms origin reserve were unchanged; the smallest observed completion margin was 35.506 ms. Each role retained one recoverable playlist HTTP 503; both donors stalled once, baseline/consumer had no stalls, and fatal/native/ append errors were zero. Actual server close left zero blocked reloads/watchers. This injected headless loopback result has no independent OS resource/reaping journal and does not qualify ordinary public, physical-device or sustained use. The offline audit is retained in `artifacts/candidate-cf479eb-ci-observation-20261014/analysis`. Fresh offline production-only consumption of the same exact source passed all 247 package members against committed bytes, eleven documented imports, the installed CLI/demo, durable ledger replay, separate-process verified native transfer/HTTP fallback and rebuilt browser ESM. The unpublished tarball is 1,124,565 bytes, SHA-256 `d1d2125e8e4641a67f0f78ea562a7f13a4143511640309d4a7639ab2377a0a5c`. Owned phase groups, sampled probe children and recorded scratch cleanup passed. Receipts are in `artifacts/clean-consumer-cf479eb-diagnostics-preparation-20261014`. Publication, downloaded-release consumption and final deployment acceptance remain pending. The pending glare-reuse correction builds on that source. When simultaneous offers make a viewer yield under the existing public-key tie-break, it reuses only that peer's still-pending outgoing connection, with serial native operations, negotiation-generation fences and the original absolute deadline/capacity slot. Admission is checked before and after asynchronous rollback and before answering; unsupported/failed rollback falls back without a replacement connection. Its initial reviewed source/test SHA-256 pins are: | File | SHA-256 | |---|---| | `src/browser/hls-swarm.mjs` | `bf729d7fcc08d3d1e599053e5eff789e98195878130c037ad24cb2fa08d49004` | | `test/browser-hardening.test.mjs` | `71187521d2d50738577c59c82419c06bb3a133ff6f84e35039bf0f0d9d7f9188` | All 121 maintained swarm tests passed with no failures, cancellations or skips in a 19.781 s outer run, within the original 40/60 s and sampled 3 GiB/64-process/minimum-25%-free bounds. Worker/group/birth and probe reaping passed. This is stateful fake-RTC/in-memory-signalling unit qualification; native browser rollback/SCTP/channel reuse and genuine Internet renewal/media remain unproved. The exact-CF CI/package results above do not cover this pending source. Evidence: `artifacts/glare-reuse-r2-unit-validation-20261015/analysis`. A subsequent real Chrome 155.0.8059.41 collision test on exact `b9a9be4` remains RED. Both pages reached native local offers on one connection each, with fresh admission and over 11.839 s left on their original dial deadlines. The link checkpoint then failed. The receipt retained no failure-state snapshot, so rollback, ICE, channel and admission causes remain unproved. All six worker and six supervisor cleanup flags passed in 16.972 s; sampled resources stayed within the original bounds. The retained audit is in `artifacts/native-chrome-glare-b9a9be4-run-20261015/analysis`. The follow-up fixture retains bounded read-only failure snapshots and passive native-state counts; this instrumentation is no runtime repair. Exact-b9a Windows CI separately passed 120 of 121 swarm tests, then failed the existing own-ticket-renewal test's second-upload EOF wait. Its readiness predicate observed an HTTP request rather than accepted admission. A fixture correction holds that response and waits for a public acceptance marker within the same five-second budget, preserving the original upload and revocation assertions. The actual Windows response order and failure cause were not retained. Product admission/presence code is unchanged from exact CF. The corrected full local swarm suite passes 121 tests with no failures, cancellations or skips; syntax passes for 141 modules. The combined outer run completed in 20.962 s within the original guard, with recorded worker/group/birth and probe reaping. Windows subsequently passed this suite on exact 1b, before its separate publisher failure above. These follow-up results are recorded in the [browser and admission checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/glare-browser-and-admission-checkpoint-20261015.json). Separately, 30 pure observer/model tests passed in 355 ms, preserving unknown selected-pair counters as null/status rather than zero and retaining the strict positive selected relay/TLS gate. Evidence: `artifacts/turn-selected-pair-observation-r2-pure-validation-20261015`. The actual Internet R4 remains RED: accepted refreshed credentials and preserved consent/spend did not prove post-renewal TLS/media, and its selected-pair counter ambiguity cannot be repaired retrospectively. Native browser, Internet renewal, ordinary public contribution, sustained/churn and full field gates remain open. Earlier failures remain separate. Exact `83f72de` Windows native/swarm passed before two publisher failures: directory replacement exhausted the unchanged revalidation budget, and the master-removal mock selected a parent watcher without a filename. The correction narrowed Windows parent metadata events and fixed the mock; its local publisher suite passed 264 tests with two skips. The native fourth-pass event chronology remains unproved. Exact `4aa87c7` [CI 38646569729](https://github.com/forgesworn/relayswarm/actions/runs/38646569729) retains three publisher-matrix failures. An intervening local 260-pass/one-fail/ two-skip run failed guardian descendant cleanup; later diagnostics and the 263-pass/two-skip suite did not identify that failure's cause. The [correction evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/playlist-ci-and-guardian-correction-20261014.json) retains those source hashes and outcomes. No prior RED is reclassified by the current passes. ## Complete-playlist blocking reload candidate The example origin now supports bounded blocking reload for compatible complete live playlists, consistently across all renditions. The [API contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#example-origin-http-playlists) keeps raw media, peer deadlines, origin reserve and playback holdback unchanged. Independent review addressed shared directory-watch replacement/rearm races, observed-change reauthorisation and response-slot retention until transmission finishes. All 49 focused tests pass, including five actual loopback HTTP cases; worker reaping and group/birth absence passed. This focused guard has no resource sampler. The [source-check summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/blocking-playlist-reload-source-checks-20261014.json) records exact file hashes and scope. Exact `dd953eeffb36f16674b8afaa01d29cbe2a7f0deb` then passed one fully serial [paired browser journey](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/blocking-playlist-reload-paired-browser-20261014.json) with blocking reload enabled and disabled. Both passed low/high peer delivery and producer-restart sharing under the original guards. Candidate: six verified loads/3,245,444 bytes in 29.285 s; control: six loads/3,079,252 bytes in 28.715 s. The candidate served 17 blocked reloads, with no blocked requests or watchers left after actual server close. All seven worker and six supervisor cleanup flags passed; the original resource bounds held. Each donor stalled once in both runs; baseline/consumer had no stalls and all fatal/native errors were zero. Candidate players each recovered from one HTTP 503 playlist error during restart; control players had none. Its cause remains unproved and is retained as a transient restart risk. This single injected, headless loopback pair does not establish a reliability improvement, causality, ordinary public/physical acceptance or sustained benefit. Required hosted CI and the remaining field gates are separate from these local results. The preceding exact `fc39e32` check passed eight of nine required jobs in [CI 38640084885](https://github.com/forgesworn/relayswarm/actions/runs/38640084885). The broadcast failed initial low-quality peer delivery, before high-quality or restart checkpoints. Healthy connections and late donor availability did not establish a runtime fault or a polling cause. That failure remains separate from the older all-green 7a check below; this capability is not yet a proved fix. Release, deployment and the remaining field gates stay open. ## Earlier source checkpoint: 7a on 14 October 2026 Exact `7a5de06a97baf14c00e3a420944b75a730042c85` passed all nine required jobs on attempt 1 of [CI 38625083620](https://github.com/forgesworn/relayswarm/actions/runs/38625083620); the optional soak was skipped. The injected loopback broadcast passed both qualities and producer-restart sharing: six verified loads/3,240,180 bytes, including one post-restart high fragment/791,856 bytes. That fragment finished 1,291.1 ms before its original deadline with the unchanged 2,000 ms reserve. Each donor recorded one stall; baseline/consumer recorded none. Fatal, native and append failures were zero. All 246 observation rows and four extractions were retained without drops/unknowns/unlabelled objects. Recorder release does not prove missing actor/API or OS reaping. TURN renewal was off in this fixture; its PASS does not establish that the cache correction repaired broadcast recovery. The da9 media RED and deterministic cache reproduction remain unchanged. Fresh exact-7a offline production-only consumption passes all 239 package members against committed paths/modes/bytes, eleven documented imports, installed CLI, sequential durable ledger replay, separate-process verified native transfer/HTTP fallback and rebuilt ESM. The unpublished tarball is 1,088,342 bytes, SHA-256 `10e2c0e972ecc176754d12db3ca1bbe31cec2489efe300a80b1c9e17d12816d3`; the fresh ESM is 121,478 bytes, SHA-256 `612f5f502964462d8eba8909e5041db1030da96edbaea7dd5caa1088d1eac171`. Owned phase groups, sampled direct-child probes and scratch cleanup pass. Earlier da9 consumer R1 RED/R2 PASS remain separate. The hosted mock-issuer renewal fixture passed in 50.904 s, retaining consent and spend through new-swarm peer delivery, account linking, restart and reset. It uses 15 s fake credentials and loopback host WebRTC, not an Internet relay. Actual existing-service forced-renewal attempts R3 and R4 remain **RED**. R3 omitted its failed sample, so the exact terminal assertion remains unknown. R4 retained the failure: three constructor refusals under its unchanged maximum of two lifetime PCs per page, after legitimate initial glare consumed the donor's first PC and serving used its second. The client accepted refresh 2 and a new 3,600 s lease, retaining checked consent and nondecreasing spend; no new PC or post-renewal TLS/media was proved. R4 recorded 16 prior verified fragments/1,861,388 bytes but no strictly selected positive TLS-pair sample. All owned worker/fixture/group/scratch cleanup flags passed; shared allocation absence was not inspected. These attempts do not diagnose a product renewal failure, server quota refusal or the earlier connection-closure cause. A separate installed Safari 26.6.2 tooling check on M4 remains **RED**. Driver status returned ready, but POST/session reached its 14,506.1 ms whole-call deadline without a response or session ID. No page navigation, button click or RelaySwarm test ran. The owned driver and two wire workers were reaped; runner, guardian and group absence and inert scratch removal passed. Session destruction remains unknown. M4's resource observation preceded the blocked call and does not prove continuous monitoring during it. The [7a checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/7a5de06-ci-consumer-and-renewal-checkpoint-20261014.json) keeps these source-bound results separate. The last-attested pilot remains 8f, with reporting/forwarding off; no fresh deployment is claimed. v0.1.0 remains published, candidate assets unpublished and PR 8/P01–P12 open. Ordinary sharing, complete Safari/physical devices, sustained 7,200 s/22 churn, natural expiry/reconnection, matched wire/cost and final release acceptance remain open. ## Cached TURN credential correction A deterministic clock test at da9 reproduced an unchanged cached reply rebuilding peers and moving the conservative local expiry. The follow-up client keeps the original lease for identical credential material, skips the refresh counter and callback, and retries within the existing bounds. All expiry, generation, suspension and consent checks still run before acceptance. Eleven lifecycle and four page-VM cases pass in one 481 ms focused run. The worker was reaped and its group and original birth were absent. This focused guard has no RSS/pressure sampler; no such resource proof is claimed. The [correction checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/turn-cached-lease-fix-20261014.json) records the exact source digests and preserved reproduction. Exact-7a CI/package results and the separate RED Internet-renewal attempts are recorded above; the da9 results below belong to the preceding source. The pilot is unchanged. ## Optional TURN renewal candidate Exact source `da9ac9202fd8794a68d6d707a1ab5d8109bbbb34` completed attempt 1 of [CI 38620173084](https://github.com/forgesworn/relayswarm/actions/runs/38620173084) with eight required jobs PASS and the media job RED; the optional soak was skipped. Both low/high peer checkpoints passed, but the unchanged 60 s post-producer-restart peer-fragment gate timed out. All 31 consumer fragments at discontinuity 1 came from origin. Their peer budgets were zero: playable ahead was 1,159–1,202 ms against the unchanged 2,000 ms reserve, even though matching donor completions preceded consumer loading. Accepted HAVE rows do not reconstruct current membership. This is a policy observation, not a playback repair or a reason to relax the gate. Each donor recorded one stall; baseline/consumer recorded none, with zero fatal/native/append failures. Broadcast recorder release does not establish missing actor/API or OS cleanup. The optional server-owned [credential adapter](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#optional-turn-credential-renewal) is off by default. Eleven server/owned-HTTP tests, ten client lifecycle tests and four page-VM cases pass. The retained retry-liveness finding is closed by the separately reviewed R2 correction. A real local Chrome fixture passed in 47.010 s, and the equivalent hosted fixture passed in 50.433 s. Both use an owned fake issuer, 15 s credentials and real loopback WebRTC host media; the TURN endpoint is unavailable loopback port 9. Rollover retains consent and accepted spend, delivers new-swarm peer media, and passes link/restart/reset checks with scoped worker/API/group/scratch cleanup. These are browser integration passes, not Internet TURN renewal. At that da9 checkpoint the existing-service renewal check was pending; the later exact-7a attempts are recorded separately above. Fresh exact-da9 offline production-only consumption passes eleven documented imports, installed CLI, sequential durable ledger replay and separate-process verified native transfer/HTTP fallback. All 237 package member paths, modes and bytes match committed source. The unpublished tarball is 1,082,277 bytes, SHA-256 `6d618c25d15032a79cb07a5050dd51f2aa9273575f511c1b83a1b1906e475412`; the rebuilt ESM is 121,478 bytes, SHA-256 `612f5f502964462d8eba8909e5041db1030da96edbaea7dd5caa1088d1eac171`. Owned phase groups, sampled direct-child probes and scratch cleanup pass. The first consumer attempt remains RED: its new smoke assertion expected POST 404 where the unchanged disabled-route method contract returns 405; the corrected R2 proof does not relabel that attempt. The [da9 checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/da9ac92-ci-and-consumer-checkpoint-20261014.json) retains exact hashes and fixture limits. The deployed pilot remains 8f with reporting/forwarding off; v0.1.0 is published, candidate assets are unpublished, and PR 8/P01–P12 remain open. Ordinary sharing, physical devices, sustained load/churn, real credential-expiry/reconnection, matched wire/cost and release acceptance remain separate gates. Earlier source evidence below is unchanged. ## Earlier completed CI source: 07 on 14 October 2026 Exact source `07ea96becce44fec6baa0b41f7719e0e99ee4031` passed all nine required jobs on attempt 1 of [CI run 38616043417](https://github.com/forgesworn/relayswarm/actions/runs/38616043417); the optional soak was skipped. The Windows CRLF observation-test correction retains six meaningful cases and the byte-exact LF diagnostic bundle. The Linux Chrome 155.0.8059.79 broadcast diagnostic passed all four checkpoints, including producer restart, with six verified peer loads/3,125,876 bytes. Low/high contributors recorded 221,840/2,904,036 uploaded bytes. All 239 observation rows (77/82/20/60) were retained with zero drops, unknowns or unlabelled objects, and all four final extractions passed. Each contributor recorded one stall (2,938/1,968 ms); baseline and consumer recorded none. Fatal, native and append failures were zero. This uses an injected diagnostic bundle and declared loopback/headless/fake-media RTC fixture settings. It does not establish ordinary/physical qualification or repair the earlier failures. The raw receipt has no full actor/API or OS-reaping cleanup flags; recorder release does not replace that missing proof. The earlier `abb5de7` CI remains seven required PASS/Windows FAIL, with the media job PASS and dependent live-relay/optional soak skipped. The 426 CI's eight required PASS/media FAIL also remains. Exact-426 package/consumer/ESM proofs below remain bound to 426; fresh 07 package proof has not run. The [07 summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/07ea96b-ci-checkpoint-20261014.json) records these separate results. The deployed pilot stays 8f; v0.1.0 is published and PR 8/P01–P12 remain open. Exact 07 retains the static TURN credential limitation below; the later renewal candidate's component evidence is separate. ## Earlier source checkpoint: 426 on 14 October 2026 Exact source `42608f758919628dfa86dee667f6c7f3050fbcc4` completed [CI run 38607468217](https://github.com/forgesworn/relayswarm/actions/runs/38607468217) with eight required jobs passing and one media job failing its first low-quality peer-load gate after 30 s. That RED remains. The later test-only diagnostic adds observation, preserving playback policy, peer deadlines, origin reserve and upload consent; its later CI results are recorded separately above. The separate local injected HAVE/deadline diagnostic passed in 33.759 s with six total verified peer loads/3,107,076 bytes across both qualities. Only the last observed high-quality object was post-restart. Its load completed 366.123 ms before the recorded deadline. All 277 observation rows were retained without drops. This used Mac Chrome 155.0.8059.41 and an injected diagnostic bundle; the failed Linux CI used 155.0.8059.79 without that injection. It neither reproduces the CI failure nor establishes a repair. The queued/accepted HAVE observations are now maintained test instrumentation only. Fresh exact-426 offline production-only consumption passed eleven documented imports, sequential durable ledger replay, installed CLI and separate-process verified native transfer/HTTP fallback. All 226 package member paths, modes and bytes match committed source, including the new Darwin filesystem verifier. The unpublished tarball is 1,044,255 bytes, SHA-256 `78edf82d98481e0a4452f4f9c1aaa06f162adf3c6ce2c001328de4ee4c9c9935`; the rebuilt ESM is 121,478 bytes, SHA-256 `612f5f502964462d8eba8909e5041db1030da96edbaea7dd5caa1088d1eac171`. Both workers, their groups, sampler children and scratch cleanup passed. These proofs belong to 426, not 07, another documentation/test commit or a release. An existing shared TURN service was then confirmed separately from the earlier Till inventory. One controlled RelaySwarm TLS-relay check passed over 90.005 s of measurement (105.150 s whole): the receiver recorded 34 complete verified peer fragments/3,956,272 bytes; the contributor recorded 4,175,104 uploaded bytes. Both pages showed positive selected TLS-relay pairs in 67 of 91 samples. Each constructed two peer connections; the final seven samples had no active peer connection while video/time continued. This is not continuous 90 s TLS, one stable connection, both-rendition, physical-device or hard-NAT proof. Recorded stall/fatal/native projections were zero; unavailable fields can project to zero. The run used two headless pages, local synthetic HLS/Nostr and injected relay policy, with trusted Start/upload and programmatic dropdowns. Server quotas, shared allocation absence and matched wire/billing remain unproved. Both CLIs read `--ice-config` once; session responses reuse that array and new outgoing/incoming peer connections use captured options. No supported ICE credential renewal exists. The observed issuer TTL is 3,600 s against the 7,200 s goal, so fresh allocations/reconnections after expiry remain unproved; this does not establish that existing allocations die at that TTL. An optional server-owned credential endpoint and expiry-aware client refresh remain follow-up work, retaining consent, admission and durable spend, with origin fallback on failure. Client/worker/group/scratch cleanup passed, and the issued private ICE file and directory were removed separately. The existing service and network rules were unchanged; no new infrastructure or Till/provider exposure was created. The [426 evidence summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/42608f7-source-and-tls-checkpoint-20261014.json) retains the exact scopes. The deployed pilot remains 8f, with reporting and forwarding off; PR 8, P01–P12 and final release acceptance remain open. ## Shared account allowance implementation checkpoint The current branch adds both requested account methods: explicit Nostr sign-in and an integrating website's authenticated account. One private durable ledger serialises reservations across devices. Explicit linking adds spend and retains the lower limit; settings, reset, linking and connection leave uploading off. See [shared upload allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md). The [controlled Chrome result](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/account-budget-implementation-20261014.json) passes in 55.780 s with both authentication methods, verified peer media at both qualities, short-grant renewal, linking, server restart/reconnection, reset and disconnect. At linking, receiver bytes, committed upload totals and merged spend equal 6,337,480 bytes; the same balance survives restart. All browser, server, media, owned-group/reap and scratch cleanup checks pass. This uses disposable Nostr signatures, an owned website session and explicit loopback RTC fixture flags, not physical phones or a real owner's signer. Local tests pass: 177 publisher cases (two Windows-only skips) and 92 swarm cases. The earlier 49.043 s pass is retained with its provisional upload-counter caveat. The corrected source separates pending quota from committed uploads. One intervening full-suite guard test failed on `EPERM`; its original cleanup remains unknown because its exact PID was not retained. A later read-only check found no matching test program; this does not reconstruct original cleanup. The final guard waits for explicit absence within the unchanged deadline, and the corrected full suite passes. Original failures are not replaced by later passes. The deployed `8f482b4` checkpoint below includes this account service. All nine required CI jobs, clean package consumption and guarded pilot deployment pass. The pilot offers Nostr sign-in; integrating sites supply their own authenticated website resolver. Actual owner authentication, complete physical journeys and network/sustained/release acceptance remain open. ## Earlier source checks: restart sharing failures Checkpoint `a2c99a9` finished attempt 1 of [CI run 38569064323](https://github.com/forgesworn/relayswarm/actions/runs/38569064323) with eight of nine required jobs passing. The playback job failed its unchanged 60 s post-producer-restart peer-fragment assertion. Both pre-restart peer qualities passed. After restart baseline and consumer playback progressed without stalls, fatal/native errors or append failures, but the consumer loaded all 30 completed new-discontinuity fragments from origin. Its 31 measured peer waits had initial budgets of 286.846–337.173 ms: 17 aborted, 13 expired and one remained pending. Established links and upload consent remained active. Thirty matching donor fragment-completion events occurred 53–108 ms after consumer origin completion, subject to the retained cross-page clock limits. This does not establish a lost notification, key mismatch or exact scheduling cause. Per-load buffer geometry and actual request start timings were absent. The [original failure summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/a2c99a9-ci-restart-failure-20261014.json) retains that failure and its cleanup limits. Later observations are separate results. Playback policy, fallback cap and origin reserve remain unchanged; at that checkpoint the deployed pilot was still `df51cbe`. Current source adds bounded numeric `budgetGeometry` to the existing local eligibility records using only values already read by the calculation. Wait outcomes retain the original values, and returned snapshots own copies. The full 94-case swarm suite passes locally; an independent source review found no getter-order, formula, deadline or authority change. See the [metrics contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md). This observation is not a sharing repair or new hosted/physical acceptance result. The broadcast fixture also records cached request lifecycle timings without extra requests or body reads; ten pure observation tests pass, including release after each possible teardown rejection. Its original startup, waits, launch flags and peer assertions are preserved. The [broadcasting guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md#verification-boundary) describes the bounds and diagnostic scope. The instrumented `d283071` attempt of [CI run 38575462650](https://github.com/forgesworn/relayswarm/actions/runs/38575462650) finished with six required jobs passing, two failing and the dependent live-relay job skipped; the optional soak was also skipped. The unchanged post-restart peer assertion failed again. Its 31 initial waits had 2,268.463–2,329.467 ms of playable buffer and the unchanged 2,000 ms reserve, leaving 268.463–329.467 ms. For all 30 matched high-quality segment objects, cached native request timings place the donor request start 46.694–102.418 ms after consumer response completion. These donor HTTP intervals did not overlap the receiver's origin interval; the newly loaded bytes were too late for the preceding peer wait. This does not identify the exact playlist scheduling cause or a lost HAVE notification. The other failure was an existing macOS HTTP cancellation test: immediate invalid policy could legally cancel a session before server ingress, while the assertion required ingress first. A test-only phase gate establishes that precondition, preserving the real start/cancellation checks, hidden-page phase and all deadlines. All four focused real HTTP cases pass locally, and an independent source review passes. The [d283 observation and correction summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/d283071-ci-observations-20261014.json) retains both original failures, exact inputs and limitations. Neither correction nor later CI removes the restart-sharing gate; these checks did not change the then-deployed pilot. ## Historical deployed checkpoint: 8f on 14 October 2026 The deployed application is `8f482b4528a671acfe9f1afc336cce5743aaaefd`. All nine required jobs passed on attempt 1 of [CI run 38578315372](https://github.com/forgesworn/relayswarm/actions/runs/38578315372); the optional soak was skipped. The non-root image passed 54 runtime-file checks before guarded replacement, preserving publisher identity, permanent leases, private account state and the independent EE HTTP/1.1 proxy. The normal-TLS public client is 746,875 bytes, SHA-256 `70e92c18234375ae437b0ad3d9c1ba47d4ecbd6a12836e15540b1ce34111a87f`. The image is `sha256:c89bbed80eaa89b750f91f594a7c2c08940ccfa9b7188cf7e4264a8225b27cfd`. Both fresh rendition playlists were attested. Reporting and forwarding remain off, and the verification source was removed. The pilot offers Nostr sign-in; its website account resolver remains unconfigured. Fresh production-only consumption passed eleven documented imports, durable ledger replay, the installed CLI and separate-process verified native transfer and HTTP fallback. The unpublished package is 1,024,043 bytes/219 files, SHA-256 `3505d8b086c4be44a414bee829872915fb4383ae94251f44e24b856fcdef9198`. The archive is 3,758,080 bytes, SHA-256 `591ea9994fcc7a03d77f8820c50b31bf6820ea29408ba547abfca91a51201cf2`; the standalone ESM is 121,478 bytes, SHA-256 `612f5f502964462d8eba8909e5041db1030da96edbaea7dd5caa1088d1eac171`. These local proofs do not establish published/downloaded-release acceptance. The CI broadcast fixture verified both peer renditions before producer restart, then one 819,868-byte high-quality fragment afterwards. Receiver and origin baseline recorded no stalls, fatal/native errors or append failures. Explicit RTC/fake-media fixture flags and loopback topology limit that result; earlier restart-sharing failures remain separate. The ordinary cross-Mac R2 check measured 60.119 s: playback passed, contribution and both-quality peer delivery failed, with zero peer channels or verified peer bytes. Six dials installed remote SDP and reached ICE checking before timeout. All 335 retained control requests finished HTTP 200 over HTTP/1.1; status alone does not prove an admitted response body. Across the retained whole journey, all 120 buffer geometries matched the existing budget formula; three startup rows remained unknown. No peer wait entered or expired. The two measured high-donor zero budgets had less playable time than the actual dynamic reserve. This does not establish a scheduler or connectivity defect or justify changing playback policy, origin reserve or deadlines. Original execution cleanup remains red. The outer ownership probe exceeded its unchanged 0.5 s limit; M4 refused watcher termination because the full command changed while birth and process group matched. The actual differing command was not retained, so the canonical interpreter pin has not proved a repair. Later exact owned process/group/path absence and helper-stage removal are separate proofs; they do not reconstruct original watcher reaping. Source cleanup v2 matched all five provenance guards and removed the finite encoder, retaining its observed exit 255. A preceding R1 capture refusal launched no browser; its original cause remains unknown. A separate R3 attempt stopped before source or browser workload: its authenticated interpreter capture exited normally, but the freshness validator rejected a remote timestamp 68 ms ahead of this Mac's clock. That specific refusal is recorded; it does not establish the earlier R1 cause or a completed correction. No system clock or freshness limit changed. The earlier temporary coturn fixture passed two verified segments through an owned SSH tunnel, then its service and credentials were removed. A fresh read-only Till observation found no known TURN service or standard TURN listeners, while the pinned image remains cached. That scoped Till inventory did not cover the separate existing shared service tested in the latest checkpoint above. The SSH result remains separate from direct Internet TLS evidence and hard-NAT acceptance; no new public TURN service started. The [8f checkpoint summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/8f482b4-current-checkpoint-20261014.json) records exact artifacts, separate cleanup results and retained local receipt hashes. All P01–P12 acceptance remains open, including the same-topology 300 s qualifier, two-hour/churn, physical/Safari, hard NAT, matched wire/cost and final release/download checks. PR 8 remains open; v0.1.0 remains the published release. This documentation checkpoint does not change the deployed runtime source. ## Previous deployed checkpoint: df51 on 14 October 2026 The deployed application is `df51cbed1ebb3bd09ef1b521c451d6b47989a664`. All nine required jobs passed on attempt 1 of [CI run 38554223220](https://github.com/forgesworn/relayswarm/actions/runs/38554223220); the optional soak was skipped. The normal-TLS public client is 746,356 bytes, SHA-256 `875d1a24c90cac5ea0df5b9a1dd2557df606aa0c5ba75ff1a60216ad12b0c6dc`. The image is `sha256:bec569791de3ed2b077a83a79eb26d6a3741d051fda265336e97919b17f191c1`. Guarded deployment preserved publisher identity, private account state and the independent EE HTTP/1.1 proxy. Both fresh rendition playlists were attested; finite verification sources are now removed, so this is no ongoing-ingest claim. The fresh offline production-only consumer passed eleven documented imports, durable account-ledger replay, installed CLI and separate-process verified native transfer/HTTP fallback. The unpublished package is 993,652 bytes/212 files, SHA-256 `ad57ea048ba9f098aec5ecd9028f9b5a5c7d1168b21a9957ee1b53d4b3fc9db4`. The source archive is 3,645,440 bytes, SHA-256 `b3607b6fc069a14330c75fd1426205f8e3c76df0f848af4d93df7e0f1c5880de`; the standalone ESM is 120,957 bytes, SHA-256 `50647647b96a0ce4a89fdfb0a42b053601d2cd5b10c2525cc57e283af2900c63`. These local assets do not prove downloaded immutable-release acceptance. The later documentation checkpoint `e144b8c` recorded a macOS CI test failure: one eligibility case expected two peer requests but observed one. Its real 60 ms branch budget competed with cryptographic work, while identical fixture origin/peer bytes could conceal fallback. A test-only correction retains real signatures/hashes and the same 60 ms budget, drives virtual time at observed phases, and requires two peer deliveries plus exactly one origin fallback. Four focused cases and the full 92-case swarm suite pass locally. Real timers are restored before closing the fixture; an intermediate delayed exit remains recorded. No production code or deployed runtime changed, and the exact CI scheduling cause was not reproduced locally. See the [retained failure and correction](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/e144b8c-ci-test-timing-20261014.json); new-head hosted checks are a separate result. Checkpoint `18729eb` then passed all 92 swarm cases on macOS, including that eligibility case. Its publisher suite exposed a different test assumption: two concurrent HTTP reservations returned one refusal and one acceptance in the opposite order to the assertion. The correction requires exactly one acceptance, 70 bytes reserved/spent and an unchanged replay decision, without requiring an HTTP arrival order. All ten account HTTP cases pass locally. Production code, limits and deployment are unchanged; the [original failure and test correction](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/18729eb-ci-account-http-order-20261014.json) remain distinct from later CI. The ordinary four-role check remains **RED** over 60.110 s: requested video and native audio progressed, but no peer channel opened and verified peer/upload bytes were zero. All 91 measured eligibility decisions had a positive 1,500 ms budget and no matching advisory HAVE; none failed for zero budget. All 335 controls finished HTTP 200/H1, which does not itself prove admitted bodies. Six dials timed out after remote SDP installation and ICE checking. Missing HAVE with no channel does not establish a cache defect or justify a budget change. A separate 60.027 s heap/native-stats diagnostic also passed playback and failed sharing. Twelve retained pair observations across four page-local PC labels showed UDP host/host or host/srflx pairs in progress, request counters 22–80 and zero observed received requests/responses. These include repeated snapshots, not twelve unique pairs or traffic deltas; selection was unknown. Fifty batches completed, but only 42 latest snapshots were retained; eight remain unobserved. All diagnostic handles were released and contexts closed. This narrows the observed failure to unanswered ICE checks, without identifying its network cause. Heap/native inspection means this is diagnostic evidence, not ordinary qualification. Original M4 controller cleanup timed out in both checks; recovered endpoint watcher cleanup was false. The diagnostic's guard refused before TERM because full command text differed despite matching birth/PGID. Its replacement command and cause were not captured. Later exact PID/group absence, profile/TMP removal and owned-stage removal were proved separately without signals. They do not prove original parent reaping. M1 cleanup and both separate source-cleanup-v2 proofs passed; source exit 255 remains recorded. Private duplicate archives were removed; named originals and review evidence remain. See the [df51 evidence summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/df51cbe-current-checkpoint-20261014.json). The full P01–P12 checklist remains open, including the same-source/topology 300 s qualifier, 7,200 s/22 churn, complete physical/native-input/Safari journeys, hard NAT, matched wire/cost measurements and final release acceptance. Earlier references to 37 review items have no separately located row-by-row ledger; no 37-item completion is asserted. PR 8 remains open; no new release is published. ## Published v0.1.0 capabilities | Capability | Implementation and evidence | Remaining boundary | |---|---|---| | Original WebRTC CLI | Signed relay rendezvous, transfer and same-peer SHA-256 verification; public-relay tests | Plaintext SDP; no authenticated malicious-seeder defence | | Browser shadow mode | hls.js keeps origin in the playback path; sampled verified peer measurements | Adds traffic; results are not origin savings | | Browser peer-first | Author-signed exact-context commitments, bounded deadline, normal HTTP fallback | Limited scheduling; benefits differ by viewer | | Publisher/player | Local playlist-bound signing, full segments/ranges/discontinuities, server-only key, explicit upload consent and local receipts | Limited HLS subset; no production hosting/admission service | | Playback regression | Real Chrome, two renditions, seeks, timestamp reset, byte-range HTTP, relay reconnect and kill switch | Loopback desktop test, not physical-phone acceptance | | Native HyperDHT | Local relay/DHT tests on Linux/macOS/Windows; Noise and one-use dial authorisation | No executable packaging, real-NAT acceptance or automatic HTTP fallback | | GitHub distribution | Public installable tarball, standalone browser bundle and SHA-256 manifest; downloads verified | Prerelease, npm registry unpublished | | AI documentation | Curated `llms.txt`, generated `llms-full.txt`, public Markdown and repository/package metadata | Publication does not establish crawler discovery, indexing or recommendations | ## Release verification ### v0.2.1 (21 October 2026) [v0.2.1](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.1) is an experimental GitHub prerelease of merge commit `1d54538c56179387b7541924e068d0d9c41d18e6` (PR 9), with an annotated `v0.2.1` tag, published by owner decision with Item 5, P06 and Safari 17.6 RED and open. [Main CI run 39601445318](https://github.com/forgesworn/relayswarm/actions/runs/39601445318) passed all nine required jobs on that commit (soak skipped); attempt 2 reran only the hls.js playback job after the account-budget TURN renewal browser case timed out in attempt 1. The merged tree is identical to PR head `55c0f68`, which passed [run 39589990218](https://github.com/forgesworn/relayswarm/actions/runs/39589990218) on attempt 2 after one wall-clock-bound unit test failed on the macOS runner. Fresh consumption of the merge commit passed with 287 package members. Assets were built from a clean `git archive` of the commit after `npm ci`, with the v0.2.0 commands; the same bundle command rebuilds the published v0.2.0 bundle byte for byte. | Asset | SHA-256 | |---|---| | `relayswarm-0.2.1.tgz` (287 files, 1,420,583 bytes) | `9f67a5f3ea8f5dffdf2e574d33703dfe952e01069a57635ae8349dd6d85455cb` | | `relayswarm-hls-swarm-0.2.1.mjs` (148,439 bytes) | `358a026a563d645498faa1461d76ad44e64ae9cfe3d8de234c25c6e78025cda2` | After publication, all three assets were downloaded from their public URLs into an empty directory and passed `shasum -a 256 -c SHA256SUMS`. Installing the tarball by URL into a clean production consumer imported the package; the downloaded tarball imported all ten public export paths; and the bundle loaded in headless Chrome 155 with `createHlsSwarm` exported and no page errors. These are distribution checks on macOS arm64 and close no field gate. The merge commit was then deployed to the pilot through the guarded cycle, with `140c256` as the predecessor and its positive P07 as the incoming handover, and passed its independent deployment review. The pilot app is `ce410033`, started 14:56:56 UTC. Normal HTTPS attestation matched the 787,462-byte client and read two fresh rendition playlists, and the deployment's verification source was removed. Reporting and forwarding remain off. The runtime of `1d54538` differs from `140c256` only in the package version fields. After deployment, P06 at 6 MB (RED), R67 (stopped at controller binding on a harness pin) and R68 (RED, 15 of 16 gates) ran on `1d54538`; see the [current delivery checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint). The v0.2.0 record below is unchanged. ### v0.2.0 (21 October 2026) [v0.2.0](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.0) is an experimental GitHub prerelease of merge commit `bf4394031809abb37b6a534d6be86aae3a3c556b` (PR 8), with an annotated `v0.2.0` tag. [Main CI run 39514327948](https://github.com/forgesworn/relayswarm/actions/runs/39514327948) passed all nine required jobs on that commit (soak skipped). The merged tree is identical to PR head `fd046f5`, which passed [run 39512633566](https://github.com/forgesworn/relayswarm/actions/runs/39512633566). Assets were built from a clean `git archive` of the commit after `npm ci`: `npm pack`, and esbuild 0.28.2 with `src/browser/hls-swarm.mjs --bundle --format=esm --platform=browser --minify --legal-comments=inline`. The same command rebuilds v0.1.0's bundle byte for byte from its tag. | Asset | SHA-256 | |---|---| | `relayswarm-0.2.0.tgz` (286 files, 1,394,299 bytes) | `221324ea5e6cb8f9a56ee67c8dc60f9bd91c3ee0f302b7901b93eef046c214b7` | | `relayswarm-hls-swarm-0.2.0.mjs` (145,696 bytes) | `376cf5296b298a41e00de85f460ea9141200794036863c979ee7fabe81c06d13` | After publication, all three assets were downloaded from their public URLs into an empty directory and passed `shasum -a 256 -c SHA256SUMS`. Installing the tarball by URL into a clean production consumer imported the package; the built tarball imported all ten public export paths; and the bundle loaded in headless Chrome 155 with `createHlsSwarm` exported and no page errors. These are distribution checks on macOS arm64 and close no field gate. The public pilot still runs `5f2ece0`; the release's later loader clock-skew diagnostics are not deployed. ### v0.1.0 This subsection records v0.1.0's release checks. [Main CI run 38233694634](https://github.com/forgesworn/relayswarm/actions/runs/38233694634) passed seven standard jobs: native suites on three operating systems, shadow and peer-first Chrome harnesses, the publisher/player regression and live public-relay transport tests. Local suites recorded 25 swarm/hardening tests, ten publisher/ HTTP/relay tests and six native tests. These counts describe that release checkpoint. The recorded local [two-rendition playback receipt](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/hls-playback-20261012T091818Z.json) reports 27 peer-first fragments (7,290,640 bytes), zero stalls/fatal errors, zero consumer uploading, verified delivery in both levels and across the discontinuity, and restored origin loading after the kill switch. [Hosted soak run 38231951028, attempt 2](https://github.com/forgesworn/relayswarm/actions/runs/38231951028/attempts/2) tested twelve honest viewers, a tampering seeder and an origin-only baseline, with three arrival waves and a 180 s final measurement window. Its `hls-soak-receipts` artifact and [committed summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/hls-soak-summary-20261012T100026Z.json) record: - 923 of 1,343 fragment loads from verified peers (68.7%), 385,107,472 media bytes. - Zero stalls/fatal errors for all twelve viewers and the baseline; zero swarm/page errors. - Seven viewers banned the tampering peer. Two honest viewers used origin throughout. - 571 samples: at most four connected/dialling peers, 5,091,228 held bytes and one relay. - All stopped swarms released resources and restored the original loader. The short soak used loopback `host/host` candidates and capped honest/baseline forward buffering at 4 s (maximum 6 s). It is not evidence of hours of operation, internet throughput or net data savings. Older [spike measurements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/RESULTS.md) retain their own dates, topology, code and integrity assumptions. ## Outstanding gates **v0.2.0** includes the additions below. These changes are absent from v0.1.0's immutable release assets. Release and merged source do not establish production readiness. ## Previous deployed checkpoint: 2dd on 14 October 2026 The deployed application checkpoint is `2dd156e64f86e6f18b616e7d87159aee1c43eac2`. All nine required jobs passed on attempt 1 of [CI run 38525990386](https://github.com/forgesworn/relayswarm/actions/runs/38525990386). The optional CI soak was skipped; it is not a new sustained pass. The normal-TLS public client is 734,604 bytes, SHA-256 `34259c97f1317c3ae4668c2634df6d57287ca8a40b4c8a249088c0400f3c1a61`; the image is `sha256:200807d127f0e8cac781b1d9bd36ddfb0541285cc3eae2db96590d5410dc189c`. Guarded deployment preserved publisher identity and private state. The permanent HTTP/1.1 proxy retains independent EE provenance; a later documentation commit does not change the recorded application source. The fresh offline production-only consumer passed ten documented imports, byte-exact packaged demo/browser modules, installed CLI configuration and separate-process verified native transfer/HTTP fallback. The local tarball is 924,153 bytes/197 files, SHA-256 `b1b35376140af23aedb021598f33dbd4d1da69568405853b1d257a9549804ae3`. The exact source archive is 3,358,720 bytes, SHA-256 `bdb50144f30d089a6fee2baa9ffe6aa98005e1b76b45d282951a6a988a335d04`. The rebuilt standalone ESM is 119,525 bytes, SHA-256 `c3df43a8d16bb1a4bd7e6fb2373b9f5e70e9c70871b6763c079136beed4e5a24`. These assets remain unpublished; local checks do not prove downloaded immutable-release acceptance. The ordinary four-role public check remains **RED** over 60.049 s: playback passed, but contribution and both-quality verified payload failed. The receiver accepted 15 low-quality loads/3,169,304 bytes and no high-quality peer payload; both contributors retained consent/serving, while the high donor uploaded zero. All 358 fixed-route controls finished HTTP 200/H1; HTTP 200 does not prove an admitted response body. There were no new measured stalls, fatal/native/page errors or zero-frame intervals. The high donor's earlier 1,247 ms stall remains recorded. Actor/provider/controller/outer and actual source-cleanup-v2 proofs passed; source exit 255 is retained. No connectivity cause or fix was established. The same-source distributed checks used fourteen total roles: four M1 contributors in one Chrome process, and ten M4 roles in two Chrome processes (four contributors, four receivers and two origin baselines). They used installed headless Chrome, trusted DOM Start/upload and programmatic dropdowns, without extra RTC/network/permission flags. Their outcomes remain separate: | Case | Actual stopping condition | Result and retained limitation | |---|---|---| | R7 | M4 descendant-resource probe timed out after 52.501 s of measurement | RED; last accepted RSS 8,375,910,400 bytes, process highwater 48/96 and reported free memory 78%; no observed cap crossing or rejected-probe RSS proof; all actor/source cleanup passed | | R9 | M1 process count 33 exceeded the declared 32 after 6.453 s | RED; rejected instant RSS unknown; original explicit browser context-close acknowledgements were false, separately proved endpoint/profile/process/stage/source removal retained | | R10 | Complete M1 orchestration tree count 41 exceeded 40 during setup | RED before measurement; endpoint-only process highwater 33 is a different scope; original unfinished browser cleanup and failed M4 receipt read remain unknown/false, with later exact-identity M4 recovery/removal and source cleanup separately proved | | R11 | Peer-readiness preflight found zero links and zero verified payload | RED before measurement; all fourteen decoded video/native audio in setup, but 300 s/both-quality/two-renewal gates never ran; resource and all original actor/source cleanup proofs passed | R11's separately declared M1 process cap was 64 with the same 3 GiB limit; its complete-tree sampled highwaters were 46 processes/2,590,523,392 bytes. M4 remained at 12 GiB/96 processes, with sampled highwaters 8,060,862,464 bytes/ 52 processes. Reported free-memory minima were 29%/77%. Summed sampled RSS is neither unique physical RAM nor an unsampled peak. Earlier resource REDs remain RED; changing a declared later limit does not retroactively qualify them. R11 retained 133 local peer-connection IDs: 120 timed out after remote SDP was installed and ICE checking observed, with zero opened channels or observed native failure before the engine timeout. These are local endpoints, not unique cross-page peer pairs. All 1,211 fixed-route statuses were 200; 1,210 had terminal CDP completion, with one post-200 policy request still unobserved at shutdown. All 483 admission observations finished without refusal/unknown status; 227 accounted detail evictions do not provide a complete timeline or admitted-body proof. The underlying reachability cause remains unresolved; neither a timeout increase nor a production connectivity fix is supported by these records. Installed M1 Safari 17.6 R2/R4/R5 were **bootstrap-only REDs**, with zero media measurement and no Start/upload action. R2 retained hidden/unfocused readiness snapshots; a fractional-timeout harness defect was reproduced separately without proving the exact terminal cause. R4 refused a maximise route in its own worker allowlist before readiness; that is not proof Safari lacks maximise support. R5 reached its readiness deadline: the last 15 snapshots were hidden/unfocused, 50 earlier predicates were evicted, and late authority withdrawal remains recorded. Exact owned sessions, drivers, workers, stages and outer processes were cleaned; these checks do not establish Safari playback, input or phone acceptance. The actual physical-iPhone read-only USB R2 attempt stopped RED at usb-lockdown in 2.464 s, before any Runtime.evaluate or numeric sample. Its original operation error was not retained separately from cleanup-incomplete; lockdown closure remains unknown. The exact worker/group, private SDK scratch and empty pairing cache were removed. This is no phone playback/gesture/peer acceptance. A prepared diagnostic successor is not an executed test. No further phone result is claimed. See the [current 2dd evidence summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/2dd156e-current-checkpoint-20261014.json). Earlier f393 short passes and older dated Kit, OBS and private-YouTube results below retain their source, date and scope; none is a current 2dd field pass. The full P01–P12 and 37-review-item scope remains open, including a completed same-topology 300 s qualifier, 7,200 s/22-churn operation, complete physical/native-input journeys, Safari, hard NAT, matched total-wire/ actual-cost evidence and immutable-release acceptance. No production-ready or new publication claim is made; completed finite sources are not a live-ingest claim. ## Previous f393 checkpoint on 14 October The previous deployed application checkpoint was `f393abf3d55215bdf58241a4a2af74245d646117`. All nine required jobs passed on their first attempt in [CI run 38511479806](https://github.com/forgesworn/relayswarm/actions/runs/38511479806). The optional twelve-viewer CI soak was skipped, not a new sustained pass. The permanent HTTP/1.1 proxy retains independent EE provenance. The normal-TLS served client is 734,441 bytes, SHA-256 `4fdb2861b08f42e4c82788a5940e0b2b436be52af84bc264998d41cf81938fcb`. The exact image is `sha256:d3bba4a8e8c991cf38d89a3d3a619868851842cda4187c2c0e58c58d4ca5a626`. Its 51-file non-root preflight and actual guarded deployment/public-client attestation passed, preserving publisher identity and private state. The fresh offline production-only consumer passed ten documented imports, byte-exact packaged demo/browser modules, actual installed CLI configuration, independent-process verified native transfer and verified HTTP fallback. The unpublished package is 902,933 bytes/193 files, SHA-256 `f978dcb53dfa7a6e2db9d6c9af23f95e805a75d92a71a1644220853be8b22294`. The exact Git archive is 3,276,800 bytes, SHA-256 `ccf46b011da5fad21a518f4ee8ade29a160bfc8ad4d8dea4fdf22ad006ca6646`. The rebuilt standalone ESM is 119,525 bytes, SHA-256 `c3df43a8d16bb1a4bd7e6fb2373b9f5e70e9c70871b6763c079136beed4e5a24`. Six repository inputs and 20 locked dependency input files, expected exports, absence of external imports, actual import and retained 64-record diagnostics were checked. These local assets remain unpublished and do not prove downloaded- release acceptance. Named receipts are `clean-consumer-f393abf-20261014` and `standalone-esm-f393abf-20261014`; public-client attestation is separate. [Both ordinary cross-machine short checks](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-ordinary-cross-machine-20261014.json) passed playback, contribution and both-quality verified payload. Forward M1 contributors → M4 receiver measured 60.050 s: 28 loads/12,763,132 bytes (13 low/2,732,956; 15 high/10,030,176), with zero link closures and one outgoing dial superseded by a crossed offer. Reverse M4 contributors → M1 receiver measured 60.023 s: 17 loads/8,179,316 bytes (seven low/1,476,364; ten high/6,702,952). It retained two initial donor dial timeouts after admitted remote SDP installation/ICE checking, two receiver request-timeout link closures followed by replacement connections, and two donor channel-error closures. Numeric PC IDs do not identify remote roles; these records do not establish the underlying routing or request-budget cause. No connectivity fix is claimed. All roles recorded zero stalls/fatal/native/page errors or frame-freeze intervals, and both contributors retained consent/serving in each run. Forward controls: 383 HTTP/1.1 responses, 382 finished and one commitment GET cancelled after HTTP 200 headers. Reverse controls: 387 HTTP/1.1 responses, 386 finished and one admission verification still pending after HTTP 200 in the final observer snapshot; its terminal result is unknown. HTTP 200 does not prove an admitted response body. Each run retained a pre-measurement media abort. Start/upload consent was trusted; dropdowns were programmatic, with no native-menu claim. No extra RTC/media/permission flags or whole-heap inspection were used. All actor/provider/controller cleanup passed. Source cleanup v2 matched stable identity, helper/input pins and start/cleanup journal receipt hashes; the reverse review did not independently reread the raw remote journal. VPN Connected was observed before and after each run only, not continuously. Bounded local transport metrics are now deployed; they add observation without changing transport policy. The earlier ordinary sharing reds below remain unexplained. [Distributed fourteen-role qualification](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-distributed-qualification-20261014.json) remains RED; sustained 7,200-second/22-churn, physical/native-input, hard-NAT, matched field-benefit, cost and immutable-release gates remain open across the full P01–P12 and 37-review-item scope. The first distributed attempt (R2) stopped before measurement after a resource assertion whose rejected numeric sample was not retained; original cleanup errors and independent stage recovery remain separate. R3 retained an endpoint subtree RSS rejection of 2,318,106,624 bytes against 2 GiB, at 20 processes and reported free memory 35%. This summed RSS is neither unique RAM nor a simultaneous outer tree peak, and does not retroactively explain R2. R3 actor/source cleanup passed. These distributed checks use installed Chrome in headless mode with loopback remote debugging. They retain trusted DOM Start/upload input and programmatic dropdowns; they do not establish physical input or native-menu acceptance. A separately reviewed R4 changed only M1's complete-tree RSS cap to 3 GiB, keeping the 25% headroom guard, process limits and all admission/authority/deadline gates. All fourteen players started and decoded; measurement stopped RED after 57.222 s on two admission-verification requests without HTTP status. The 1,046 observations retained zero HTTP refusals/429s, two failed unknown-status verifications, 790 accounted detail evictions and no pending overflow. The underlying cancellation/network cause remains unproved. Latest rows precede those failures: seven of eight contributors had positive accepted/reserved upload accounting, two of four receivers had verified payload, and all fourteen had frame/audio decode progress without recorded fatal/native/integrity/policy errors. Aggregate readiness is not complete per-actor qualification. The R4 complete M1 tree sampled at most 2,753,413,120 bytes and M4 endpoint tree 6,650,544,128 bytes, within their declared limits. All browser/context/CDP, endpoint/controller/provider/outer group and stage cleanup passed. Actual source cleanup v2 removed its source, retaining exit 255; a 35-check independent retained proof audit passed, with raw remote journal bodies not independently reread. VPN Connected was observed before and after only. No fourteen-role, two-hour, churn or production-readiness pass follows from these partial results. The R5 diagnostic successor retained seven status-unknown verification failures, zero HTTP refusals and 19.404 s of measurement before stopping RED. Its first failed request was browser-labelled aborted after 3,001 ms; the local fetch record was cancelled after 3,004.9 ms without headers/status. The subsequent own-page snapshot still had the same active swarm, no archived sessions, serving enabled and fresh policy. Exact executed-code review excludes the monotonic stopped lifecycle for this first call, leaving its three-second bounded-operation timer as the inferred abort source. The signal reason itself was not recorded. Why headers had not arrived, and whether all seven cancellations share that source, remain unproved. Resources and all owned/source-v2 cleanup passed; exit 255 is retained. The original conservative audit and separate code-inference addendum remain distinct. No long or production-readiness pass is claimed. R6 stopped RED after 26.930 measured seconds with twelve status-unknown verification failures and zero observed HTTP refusals. Passive browser-network events retained request creation and cancelled terminal events for those calls, with no request-extra or response metadata. All ten M4 roles also retained a failed policy or session poll, including both origin-only baselines; all four M1 roles retained later successful policy/session polls. Separate M1 commitment cancellations remain recorded. This broadens the observed completion gap beyond admission but establishes no browser, queue, VPN, network or server cause. The first later snapshot was already origin-only, so R5's timer inference cannot be reused. All 56 diagnostic lifecycle operations acknowledged; 24 requests still pending when observation stopped have unknown terminal results. Resource and all owned/source-v2 cleanup passed. The linked distributed summary retains these limits and the earlier failures. R7 tested the same fourteen roles with M4's ten contexts split between two independently owned Chrome profiles, five each. The combined 12 GiB/96-process M4 cap, M1 cap, consent, authority and timing gates stayed unchanged. It stopped RED after 13.539 measured seconds with four status-unknown verifications, all in M4-B; M4-A had none. Both origin baselines retained late successful policy/session polls without control failures. This establishes neither a shared failure across both profiles nor a successful mitigation. Two failed verifications had browser request-extra metadata, none had response metadata; wire/server arrival remains unproved. The first later snapshot was already origin-only, leaving lifecycle cancellation possible. Three admission observations remained pending at shutdown (two with HTTP 200, one without status). All three profiles, resources, coordinated actor/provider/controller/outer cleanup and separate source-v2 removal passed. The existing long-run proposal rejects this new topology; no sustained pass follows. The separate [desktop Safari 26.6.2 attempt](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-safari26-session-creation-20261014.json) failed before application navigation: session creation reached its 14.5 s I/O deadline, and the outer attempt ended after 18.810 s. Both HTTP workers were reaped and the exact owned driver exited. No session ID returned, so allocation and session deletion remain unknown. Later guarded checks proved the old processes/socket absent; the nine-file owned scratch stage was archived, verified and removed. No shared Safari process was signalled. The separate source cleanup passed; a single bounded exact-driver log read found no matching events. This does not establish a playback, codec, peer or physical-device result. The separate [desktop Safari 17.6 attempt](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-safari17-startup-20261014.json) created its session and passed resource checks, then stopped before its first mode selection or Start command. The 32.973 s outer attempt completed no media measurement; the individual failed readiness predicate was not retained. This case used a separately reviewed 48-process M1 aggregate limit, retaining the 3 GiB memory cap and 25% headroom guard. Exact-session deletion, owned driver, wire workers, both endpoint stages, provider, outer group and source removal passed. It does not close the earlier M4 Safari 26 unknown-session result or establish Safari media/input acceptance. The subsequent 2dd deployed checkpoint above starts the policy and publisher-session GETs concurrently, retaining no-store reads, two-second polling, five-second authority from issuance and at most three pending checks. Eligible operator OFF is applied before waiting for the session result; session/identity/admission validation and consent rules remain unchanged. A regression using the actual compiled client, fixture media/swarm and real loopback HTTP reproduced expiry with sequential two-second policy plus two-second session responses, then passed with concurrent reads. All 37 focused client/renewal/fetch tests and the maintained Chrome cache regression passed; four HTTP races were independently rerun. Held-session OFF, early session failure before OFF, cancellation, real-outage withdrawal and recovery without restored consent passed. This component evidence does not establish the cause or resolution of the public fourteen-role failures, and the older f393 field records remain separate from the later 2dd deployment and RED checks above. Earlier deployed `0e688470b6746b3a9afe80e1192ac4d46fa6aaea` passed all nine required jobs on its first attempt in [CI run 38500343145](https://github.com/forgesworn/relayswarm/actions/runs/38500343145). Documentation checkpoint `8c09478830e80f781dd01779181174e2cf8693be` subsequently passed [CI run 38506350320](https://github.com/forgesworn/relayswarm/actions/runs/38506350320) without changing that deployed runtime. The following 0e observations retain their original scope and results; f393 diagnostics do not retroactively explain them. The ordinary four-role public short check passed playback, contribution and verified peer payload over 60.013 s: 19 peer loads/6,285,968 bytes across both qualities, with zero recorded stalls/fatal/native/page errors or freezes. Its 369 completed controls returned HTTP 200 over HTTP/1.1; four commitment request aborts remain recorded. The initial wrong-Node-path invocation refused before creating a browser and remains separate evidence. The [180.015 s public renewal check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/0e68847-public-renewal-180-20261014.json) then passed all four declared gates, including own-ticket renewal for all three peer actors. The receive-only actor accepted 90 completed peer loads/39,608,780 bytes: 45 low/9,488,548 bytes and 45 high/30,120,232 bytes, matching donor uploads. These are 89 unique segment contexts; one high context completed twice. Each contributor retained one completed post-warm-up, pre-measurement stall (550 ms low, 2,372 ms high); neither added a stall during measurement, and baseline and receiver recorded none. Fatal/native/page errors and sampled frame freezes were zero. A setup media abort and a nonfatal receiver abort near the quality switch remain recorded. First settled renewal witnesses were at 02:45:39.198 UTC for both contributors and 02:45:59.232 UTC for the receiver on 14 October. Sampled session/stream/key, complete peer-set and link-counter equality held around successful renewal; each peer actor retained two connected links, two opened and zero closed. Consent, serving, monotonic uptime and spent allowance were preserved without reset or reconsent. These passive observations do not prove direct credential CAS or RTCPeerConnection object identity. All 1,009 pre-cleanup controls finished HTTP 200 over HTTP/1.1, with zero failed/pending/dropped controls; initial loading policy-unknown samples occurred before Start. Dropdowns were programmatic; Start/upload input was trusted. Muted native audio decode does not prove audibility. The single-browser, four-context host/host scope does not qualify fourteen roles, 7,200 seconds/22 churn cycles, physical devices, hard NAT or financial savings. A later cross-machine public HLS check on the same 0e revision completed 60.060 s with playback green but contribution and verified peers red. M1 contributors remained consented/serving but uploaded zero; the M4 receiver had two outgoing dial timeouts, zero opened links and zero peer bytes, using origin fallback. All recorded stalls/fatal/native/page errors/freezes/withdrawals were zero. Of 323 controls, 321 had finished HTTP 200/H1 before cleanup and two pending policy requests finished HTTP 200 later; HTTP 200 alone does not prove admission. The observer did not retain gathering completeness, individual ICE states or end-to-end SDP identity, so the failed phase and transport cause remain unproved. Named evidence is `public-cross-hls-0e-analysis-20261014`. The separate raw RTC topology comparison used literal loopback HTTP origins, without HLS/Nostr/admission: cross-machine M1/M4 exchanged 8,192 verified bytes each way in 5.989 s, while same-M4 single-process (fa79) and separate-process (0e) cases transferred zero. Gathering completed in all three; ICE error 701 also occurred in the successful case. Chrome patch versions/topology differ, so neither separate processes nor a named browser/network/mDNS/NAT cause is established. A separate public-origin raw M1-offer → M4-answer case then passed in 7.972 s (`public-origin-raw-rtc-0e-20261014`). Both pages loaded the exact deployed 0e client above and exchanged one hash-verified 8,192-byte message each way. Gathering completed; each actual SDP contained one mDNS-form and one IPv4-form candidate. Both applications remained unstarted, with no media, admission or upload consent; all owned cleanup passed. A read-only receipt still showed the M4 VPN connected at 03:14:35 UTC, with no setting changes. This single raw case does not resolve the separate public HLS sharing red or prove an mDNS/VPN cause. The separate reverse-direction M4-offer → M1-answer case also passed in 7.566 s (`public-origin-reverse-raw-rtc-0e-20261014`): one hash-matched 8,192-byte message each way, complete gathering, and one mDNS-form/one IPv4-form candidate in each actual SDP. Both apps remained unstarted with no media, admission or upload consent; all owned cleanup passed. These raw cases do not reproduce the hosted HLS rendezvous/admission journey or identify its failed phase; investigation continues. A later instrumented restored-VPN cross-machine check passed all three gates for 60.074 s, with 22 verified peer loads/10,151,436 bytes across both qualities and zero recorded stalls/errors/withdrawals. Its whole-heap PC-state sampling could affect timing. The subsequent ordinary check on the same finite source remained red for sharing over 60.020 s: only four high loads/2,697,988 verified bytes (three unique contexts, one completed twice), low zero. Both contributors retained consent/serving. High's 4,038,428-byte/6-served/1-refused counters measure accepted/reserved accounting, not verified receiver delivery or wire bytes. All recorded stalls/fatal/native/page errors/freezes/withdrawals were zero. Of 357 controls, 356 finished; one receiver commitment aborted after HTTP 200/H1 headers. No policy/session failure was recorded. VPN service observations were Connected before ordinary at 04:11:36.953324 UTC and afterward at 04:17:22.016533. These finite, sequential observations establish neither a heap-instrumentation cause nor a VPN mechanism. Named evidence is `independent-ordinary-restored-vpn-0e-analysis-20261014` and `public-passive-hls-restored-vpn-analysis-20261014`. A separate same-M4, two-process raw comparison passed in 6.517 s while the owner had disconnected the VPN, then failed in 27.113 s after confirmed restoration. The pass exchanged one verified 8,192-byte message each way; gathering completed in both cases and ICE error 701 occurred even in the pass. Literal loopback origins, no HLS/Nostr/admission, one attempt per state and owner-managed setting changes limit the result; no sole-cause or public-HLS qualification follows. Receipts are retained in `m4-raw-vpn-restoration-comparison-20261014`. The ordinary run's browser/controller/provider cleanup and actual source cleanup-v2 all passed, including 34 independent retained identity/helper/input/journal checks. This does not upgrade raw remote journal digest claims to an independent host rehash. All owned browsers, readers, test services and finite sources for these completed checks are closed. Renewal source cleanup-v2 matched actual source identity, helper/input pins and before/after journal digest claims; an independent audit passed 29 checks. Raw remote journal bodies were not independently rehashed. At that checkpoint the installed pilot awaited another ingest; no live source was claimed. The earlier public reds, local fourteen-viewer admission reds and original physical/Safari/hard-NAT/cost/7,200-second/release gates remain open. The earlier deployed application was `fa79c2260431cf7901921fab4eaca251c4988f4b`, with all nine required jobs green on their first attempt in [CI run 38496983011](https://github.com/forgesworn/relayswarm/actions/runs/38496983011). The independent permanent HTTP/1.1 proxy remains attested to EE. The new image passed non-root preflight, clean writer drain, stable identity/lease checks and normal-TLS attestation. Its public client is 728,551 bytes, SHA-256 `398ac43764774747fa2fa9a3d15805d66c30101057f664212c05f56cf5250702`. The [fresh fa79 public short check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/fa79c22-permanent-public-short-20261014.json) passed all three gates over 60.011 s: 30 verified peer loads and 13,206,248 bytes across both qualities. All recorded stalls, fatal/native/page errors, freezes and consent withdrawals were zero. All 393 completed controls used HTTP/1.1 and returned HTTP 200. Actual deployment/source identity and cleanup-v2 helper, input and journal provenance passed independent checks. All actors/source closed. Its offline production-only consumer passed all ten imports, packaged demo, installed CLI, verified separate-process native transfer and HTTP fallback. The unpublished tarball is 867,160 bytes/191 files, SHA-256 `149eda2cea6abeb440e3a3d9a993bc2aadc302b5975dc9da79ae776be9e2eed9`. The rebuilt standalone ESM is 114,437 bytes, SHA-256 `cb8e14ee74bf8eeaf6fbb88b9026b00de005190b23b6e7e4ceecd4d8a683b00e`. These remain local artifacts; publication/downloaded-release checks are open. M4 qualification remains red. The accelerated run completed 22 stop/rejoin cycles in 91.208 s before authority expiry; a separate zero-churn steady run stopped after 91.990 of 300 s on seven observed admission address-limit HTTP 429s. It observed zero completed peer links/payload and healthy resource headroom. A burst followed successful ticket renewals; the existing client rebuilt each swarm on renewal. A raw two-context M4 RTC diagnostic also selected no candidate pair and transferred zero bytes, without Nostr or admission. These results do not identify a VPN, browser or transport implementation cause. All owned test resources were removed, including a separately audited scratch-directory recovery. The subsequent 0e source adds in-place opaque-ticket renewal and early outgoing- capacity checks. Host identity/expiry checks, remote online admission, consent, limits and five-second authority remain enforced. Its dated CI/package/public renewal evidence is recorded above; fourteen-role capacity and sustained acceptance remain open. M4 peer connectivity and the earlier admission demand failure are not established as resolved. The preceding deployed application and permanent HTTP/1.1 proxy checkpoint is `ee1510d429ac85f3738c03f10a09b753ec4eb037`. All nine required jobs passed in [CI run 38492003110](https://github.com/forgesworn/relayswarm/actions/runs/38492003110) after one failed-job retry. The original fMP4 startup timeout remains recorded; its cancellation owner is unproved. A preceding Windows cache-hit fixture failure was corrected by measuring expiry renewal relative to its own baseline, preserving the single-read and deduplication assertions. Runtime code was unchanged by that fixture correction. Permanent proxy commit/audit preserved the original inode and shared services. App deployment passed the 51-file non-root preflight, clean writer drain, stable identity/lease checks and normal-TLS client/fresh-media attestation. The image is `sha256:b42b383fbd95bcf6628ade7d0e0acc803b1bb393e210b4c3b9b900f7737b4275`; the public client remains 728,315 bytes, SHA-256 `c264287acad81090c8952f99946f75f844e8f5fa718e907899dc77cacf04ef59`. The [fresh permanent-deployment short check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/ee1510d-permanent-public-short-20261014.json) passed all three original gates over 60.014 s in ordinary Chrome 155.0.8059.41: 13,188,200 verified peer bytes in 30 loads, comprising 15 low loads (3,151,256 bytes) and 15 high loads (10,036,944 bytes). Both contributors retained consent/serving. Fatal/native/page errors and sampled frame freezes were zero. The high contributor retained one 143 ms stall before measurement; no new stall was recorded during measurement. All 405 completed fixed-route CDP responses used HTTP/1.1. Dropdowns were programmatic; Start/upload clicks had trusted witnesses. Browser/provider/group cleanup and exact finite-source removal passed. This short desktop result does not close sustained, physical/NAT or cost gates. A separate fourteen-viewer M4 qualification remains red. The fresh 300 s attempt stopped after 98.945 s when admission HTTP 429 responses prevented ticket renewal and authority expired. Policy/session responses stayed fast. Summed RSS peaked at 8,987,213,824 bytes below its declared 12 GiB cap; all 13 memory-pressure probes reported at least 80% free. Summed RSS is not unique physical memory. The earlier 8 GiB resource-stop result is retained separately. Admission heartbeat traffic and the shared-address limiter are under investigation; no limiter or authority deadline has been relaxed. All owned qualification resources were removed. The loader now skips redundant admission requests for unchanged credentials on connected/dialling peers and for unknown peers while full or cooling down. Changed credentials on active peers still refresh. Every SDP/retry and served object retains its online admission check; no positive-authority cache is added. The new source requires fresh cohort and deployment acceptance before this qualification failure can be considered resolved. Fresh offline consumption of the deployed head passed ten imports, packaged demo, installed CLI, separate-process verified native transfer and HTTP fallback. Its unpublished 190-file tarball is 859,013 bytes, SHA-256 `575e443e3bbe73fa811151ff8ae73c421067e65fa653faeb3523eaf226ec5490`. The unchanged standalone ESM hash is recorded below. Downloaded-release acceptance and v0.2.0 publication remain pending. The preceding deployed checkpoint was source `2e1bdeb724eb45e37f7b97604e4f396a73985719`. All nine required jobs passed in [CI run 38483497575](https://github.com/forgesworn/relayswarm/actions/runs/38483497575); the optional long soak was skipped. Fresh offline production-only consumption passed ten documented imports, exact packaged demo/renewal/recovery bytes, the installed CLI, separate-process verified native transfer and HTTP fallback. The unpublished tarball contains 190 files, is 847,937 bytes and has SHA-256 `21103ad4dc0701ed41d07f4393560053a480963995bbe4682bfda76bf4b0c0e1`. The standalone ESM remains 114,201 bytes, SHA-256 `01de11837fbd08098bf98b6e8be945866ef766f76629030fec89de2318170d19`. Local artifacts do not prove downloaded-release acceptance. The guarded app-only deployment passed the 51-file UID-1000 image preflight, clean writer drain, stable identity/private lease/shared-service preservation and normal-TLS exact-client/fresh-playlist attestation. Image is `sha256:e73b4a0bb57ca37950abab2ae5c9f22c63a1ab4128880b9c85883d438701d87a`; public client is 728,315 bytes, SHA-256 `c264287acad81090c8952f99946f75f844e8f5fa718e907899dc77cacf04ef59`. Reporting remained off. The maintained no-store real-HTTP renewal regression passed, but the deployed ordinary four-role Chrome 155.0.8059.40 check recorded red for contribution and verified peers: 60.013 s of requested video/native-audio decode passed, with zero fatal/native/page errors or stalls, while both contributors uploaded zero and the receiver verified zero peer bytes. Authority-expiry timing is retained; the underlying missing-response cause remains unproved. A subsequent sequential comparison used Chrome 155.0.8059.41 and the same finite source/client. Adding only `--disable-http2` passed all three short gates in 60.009 s: the receive-only actor accepted 2,806,464 verified peer bytes at both qualities, and both contributors retained consent/serving. Successful fixed-route responses reported HTTP/1.1; the high contributor's one stall is retained. A fresh default-browser check on the same source measured 60.015 s: playback passed but both contributors withdrew, uploaded zero, and the receiver verified zero peer bytes; successful requests used HTTP/2. These sequential same-desktop checks isolate a useful transport diagnostic, not a proven HTTP/2 implementation cause or default production acceptance. No quota resets, automatic reconsent, fake media or permission overrides were used. Browser/provider cleanup passed in all three windows. The independently bounded source remained Root-owned and separate from observer cleanup. Named evidence: `artifacts/public-cdp-2e1bdeb-run-20261014`, `artifacts/public-cdp-2e1bdeb-http1-diagnostic-r2-run-20261014` and `artifacts/public-cdp-2e1bdeb-http1-window-default-run-20261014`. The later temporary server-H1 trial used ordinary Chrome 155.0.8059.41 with no browser transport override and unchanged app/client source. Its 60.009 s measurement retained a partial red result: playback passed and both contributors kept consent/serving, but only high delivered peer media (10,082,816 verified bytes in 15 loads); low delivered zero. Contribution and both-quality peer gates therefore failed. All 385 successfully completed fixed-route responses in the four pre-cleanup CDP ledgers reported HTTP/1.1, with no ledger records dropped. Fatal/native/page errors and sampled zero-frame intervals were zero; the high contributor's one stall is retained. This short diagnostic does not establish sustained benefit, a named HTTP/2 defect or permanent H1 readiness. The first trial preparation failed before proxy mutation because the image's file-capability binary could not execute with all capabilities dropped. That setup red remains retained. The isolated r2 preflight passed after copying and hash-verifying the same public binary bytes without capability attributes in private tmpfs; non-root/no-network/no-shared-mount/cap-drop/NNP bounds stayed in place. This setup correction is not a product or transport fix. Browser/provider cleanup passed despite the overall red outcome. Explicit controller finish and audit restored the original H1/H2 file and complete runtime at the same inode, proved the watchdog absent, and separate source cleanup removed the exact owned source (retained exit code 255). Named evidence is `artifacts/public-cdp-server-h1-trial-r2-run-20261014`, `artifacts/caddy-http1-trial-2e1bdeb-r2-preparation-20261014` and `artifacts/public-proxy-http1-trial-source-2e1bdeb-r2-preparation-20261014`. No permanent protocol change was made or authorised by this partial trial. A subsequent r3 trial retained ordinary Chrome 155.0.8059.41 and the same application/client, with only temporary server H1 and bounded read-only metrics. All three gates passed in 60.010 s: the receive-only actor accepted 13,205,308 verified peer bytes in 30 loads, comprising 3,151,444 low and 10,053,864 high bytes. Both contributors kept consent/serving throughout; fatal/native/page errors, stalls, sampled zero-frame intervals and contribution withdrawals were zero. All 407 successfully completed fixed-route CDP responses reported HTTP/1.1. No browser transport override, quota reset or reconsent was used. Browser/provider cleanup, controller finish/audit and exact source removal passed. The original H1/H2 file/runtime and inode were restored and the watchdog was absent. Evidence is retained under `artifacts/public-cdp-server-h1-trial-metrics-r3-run-20261014`, `artifacts/caddy-http1-trial-2e1bdeb-r3-preparation-20261014` and `artifacts/public-proxy-http1-trial-source-2e1bdeb-r3-preparation-20261014`. This one-minute ordinary-browser result supports selecting H1 as a deployment mitigation; it does not establish a specific HTTP/2 implementation fault or replace the r2 partial red. Permanent H1 has not been deployed: it still requires a new clean commit, all nine exact-source CI jobs, guarded actual application of the proxy change, and fresh default-browser short and full two-hour gates. Decoded audio bytes do not prove audible output. Prior red outcomes, sustained load, full physical/hard-NAT/cost gates, v0.2.0 publication and downloaded-release acceptance remain open. ## Earlier bb90 checkpoint and no-store regression The earlier deployed checkpoint is source `bb90bd6a54cabc163846ee1737ac3fe28b63eaa2`. All nine required jobs passed in [CI run 38478501111](https://github.com/forgesworn/relayswarm/actions/runs/38478501111); the optional long soak was skipped. Fresh offline production-only consumption passed all ten documented imports, exact packaged demo/renewal/recovery bytes, the installed CLI and independent-process verified native transfer plus HTTP fallback. The unpublished tarball contains 188 files, is 837,701 bytes and has SHA-256 `7358efafe3e3332d749e8ea515a70d8d2e8b8bb5721f97d2054e962170dce49e`. The standalone ESM is 114,201 bytes, SHA-256 `01de11837fbd08098bf98b6e8be945866ef766f76629030fec89de2318170d19`. These local candidates do not prove downloaded-release acceptance. The guarded app-only deployment passed exact archive-byte verification, a 51-file UID-1000 no-network/no-state-mount image preflight and a clean drain with all scoped old writers gone. Stable publisher identity, private lease/token metadata, shared services and the active TCP-only proxy configuration were preserved. The actual image is `sha256:1e63daaf47dd4e41cd28713838112e816a679a6017d1d440ce9e70a7a400a592`; its app started at 22:49:26.883960902 UTC on 13 October. Normal-TLS public client bytes matched SHA-256 `25a8416911bc51b1f6764a784d4444295db02c12396c59ddd82450bf56fff58c` (728,262 bytes), both fresh playlists passed and reporting stayed off. The subsequent ordinary four-role Chrome 155.0.8059.40 public check measured 60.010 s. Requested video/native-audio decode passed with zero fatal, native or page errors in every role; each contributor retained one stall. Both contributors uploaded zero bytes and the receiver verified zero peer bytes, so contribution and peer acceptance remain **red**. Trusted input enabled both upload controls, and recorded contributor rows stayed visible/focused. Their withdrawals closely matched the last completed renewal's issuance plus the five-second authority lifetime. Later overlapping policy requests showed about three seconds of delay before send and completed too late to preserve authority. This supports expiry as the withdrawal boundary, without a captured reason code or a proven cache, protocol, transport or host cause. The initial cancelled requests had no response, extra-info, protocol or send timing; successful neighbours used reused HTTP/2. A later admission-verification cancellation occurred after withdrawal and cannot explain its onset. Named receipts are `artifacts/public-cdp-bb90bd6-r3-analysis-20261014/analysis.json` and `artifacts/public-cdp-bb90bd6-r3-run-20261013/wrapper-receipt.json`. The public-safe analysis manifest SHA-256 is `bd2d5ad098ca639f83398aff5a8b4b23994817b67a892d723193439fd439c926`. Browser/provider cleanup passed. The observer intentionally did not remove Root's finite source; separate guarded cleanup passed in `artifacts/public-m4-phone-source-bb90bd6-preparation-20261013/host-cleanup.json`. This short desktop check does not close sustained, physical, hard-NAT or cost gates. v0.2.0 publication and downloaded-release acceptance remain pending. A separate local real-HTTP comparison on 14 October held the first policy response before headers. With the default client, the next identical-URL request reached the server after 5,002 ms and consent expired. An in-memory no-store comparison reached the server after 2,001 ms while the first request was still held, preserving consent and serving. Both retained the original five-second request timeout (5,000.4/5,000.8 ms observed). Ordinary Chrome, trusted native controls and real server arrival evidence were used, without route interception, cache flags, fake media or permission overrides. The supported production change adds `cache: 'no-store'` to three authoritative policy/session fetch calls; authority lifetimes, request deadlines and admission checks are unchanged. Prepared client SHA-256 is `b0bc1f84f9c24cdf210bbfdfec9eb25cbfdd07521fad0b43c90f299c66b8b2b8`. The comparison receipt is `artifacts/policy-cache-lock-20261014-run-r2/receipt.json`; its original failed setup and the earlier maintained-harness result remain separate. This establishes a local identical-request scheduling defect and a supported correction; it does not identify why the initial public request had no response. The final corrected maintained regression passed: later policy/session requests reached the real server after 2,000/2,001 ms while their predecessors were held. Full 503 outage expired authority and cleared consent; restored policy left consent off. Root's combined suite exited zero with eight existing operator checkpoints, 117 publisher tests passed/one skipped and syntax checks for 105 modules. Source and evidence hashes were rechecked unchanged in `artifacts/policy-cache-integration-20261014/validation.json`. Browser/demo/relay/ media closes were awaited; no independent kernel inventory was captured. The later exact-2e1 CI, package and deployment gates are recorded above. The earlier bb90 contribution result remains red, and the no-store regression does not close the later ordinary public sharing gate. The earlier candidate checkpoint is source `cee92281b20aa5e60fc39d0e0cb2a368daa83747`. All nine required jobs passed in [CI run 38471147105](https://github.com/forgesworn/relayswarm/actions/runs/38471147105); the optional two-hour soak was skipped at this head. Fresh offline, production-only package consumption passed all ten documented imports including metadata, exact packaged demo/recovery bytes, the installed ICE CLI and actual separate-process native delivery of 131,097 verified bytes. Native delivery used zero HTTP origin requests; peer absence then produced one verified loopback origin fallback. Owned services and scratch were removed, and HEAD stayed clean. The tarball contains 186 files, is 823,201 bytes and has SHA-256 `b847aa0d57f68975aa69bdc70589f1aa5066b757e748001ccb7bb967853a3d3a`. The standalone ESM candidate is 114,201 bytes, SHA-256 `01de11837fbd08098bf98b6e8be945866ef766f76629030fec89de2318170d19`, with the expected five exports, no external imports and a successful local import/off-mode check. These are local candidate artifacts, not published or freshly downloaded release assets. At the cee checkpoint, all 48 runtime/package/lock inputs were unchanged from f999 and 6b2; the six browser inputs and resulting ESM bytes were identical. The preceding 6b2 Ubuntu job's native suite passed 17 tests but its publisher fixture failed a server-relative body timing assertion. That original CI red is retained. The narrow test-only correction holds the real HTTP body after client header observation and preserves the timing assertions, including an 80 ms delayed client continuation. The cee checkpoint does not replace the deployed f999 application or close its sustained public contribution/device/cost gates. The earlier verified public pilot checkpoint used source `f9990b36956282f3d4e849b55bd64a79eb440151`, whose nine required jobs passed in [CI run 38449139246](https://github.com/forgesworn/relayswarm/actions/runs/38449139246). Its image is `sha256:20199491827b9ea69ac560ac50be5eed5376aab30fbd0a07227544ce8898b243`; its public client SHA-256 is `b746f45216d3ac6e5d1bd21b5748f91c0115c71d00ee678c930070596bbef50d` (723,954 bytes). Normal public TLS, both fresh rendition playlists and retained publisher identity were verified. The image permission challenge extracted public directories as 0700 and files as 0600, then proved all 50 copied files, module imports and actual entry-point help readable by UID 1000 without network or state mounts. The permanent Dockerfile defence normalises copied public runtime permissions while leaving private state untouched. Clean production-only package consumption and the standalone ESM candidate also passed locally. These facts bind the f999 application snapshot. A later proxy-only change was validated with the pinned Caddy 2.11.7 binary and reloaded in place: the TCP-only overlay now enables HTTP/1.1 and HTTP/2 and returns `Alt-Svc: clear`. Fresh normal-TLS checks passed for both protocols with the same client identity. The Caddyfile inode, app/router/proxy container identities and mounts remained unchanged; no UDP 443 listener remained and the rollback watchdog was reaped. This corrects an unavailable HTTP/3 advertisement; it does not establish the cause of previous policy timeouts. The cee candidate CI and local package/bundle gates above are green; v0.2.0 publication, fresh downloaded-release consumers and final exact-source deployment acceptance remain pending. The earlier `768a3a4f20d91bf2194513181354be70f6a8e5da` passed nine required jobs in [CI run 38439565770](https://github.com/forgesworn/relayswarm/actions/runs/38439565770). Its first image failed before startup because archived public directories were unreadable by UID 1000. Explicit audited rollback restored the previous image without deleting state or fences; the corrected image passed its non-root 50-file/import/entry-point preflight before replacement. Source `a0231aadcdd81fe67fe702ac7214042d196eb39f` passed ten jobs, including the optional two-hour soak, in [CI run 38392804791](https://github.com/forgesworn/relayswarm/actions/runs/38392804791). Each result retains its original tested source. The a023 CI soak measured 7,200.366 s after its final arrival wave, with twelve honest viewer roles, one corrupt peer and one origin-only baseline. Twenty-two departures/rejoins replaced eight roles; it was not twelve uninterrupted two-hour sessions. Final incarnations accepted 8,268,934,096 peer bytes, and departed incarnations separately recorded 7,396,517,088. All twelve honest roles banned the corrupt peer. Retained final/departed stall and fatal hls.js counts were zero, and resource/loader cleanup passed. Native media errors were not separately instrumented, so no independent zero-native-error claim follows. This was a single-Chrome loopback fixture with fake microphone/permission flags, an mDNS override and `host/host` candidates, not public-network acceptance. The deployed a023 HTTPS/WSS four-context run completed 7,205.094 s but **failed sustained contribution**. After policy timeouts around 13:24:57 UTC, both contributors withdrew with allowance remaining. No automatic reconsent or quota reset was applied. The receipt retains 34 of 2,932 sampled intervals without decoded-frame progress, plus 23/20/45/15 stalls for low/high/baseline/ receive-only roles. Fatal hls.js errors, separately observed native media errors and repair attempts stayed zero. The receive-only role accepted 572,731,284 peer bytes with zero uploads, including receiving from separately recorded support actors after formal contribution stopped. The red result is not reclassified as a sustained peer or production-capacity pass. A later f999 public ordinary-Chrome observer measured 60.008 s and passed its three separate gates: video/native-audio decode at the requested qualities, both explicit contributors remaining serving, and verified receive-only peer payload at low and high. Contributors reserved 3,151,256 and 8,106,372 media bytes; the receiver accepted 10,576,128 bytes in 26 verified loads with zero upload. Fatal/native/page errors and stalls were zero. No fake media, permission, mDNS, RTC or TLS overrides were used. This short same-laptop `host/host` result does not close the deployed two-hour gate. The preceding public contribution red and first diagnostic observer's receipt-file race remain preserved separately. The next f999 public two-hour attempt was stopped incomplete after 644.855 s whole observer lifetime and 611.134 s measured, rather than 7,200 s. High contribution failed during warmup: `/delivery-policy.json` started at 20:18:17.082 UTC, returned no observed headers or body, and was cancelled by the existing five-second deadline. At 20:18:22.308, the own DOM showed policy unavailable, upload unchecked and origin fallback. At 20:18:24.323 the policy was available again, with upload still unchecked. No reconsent or quota reset was applied. The request is the demonstrated withdrawal trigger; aggregate server windows showed fast handler work, but cannot establish whether this individual request reached the app or identify transport, proxy or browser scheduling as the cause. Partial video/audio progress and zero fatal/native errors/stalls were retained; the receiver accepted 60,508,176 low-quality peer bytes. There was no measured high receiver phase or completed sustained pass. The first source-expiry refusal created no Chrome actor. All owned sources, browser groups, profiles and readers from these checks were subsequently removed/stopped with guarded receipts; the pilot awaits its next ingest. A subsequent public Chrome check after the proxy change measured 60.120 s. Video/audio decode passed; contribution and peer payload at both qualities failed. A five-second session fetch cancellation withdrew high contribution during warmup, and a later policy cancellation withdrew low contribution. The receiver accepted 2,731,076 low-quality peer bytes in 13 loads, with no upload or verified high-quality loads. Fatal/native errors were zero; stalls were 1/2/0/1 across low/high/origin/receiver. The requested private NetLog capture was empty, so protocol and queue attribution remain unavailable. All owned browsers, readers and the finite source were stopped/removed. The independent proxy correction does not close sustained contribution or identify the cause. The subsequent passive CDP observation of f999 measured 60.015 s: playback passed, contribution and verified peer payload failed. Both contributors uploaded zero bytes, the receiver accepted zero peer bytes, fatal/native errors were zero and high recorded one stall. The first policy requests at 22:05:38.226/22:05:38.230 UTC cancelled about five seconds later without a response or response-extra-info event, even after cleanup. Adjacent successful responses reused HTTP/2; the failed requests' protocol remains unknown. Nearby server windows recorded eight completed policy requests with at most 2.2 ms app header work, without an individual request identity match. Browser, provider and source cleanup passed. The transport/queue cause remains unproved; the later renewal-resilience candidate is not deployed by this observation. The renewal-resilience implementation keeps unexpired policy and admission authority during one transient refresh cancellation. It stops serving when that authority expires; a later successful refresh leaves upload consent off. The maintained local Chrome operator regression recorded a 5,000.8 ms policy cancellation while all 63 observations retained consent and serving, with 461,352 uploaded bytes and unchanged quota accounting. A full 503 outage expired authority and stopped serving; later recovery did not restore consent. Eight operator checkpoints, 25 focused tests and syntax checks for 103 modules passed; the publisher suite passed 117 tests with one skip. This loopback fixture uses its existing fake WebRTC permission/media flags and does not prove public, physical or NAT behaviour. Normal exit followed all close awaits; no separate kernel process inventory was captured. The bb90 committed-source CI, package and guarded deployment passed as recorded above; its public contribution/peer gate and the historical f999 failures remain open. A separate TCP TURN test accepted 224,096 signed, verified media bytes in two segments during 5.036 s. It used actual temporary browser credentials and a forced relay policy over an operator-owned SSH TCP forward to the relay host's self-routing fixture. It was a data-channel simulation with a local publisher, not direct Internet TURN, hard-NAT or physical playback proof. The browser receipt passed, while the original controller cleanup stayed red; a later explicit root audit verified fixture/container/credential/listener removal and unchanged project services/firewall rules. An observed existing firewall set membership difference was retained without a proven expiry cause. An installed Firefox 152.0.6 public journey with ordinary Chrome contributors passed verified receiving/uploading, quality and seek, durable quota across reload, fresh consent and origin-only kill. Its pre-reload checkpoint recorded 2,524,652 received peer bytes and 219,020 uploaded bytes. No fake media or permission overrides were used. The corrected visible Safari 26.6.2 journey played video without reported media errors but received zero verified peer payload within 45 s despite five RTC links; its complete peer journey remains red. The earlier Safari journey's peer bytes and later pause are retained separately and do not close that gate. A later physical Pixel/Vanadium check against f999 passed actual origin frames at low and high quality, seek and background/resume. Uploading stayed off, the existing UDP privacy policy was unchanged, and the owned phone access was closed by 20:12:38 UTC. Peer payload was zero because no contributor actor was available for that check; peer acceptance is unmeasured. Its raw overall receipt stays false and the earlier default/temporary-policy peer reds are retained. Physical Pixel/Vanadium peer acceptance from the earlier tests remains red. A separately authorised temporary public-interface-only WebRTC policy test also missed its 45 s peer gate; the original restrictive policy was restored and verified by 14:37:34 UTC. All retained links in that diagnostic matched known non-serving formal roles, not the ordinary serving support actors. Connections alone are not peer transfer or proof that the device can reach every serving actor. The iPhone owner confirmed moving origin video and an audible tone, then reported that playback did not resume after backgrounding or an explicit Play action. Engine/error diagnosis, complete peer/background journeys and automated native input remain unproved. The a023 host parent-crash observer closed green over 309.682 s. A guarded main-process `SIGKILL` stopped the old container namespace. A complete scoped writer/volume/descriptor audit established absence before explicit operator recovery of the retained dirty marker while holding both permanent leases. Publisher identity, client hash and both lease inodes were preserved. The same origin-only page decoded low and high video/audio after continuity advanced from 16 to 17; its final 15 s check advanced 475 frames. One 285 ms stall, transient HTTP 502/503 responses and level-load errors remain recorded; fatal and native media errors were zero. The observer/profile cleanup passed. This proves the measured explicit recovery path, not automatic guardian clean-drain. Scoped resource observations collected 111 exact-container/owned-Chrome samples and 87 isolated HTTPS active-socket samples, with all readers stopped before the run deadline. The main counter prefix missed 8m30s; closed/short socket terminal bytes and browser counter resets leave further gaps. Sampled app raw memory peaked at 308,580,352 bytes. The observed HTTPS acknowledged TCP counter deltas sum to 4,509,684,301 bytes, covering all audiences and excluding complete IP/link overhead. Internal bridge counters are not summed as Internet egress. There is no matched origin-only network baseline or provider billing evidence: total wire reduction and net cash saving remain unproved. Later retained MPEG-TS segments reproduced a fatal hls.js AAC track-discovery error: the first segment contained video without AAC, and the next introduced audio after only a video SourceBuffer existed. The earlier one-shot repair recovered through the alternate rendition in 603 ms. A constructed single-variant VOD then reproduced the same low-only failure: resetting MSE immediately reloaded the video-only prefix and failed again. The next repair waits for the actual media attachment, then resumes at the validated failing fragment. Exact unchanged low bytes recovered in 403 ms with 60 decoded video frames and 4,206 decoded audio bytes; the original fatal error remained. Uploading/reporting stayed off and the spent allowance stayed at 1,234 bytes. The maintained browser regression uses those synthetic bytes. This supported case differs from the original failing live window, whose missing bytes still prevent a causal claim. The diagnostics/CLI source passed 95 publisher tests with one opt-in skip and serial Chrome operator/playback checks. Playback accepted 28 verified peer loads (7,805,572 bytes), both renditions, with zero observed stalls, fatal/native errors or uploads by the receiver. Those existing loopback fixtures use fake-media and mDNS accommodations. A failed-TLS-startup regression also verifies timer and private operational-lease cleanup. Local results do not inherit the deployed source's CI or establish physical acceptance. The first deployed 219 reporting attempt recorded trusted Start and reporting opt-in, then timed out before a report response within 17 s. Root verified reporting-off restoration and removal of its temporary source. Request lifecycle and later checkbox/policy state were not retained, so no collector or transport cause is inferred. A fresh diagnostic setup subsequently lost host connectivity before a browser started; later inspection found no resources from that interrupted attempt. The subsequent deployed 768 reporting check passed with ordinary Chrome, normal TLS and trusted Start/reporting opt-in. The numeric measurement survived a real same-volume process restart; exact duplicates preserved totals and acceptance time. Its entry remained at age 295,610 ms and expired naturally at 301,767 ms. Reporting-off restoration, original policy, lease inodes and temporary-source cleanup passed. No clock, timestamp or retention override was applied. The first red attempt's cause remains unknown. The [later acceptance summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/recovery-reporting-acceptance-summary-20261013.json) records the separate source and scope of these results; the earlier [investigation summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/control-path-media-investigation-summary-20261013.json) remains unchanged. The [13 October acceptance summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/current-source-acceptance-summary-20261013.json) names the receipts, source and scope. Historical MSE causation, sustained contribution, complete Safari/physical-device journeys, varied/hard NAT, resource/cost attribution and released-asset acceptance remain open. The [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) retains the full requested scope. ## Earlier production checkpoints on 13 October The [feature guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) describes the implemented changes; the [delivery checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) retains their full acceptance scope. Local receipts record unmodified-playlist live peer delivery and actual fMP4 automatic quality changes under network shaping. Alternate-audio, authorised AES-128 and mixed HEVC/AVC journeys each have a passing current receipt. Low-latency playback includes verified one-second parts before and after warm delta playlists; the consumer received four peer parts (209,514 bytes) with zero uploads, stalls or fatal/native errors and 3.704 s live lag against a 3 s target. These are desktop Chrome fixtures, not physical acceptance. New integrated adversarial tests cover malformed remote filters, admission and signed-presence churn, oversized frames, cancelled HTTP work, concurrent commitments, relay withholding and stalled native-origin bodies. Forced parent termination tests verify supervised worker groups are killed/reaped before a new broadcaster owns publication. Guardian failure leaves a durable fence for explicit recovery. The Windows cache race has a deterministic local regression; actual Windows CI must still verify the final source. The next native candidate passes 14 tests on both macOS and Linux. Its separate-process CLI uses the unchanged five-second peer budget. The earlier Linux failure traced to an isolated one-node DHT whose NAT analysis aborted before the server received the object request. Four independent local responders passed 20 consecutive diagnostic transfers; the fixture now models that populated network. This does not require multiple bootstrap URLs as a public-client policy or prove real-network NAT traversal. The [native review summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/native-readiness-summary-20261013.json) also records cached-presence discovery, a shared open/ACK deadline and late completion rejection. Final-source CI remains required. A historical Swift adapter using unchanged Kit v2 components completed an encrypted session and a verified 262,181-byte transfer. The subsequent authorised upgrade is published as [RelaySwarmKit v0.5.0](https://github.com/forgesworn/relayswarm-kit/releases/tag/v0.5.0) at `2f0b26a`, with PR/main CI green (39 tests, one opt-in skip) and all five public assets checksum-verified. Its actual public SDK and the production browser sender completed author/delegate transfers of 108,950 fMP4 bytes; corruption, tampering and both pre-request/EOF revocation returned zero bytes. That macOS arm64/Chrome loopback journey uses no wire adapter. The [protocol draft](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NIP-DRAFT.md) and [interop guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/interop/README.md) distinguish the published SDK from the historical incompatible v2 baseline. The player now retains fatal/native error records and permits one bounded origin-only MSE repair per viewing session. Five real corrupt-fMP4 Chrome journeys verify live/VOD recovery, repeated-error termination, cancellation and a ten-second no-progress timeout. Recovery stops contribution and preserves spent allowance; successful repair is recorded separately from the fatal error. This impact treatment does not establish the historical hosted failure's cause. All nine required [CI jobs at `4bffa96`](https://github.com/forgesworn/relayswarm/actions/runs/38375824009) passed. That exact image runs on the public pilot; its browser bundle matches the committed source. The old app stopped cleanly, and an encrypted private state backup passed an isolated identity/token/generation and permission restore check. An actual fifteen-minute four-context HTTPS/WSS diagnostic received both peer qualities (145,183,188 bytes), with zero receiver upload and zero fatal/native errors. All 372 sampled intervals advanced decoded frames. Stalls and one explicit reconsent following a policy timeout remain recorded. This is short, same-Mac synthetic-source evidence. The subsequent host-callback correction aborts each expired operation's HTTP request; real withholding tests show no outstanding request accumulation. Native discovery also works with zero ephemeral-history replay: a separate process verified 131,097 bytes. Both changes retain the existing deadlines, authorisation and consent rules. All nine standard jobs passed at [`8d5cae3`](https://github.com/forgesworn/relayswarm/actions/runs/38383249960), and its exact image and committed browser bundle run on the public pilot. The playback job required an unchanged-source rerun. A later dispatch repeated the high-rendition miss: the fixture sought before that rendition's peer opportunity completed. Bounded per-rendition checkpoints now precede the intentional seek; the actual corrected test received 31 peer loads (8,662,100 bytes), with zero stalls or fatal/native errors. Separately, one native WAN retry accepted all bytes within 8,873 ms, while another timed out before a UDP route/Noise handoff. That variability remains open and is not explained by the ephemeral-history discovery correction. The Pixel is connected again and initial origin playback started, but its first acceptance run received no verified peer media. Firefox also missed peer delivery in its first run. Safari automation is now enabled: omitting its optional certificate capability returned `acceptInsecureCerts: false`, and selecting its own automation window passed visible-tab readiness with consent off. Complete device/browser journeys remain open. The authorised private YouTube test reported excellent stream health; its owner watch page decoded 428 more video frames and 232,756 more audio bytes over 14.268 s. The stream ended, the archive was deleted and verified unavailable, forwarding was disabled and both temporary credential copies were removed. The channel's default stream key was unchanged. This proves synthetic-source external platform acceptance, with no public broadcast or OBS workstation claim. A separate installed OBS 32.1.2 test used only a generated video/audio scene, the localhost-only SSH ingest forward and an isolated task configuration. Over 92.7 s the public origin-only player decoded both qualities and audio, with zero stalls, fatal/native errors or uploads. OBS closed and the temporary configuration routes were restored. This is real OBS ingest acceptance; it does not combine OBS and YouTube into one measured run or prove physical audibility, screen/camera capture or peer delivery. An actual same-volume `4bffa96` to `8d5cae3` upgrade, rollback and second upgrade retained public identity, increasing sequences and both permanent lease inodes after clean worker shutdown. The same origin-only page recovered both qualities after the first two switches, but remained stalled after the last despite fresh playlists and zero fatal/native errors. Read-only library inspection and a real rolling-playlist control reproduced the obsolete continuity selection. The correction shares the existing one-attempt repair budget, revokes uploading and observes real decoded-frame progress. Treatment, actual held-request cancellation and the ten-second deadline pass locally; the new runtime still needs host acceptance. Old-source long runs were cancelled and are not final sustained-operation evidence. The [private-platform and live-restart summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/youtube-live-restart-summary-20261013.json) retains these outcomes. The earlier hosted H.264 MSE cause, varied NAT, hours of audience/cost evidence and final release/deployment acceptance remain open. Initial wider-media failures and later passes are retained; corrected codec-fixture metadata and startup quality handling do not by themselves establish the cause of the earlier hosted failure. ## Recorded broadcaster pilot evidence from 12 October The table and receipts below describe that earlier checkpoint; newer source changes and their acceptance are recorded above. | Addition | Recorded local evidence | Remaining boundary at that checkpoint | |---|---|---| | Live ingest and forwarding | Synthetic H.264/AAC over actual local RTMP/RTSP, two HLS encodes, separate forward loss/recovery, untrusted RTMPS certificate rejection | Actual OBS workstation and external platform acceptance | | Publisher persistence/cache | Private POSIX state, stable authorisation/swarm after orderly restart, deduplicated streamed hashes and bounded signatures | Windows ACL support; automatic recovery after unclean process termination | | Viewer allowance/scheduler | Concurrent/interrupted payload reservations, cumulative page allowance, healthy-peer preference and measured deadline budget | Full page reload resets allowance; real-network cost and live-edge peer coverage | | Operator controls/reports | Actual Chrome default report silence, explicit numeric reporting, remote off/on, viewer-off priority and policy outage recovery | Admission/Sybil resistance, persistent aggregated operations data | | Trusted stream adapter | Signed latest-update selection, author/origin allowlists, host relay/ICE policy, query flood/timeout/abort bounds | Host query/resource lifecycle, redirects/assets, publisher trust and complete NIP-53 advertisements | | Broadcast browser journey | Actual Chrome, both qualities, source reconnect, continuous visible sequence/CC and stable publisher identity | Synthetic loopback producer; receiving-viewer playlists wait for real peer availability advertisements | | Container package | Non-root image build, pinned router/proxy manifests, private ingest, resource/log bounds, Compose configuration | Sustained host capacity, disaster recovery and independent audience acceptance | An earlier local broadcast Chrome run, using a fixed 600 ms receiving-viewer playlist delay, recorded five verified peer loads, 3,053,872 media payload bytes and zero consumer upload. All four players had zero stalls/fatal errors; its receiving viewer made three media HTTP requests versus ten for the baseline. Those counts exclude signalling, commitments and wire overhead. A separate run at a synchronised live edge received no peer media. An earlier concurrent fixture attempt reported MSE append failures including on the origin-only baseline; its cause remains unresolved. The later isolated success does not close that load/decoder gate. The [current local broadcast receipt](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/broadcast-browser-readiness-summary-20261012T143123Z.json) records six verified peer loads (3,065,716 bytes), both qualities and peer delivery after producer reconnection, zero consumer upload and zero fatal errors across all four players. The consumer recorded one 799 ms restart stall. The fixture now releases each unchanged playlist snapshot after its last four segment keys arrive in real peer HAVE frames, with a 10 s bound; all eleven availability checks succeeded. This controls segment availability for the transfer regression. It does not establish synchronised live-edge coverage, uninterrupted playback or net bandwidth savings. Current checks include 53 swarm/discovery tests, 39 passing publisher/operator tests with one Windows-only test skipped on macOS, 21 broadcast fixture/transport tests, six native tests, Chrome operator/ playback/broadcast receipts and public-relay transfers. These are local checks; the existing release CI links above cover the earlier release checkpoint. Broadcaster feature checks are available on [broadcaster pilot PR 8](https://github.com/forgesworn/relayswarm/pull/8). The initial branch CI found a TLS test that incorrectly required GnuTLS to reject a certificate before completing negotiation. The corrected test measures zero RTMP application bytes plus prompt certificate failure; it passes on actual macOS/OpenSSL and Linux/GnuTLS. A separate peer-first job was cancelled during package installation before its browser test started. A later branch run passed the Windows atomic-playlist regression using a real in-place mutation when Windows denied rename with `EPERM`. Its sole failure was the broadcast browser's low-rendition peer deadline: the consumer requested fresh segments before either contributor held them. The fixed 600 ms playlist delay did not establish availability; the bounded HAVE barrier above replaces that timing assumption. [Branch CI run 38264629670](https://github.com/forgesworn/relayswarm/actions/runs/38264629670) passed all eight required jobs for source `0d8ebd2`; the optional soak was skipped. Its Linux broadcast receipt verifies both qualities and producer reconnect, with zero consumer upload/fatal errors/stalls. Contributor stalls during the source outage remain recorded in the [final pilot summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/broadcaster-pilot-final-summary-20261012T144924Z.json). An external pilot is available at [relayswarm.forgesworn.dev](https://relayswarm.forgesworn.dev) on the existing Hetzner host Till. HTTPS uses a verified certificate; RTMP remains host-loopback only and the test source arrived through SSH. The [hosted summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/hosted-pilot-summary-20261012T131905Z.json) records four Mac Chrome contexts, both video qualities, actual HTTPS HLS/WSS signalling, three verified peer loads (1,563,784 bytes), zero consumer uploads and zero stalls/fatal errors. No playlist delay was needed for that success. A preceding run lacked low-rendition peer payload within its deadline; peer coverage remains variable. A later four-context run against source image `30ffd2c` failed: both contributors and the origin-only baseline recorded fatal MSE append errors, the receiving viewer stalled, and the 90 s watchdog ended the journey. Those failures remain open. A subsequent instrumented 25 s origin-only probe recovered from a catalogue-refresh HTTP 503 without a fatal error; a four-context probe had healthy readable samples before all browser evaluation polls timed out during its final ten seconds. Neither diagnostic probe closes the earlier failure. The observed atomic playlist replacement race now has one bounded fresh-catalogue retry, with deterministic mutation/signature regressions; that fix does not establish the cause of the MSE failure. Raw origin request totals have staggered viewer starts and do not establish matched-interval or net bandwidth savings. The [final-image external check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/broadcaster-pilot-final-summary-20261012T144924Z.json) ran once against deployed image `pilot-0d8ebd2` for 51.6 s including setup and cleanup. Four independent contexts on one Mac Chrome host recorded both-quality origin and verified peer playback, five peer loads (2,955,548 bytes), zero consumer upload and zero stalls/fatal/native media errors. No playlist delay or availability barrier was applied. Actual HTTPS/WSS and stable public identity passed; the publisher matched the earlier pilot. This passing sample does not explain or close the earlier hosted MSE failure. A separate orderly app-container restart restored the same publisher, authorisation, swarm and manifest in 5.4 s. No browser was connected during that restart. Five encoding-only samples over 32 s recorded 30.15–30.29 fps, 1.01x speed, 74.46–90.78% of one CPU core and 122.4–123.6 MiB app memory. These short measurements do not close sustained audience capacity, physical devices, peer NAT diversity or external platform acceptance. The pilot displays a waiting page until a source publishes. The synthetic acceptance source and its SSH tunnel are stopped; the final image was restarted orderly to its verified HTTPS waiting page. Its healthcheck remains unready until fresh media arrives. | Gate | Evidence needed | |---|---| | Physical Android/iPhone | Actual playback engine, consent, background/resume, battery and metered-data receipts | | Separate networks and hard NAT | Paired baseline/swarm measurements, candidate types, origin fallback under failed peer reachability | | Firefox and broader Safari coverage | Current loader journeys on actual browsers/devices | | Sustained sessions and larger churn | Hours of resource/cost measurements with peer arrivals, departures and relay/network changes | | Broader media/ABR | fMP4 playback, alternate media arrangements and evidence-led scheduling beyond the tested subset | | Adversarial coverage | Larger Sybil floods, selective relay withholding and combined exhaustion cases | | Independent implementation | Matching current wire envelopes, signed commitments and successful cross-client journeys | | Protocol/release maturity | Accepted NIP, stable compatibility policy and production distribution/operations evidence | Use [FIELD-TEST.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md) to collect receipts. A second related codebase, successful local tests or a published prerelease does not close these gates. --- Source: [docs/FIELD-TEST.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md) # Publisher/player field test [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Installation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) · [Publisher API](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#node-hls-publisher) · [Release evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) The demo is a runnable publisher and an hls.js player with origin-only, shadow and authenticated peer-first modes. Uploading starts **off**. Receipts are downloaded locally. Reporting is disabled by default; v0.2.1 can offer explicitly opted-in numeric reports and authenticated operator controls. See [operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md). The publisher's signing key stays on the server. v0.1.0 release assets retain their original behaviour. ## Current pilot and evidence scope The experimental pilot runs exact `44b21d6`. Nine required CI jobs, fresh 273-member consumption, guarded deployment and normal HTTPS client/two-playlist attestation passed. Relay-only ICE, TLS/TCP TURN projection, admission 32 and an explicitly selected 900-request address budget are deployed. Nostr account allowances are enabled; integrating websites supply their own authentication through the reusable host account API. Reporting and forwarding remain off. Private state, permanent leases and the independent proxy were preserved. Deployment and finite-source cleanup passed independent fresh reviews. The latest fourteen-role R30 test measured 36.188 s before one contributor recorded an 82 ms origin-only interval. Peer-first recovered, but that does not pass uninterrupted authority. Its delayed session check and later renewal timings fit the interruption without proving an exact request/clock join or downstream cause. All fourteen contexts and owned processes, profiles, tunnels and source passed independent cleanup. The short qualifier remains RED; no matching 300 s or eligible 7,200 s/22-churn result exists. Historical ordinary public, Internet TURN, shared account API, focused LOW lifecycle and native iOS Simulator passes keep their original revisions and limits. Simulator return was still playing, so it did not reproduce the physical stopped-video fault. Natural expiry, browser/network breadth, full shared-media budgets, sustained operation and matched wire/cost benefit remain open. No new manual phone check is required for the accepted Simulator scope. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint), the [checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/44b21d6-current-delivery-checkpoint-20261016.json) and [P01–P12 checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Run locally From the [current source candidate](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md#run-the-source-demo) or a current main checkout: ```bash npm ci npm run demo ``` Open `http://localhost:8787`. Without a media directory, ffmpeg generates two live H.264/AAC renditions (240p/350 kbps and 360p/1 Mbps video, each with 64 kbps audio and 2 s segments). Requires ffmpeg with libx264 and Node 22+. Open several browsers, enable uploading on at least one willing participant, then compare origin-only, shadow and peer-first on another. The demo starts its own in-memory Nostr relay on `/relay`; it uses the engine's default STUN unless `--stun` is supplied. It never asks for microphone or camera permission. `Use origin only` stops the swarm and restores the original fragment loader while the player continues. Applying settings also stops the previous swarm before starting another. Uploading and cellular peer traffic require separate opt-ins. The engine's upload token bucket permits a burst of up to two seconds of the selected limit; it is not a strict per-second traffic shaper. Hiding or leaving the page stops its swarm and clears upload and reporting consent. Returning uses origin until settings are applied again; physical background/resume playback remains a field gate. The unreleased source adds **Resume playback** beside Quality. If returning to the page leaves the video stopped, tap it to reload playback from the origin. It clears uploading/reporting consent and retains errors and spent allowance. The selected peer mode stays selected; press **Apply settings** to rejoin peers and explicitly opt in again before contributing. Returning to the page alone does not request playback. Native iPhone acceptance remains outstanding. When reporting is disabled by the operator, its label says it is switched off and the checkbox remains unavailable. If the host offers a shared account allowance, connecting it is a separate, explicit action using a Nostr signer or the host's signed-in website account. It adds the service's cumulative cap to this browser's allowance and leaves uploading off until a fresh Apply. See [shared upload allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md) for linking, resetting, reconnecting after reload and the service's privacy boundary. The deployed `44b21d6` pilot offers Nostr sign-in; its host website account resolver is unconfigured. The source candidate can fetch policy and publisher session together from an advertised `inline-v1` endpoint. Legacy descriptors retain two parallel reads; malformed advertised snapshots fail closed. The combined response reduces requests without changing authority lifetime or proving a field repair. The player checks operator policy and publisher identity every two seconds, with at most three independent checks in flight. A stalled check cannot block a newer successful check. A fully validated check permits peer delivery for at most five seconds from its issuance, using both elapsed and wall time; delayed responses cannot extend that period. Expiry clears upload and reporting consent and restores origin delivery. A later successful check does not restore those opt-ins. An operator's origin-only policy stops uploading immediately. Local receipts retain failed control requests and bounded renewal observations; these timings do not identify the cause of a network timeout. ## Publish your own media ```bash npm run demo -- --media-dir /path/to/hls --manifest master.m3u8 ``` Use a directory of media you are authorised to redistribute. The directory is not exposed as a general file server: only the entry playlist, its supported variant playlists, their media URIs and init maps are served. Symlinks cannot leave the media directory. Signing requests must match the publisher's current playlist context; a viewer cannot ask it to sign an arbitrary file or digest. The Node-only helper is also exported as `relayswarm/hls-publisher`: ```js import { createHlsPublisher } from 'relayswarm/hls-publisher'; const publisher = await createHlsPublisher({ mediaDir: '/path/to/hls', manifest: 'master.m3u8', // secretKey: yourPublisherKey, // optional; a fresh key is the default }); const event = await publisher.commitment({ path: '/media/low/shared.ts', level: 0, sequence: 12, discontinuity: 1, rangeStart: 188000, rangeEnd: 282000, // end is exclusive, as in hls.js }); ``` Omit both range fields for whole-segment media. The helper derives a fresh, 60 s commitment from the exact file bytes and its playlist records. It coalesces concurrent catalogue reads and allows at most eight concurrent signing operations. It caps playlists at 256 KiB, variants at eight, fragments at 4,096 per variant and signed segments at 16 MiB. hls.js level order is height then bitrate within the supported single codec/frame-rate family. The current publisher supports local full segments/ranges/discontinuities, fMP4, alternate audio, mixed variants, complete parts and warm delta playlists. AES-128 ciphertext requires explicit opt-in; keys and init maps stay on HTTP. Remote/query assets, DRM/SAMPLE-AES, subtitles, I-frame variants and cold delta reconstruction remain unsupported. See [production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) for exact schema 2 contexts and the scope of actual Chrome media tests. The example origin can hold complete live playlist reloads until the requested sequence is published, using the [bounded HTTP contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#example-origin-http-playlists). This changes HTTP playlist representations only; imported parts/deltas, ended streams and mixed unsupported presentations receive no added capability. Keys are ephemeral by default and in v0.1.0's CLI. Current source optionally accepts `--publisher-state /private/path/publisher.json`; preserve this 0600 file in an owner-controlled directory for a stable identity across restarts. Without it, restarting creates a new authorisation and swarm. Current viewers poll session identity and rejoin while retaining the persistent browser allowance. The demo does not establish trust in external publishers. For live OBS ingest and optional independent RTMPS forwarding, use the [broadcast launcher](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md), which manages persistent publisher state automatically. Existing media remains usable without ingest. ## Use separate devices and networks Remote browsers need an HTTPS address trusted by the devices. Configure an HTTPS reverse proxy to the loopback server, including WebSocket upgrades, then: ```bash npm run demo -- --public-url https://trial.example ``` The public URL must be an HTTPS origin with no path or credentials. The demo uses that explicit origin for session and relay URLs; it does not derive it from an untrusted Host header. Your proxy must forward `/relay` with WebSocket upgrade support. Alternatively supply `--tls-key FILE --tls-cert FILE` and `--host 0.0.0.0` with a certificate trusted by all the devices. A plain HTTP LAN address is insufficient for browser WebCrypto. Optional `--relay wss://relay.example` (repeatable, at most eight) chooses external relays instead of the embedded one. Optional `--stun stun:stun.example:3478` (repeatable) overrides STUN. Alternatively, `--ice-config FILE` reads a private STUN/TURN configuration. The same option is available to the broadcaster. The file is a canonical, owner-controlled POSIX regular file, mode 0600, with one link and at most 16 KiB; its parent must have no group/world writes or symlinks. Supply only one of `--stun`, `--ice-config` or the optional renewal setting below. ```json { "v": 1, "iceServers": [ { "urls": "stun:stun.example:3478" }, { "urls": "turns:turn.example:5349?transport=tcp", "username": "temporary-user", "credential": "temporary-browser-password" } ] } ``` The configuration permits at most eight servers, four URLs per server and 512 characters per URL. TURN requires username/password strings of at most 256 characters; keep STUN in a separate entry without credentials. Use only browser credentials, preferably short-lived: `/session.json` intentionally discloses them to viewers. Never put a TURN server's shared signing secret in this file. Restart the server and reload players when the configuration changes. The CLI configures an existing host-provided service; it supplies no managed TURN or super-peer deployment. A TCP TURN configuration needs its own actual transport, capacity and privacy acceptance. An unreachable peer should leave the viewer playing from origin. ### Optional TURN credential renewal The demo and broadcaster accept `--turn-credentials-url https://issuer.example/turn`. It is disabled by default and uses an existing issuer; it does not deploy TURN. The fixed HTTPS URL must have no credentials, query or fragment. Its JSON response must contain exactly `urls` (one to four TURN URLs), `username`, `credential` and integer `ttl` (5–3,600 seconds). The issuer must mint fresh browser credentials per request. Its shared signing secret stays outside RelaySwarm. The server exposes a separate same-origin POST endpoint. Explicit peer Start/Apply obtains credentials; origin-only/native playback and two-second session polls do not mint them. A three-hour HttpOnly, SameSite=Strict cookie isolates each viewer's bounded cache; it is Secure on HTTPS and is not account authentication. Bounds are 64 viewer caches, 64 active endpoint requests, 10 upstream tasks, a burst of 10 with one token restored per three seconds, four seconds for upstream headers/body and 16 KiB per response. Excess work is refused without evicting active viewer state. Settled entries without a live credential cache are reclaimed after expiry or a failed initial issuance; fresh caches and unresolved issuance retain their slots. A reclaimed cookie requires new issuance through the same limits and grants no cached authority. The client refreshes at two thirds of the conservative credential lifetime, with one request at a time and a five-second whole-request limit. New credential material rebuilds peer connections while retaining valid consent, admission identity and spent allowances. An identical cached reply keeps the original lease and peers, does not increment the refresh counter, and uses a bounded retry without extending expiry. Unexpired credentials can survive a failed refresh; expiry, configuration changes or page suspension stop peer delivery. Expiry clears uploading and requires fresh Apply. Returning credentials or returning to the page cannot restore upload consent. Origin playback remains available during peer reconnection. Receipts contain fixed lifecycle counters and redacted lease timing/provenance, never credential values, cookies or issuer addresses. Distinct automatic leases have an ordinal and authority epoch; cached responses keep their original record and deadlines. The debug API `relaySwarmDemo.turnLeaseObservation()` returns only the last observed epoch, ordinal and response timestamp without checking or granting freshness. A full TTL after the observed response is a conservative timing boundary, not proof that the TURN server rejected old credentials or expired an allocation. Focused lifecycle, page-VM and owned HTTP tests pass. The preceding da9 source also passed mock-issuer Chrome rollover locally and in CI. Fresh browser/CI coverage of the cached-reply correction, Internet relay renewal and sustained capacity remain acceptance gates. The embedded relay is for a controlled trial: at most 64 connections, eight subscriptions per connection, 24 KiB frames, 80 incoming messages per 10 s per connection, 512 retained events for up to two minutes, and a 1 MiB outbound queue limit. The HTTP server allows 32 concurrent media responses and 240 commitment requests per 10 s. These bounds do not turn it into a production hosting service or a Sybil-resistant relay. ## Collect comparable receipts 1. Keep the source, selected quality, device and playback window the same. 2. Play origin-only for at least two minutes and download a baseline receipt. 3. Reload, choose shadow or peer-first, and keep at least one opted-in seeder ahead of the viewer. Use the same playback window and download its receipt. 4. Repeat on a different network, then with quality changes, seeks, a late joiner, one seeder leaving, and a brief relay outage. 5. Use origin-only during playback and confirm it continues; download the receipt so the previous session's stopped resource counts are retained. Record your device and network labels before downloading. The labels are viewer-supplied; they do not prove the network topology. A receipt includes the browser version, startup time, stalls, seek recovery, fragment contexts, resource timings and engine metrics. It records no peer addresses or private signing key, but an ephemeral public key can correlate it with relay activity. Nothing is submitted automatically. `totals.peerFirstBytes` measures verified media delivered instead of starting an origin fragment request. It excludes commitment traffic, signalling and peer protocol overhead, so it is **not net connection data saved**. Shadow results measure extra sampled transfers and cannot be labelled origin savings. The upload allowance counter (`bytes.uploaded`) counts full media payloads accepted for serving, including any transfer later interrupted. Pending or refused reservations do not enter this counter; durable quota can retain charges for media never handed to the transport. Neither counter measures acknowledged bytes or total network data. Use device/network measurements for actual data cost. Resource timings count same-origin media requests, including init segments and cache hits. Native-HLS browsers use origin-only playback and report origin resource measurements as unavailable rather than zero. Aggregate counts cover the whole page session. Detail is bounded to the last 256 fragments, 60 snapshots (five-minute window) and 64 mode sessions; older session totals are retained. Stalls exclude user seeks, whose recovery is recorded separately. Startup begins at the Start playback action. ### Scheduler traces The demo player always loads the Rust core. Two page URL parameters, off by default, record what the multi-holder scheduler needs offline: - `multiHolder=1` turns on multi-holder transfers (`multiHolder` in [INTEGRATION.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md)). They need schema 3 commitments, so start the server with `--piece-commitments`. Without it every segment carries schema 2 and the option does nothing. - `trace=N`, with N from 1 to 32,768, keeps N trace rows per mode session (`traceRequests`). Any other value records nothing. - `abrIgnorePeers=1` keeps peer-delivered segments out of the player's bandwidth estimate (`abrIgnorePeers`), so automatic quality follows the origin path. For example `https://demo.example/?multiHolder=1&trace=4096&abrIgnorePeers=1`. Each viewer opens the same URL. The receipt records all three values in `current` and `sessions`, and each fragment record carries hls.js's `bandwidthEstimate` as that fragment arrived. It keeps the trace of the running session and of the latest eight stopped ones. Traces name holders only by per-session labels. `node scripts/trace-report.mjs receipt.json...` replays every multi-holder transfer in the receipts through the committed module and reports holder shares, request timing and buffer ahead; `--what-if 1,2,3` adds an estimate for other holder limits. Loopback traces test the tool only; they do not set scheduler defaults. ## Automated coverage and remaining field gates ```bash npm run test:publisher npm run test:playback -- --resultsDir artifacts/playback ``` The playback test drives these same controls in real Chrome, using two VOD renditions with 2 s shared-file ranges and a timestamp reset after 24 s. It checks both renditions receive verified peer bytes, forward/backward seeks, discontinuity delivery, range responses, retained hls.js statistics, receive-only behaviour, relay reconnect, the kill switch and the downloaded receipt. It compares playback stalls with an origin-only player. Forced quality switches and returning to automatic selection are covered; optimal or broadly adaptive ABR scheduling is not established. Loopback tests grant a fake microphone permission to unlock interfaces; the demo itself does not. GitHub CI runs this regression alongside both live harness modes. A manual workflow dispatch with `soak=true` adds twelve viewer roles in three arrival waves. `soak_duration` selects a 180 s or 7,200 s measurement window; the longer choice includes repeated departures/rejoins and sampled resource bounds. Both are loopback fixtures. The 13 October two-hour result and its instrumentation limits are recorded below; they do not establish deployed or physical acceptance. The v0.1.0 [completed soak](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#release-verification) recorded zero stalls/fatal errors and 68.7% peer-first fragment loads, with uneven per-viewer benefits. Its recorded receipt does not establish separate-network performance. The live peer-first fixture caps forward buffering at 4 s (maximum 6 s), keeps its tampering seeder ahead in availability, and waits for an observed ban before adding other peers. Its origin-only baseline uses the same buffer settings. A playhead lead alone does not guarantee that a live-prefetching viewer will ask the tampering seeder for bytes. Presence remains swarm-wide; encrypted signals are subscribed to by recipient. Clients also check the subscription's filter before verifying and dispatching relay frames, so a relay cannot widen it into an all-audience signal feed. | Gate | Evidence required | |---|---| | Desktop Chrome and Firefox on real networks | Current installed Firefox journey passes; paired matched network/cost receipts and broader coverage remain open | | Physical Android and iPhone | Playback engine identified, consent respected, background/resume and metered-data behaviour | | Home broadband vs mobile carrier | Selected candidate types plus paired receipts from separate networks | | VPN or hard NAT | Playback continues from origin when direct peers cannot connect | | Longer sessions and audiences | Loopback two-hour churn passes; deployed two-hour sustained-contribution gate red; attributable wire/cost measurements remain open | | Independent-client protocol interoperability | Current public Swift SDK/browser journey passes; actual native application/input and wider physical integration remain open | These field gates remain outstanding until their actual receipts are recorded. No new physical-device or internet-network result is claimed by the automated Chrome tests. ## Earlier completed fixture checkpoint: 07 on 14 October 2026 [Exact 07 CI 38616043417](https://github.com/forgesworn/relayswarm/actions/runs/38616043417) passed all nine required jobs on attempt 1; optional soak was skipped. Its Linux Chrome 155.0.8059.79 injected broadcast fixture passed four checkpoints with six verified peer loads/3,125,876 bytes (low/high uploads 221,840/2,904,036). All 239 numeric observation rows and four final extractions passed without drops/unknowns/unlabelled objects. Each donor retained one stall; consumer and baseline had none, and fatal/native/append failures were zero. The raw receipt has no full actor/API or OS-reaping cleanup flags. This is automated headless loopback coverage with declared RTC/fake-media settings, not physical acceptance. Prior abb Windows RED and 426 media RED remain separate; no historical cause or playback repair is established. Package/ESM proofs belong to 426, with no fresh 07 package proof yet. Deployed 8f is unchanged. Static credentials still limit exact 07; that CI does not qualify the later optional renewal candidate. The [07 summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/07ea96b-ci-checkpoint-20261014.json) retains these scopes; P01–P12, long/churn/physical/hard-NAT/cost and release gates stay open. ## Earlier controlled checks: 426 on 14 October 2026 The deployed pilot remains 8f. Later exact source 426 passed fresh offline package/ESM and installed native/fallback checks, but [CI 38607468217](https://github.com/forgesworn/relayswarm/actions/runs/38607468217) finished eight required PASS/one media FAIL at the first low-quality peer gate. A separate 33.759 s local injected diagnostic passed with six total peer loads/ 3,107,076 bytes across both qualities; only the last high object was observed post-restart, completing 366.123 ms before its recorded deadline. Its Mac Chrome 155.0.8059.41 differs from CI Linux 155.0.8059.79. Maintained queued/accepted HAVE test observations add evidence; they do not repair playback or replace that RED. One controlled test used an existing shared Internet TLS TURN service, two headless pages, local synthetic HLS/Nostr, injected relay policy and trusted Start/upload. In 90.005 s measured/105.150 s whole, the receiver recorded 34 complete verified peer fragments/3,956,272 bytes and the contributor recorded 4,175,104 uploaded bytes. Both pages reported positive selected TLS pairs in 67 of 91 samples. Each constructed two PCs; the final seven samples had no active PC while video/time continued. Recorded stall/fatal/native projections were zero, with missing-field zero defaults retained as a limitation. The fixed low-quality control did not retain per-fragment level identifiers; this is not both-rendition or continuous 90 s TLS evidence. The CLIs read `--ice-config` once, session responses repeat the initial array, and new peer connections use captured options. There is no supported ICE refresh path. The observed 3,600 s issuer TTL leaves fresh allocations or reconnections during a 7,200 s session unproved, without establishing that already-created allocations die at credential expiry. The 90 s result does not close that gap; an optional server-owned, expiry-aware refresh path remains follow-up work with consent/admission/spend retained and origin fallback. Client/group/scratch cleanup and separate issued private ICE file/directory removal passed. The shared service, firewall and provider settings were not changed. Its actual server quotas/allocation absence, physical devices, difficult NAT, wider networks, sustained cohorts/churn and matched wire/cost remain unproved. This result is separate from the earlier SSH-only simulation and Till inventory. See the [sanitised checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/42608f7-source-and-tls-checkpoint-20261014.json). Later exact-07 CI passed separately above; the full P01–P12/release gates remain open. ## Current field checkpoint: 8f on 14 October 2026 The deployed source is `8f482b4528a671acfe9f1afc336cce5743aaaefd`; all nine required CI jobs, fresh local consumer/ESM checks and guarded deployment pass. See [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#historical-deployed-checkpoint-8f-on-14-october-2026) and the [8f summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/8f482b4-current-checkpoint-20261014.json). Ordinary cross-Mac playback passed over 60.119 s, but contribution and both-quality peer delivery failed: no channel opened and verified peer bytes were zero. All 120 populated retained buffer geometries matched the existing calculation. Original cleanup failed its 0.5 s process probe and strict M4 watcher command comparison; later exact absence/removal and source cleanup are separate proofs. A further prelaunch interpreter capture refused a remote timestamp 68 ms ahead; no workload, clock change, timeout extension or repair is claimed by that result. The earlier TURN test used an SSH tunnel and its temporary server was removed. Fresh Till metadata confirmed no known running TURN service on that host; the later existing shared-service TLS result is recorded separately above. Hard-NAT and complete field acceptance remain open. Physical/Safari, same-topology 300 s, 7,200 s/22 churn, matched wire/cost and release/download gates also remain open. ## Previous field checkpoint: df51 on 14 October 2026 The deployed source is `df51cbed1ebb3bd09ef1b521c451d6b47989a664`, with all nine required CI jobs and guarded pilot deployment passing. Both shared account methods are implemented; the pilot offers Nostr, while a website supplies its own authenticated resolver. See [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#previous-deployed-checkpoint-df51-on-14-october-2026) and the [df51 evidence summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/df51cbe-current-checkpoint-20261014.json). The ordinary 60.110 s four-role check passed playback but opened no peer channel and received zero verified peer bytes. Positive 1,500 ms budgets and no matching HAVE were observed; a scheduler/cache cause was not proved. A separate 60.027 s heap/native-stats diagnostic retained in-progress UDP pairs with positive ICE request counters and zero observed replies. Repeated observations are not unique pairs or traffic deltas; eight completed latest snapshots remain unobserved. This identifies a connection-check boundary, without establishing a network cause or ordinary qualification. No phone, privacy or VPN setting was changed. Original M4 controller cleanup remains unknown and watcher cleanup false in both checks. The diagnostic's strict command comparison refused before TERM; birth/PGID matched, but the replacement command was not captured. Later exact process/group absence and stage removal are separate observations. M1 and both source-cleanup-v2 proofs passed; the finite sources are removed. Complete device, Safari, separate-network/hard-NAT, 300 s qualification, 7,200 s/22-churn, matched wire/cost and immutable-release gates remain open. ## Previous field checkpoint: 2dd on 14 October 2026 The deployed application checkpoint is `2dd156e64f86e6f18b616e7d87159aee1c43eac2`. All nine required jobs passed on attempt 1 of [CI run 38525990386](https://github.com/forgesworn/relayswarm/actions/runs/38525990386). The optional CI soak was skipped; it is not a new sustained pass. The normal-TLS public client is 734,604 bytes, SHA-256 `34259c97f1317c3ae4668c2634df6d57287ca8a40b4c8a249088c0400f3c1a61`; the image is `sha256:200807d127f0e8cac781b1d9bd36ddfb0541285cc3eae2db96590d5410dc189c`. Guarded deployment preserved publisher identity and private state. The permanent HTTP/1.1 proxy retains independent EE provenance; a later documentation commit does not change the recorded application source. The ordinary four-role public check remains **RED** over 60.049 s: playback passed, but contribution and both-quality verified payload failed. The receiver accepted 15 low-quality loads/3,169,304 bytes and no high-quality peer payload; both contributors retained consent/serving, while the high donor uploaded zero. All 358 fixed-route controls finished HTTP 200/H1; HTTP 200 does not prove an admitted response body. There were no new measured stalls, fatal/native/page errors or zero-frame intervals. The high donor's earlier 1,247 ms stall remains recorded. Actor/provider/controller/outer and actual source-cleanup-v2 proofs passed; source exit 255 is retained. No connectivity cause or fix was established. The same-source distributed checks used fourteen total roles: four M1 contributors in one Chrome process, and ten M4 roles in two Chrome processes (four contributors, four receivers and two origin baselines). They used installed headless Chrome, trusted DOM Start/upload and programmatic dropdowns, without extra RTC/network/permission flags. Their outcomes remain separate: | Case | Actual stopping condition | Result and retained limitation | |---|---|---| | R7 | M4 descendant-resource probe timed out after 52.501 s of measurement | RED; last accepted RSS 8,375,910,400 bytes, process highwater 48/96 and reported free memory 78%; no observed cap crossing or rejected-probe RSS proof; all actor/source cleanup passed | | R9 | M1 process count 33 exceeded the declared 32 after 6.453 s | RED; rejected instant RSS unknown; original explicit browser context-close acknowledgements were false, separately proved endpoint/profile/process/stage/source removal retained | | R10 | Complete M1 orchestration tree count 41 exceeded 40 during setup | RED before measurement; endpoint-only process highwater 33 is a different scope; original unfinished browser cleanup and failed M4 receipt read remain unknown/false, with later exact-identity M4 recovery/removal and source cleanup separately proved | | R11 | Peer-readiness preflight found zero links and zero verified payload | RED before measurement; all fourteen decoded video/native audio in setup, but 300 s/both-quality/two-renewal gates never ran; resource and all original actor/source cleanup proofs passed | R11's separately declared M1 process cap was 64 with the same 3 GiB limit; its complete-tree sampled highwaters were 46 processes/2,590,523,392 bytes. M4 remained at 12 GiB/96 processes, with sampled highwaters 8,060,862,464 bytes/ 52 processes. Reported free-memory minima were 29%/77%. Summed sampled RSS is neither unique physical RAM nor an unsampled peak. Earlier resource REDs remain RED; changing a declared later limit does not retroactively qualify them. R11 retained 133 local peer-connection IDs: 120 timed out after remote SDP was installed and ICE checking observed, with zero opened channels or observed native failure before the engine timeout. These are local endpoints, not unique cross-page peer pairs. All 1,211 fixed-route statuses were 200; 1,210 had terminal CDP completion, with one post-200 policy request still unobserved at shutdown. All 483 admission observations finished without refusal/unknown status; 227 accounted detail evictions do not provide a complete timeline or admitted-body proof. The underlying reachability cause remains unresolved; neither a timeout increase nor a production connectivity fix is supported by these records. Installed M1 Safari 17.6 R2/R4/R5 were **bootstrap-only REDs**, with zero media measurement and no Start/upload action. R2 retained hidden/unfocused readiness snapshots; a fractional-timeout harness defect was reproduced separately without proving the exact terminal cause. R4 refused a maximise route in its own worker allowlist before readiness; that is not proof Safari lacks maximise support. R5 reached its readiness deadline: the last 15 snapshots were hidden/unfocused, 50 earlier predicates were evicted, and late authority withdrawal remains recorded. Exact owned sessions, drivers, workers, stages and outer processes were cleaned; these checks do not establish Safari playback, input or phone acceptance. The actual physical-iPhone read-only USB R2 attempt stopped RED at usb-lockdown in 2.464 s, before any Runtime.evaluate or numeric sample. Its original operation error was not retained separately from cleanup-incomplete; lockdown closure remains unknown. The exact worker/group, private SDK scratch and empty pairing cache were removed. This is no phone playback/gesture/peer acceptance. A prepared diagnostic successor is not an executed test. No further phone result is claimed. See the [current 2dd evidence summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/2dd156e-current-checkpoint-20261014.json). Earlier f393 short passes and older dated Kit, OBS and private-YouTube results below retain their source, date and scope; none is a current 2dd field pass. The full P01–P12 and 37-review-item scope remains open, including a completed same-topology 300 s qualifier, 7,200 s/22-churn operation, complete physical/native-input journeys, Safari, hard NAT, matched total-wire/ actual-cost evidence and immutable-release acceptance. No production-ready or new publication claim is made; completed finite sources are not a live-ingest claim. ### Previous f393 field checkpoint The previous deployed application checkpoint was `f393abf3d55215bdf58241a4a2af74245d646117`. All nine required jobs passed on their first attempt in [CI run 38511479806](https://github.com/forgesworn/relayswarm/actions/runs/38511479806). The optional twelve-viewer CI soak was skipped, not a new sustained pass. The permanent HTTP/1.1 proxy retains independent EE provenance. The normal-TLS served client is 734,441 bytes, SHA-256 `4fdb2861b08f42e4c82788a5940e0b2b436be52af84bc264998d41cf81938fcb`. Fresh production-only package and standalone ESM checks passed; exact image, package and source hashes are recorded in [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). These local assets remain unpublished and do not prove downloaded-release acceptance. [Both ordinary cross-machine short checks](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-ordinary-cross-machine-20261014.json) passed playback, contribution and both-quality verified payload. Forward M1 contributors → M4 receiver measured 60.050 s: 28 loads/12,763,132 bytes (13 low/2,732,956; 15 high/10,030,176), with zero link closures and one outgoing dial superseded by a crossed offer. Reverse M4 contributors → M1 receiver measured 60.023 s: 17 loads/8,179,316 bytes (seven low/1,476,364; ten high/6,702,952). It retained two initial donor dial timeouts after admitted remote SDP installation/ICE checking, two receiver request-timeout link closures followed by replacement connections, and two donor channel-error closures. Numeric PC IDs do not identify remote roles; these records do not establish the underlying routing or request-budget cause. No connectivity fix is claimed. All roles recorded zero stalls/fatal/native/page errors or frame-freeze intervals, and both contributors retained consent/serving in each run. Forward controls: 383 HTTP/1.1 responses, 382 finished and one commitment GET cancelled after HTTP 200 headers. Reverse controls: 387 HTTP/1.1 responses, 386 finished and one admission verification still pending after HTTP 200 in the final observer snapshot; its terminal result is unknown. HTTP 200 does not prove an admitted response body. Each run retained a pre-measurement media abort. Start/upload consent was trusted; dropdowns were programmatic, with no native-menu claim. No extra RTC/media/permission flags or whole-heap inspection were used. All actor/provider/controller cleanup passed. Source cleanup v2 matched stable identity, helper/input pins and start/cleanup journal receipt hashes; the reverse review did not independently reread the raw remote journal. VPN Connected was observed before and after each run only, not continuously. Bounded local transport metrics are now deployed; they add observation without changing transport policy. The earlier ordinary sharing reds below remain unexplained. [Distributed fourteen-role qualification](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-distributed-qualification-20261014.json) remains RED; sustained 7,200-second/22-churn, physical/native-input, hard-NAT, matched field-benefit, cost and immutable-release gates remain open across the full P01–P12 and 37-review-item scope. The previous deployed 0e checkpoint passed its own nine-job first-attempt [CI run 38500343145](https://github.com/forgesworn/relayswarm/actions/runs/38500343145), production-only package and standalone checks. The ordinary 60.013 s public check passed all three playback/contribution/verified- peer gates with 19 loads/6,285,968 peer bytes across both qualities and zero recorded stalls/fatal/native/page errors. The [180.015 s renewal check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/0e68847-public-renewal-180-20261014.json) passed all four declared gates with 90 peer loads/39,608,780 bytes (45 low loads/ 9,488,548 bytes; 45 high/30,120,232). Each contributor retained one completed pre-measurement stall (550/2,372 ms); no new stall occurred during measurement. All 1,009 controls finished HTTP 200/H1 before cleanup. Passive sampled session, peer-set/link counters, consent and monotonic quota held across successful own- ticket renewal for all three peer actors; direct PC object identity is not proved. Programmatic dropdowns/trusted Start and upload, one browser/four contexts and host/host links bound this evidence. Setup/nonfatal media aborts remain retained. The later cross-machine public HLS check was red for sharing over 60.060 s: playback progressed without recorded stalls/fatal/native/page errors, but both contributors uploaded zero and the receiver opened zero links/received zero peer bytes after two dial timeouts. Its 323 controls ultimately finished HTTP 200/H1; verification status alone does not prove admission. No ICE/transport cause is established. Separate loopback-origin raw RTC exchanged 8,192 bytes each way cross-machine but failed in both same-M4 topologies; this does not prove public- origin HLS or a NAT class. A separate public-origin raw M1-offer → M4-answer case passed in 7.972 s: both exact 0e public clients exchanged one verified 8,192-byte message each way, gathering completed and each SDP had one mDNS-form and one IPv4-form candidate. Both apps remained unstarted with no media/admission/ upload consent, and all cleanup passed. M4 VPN remained connected in a read-only 03:14:35 UTC receipt; no settings changed or mDNS/VPN cause was proved. The HLS sharing red remains separate. A separate reverse M4-offer → M1-answer raw case passed in 7.566 s, again with one hash-matched 8,192-byte message each way, complete gathering and one mDNS-form/one IPv4-form candidate per actual SDP. Apps remained unstarted with no media/admission/upload consent; all cleanup passed. Neither raw case proves the hosted HLS rendezvous/admission journey or its failure cause; investigation continues. All owned completed-run browsers/readers/sources are closed; the installed app awaits ingest. Fourteen-role/7,200-second/22-churn, complete physical journeys, hard NAT, cost and immutable release/download gates remain open. The earlier 0e ordinary restored-VPN cross-machine HLS check remained sharing-red for 60.020 s: four high-only verified loads/2,697,988 bytes, low zero, despite both contributors retaining consent/serving; playback and all recorded error/ stall/withdrawal counts passed. High's 4,038,428 accepted/reserved bytes are not receiver delivery or wire bytes. A preceding whole-heap-instrumented 60.074 s check on the same finite source passed with 22 loads/10,151,436 bytes across both qualities. These sequential results establish no heap/VPN cause. Separate same-M4 raw RTC passed with the owner-disconnected VPN (6.517 s/8,192 bytes each way), then failed after restoration (27.113 s); it is not HLS/admission/NAT proof. Both ordinary-run VPN observations were Connected; all browser/provider/source cleanup passed. Named receipts and precise counters are in [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). Documentation checkpoint `8c09478` passed all nine required CI jobs in [run 38506350320](https://github.com/forgesworn/relayswarm/actions/runs/38506350320); that documentation-only checkpoint did not change the then-deployed 0e runtime. The later f393 deployment above includes bounded local transport metrics; see [integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#metrics). All earlier reds and full scope remain. The earlier deployed application was `fa79c2260431cf7901921fab4eaca251c4988f4b`, with independent EE proxy provenance and all nine jobs green in [CI run 38496983011](https://github.com/forgesworn/relayswarm/actions/runs/38496983011). The [fresh public short check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/fa79c22-permanent-public-short-20261014.json) passed all three gates over 60.011 s with 13,206,248 verified peer bytes at both qualities and zero recorded stalls/errors/withdrawals. All actors/source closed. M4's zero-churn local check still hit the admission address cap and completed no peer links; raw two-context RTC also failed. The later 0e renewal evidence is recorded above; fourteen-role, sustained, device/network/cost and release gates remain open; see [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). The preceding deployed checkpoint was `ee1510d429ac85f3738c03f10a09b753ec4eb037`, with permanently committed HTTP/1.1 and all nine required jobs green in [CI run 38492003110](https://github.com/forgesworn/relayswarm/actions/runs/38492003110) after one failed-job retry. The [fresh ordinary short check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/ee1510d-permanent-public-short-20261014.json) passed all three gates over 60.014 s with 13,188,200 verified peer bytes across both qualities. The high contributor retained one 143 ms pre-measurement stall; all owned actors/source were cleaned. A separate fourteen-viewer local check stopped red after admission 429s blocked ticket renewal; the new heartbeat optimisation still needs fresh cohort/deployment acceptance. Two-hour, physical, varied-network, cost and release gates remain open. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). The preceding deployed checkpoint was source `2e1bdeb724eb45e37f7b97604e4f396a73985719`. All nine required jobs passed in [CI run 38483497575](https://github.com/forgesworn/relayswarm/actions/runs/38483497575); the optional long soak was skipped. Fresh offline production-only consumption passed ten documented imports, exact packaged demo/renewal/recovery bytes, the installed CLI, separate-process verified native transfer and HTTP fallback. The unpublished tarball contains 190 files, is 847,937 bytes and has SHA-256 `21103ad4dc0701ed41d07f4393560053a480963995bbe4682bfda76bf4b0c0e1`. The standalone ESM remains 114,201 bytes, SHA-256 `01de11837fbd08098bf98b6e8be945866ef766f76629030fec89de2318170d19`. Local artifacts do not prove downloaded-release acceptance. The guarded app-only deployment passed the 51-file UID-1000 image preflight, clean writer drain, stable identity/private lease/shared-service preservation and normal-TLS exact-client/fresh-playlist attestation. Image is `sha256:e73b4a0bb57ca37950abab2ae5c9f22c63a1ab4128880b9c85883d438701d87a`; public client is 728,315 bytes, SHA-256 `c264287acad81090c8952f99946f75f844e8f5fa718e907899dc77cacf04ef59`. Reporting remained off. The maintained no-store real-HTTP renewal regression passed, but the deployed ordinary four-role Chrome 155.0.8059.40 check recorded red for contribution and verified peers: 60.013 s of requested video/native-audio decode passed, with zero fatal/native/page errors or stalls, while both contributors uploaded zero and the receiver verified zero peer bytes. Authority-expiry timing is retained; the underlying missing-response cause remains unproved. A subsequent sequential comparison used Chrome 155.0.8059.41 and the same finite source/client. Adding only `--disable-http2` passed all three short gates in 60.009 s: the receive-only actor accepted 2,806,464 verified peer bytes at both qualities, and both contributors retained consent/serving. Successful fixed-route responses reported HTTP/1.1; the high contributor's one stall is retained. A fresh default-browser check on the same source measured 60.015 s: playback passed but both contributors withdrew, uploaded zero, and the receiver verified zero peer bytes; successful requests used HTTP/2. These sequential same-desktop checks isolate a useful transport diagnostic, not a proven HTTP/2 implementation cause or default production acceptance. No quota resets, automatic reconsent, fake media or permission overrides were used. Browser/provider cleanup passed in all three windows. The independently bounded source remained Root-owned and separate from observer cleanup. Named evidence: `artifacts/public-cdp-2e1bdeb-run-20261014`, `artifacts/public-cdp-2e1bdeb-http1-diagnostic-r2-run-20261014` and `artifacts/public-cdp-2e1bdeb-http1-window-default-run-20261014`. The later temporary server-H1 trial used ordinary Chrome 155.0.8059.41 with no browser transport override and unchanged app/client source. Its 60.009 s measurement retained a partial red result: playback passed and both contributors kept consent/serving, but only high delivered peer media (10,082,816 verified bytes in 15 loads); low delivered zero. Contribution and both-quality peer gates therefore failed. All 385 successfully completed fixed-route responses in the four pre-cleanup CDP ledgers reported HTTP/1.1, with no ledger records dropped. Fatal/native/page errors and sampled zero-frame intervals were zero; the high contributor's one stall is retained. This short diagnostic does not establish sustained benefit, a named HTTP/2 defect or permanent H1 readiness. The first trial preparation failed before proxy mutation because the image's file-capability binary could not execute with all capabilities dropped. That setup red remains retained. The isolated r2 preflight passed after copying and hash-verifying the same public binary bytes without capability attributes in private tmpfs; non-root/no-network/no-shared-mount/cap-drop/NNP bounds stayed in place. This setup correction is not a product or transport fix. Browser/provider cleanup passed despite the overall red outcome. Explicit controller finish and audit restored the original H1/H2 file and complete runtime at the same inode, proved the watchdog absent, and separate source cleanup removed the exact owned source (retained exit code 255). Named evidence is `artifacts/public-cdp-server-h1-trial-r2-run-20261014`, `artifacts/caddy-http1-trial-2e1bdeb-r2-preparation-20261014` and `artifacts/public-proxy-http1-trial-source-2e1bdeb-r2-preparation-20261014`. No permanent protocol change was made or authorised by this partial trial. A subsequent r3 trial retained ordinary Chrome 155.0.8059.41 and the same application/client, with only temporary server H1 and bounded read-only metrics. All three gates passed in 60.010 s: the receive-only actor accepted 13,205,308 verified peer bytes in 30 loads, comprising 3,151,444 low and 10,053,864 high bytes. Both contributors kept consent/serving throughout; fatal/native/page errors, stalls, sampled zero-frame intervals and contribution withdrawals were zero. All 407 successfully completed fixed-route CDP responses reported HTTP/1.1. No browser transport override, quota reset or reconsent was used. Browser/provider cleanup, controller finish/audit and exact source removal passed. The original H1/H2 file/runtime and inode were restored and the watchdog was absent. Evidence is retained under `artifacts/public-cdp-server-h1-trial-metrics-r3-run-20261014`, `artifacts/caddy-http1-trial-2e1bdeb-r3-preparation-20261014` and `artifacts/public-proxy-http1-trial-source-2e1bdeb-r3-preparation-20261014`. This one-minute ordinary-browser result supports selecting H1 as a deployment mitigation; it does not establish a specific HTTP/2 implementation fault or replace the r2 partial red. Permanent H1 has not been deployed: it still requires a new clean commit, all nine exact-source CI jobs, guarded actual application of the proxy change, and fresh default-browser short and full two-hour gates. Decoded audio bytes do not prove audible output. Prior red outcomes, sustained load, full physical/hard-NAT/cost gates, v0.2.0 publication and downloaded-release acceptance remain open. ### Earlier bb90 checkpoint Source `bb90bd6a54cabc163846ee1737ac3fe28b63eaa2` was deployed after all nine required jobs passed in [CI run 38478501111](https://github.com/forgesworn/relayswarm/actions/runs/38478501111), fresh local consumer/ESM gates, a 51-file non-root image preflight and guarded app-only clean drain. Normal-TLS public client SHA-256 is `25a8416911bc51b1f6764a784d4444295db02c12396c59ddd82450bf56fff58c` (728,262 bytes). Identity, private leases and shared service/proxy configuration were preserved; reporting stayed off. Its ordinary four-role public Chrome check measured 60.010 s: requested video and native-audio decode passed with zero fatal/native/page errors, while both contributors uploaded zero and the receiver verified zero peer bytes. Each contributor recorded one stall. Both native upload opt-ins were witnessed and recorded rows stayed visible/focused. Withdrawal closely matched issuance plus the five-second authority lifetime; later overlapping checks delayed about three seconds before send and completed after expiry. Expiry is a supported timing inference; no reason code or underlying cache/protocol/transport/host cause was proved. A later admission-verification cancellation followed withdrawal. Browser and provider cleanup passed, with finite-source cleanup verified separately by Root. Decode does not prove audible output, and this short same- desktop check does not close the sustained, physical, hard-NAT or cost gates. Named evidence is retained under `artifacts/public-cdp-bb90bd6-r3-analysis-20261014` and `artifacts/public-cdp-bb90bd6-r3-run-20261013`; the public-safe analysis manifest SHA-256 is `bd2d5ad098ca639f83398aff5a8b4b23994817b67a892d723193439fd439c926`. A later ordinary-Chrome local real-HTTP comparison held the first policy response before headers. The default client sent the later same-URL request to the server after 5,002 ms and lost consent; a no-store treatment sent it after 2,001 ms and retained consent/serving, while both kept the five-second deadline. No route interception, cache flags, fake media or permission overrides were used. The final maintained three-fetch correction passed real-server policy/session arrivals at 2,000/2,001 ms while the previous response remained held, plus full-outage expiry and recovery with consent off. Root's combined local suite/source hashes passed, and resource closes completed without a separate kernel inventory. Later 2e1 field results are recorded above; the initial public missing response remains unexplained and the earlier bb90 contribution remains red. Final receipt: `artifacts/policy-cache-integration-20261014/validation.json`. The earlier verified pilot checkpoint used source `f9990b36956282f3d4e849b55bd64a79eb440151`, client SHA-256 `b746f45216d3ac6e5d1bd21b5748f91c0115c71d00ee678c930070596bbef50d` (723,954 bytes), with nine required jobs green in [CI run 38449139246](https://github.com/forgesworn/relayswarm/actions/runs/38449139246). A later proxy-only h1/h2 and `Alt-Svc: clear` configuration passed pinned-binary validation and a guarded in-place reload, with fresh HTTP/1.1 and HTTP/2 checks and unchanged application identity. It does not establish the cause of the recorded policy timeout. The [f999 public field summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f999-public-field-summary-20261013.json) records the later measurements. These receipts describe past test windows, not a final release. The [13 October acceptance summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/current-source-acceptance-summary-20261013.json) retains the earlier a023 load/churn and field results with their original identity. Its named raw receipts remain local evidence; the summary excludes private device identifiers, credentials and personal filesystem paths. | Journey | Measured outcome | Remaining boundary | |---|---|---| | 0e ordinary public 60.013 s | Playback, contribution and both-quality verified peers green; 19 loads/6,285,968 bytes, recorded stalls/fatal/native/page errors zero; 369 completed controls HTTP 200/H1 | Four commitment aborts retained; programmatic dropdowns/trusted Start/upload; one-browser short scope; owned cleanup passed | | f393 ordinary forward M1 donors → M4 receiver, 60.050 s | All three gates green; 28 verified loads/12,763,132 bytes across low/high; zero link closures, one superseded dial; no stalls/fatal/native/page errors or consent loss | 383 H1 controls: one cancelled commitment after HTTP 200, 382 finished; finite VPN observations only; all actor/source-v2 cleanup passed; [summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-ordinary-cross-machine-20261014.json) | | f393 ordinary reverse M4 donors → M1 receiver, 60.023 s | All three gates green; 17 verified loads/8,179,316 bytes across low/high; two request-timeout closures then replacement connections, two initial post-SDP dial timeouts, two donor channel errors | 387 H1 responses: 386 finished, one post-200 admission verification terminal unknown; no stalls/fatal/native/page errors or consent loss; all cleanup passed; no underlying cause, fourteen-role or sustained claim | | f393 distributed R4, fourteen total roles | All fourteen decoded; measurement stopped RED after 57.222 s on two verification failures without HTTP status; zero observed HTTP refusals/429s; resource limits held | Seven/eight positive contributor counters and two/four positive receivers in latest pre-failure rows; incomplete quality/renewal gates; all owned/source-v2 cleanup passed; [summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-distributed-qualification-20261014.json) | | f393 distributed R5 diagnostic successor | Stopped RED after 19.404 s; seven status-unknown verification cancellations, zero HTTP refusals; first local fetch cancelled at 3,004.9 ms | Exact-code/lifecycle inference identifies the first three-second timer; missing-header cause and other abort sources remain unproved; resources and all owned/source-v2 cleanup passed; no long qualification | | f393 distributed R6 passive network diagnostics | Stopped RED after 26.930 s; twelve status-unknown verification failures, zero HTTP refusals; all ten M4 roles also had a failed policy/session poll, including both origin-only baselines | No browser/queue/VPN/network/server cause established; later snapshot was already origin-only; all owned/source-v2 cleanup passed; 24 pending requests at observation shutdown have unknown terminal results | | f393 distributed R7, two M4 Chrome profiles | Same fourteen roles and combined resource caps; stopped RED after 13.539 s with four unknown verifications confined to M4-B; both origin baselines retained late successful controls | No mitigation or shared-profile cause proved; three admission observations still pending; all three profile/actor/source-v2 cleanup passed; new topology does not qualify the existing long-run proposal | | f393 desktop Safari 26.6.2 session creation | Creation timed out before application navigation; both HTTP workers reaped and owned driver exited; no session ID returned | Session allocation/deletion unknown; exact owned scratch removed after archival and guarded checks, shared Safari untouched, source cleanup passed; [summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-safari26-session-creation-20261014.json); no playback or physical-device result | | f393 desktop Safari 17.6 startup | Session creation succeeded; startup stopped before mode selection or Start; zero media measurement | Individual failed readiness term unrecorded; separately reviewed M1 union limit 3 GiB/48 processes; exact-session and all actor/source cleanup passed; [summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-safari17-startup-20261014.json); no Safari media/input acceptance | | 0e ordinary public renewal 180.015 s | All four gates green; 90 peer loads/39,608,780 bytes (45 low/9,488,548; 45 high/30,120,232); three peer actors retained sampled session/peer-set/link counters and consent through own-ticket renewal; 1,009 controls HTTP 200/H1 | One completed pre-measurement stall per contributor, none added during measurement; 89 unique segment contexts, one completed twice; passive equality is not PC-object identity; all owned cleanup/source-v2 audit passed; [summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/0e68847-public-renewal-180-20261014.json) | | 0e cross-machine public HLS 60.060 s | Playback/video/native-audio decode green, recorded stalls/fatal/native/page errors zero; contributors consented/serving but uploaded zero; receiver two timeouts/zero opened links/zero peer bytes | Sharing red; 323 controls ultimately HTTP 200/H1 does not prove every admission accepted; ICE/SDP phase and cause unproved; both-machine browser/provider/source cleanup passed | | 0e public-origin raw RTC M1-offer → M4-answer | One verified 8,192-byte message each way in 7.972 s; exact deployed client loaded at both endpoints, complete gathering, each SDP one mDNS-form/one IPv4-form candidate; owned cleanup passed | Apps unstarted, no media/Nostr/admission/upload consent; VPN still connected/no settings changed; does not resolve cross-HLS red or prove a named cause | | 0e public-origin raw RTC M4-offer → M1-answer | Separate reverse case passed in 7.566 s; one hash-matched 8,192-byte message each way, complete gathering, every actual SDP one mDNS-form/one IPv4-form candidate; all owned cleanup passed | Apps unstarted, no media/admission/upload consent; not the hosted HLS rendezvous/admission journey, does not close its sharing red or establish cause | | 0e restored-VPN instrumented public HLS 60.074 s | Three gates green; 22 verified loads/10,151,436 bytes across both qualities, zero recorded stalls/errors/withdrawals | Whole-heap PC-state sampling; finite Connected observations; sequential pass does not establish heap or VPN causation; same-source ordinary red retained | | 0e restored-VPN ordinary public HLS 60.020 s | Playback green; receiver four high-only verified loads/2,697,988 bytes, low zero; zero recorded stalls/fatal/native/page/freezes/withdrawals | Sharing red; high 4,038,428 accepted/reserved bytes/6 served/1 refused are not delivered wire bytes; one post-header commitment abort; all actors/provider/source-v2 cleanup passed | | Same-M4 raw RTC owner VPN comparison | Disconnected: 6.517 s pass/8,192 verified bytes each way; restored Connected: 27.113 s red; complete gathering in both, error 701 also in pass | Owner changed/restored setting, fixture did not; literal loopback/no HLS/Nostr/admission; one case per state does not prove mechanism/sole cause or qualify public peers; owned cleanup passed | | Raw RTC topology comparison | Literal loopback-origin cross-machine M1/M4 exchanged 8,192 verified bytes each way; same-M4 single/separate-process cases transferred zero despite complete gathering | Different topology/Chrome patch versions; no HLS/Nostr/admission or public-origin proof; error 701 also present in pass; no named network/browser/NAT cause; owned cleanup completed, including explicit historical scratch recovery | | 2e1 ordinary public 60.013 s | Requested video/native-audio decode green; both contributor uploads and receiver peer bytes zero; fatal/native/page/stall counts zero | Sharing red; expiry timing retained, underlying transport cause unproved | | 2e1 same-source HTTP/1 browser diagnostic versus default | Chrome 155.0.8059.41: 60.009 s diagnostic accepted 2,806,464 verified peer bytes across both qualities; fresh 60.015 s default check accepted zero | Browser `--disable-http2` diagnostic only; high's one stall retained; sequential same-source/default comparison; later ordinary server-H1 trial partial red; no sustained/physical/hard-NAT/cost proof | | 2e1 temporary server-H1 ordinary 60.009 s | Consent/serving held; high delivered 10,082,816 verified bytes/15 loads, low zero; playback green, all 385 completed control responses HTTP/1.1 | Partial red for contribution/both-quality peers; high one stall retained; exact H1/H2 runtime/inode restored, watchdog absent/source removed; no permanent change | | 2e1 r3 temporary server-H1 ordinary 60.010 s | All three gates green; 13,205,308 verified bytes/30 loads across low/high, consent/serving held, all stalls/errors/withdrawals zero | One-minute same-desktop trial, exact H1/H2 runtime restored; later permanent deployment remains separate evidence | | EE permanent H1/app ordinary 60.014 s | All three short gates green; 13,188,200 verified bytes/30 loads across both qualities, consent/serving held, fatal/native/page errors zero; 405 completed controls HTTP/1.1 | High retained one 143 ms pre-measurement stall; programmatic dropdowns/trusted Start and upload; full owned cleanup; two-hour/physical/NAT/cost/publication remain open; [summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/ee1510d-permanent-public-short-20261014.json) | | EE fourteen-viewer local M4 qualification | Fresh 300 s plan stopped red after 98.945 s: admission 429s prevented ticket renewal while policy/session remained fast; RSS below declared 12 GiB cap | Same-address synthetic local workload with 22 accelerated churn cycles; not public peer or cost proof; earlier 8 GiB resource red retained, full owned cleanup | | bb90 ordinary public 60.010 s | Requested video/native-audio decode green; contribution and verified peer red, both contributors uploaded zero/receiver peer zero, all fatal/native/page errors zero | Authority-expiry timing and delayed sends retained; underlying cause unproved; short desktop scope, historical reds remain | | CI two-hour load/churn | Twelve honest roles, 22 replacements, zero retained stalls/fatal hls.js errors and clean resource stops | Loopback flags and host candidates; native media errors not separately instrumented | | Deployed 7,205 s four-context run | Completed but red: policy timeout withdrew contribution before quota exhaustion; 34 zero-frame intervals and stalls retained | Same Mac/headless contexts; separate support audiences prevent controlled traffic attribution | | f999 ordinary public 60.008 s | Requested video/audio qualities, both contributors and verified receive-only payload passed; 10,576,128 peer bytes, zero uploads/fatal/native errors/stalls | One same-laptop `host/host` browser process; short result does not close sustained/hard-NAT/cost gates | | f999 attempted public two-hour rerun | Stopped after 644.855 s whole/611.134 s measured; high upload cleared during warmup following a five-second policy fetch cancellation; low receiver retained 60,508,176 peer bytes | No high receiver phase or 7,200 s completion; individual transport/proxy/browser cause unproved; historical reds retained | | f999 public 60.120 s after proxy correction | Decode passed; contribution and peer payload at both qualities failed; receiver accepted 2,731,076 low peer bytes/13 loads; first high session timeout preceded measurement | Empty requested NetLog capture; underlying cause unproved, stalls retained, all owned actors/readers/source cleaned | | TCP TURN over owned SSH forward | 224,096 signed media bytes/two segments verified in 5.036 s; browser and later explicit cleanup audit passed | Forced relay-policy data-channel/self-routing simulation, not direct Internet TURN, physical playback or hard-NAT proof; original controller red retained | | Installed Firefox with ordinary contributors | Verified receive/upload, quality, seek, quota across reload, fresh consent and origin kill passed | One installed-browser journey; native-picker/human usability and hard NAT not proved | | Visible Safari with ordinary contributors | Origin video played; five RTC links but zero peer payload inside gate | Complete verified receive/upload/reload/kill journey remains red | | Physical Pixel/Vanadium | Later f999 actual origin frames, low/high quality, seek and background/resume passed; upload off and privacy unchanged | Peer unmeasured without a contributor in this check; original raw overall false plus default/temporary-policy reds retained; phone access closed | | Physical iPhone/Safari | Owner observed moving origin video and audible tone | Owner background/Play return remained stopped; engine diagnosis, peer and complete input journey open | | a023 host parent crash | Explicit audited dirty-marker recovery; same page progressed low/high at continuity 17, final 15 s frames and cleanup passed | One short origin-only observer, with stall and transient HTTP errors; no automatic clean-drain claim | | Resource/network supplement | Exact owned-process/container and partial isolated HTTPS TCP counters retained | Missing windows, resets and other audiences; total wire and billed cost unproved | | Deployed 219 reporting | Trusted reporting opt-in followed by a 17 s response timeout; reporting-off restoration and owned-source cleanup verified | No accepted-report/restart/retention checkpoint; original request lifecycle and later control state unavailable | | Later sparse-AAC replay | Actual retained bytes reproduce a missing audio SourceBuffer; current one-shot repair resumed through another rendition in 603 ms | Constructed VOD differs from original failing live window; low-only recovery and original cause unproved | The [investigation summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/control-path-media-investigation-summary-20261013.json) records those later observations and the local diagnostics-candidate tests. Physical and separate-network tests require their own evidence for each control, engine, contribution policy, background/resume and metered/battery behaviour. Browser RTC links, SDK loopback interoperability, an origin video observation and a passing local soak are separate claims. The complete P01–P12 requirements remain in [PRODUCTION-READINESS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md); these observations do not declare a release or close historical failed records. --- Source: [docs/NATIVE-TRANSPORT.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NATIVE-TRANSPORT.md) # Native transport spike [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Installation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) · [API reference](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#native-transfer-primitives) · [Release evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) RelaySwarm now has a second, experimental data path for installed Node applications. It uses Nostr for rendezvous and one-shot authorisation, then moves the bytes over a Noise-encrypted HyperDHT stream. It does not configure, contact or emulate a STUN or TURN server. This is deliberately a bounded spike. It proves that WebRTC is not a protocol requirement for native RelaySwarm nodes. It does not prove that arbitrary home networks are reachable, that data remains available after every seeder leaves, or that a normal browser can open this transport. ## Protocol flow Protocol version 3 continues to use experimental ephemeral kinds 24170 and 24171. They are not an accepted NIP and must not be treated as stable wire assignments. 1. Each process creates an independent ephemeral Nostr key and an independent HyperDHT Noise key. Neither is the user's social identity. 2. The seeder publishes a signed presence event containing the swarm id, its Noise public key and the SHA-256 digest it can serve. 3. The leecher sends a `dial` signal to that ephemeral Nostr key. The signal is signed and NIP-44 encrypted. It binds the leecher's Noise key to one request id, digest and byte count. 4. The seeder validates the signal, installs a short-lived, one-use firewall authorisation for that exact Noise key, then returns an encrypted `ready` signal. 5. HyperDHT locates the seeder and attempts direct UDP traversal. The resulting duplex stream is encrypted and mutually authenticated by Noise keys. 6. The leecher requests the already-authorised object. The sender re-checks its local bytes before serving them. The receiver enforces the expected byte count and computes SHA-256 itself before accepting the result. The relay never receives the object bytes or plaintext dial details. It still sees event metadata, swarm tags, ephemeral Nostr public keys, timing and source IP addresses. The installed API also handles relays that do not retain ephemeral events: after subscribing, a receiver publishes native leecher presence with `open: false` and no held hashes. A seeder coalesces live announcements globally to at most one per second, sharing one timer with its periodic heartbeat. This presence exposes the temporary Nostr/native public-key link but creates no transport grant. The exact encrypted dial remains mandatory. See the [installed API](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#installed-native-client) for verified HTTP fallback, which is separate from the original CLI spike's failure behaviour. ## What this replaces For an installed RelaySwarm process, `hyperdht-v1` can replace the WebRTC data channel and ICE/STUN signalling. HyperDHT supplies its own DHT routing, UDP hole punching and Noise transport. It does not remove infrastructure: - Nostr relays remain the signed rendezvous and authorisation path. - HyperDHT needs bootstrap/routing nodes. The default client uses HyperDHT's public bootstrap set; tests inject a private local bootstrapper. A deployment can operate several independent bootstrappers and pass them with `--bootstrap host:port`. - UDP-blocking and difficult symmetric NATs can still prevent a direct path. There is no relay or HTTP fallback in the CLI journey. An integrating application must implement its own failure handling and selected origin source. These bootstrap/routing and relay dependencies remain even without STUN/TURN. ## What this does not replace Ordinary browser pages cannot open arbitrary UDP sockets or run HyperDHT. The existing WebRTC path therefore remains necessary for browser-to-browser peer assist. A packaged desktop application, local companion process, browser extension with a native host, or suitably privileged installed web app could bridge the native path, but each has a distribution and trust cost. This is also not yet a decentralised storage network. The process serves an in-memory content-addressed object while it is online; it does not persist, pin, replicate, repair or promise availability. A useful Blossom replacement would need all of those policies plus quotas, abuse controls, garbage collection and proof that enough independent nodes retain each object. ## Security boundary The spike fails closed on the following boundaries: - relay events must have a valid Nostr signature, the exact swarm tag, bounded age and bounded payload sizes; - non-loopback relay URLs must use `wss://`; - dial details are pairwise NIP-44 encrypted; - the native listener rejects Noise keys that do not have an unexpired Nostr authorisation, and consumes authorisation on first connection; - request id, digest and size must match across the encrypted Nostr signal, firewall authorisation and transfer request; - individual frames are capped at 64 KiB and objects at 256 MiB; empty and excessive object chunks are rejected; pending authorisations are capped at 256 and active incoming transfers at 16, with a 30 s transfer deadline; - the receiver's expected digest is authoritative. Metadata supplied by the serving peer cannot change it. The application still has to obtain that expected digest from a trusted source, such as a streamer-signed manifest or a trusted HTTPS/Blossom descriptor. A malicious publisher can legitimately sign a malicious object. Hash checking is integrity, not truth or moderation. The current receiver buffers the complete object before returning it. That is reasonable for the spike and small media segments, not for large durable blobs. A production implementation needs streaming-to-disk, per-chunk verification, resource accounting, peer reputation, cancellation and origin fallback. ## Run it Node 24 is the tested runtime. ```bash npm ci npm run test:native npm run poc:native npm run poc:native -- --relay wss://your.relay --size 1048576 npm run poc:native -- --bootstrap bootstrap.example:49737 ``` The deterministic tests start a loopback Nostr relay and a loopback HyperDHT bootstrap node. They prove the complete authorisation and transfer path without using external infrastructure. CI is configured to run them on current GitHub Windows, Linux and macOS runners. The v0.1.0 native suite passed on all three platforms ([release-main run 38233694634](https://github.com/forgesworn/relayswarm/actions/runs/38233694634)); that proves those tests rather than packaging, firewall prompts or real home-network reachability. Still required before choosing this for production: - real home-to-home tests across varied NATs, VPNs, IPv4/IPv6 and UDP-blocked networks; - suspend/resume, sleep, network change and long-running resource tests; - executable packaging and firewall-prompt testing on all three operating systems; - protocol interop with a genuinely independent implementation; - dependency and native-binary supply-chain review; - a signed content manifest and a durable storage/replication policy. ## Installed client and verified HTTP fallback The current source additionally supplies `relayswarm-native` and the `relayswarm/native-client` API. It requires an independently trusted digest, size, seeder allowlist and explicit endpoint policy. A bounded native attempt precedes HTTPS fallback; redirects, excess bytes and wrong digests are refused. Cancellation stops rather than starting fallback. The executable creates a new verified output atomically and requires installed Node. The original PoC journey described above retains its original behaviour. See [production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md#installed-native-client) and [API](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#installed-native-client). --- Source: [docs/THREAT-MODEL.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/THREAT-MODEL.md) # RelaySwarm threat model [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Release evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) · [Integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md) This describes the implemented experimental boundaries and the remaining adversarial work at v0.2.1. Passing named regression cases does not establish production security or completion of the threat model. The original CLI, browser loader and native path have different trust assumptions. ## Implemented boundaries The browser peer-first loader verifies an author-signed, canonical and expiring segment commitment, including stream/rendition/sequence/discontinuity/ part and object identity. It checks the experimental publisher redistribution tag; current source also permits explicitly author-scoped delegated signers. The original CLI PoC is unchanged. Regression tests cover request floods, empty/excessive chunks, upload stalls, expired admission on retries, delayed admission during shutdown, relay startup recovery, late reconnects, commitment substitution and origin fallback. Real Chrome tests require tampering detection, compare playback stalls with a baseline, check shutdown resources and prove peer-first avoids origin requests. Native nodes bound pending authorisations and active transfers. The example Node publisher signs only a full-segment context present in its local playlists, including the exact byte range and discontinuity. It serves listed media rather than arbitrary directory files and rejects symlink escapes. Its key stays on the server; current source can persist a private identity in an owner-controlled 0600 file. This is an example publisher, not a trusted-stream discovery service: a real host must still establish which stream author it trusts. The demo's relay and HTTP endpoints have resource bounds. Current source adds key-possession tickets and live revocation; open issuance does not prove unique participants or complete Sybil resistance. Receipts stay in the browser until downloaded; optional reporting requires viewer opt-in and accepts only bounded numeric summaries, without a swarm public key. These controls do not establish unique participants or net cost. The example origin's [complete-playlist blocking reload](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#example-origin-http-playlists) uses the current authorised catalogue and a fixed deadline of three initial target durations. At most 24 requests may wait inside the existing 32-media request limit. Disconnect/shutdown releases waiters and shared directory watchers; media bytes, signing scope and peer deadlines are unchanged. Required coverage is limited to 41 directories per request, including shallow Windows parent watches; excess coverage retains ordinary HTTP without added capability. Direct watches cover all authorised playlist basenames and directory renames; unrelated named media/temporary-file events are ignored. Filename coverage changes consume the existing bounded revalidation budget. Parent-only watches ignore unrelated siblings and named metadata events; missing filenames or unknown event types fail closed. These limits do not establish Internet capacity or hard cancellation of kernel I/O. Broadcaster workers use a detached wrapper that remains their process-group leader until draining finishes. Only that executing wrapper signals its own group; the guardian sends commands over the original private IPC channel and uses numeric group IDs only for absence probes. Clean shutdown requires a drain witness, closed output pipes, settled IPC sends and observed group absence within the existing deadline. Missing evidence retains the dirty recovery fence. Guardian death and whole-host loss still require operator recovery. There are four logical worker slots and one additional Node wrapper per occupied slot; local sampled resource checks do not establish production capacity. The optional [account allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md) introduces a separate private trust boundary: its service learns a stable Nostr identity or the host's authenticated website subject and can correlate participating devices. Explicit linking reveals the association between those identities. The private ledger stores service-scoped pseudonyms and durable cumulative reservations; its secret and grant records require protection as account data. Stable identities and grants are excluded from swarm events, SDP, peer messages and downloaded or submitted reports. Host authentication, HTTPS and ledger preservation remain required. An open Nostr account service cannot establish unique humans or prevent someone deliberately using unrelated identities. These are specific tested boundaries, not completion of the adversarial suite below. Sybil resistance, broad NAT/mobile coverage and independent-client protocol interoperability remain outstanding. ## Assets - **Segment integrity** - a viewer must never play bytes the streamer did not produce. - **Viewer availability** - peer assistance must degrade to plain HLS, not to a broken player. - **Viewer privacy floor** - swarm events must carry no social npub and use independent per-session keys, and non-participation (origin-only mode) must be free. This is pseudonymity, not anonymity; relays and network observers may still correlate swarm activity with a viewer's other Nostr use through shared connections, IP addresses and timing, and a client that reuses one relay connection for both makes that correlation trivial. The browser loader creates its own swarm relay pool, but shared IPs/timing still permit correlation; applications using the lower-level session API must also consider which connections they share. - **Origin capacity** - the resource the swarm exists to protect. ## The core defence: authenticated segment commitments The original PoC verifies a SHA-256 hash supplied by the sending peer. That proves transport, not provenance: a malicious seeder controls bytes and hash. Shadow mode instead compares with origin bytes, while the browser peer-first loader requires a commitment signed by the **same author as the selected kind-30311 stream event**. It binds stream/event identity, swarm, rendition, sequence, discontinuity, part, segment key, digest, size and expiry. Wrong bytes fail verification, the peer is banned, and the normal origin loader is the fallback. Receiving a digest over HTTPS alone does not satisfy the current peer-first signature contract. The verifier requires fixed field order and exact canonical JSON with the `relayswarm-segment-v1` domain and schema version 1. It rejects altered fields, other signers, expired/stale events and substituted media contexts. The precise contract is in [INTEGRATION.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#authenticated-peer-first-loading). Current source implements author-scoped expiring commitment keys and a host-supplied revocation view; [production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) describes the trust and availability boundary. The host still establishes which publisher it trusts. A malicious authorised publisher can sign harmful bytes; cryptographic integrity is not moderation. Streams also carry an explicit **peer-redistribution authorised** flag; absent it, clients do not form a swarm. Peer assistance is something a publisher opts into for their own stream, not something viewers may switch on for any HLS URL. ## Adversarial suite These are areas for the full adversarial suite. Some individual cases are already regressed above; broader combinations remain outstanding: - Wrong bytes under every digest arrangement (peer-supplied, stale, cross-rendition, cross-stream). - Replay of expired segments and cross-rendition substitution. - Sybil presence floods - thousands of fake peers announcing. - Malformed and oversized SDP payloads. - Resource exhaustion - connection floods, chunk floods, slow-loris peers. - Relay withholding and selective event dropping. - A compromised super-peer serving many viewers. ## Client-side resource defence Event spam is not only the relays' rate-limiting problem; a client must defend itself. The engine bounds its subscriptions, enforces event-size limits, budgets concurrent dials and caps queues. Relay frames must match a live subscription id/filter before signature validation and dispatch; signals are subscribed to by recipient, while presence remains swarm-wide. The loader bounds admission checks and transfers and uses availability, rotation/referrals and deadlines. This is not an implemented reputation or Sybil-resistance system: validly signed fake presence can still consume bounded client work. ## Out of scope, stated plainly - **Metadata privacy.** NIP-44 hides event payloads, not metadata; relays see kinds, tags, timing and connecting IPs, and anyone who knows a public stream's identifier can observe its swarm activity. See the privacy section of the [README](https://raw.githubusercontent.com/forgesworn/relayswarm/main/README.md). - **WebRTC protocol fingerprinting.** A state that filters DTLS takes the swarm down to plain-HLS fallback; resistance is future work, not quietly claimed here. - **A hidden origin.** The swarm distributes egress, not ingest. No dedicated onion-service support or origin-concealment feature is implemented. --- Source: [docs/FAQ.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FAQ.md) # RelaySwarm FAQ [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Getting started](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) · [Evidence and gaps](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) ## What is released? [v0.2.1](https://github.com/forgesworn/relayswarm/releases/tag/v0.2.1) is an experimental GitHub prerelease with an installable tarball, a standalone browser ESM bundle and checksums. It includes the browser loader, local publisher/player and native transfer PoC, plus the live broadcaster, private publisher state and operator controls. The npm registry remains unpublished; the release does not provision hosting. See [Getting started](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) and [the broadcaster guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md). ## Why use Nostr instead of a tracker? RelaySwarm reuses application-selected Nostr relays for peer discovery and signalling. It still needs rendezvous infrastructure. P2P Media Loader instead uses [WebTorrent-compatible trackers](https://github.com/Novage/p2p-media-loader/blob/main/FAQ.md#what-is-tracker), which may also be redundant or self-hosted. The distinction is the discovery protocol and its fit with Nostr applications, not the elimination of operators. ## Why not combine Trystero and P2P Media Loader? Those projects provide useful building blocks. A host would still need to integrate stream identity, signed segment provenance, origin deadlines, admission, upload consent and lifecycle handling. RelaySwarm implements a bounded example of that layer; it does not claim that the alternatives cannot implement it. [Landscape](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/LANDSCAPE.md) compares their documented roles. ## Does it support MoQ or replace a CDN? The current paths are WebRTC and native HyperDHT. MoQ integration is unimplemented. The HTTP origin or CDN still supplies manifests, initial media and fallback; RelaySwarm can reduce particular origin media loads when suitable peers exist. It does not remove ingest, origin hosting or operator costs. ## Does NIP-53 automatically configure the swarm? No. The host selects trusted authors, allowed media origins, the swarm id, relays and ICE servers. The released loader accepts the selected event. An optional adapter in v0.2.1 filters a host-supplied query using those explicit allowlists; it does not choose infrastructure or establish trust in arbitrary publishers. NIP-53 can carry relay information; the redistribution tag and commitment kind are RelaySwarm's experimental contract. ## Can it send a broadcast to YouTube? The v0.2.1 broadcaster can send the same H.264/AAC source to a separately configured RTMPS endpoint while producing HLS for RelaySwarm viewers. That forwarder has its own process and retries. A valid platform stream key, account configuration and an actual platform playback test are still needed. YouTube does not participate in the viewer peer swarm. See [broadcasting](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md). ## Is signalling encrypted? The original `poc.mjs` signs **plaintext SDP**. The browser loader and shared version-3 `RelaySwarmSession` use pairwise NIP-44-encrypted signals. The native path encrypts its dial authorisation and transfers bytes over Noise. WebRTC data-channel encryption and SDP encryption are separate properties. Relays still see event kinds, tags, timing and connecting addresses. ## Can a peer poison a video segment? The browser peer-first path accepts bytes only after verifying an expiring commitment signed by the selected stream-event author and matching the exact stream, rendition, sequence, discontinuity, part, segment key, size and digest. Invalid bytes are discarded and the peer is banned; failures use the original HTTP loader. The publisher must authorise redistribution explicitly. Shadow mode compares peer bytes with origin bytes. The original CLI's same-peer digest detects corruption but cannot authenticate a malicious seeder. The native receiver needs a digest from a trusted application source. Hashes do not establish whether content is truthful or safe. ## Can I upload without the viewer opting in? Contribution defaults to off. A host must obtain explicit opt-in before setting `serve: true`; the demo has a separate upload checkbox and limit selector. Known cellular connections are excluded by default, but connection detection is advisory and missing in some browsers. Publisher permission and viewer consent are both required. The upload token bucket permits a burst of up to two seconds of its configured allowance. ## Does receive-only mean private? Receive-only disables uploading, but still joins the swarm and can reveal the viewer's address to connected peers. Ephemeral keys provide pseudonymity, not anonymity. A public swarm identifier lets observers correlate presence. `mode: 'off'` or `stop()` provides origin-only playback without swarm sockets, events or peer connections. The origin still sees ordinary HLS requests. ## Do phones and Safari work? The earlier spikes recorded desktop Chrome/Safari transfers and limited phone origin-playback observations. They did not validate the current signed peer-first loader on iPhone or Android. The new regression uses desktop Chrome on loopback. The demo uses native origin-only HLS where the browser supports it but hls.js does not; origin resource measurements then report unavailable. Physical playback, consent, metered data and background/resume remain [field gates](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#automated-coverage-and-remaining-field-gates). ## What happens when peers, relays or WebRTC are blocked? The original HTTP fragment loader remains the fallback. Missing availability, invalid commitments, corruption and peer deadlines lead to origin. An origin outage can still stop playback; the swarm is not durable storage. Relays may change policies, reject kinds or rate-limit. Historical public-relay acceptance does not guarantee future service. A deployment should choose and test its own relay and ICE policy. ## Does it use STUN, TURN or super-peers? The browser loader defaults to Google's public STUN endpoint and accepts host `iceServers`; the demo accepts `--stun`. Hosts can supply TURN credentials through `iceServers`; no managed TURN or super-peer service is supplied. Difficult NATs can fall back to origin. Native HyperDHT uses its own bootstrap/routing infrastructure rather than STUN/TURN and has no automatic origin fallback in its CLI journey. See [Native transport](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NATIVE-TRANSPORT.md). ## Can I use HyperDHT in a normal browser? No. This native implementation requires installed Node applications and UDP access. Browser pages use WebRTC. Installed companion processes would need their own integration and distribution work. ## Does RelaySwarmKit interoperate with this release? v0.2.1 passes author, delegated-signing and adversarial transfer journeys with the published RelaySwarmKit v0.5.0 public SDK. These are macOS arm64/Chrome loopback checks, not physical iPhone acceptance. The earlier version-2 Kit baseline is incompatible with the release's version-3 signalling. Published RelaySwarm v0.1.0 assets keep their original protocol; do not infer compatibility from matching event kinds alone. See [the recorded SDK evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) and [interop guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/interop/README.md). No RelaySwarm NIP is accepted yet. ## Can one upload allowance cover my phone and computers? The current source offers an optional [shared account allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md). Devices explicitly connect using the same Nostr identity or an account authenticated by the host website, and use one durable ledger. Both methods are supported; linking them requires fresh proof of both. Their recorded spend is added and the lower cap is retained. Local browser allowances still apply, and each page separately requests upload consent. The deployed `8f482b4` pilot offers Nostr sign-in; integrating sites supply their own website resolver. Actual owner and complete physical acceptance remain open. The allowance counts reserved media payload rather than total device traffic. ## Do the receipts measure money or data saved? `peerFirstBytes` measures verified media delivered in place of starting an origin fragment load. It excludes commitment, signalling and protocol traffic. Shadow transfers add traffic. `bytes.uploaded` counts full payloads accepted for serving after any host reservation callback succeeds and current serving checks pass. Pending or refused callbacks do not enter that counter. Interrupted accepted transfers can send less; durable allowances can also retain charges for media never handed to the transport. These are not acknowledged network delivery totals. Receipts stay local until downloaded. Use paired device/network measurements to establish total data cost. See [receipt interpretation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#collect-comparable-receipts). ## What remains before production? Complete physical-device journeys, separate-network/hard-NAT trials, sustained resource/churn and matched cost measurements, and final immutable release acceptance remain open. Current deployed sharing and fourteen-role qualification are red; earlier short passes retain their own source and scope. Wider-media and independent SDK fixtures have passing evidence, which does not close those field gates. [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) records both results. There is no prediction that audience upload capacity will cover a given deployment. ## What permission does a contributing viewer need? A contributing viewer redistributes media. The publisher authorisation tag expresses the publisher's opt-in; it does not establish ownership of every right or settle a viewer's legal/contractual obligations. The demo should be used with media participants are authorised to redistribute. Host policy and explicit viewer consent remain application responsibilities. ## What does the current production candidate add? [Production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) covers wider HLS, scoped delegation, full linked stream advertisements, bounded admission, persistent browser upload budgets, durable idempotent reports, worker supervision and native HTTP fallback. [Delivery requirements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) separates implementation from publication, physical devices, varied networks and sustained acceptance. --- Source: [docs/LANDSCAPE.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/LANDSCAPE.md) # RelaySwarm landscape [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [FAQ](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FAQ.md) · [Current scope](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) Documentation comparison refreshed on 12 October 2026 from the linked primary sources. This is a comparison of documented roles, not a performance benchmark, an exhaustive novelty claim or evidence of integration between projects. | Project | Documented role | Relationship to RelaySwarm | |---|---|---| | [P2P Media Loader](https://github.com/Novage/p2p-media-loader) | Peer-assisted media delivery; its [FAQ](https://github.com/Novage/p2p-media-loader/blob/main/FAQ.md#what-is-tracker) specifies WebTorrent-compatible trackers for WebRTC signalling | Closest HLS-engine comparison; RelaySwarm uses Nostr rendezvous and an experimental stream-author commitment contract | | [Trystero](https://github.com/dmotz/trystero) | Generic WebRTC matchmaking and data/media APIs across several signalling strategies; the default package uses Nostr | Nostr-signalled browser transfer already exists; an HLS host still needs media-context, deadlines, provenance and consent integration | | [MoQ working group](https://datatracker.ietf.org/wg/moq/about/) | Media transport over QUIC with relay-capable distribution | A different transport/distribution design; RelaySwarm has no MoQ implementation | | [Snowflake](https://snowflake.torproject.org/) | Volunteer proxies supporting access to Tor | A different application of volunteer connectivity; it does not establish HLS scheduling or RelaySwarm reachability | | [RelaySwarmKit](https://github.com/forgesworn/relayswarm-kit) | Swift Nostr rendezvous and encrypted SDP with a separate data-channel transport | Related implementation, but its README describes wire version 2 while the shared session here uses version 3; current interoperability is unverified | P2P Media Loader's FAQ recommends operated tracker infrastructure for production; multiple trackers can be selected. Nostr relays are also operated infrastructure whose policy and capacity must be tested. Neither design removes the HTTP origin. ## The project's scope RelaySwarm evaluates application-selected Nostr relays as the rendezvous path for peer-assisted HLS. [NIP-53](https://github.com/nostr-protocol/nips/blob/master/53.md) kind-30311 events can advertise relay information. The current host passes its trusted stream event and network policy explicitly; automatic stream discovery and policy extraction are not implemented. The release adds a bounded hls.js loader, origin deadlines, admission callbacks, upload opt-in, an origin-only mode and author-signed media commitments. Those capabilities are documented in [INTEGRATION.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md). They do not establish an accepted NIP, broad ABR scheduling, production readiness or compatibility with another implementation. ## Historical relay measurements The August 2026 CLI/fan-out runs recorded acceptance of experimental kinds 24170/24171 on relay.damus.io, nos.lol and relay.primal.net and approximately 0.57 s average fan-out signalling. Recorded Chrome/Safari transfers finished inside a common four-second segment. These are dated feasibility observations, not relay service guarantees or mobile-loader validation; the original CLI signalled plaintext SDP. [Spike results](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/RESULTS.md) retain provenance. Current release evidence includes desktop Chrome playback and a twelve-viewer loopback soak. Separate-network performance and stronger adversarial tests remain outstanding, as listed in [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). --- Source: [docs/MAINTAINING-DOCS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/MAINTAINING-DOCS.md) # Maintaining RelaySwarm documentation [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) · [Changelog](https://raw.githubusercontent.com/forgesworn/relayswarm/main/CHANGELOG.md) ## Public entry points The current public documentation surface is the GitHub repository. There is no configured standalone documentation site. README and `docs/README.md` provide human navigation; package metadata and GitHub description/topics identify the actual technologies and experimental status. AI readers can use the [raw index](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms.txt) or [full context](https://raw.githubusercontent.com/forgesworn/relayswarm/main/llms-full.txt). The index follows the [llms.txt proposal](https://llmstxt.org/): a title, summary, scope notes and groups of annotated Markdown links. The optional full file is generated from authored guides, with relative links resolved to public sources. It excludes historical spike receipts/code; the index links that evidence separately. These files make public information easier to retrieve. They do not prove that search engines or assistants have crawled, indexed or recommended RelaySwarm, and they do not grant crawler permission or change GitHub's robots policy. ## Edit and verify 1. Update authored Markdown, `llms.txt` and relevant package metadata from the implementation. Label dated evidence and planned work explicitly. 2. Run `npm run docs:generate` to rebuild `llms-full.txt`. Do not edit it by hand. 3. Run `npm run check:docs` and `npm run check`. 4. Commit authored and generated files together. CI runs the documentation check. 5. After merge, fetch the public raw files and compare them with the merged content. Check GitHub description/topics and release links separately. `check:docs` requires only Node built-ins: it checks local/public-repository Markdown link targets and local heading anchors, AI-index file-list structure, documented module exports, command names and generated-context freshness. It does not assert external website availability or rendering, and skips code blocks when checking links. Verify external factual claims against primary sources when updating them, rather than trusting an old comparison date. ## Release versus current documentation Each immutable release tag (v0.1.0, v0.2.0, v0.2.1) and its downloadable assets contain release-time documentation. Main-branch guides can correct examples and claims after a release. Use [Getting started](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md) for pinned installation and [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) for the release checkpoint. Never retag or silently replace release assets to make a documentation correction. Keep package, wire, commitment and metrics versions distinct. Preserve the original CLI's plaintext-SDP and same-peer-digest limitations. Treat signed media integrity, upload consent, phone acceptance, NAT reachability, hosted CI and public distribution as separate claims. `peerFirstBytes` and upload quota counters are not total network-data or financial-savings measurements. ## Future documentation hosting If a public documentation site is added, publish its Markdown, an applicable `llms.txt`, canonical URLs, navigation and search metadata as part of that site's deployment. Verify its actual public responses before claiming discovery or deployment. Do not add fictional domains, indexing guarantees or unsupported production/security claims to this repository's metadata. --- Source: [docs/ACCOUNT-UPLOAD-BUDGET.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md) # Shared upload allowance [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md) · [Delivery requirements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) The current source implements an optional account allowance shared across devices, supporting Nostr sign-in and host website accounts. The [controlled Chrome journey](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/account-budget-implementation-20261014.json) passes both methods, real peer uploads, renewal, linking, restart persistence and fresh consent. It uses disposable signatures and an owned website session on loopback; physical devices and actual owner authentication remain separate acceptance gates under P06/P12. The [current pilot](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) offers Nostr sign-in and preserves the private durable ledger. Integrating websites supply their own authenticated account resolver; none is configured on this pilot. The account service records cumulative media payload reservations. Every participating device uses the same service and durable ledger. The browser's local allowance continues to apply as well. These limits exclude signalling, connection overhead and other HTTP traffic; they are not wire-traffic meters. ## Enabling the service The standalone demo accepts `--account-budget-state FILE`. Its parent directory must be private, owned by the service user and free of symlinks. The ledger is a 0600 file on a supported local POSIX filesystem, protected by an exclusive writer lease. Preserve it and its lease files during upgrades and backups. Operations apply and settle one at a time in arrival order; those that arrive while a write is in progress share the next durable write. No acceptance, refusal or read is returned before every write it may depend on completes, and if a shared write fails every operation in it is refused with `account-persistence-unavailable`. Keep account state outside the source checkout. The default `account-budget.json` name and its sidecars are excluded from Git, package and container contexts; a custom filename needs equivalent protection. The broadcaster accepts `--account-budget` and uses `account-budget.json` inside its existing private state directory. The Compose template offers the service with `ACCOUNT_BUDGET_ENABLED=1`; set that value to `0` to omit it. Offering the service does not connect a viewer's identity or enable uploading or reporting. The CLI supplies optional Nostr authentication. A website integrating the server supplies its own authenticated account resolver: ```js await startDemoServer({ // Existing publisher and HTTPS configuration goes here. accountBudget: { statePath: '/private/relayswarm/account-budget.json', async resolveWebsiteAccount(request, { signal }) { const session = await yourAuthentication.requireSession(request, { signal }); return { issuer: 'your-website', subject: session.userId }; }, }, }); ``` `yourAuthentication` represents the host's existing session authentication. Derive the subject from verified authentication. A submitted account ID, request header chosen by the viewer, operator token or displayed public key does not establish that authority. No account-registration system is supplied. Both identity methods use the same reservation implementation; the website method appears only when the host configures it. ## Connecting and linking identities The viewer explicitly chooses a connection method. Nostr uses the browser signer's `getPublicKey` and `signEvent` capabilities from [NIP-07](https://github.com/nostr-protocol/nips/blob/master/07.md). Private keys stay with the signer. Website authentication uses the host's existing signed-in session. Neither connection enables uploading. Each new page still requires fresh upload consent. A connection obtains a short-lived opaque grant bound to that page's separate ephemeral key. Renewal remains inside the original account-authorised delegation deadline. It cannot raise the limit, reset spent bytes or extend that deadline. Website renewal checks the current authenticated website account. Authentication proofs use a private, versioned contract; they are not NIP-98 HTTP-auth events and are never broadcast to Nostr relays. Different unlinked identities have separate allowances. Linking a Nostr identity and a website account requires fresh proof of both and an explicit linking action. Their recorded spend is added and the lower limit is retained. Existing grants are revoked; uploading requires a fresh Apply action. Connecting another device or reconnecting after a reload reads the existing balance. The initial account allowance is 100 MB unless the host chooses another supported default. Raising its limit or resetting recorded spend requires a separate explicit action with fresh account authentication. Local allowance settings are not copied over an existing account balance on sign-in. The two shared-limit buttons both apply the selected limit; the reset button also clears recorded shared usage. ## Reservation and failure behaviour Before sending media, the client reserves its full payload against both local and account allowances. The server serialises concurrent devices, checks the grant and remaining allowance, and durably commits the charge before returning acceptance. Repeating the exact same reservation operation does not charge it again; reusing its operation ID for a different amount is refused. The demo checks media-operation and account authority before submitting an account reservation. That request then uses the account client's own lifecycle and five-second deadline. A routine peer refresh can therefore settle the charge without revoking the account; the cancelled media operation cannot send bytes. Explicit account revocation still cancels the request, and an unknown or invalid result revokes account authority. An accepted or ambiguous reservation remains charged after cancellation, disconnect or crash. There are no automatic refunds, retries or allowance resets. A failure between the local and remote reservations can therefore consume allowance without uploading. A connected account's unavailable or expired authority stops contribution; it never silently substitutes a fresh local-only allowance. Receiving can continue through the normal origin loader. Disconnecting explicitly clears upload consent, leaves recorded spend intact and keeps the page's requirement for account authority. Reconnecting is required before that page can contribute again. Account and replay-record capacity limits refuse new work rather than discarding spent counters to make room. Preserve the ledger: deleting it discards the service's record of account expenditure. Independent deployments with separate ledgers do not enforce one shared limit. Grant expiry uses wall time and monotonic time while the service runs. Observed wall-clock rollback fails closed; orderly shutdown persists the highest observed time. After restart the service trusts the host's UTC clock and that durable high-water mark. It cannot establish physical elapsed time during an unobserved crash or clock change. Recorded spend persists independently of grant expiry. Use a reliable host clock and preserve the private state. The browser measures the issuer's lifetimes from the signed challenge rather than assuming its device clock exactly matches the server. The challenge uses one server timestamp for its event and both deadlines. The client counts the whole request round trip and subsequent signing time against those deadlines, using the greater of wall and monotonic elapsed time. Each grant also retains its original request-start lifetime cap; renewal keeps the first delegation anchor. Observed rollback of either browser clock revokes authority. The existing 30-second proof freshness bound and server-side expiry checks remain. Deploy this browser client with the matching server: older challenge handlers with separately sampled timestamps can fail the client's coherence check at a second boundary. ## Privacy and scope The account service necessarily learns which devices connect to the same identity, and an explicit link reveals that the two identities belong together. Its private ledger uses service-scoped pseudonyms. Protect that state and its pseudonymisation secret as account data. Account subjects, stable Nostr identities and grants stay out of public admission tickets, relay events, SDP, peer messages, downloaded player receipts and opt-in operational reports. Swarm identity remains ephemeral. Reporting still requires its separate opt-in. This is a cooperative payload allowance for clients using the account service. It does not identify unique people or impose an operating-system-wide limit on other browsers, applications or unrelated services. Physical device, sustained operation and release acceptance remain separate gates. --- Source: [docs/AGENT-GOALS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/AGENT-GOALS.md) # RelaySwarm goals and agent handover Snapshot: 19 October 2026. Repository: this checkout. ## Assignment Finish the agreed production work, verify it against the acceptance requirements, and ship RelaySwarm 0.2.0. The owner asked to get the work finished and into production. Preserve the full P01–P12 scope below; do not declare completion because implementation, CI or deployment passes alone. RelaySwarm provides peer-assisted HLS: browsers exchange hash-verified media over WebRTC, use Nostr for rendezvous/signalling, and retain HTTP fallback. A separate installed Node path uses HyperDHT/Noise. Optional RTMPS forwarding to YouTube is a broadcaster output, separate from viewer peer delivery. Read [AGENTS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/AGENTS.md) before working. Use the [delivery checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist) for the full acceptance requirements and [production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) for implemented behaviour. This handover records a newer deployment than the `3f706a9` current-checkpoint prose in those guides. Reconcile that prose after reviewing the newer evidence; retain the historical failures. ## Starting position The agreed source feature surfaces are implemented. **Production acceptance and the 0.2.0 release are incomplete.** | Item | Position at handover | |---|---| | Branch and source | `feat/broadcaster-pilot`, `46494d5acba88654cf7a93aaa26685bce25467e2`; this handover is a later documentation edit | | Pull request | [PR 8](https://github.com/forgesworn/relayswarm/pull/8), open and unmerged; head verified when writing this handover | | Required CI | All nine jobs passed on that exact source in [run 39180173046](https://github.com/forgesworn/relayswarm/actions/runs/39180173046); optional soak was skipped | | Package consumption | Fresh install/import, native transfer/HTTP fallback, ledger and browser bundle checks passed; 283 package members | | Pilot | Last deployment record: source `46494d5` on Till at `https://relayswarm.forgesworn.dev`; HTTPS client hash and two fresh playlists matched | | Deployment cleanup | Deployment lifecycle and its local finaliser passed; separate fresh post-cleanup review is still pending | | Pilot account support | Nostr enabled; authenticated host-supplied account API implemented, with no website resolver configured | | Pilot reporting and forwarding | Both off after the recorded deployment | | Public release | Only v0.1.0 experimental prerelease is published; 0.2.0 is a source candidate; no npm publication | | Swift client | RelaySwarmKit v0.5.0 published with wire-v3/signed-media interoperability; physical Apple/public-NAT interoperability remains unproved | The deployment entry above comes from retained execution records, not a fresh host observation during this write-up. Recheck runtime and resources before running another acceptance test. ## What has been built and verified - Browser peer-first and shadow loaders, signed exact-context commitments, encrypted browser signalling, bounded peer work and HTTP fallback. - Live ingest producing two HLS renditions, persistent publisher identity, supervised encoders and optional TLS-verified RTMPS forwarding. The authorised private YouTube test was completed and deleted; its keys were removed. - Broader supported HLS media, delegated signing, signed stream advertisements, admission tickets, revocation and operator controls. Supported-media limits remain explicit in the feature guide. - Persistent browser upload allowances and an optional private shared-account ledger. Both Nostr and a host-supplied authenticated account API are required and implemented. No named website integration or human wallet is required. - Durable, idempotent, explicitly opted-in numeric reports. The real-browser reporting check passed on `3f706a9`, including same-volume restart and natural expiry after 304.105 seconds; repeat it on the new candidate as described below. - Permanent publication/worker leases, guardian cleanup and guarded recovery; installed native transfer with verified HTTP fallback; protocol fixtures and independent Swift SDK/browser journeys within their recorded scope. - The latest fix bounds established-live playlist HTTP 502/503/504 recovery to one 60-second episode and preserves an origin-only player across an admission epoch change. Final focused suites passed 141 tests and 21 full-controller tests. Real Chrome passed recovery after a 35-second outage, cancellation and deadline failure. Actual deployed parent-crash playback still needs retesting. These results have different scopes. Loopback, simulator, unit, package and CI results do not establish physical-device, difficult-network or sustained-load acceptance. ## Goals and completion criteria | ID | Goal | Evidence still needed or responsibility to preserve | |---|---|---| | P01 | Reliable live-edge peer delivery and quality changes | Matching short and sustained field qualification, every receiver obtaining verified peer media at both qualities, and a paired origin baseline | | P02 | Playback recovery without hiding failures | Preserve reproduced media regressions and fatal records; repeat concurrent hosted playback, including the deployed restart journey | | P03 | Supported wider HLS media | Preserve exact-context/media tests; complete the outstanding browser/device coverage of the supported subset | | P04 | Admission and bounded adversarial work | Preserve tickets, revocation and exhaustion tests; qualify the selected field profile within its original resource limits | | P05 | Durable operational measurements | Repeat trusted opt-in, idempotence, restart persistence and natural expiry on the current candidate; restore reporting off and verify cleanup | | P06 | Persistent and shared upload budgets | Complete the original 3 MB both-quality/exhaustion and account lifecycle trial; preserve reload/tab/device spend, failure handling and fresh upload consent | | P07 | Safe broadcaster crash recovery | Pass actual parent termination, writer audit, guarded recovery, stable identity/state/leases and decoded/audio playback after restart within the original bounds | | P08 | Delegated signing and advertisements | Preserve scope, expiry, revocation and signed live/ended tests; document caller-owned author trust and revocation freshness | | P09 | Installed native delivery | Preserve independent-process native/fallback and clean-consumer checks; verify the final downloaded release assets | | P10 | Protocol compatibility | Preserve wire-v3/schema conformance and independent SDK journeys; complete physical/public-network integration evidence under P12 | | P11 | Release and production deployment | Final-source required CI and consumption, completed field gates, merge/release, immutable checksums/assets, downloaded-asset verification and deployment/readback | | P12 | Real-world acceptance and benefit | Remaining physical Android/iPhone, Safari/Firefox, separate-network/hard-NAT, sustained/churn/TURN-expiry and matched wire/cost checks | No separately completed 37-item review ledger has been located. Do not turn old references to 37 review items into a claim that such a ledger is complete. ## Progress on 19 October 2026 (after the snapshot above) Steps 1 to 3 below are complete on source `46494d5`, pilot on Till, M1 browser host. Each has an actor result and a separate independent review. | Step | Verdict | Evidence | |---|---|---| | 1. Deployment cleanup review | PASS, fresh Till read 07:05:32 UTC | `artifacts/independent-deployment-46494d5-review-20261019/review.json` | | 2. P05 reporting lifecycle | Actor pass 379 s; natural expiry 304.4 s; reporting restored off. Independent OWN review PASS | `artifacts/p05-46494d5-run-r2-20261019/`, `artifacts/independent-p05-46494d5-positive-own-review-20261019/review.json` | | 3. P07 parent crash | Actor pass 122 s; kill to healthy 24.6 s; Root marker decision 9.2 s; both qualities decoded video and audio on new continuity. Independent native review PASS | `artifacts/p07-46494d5-run-20261019/`, `artifacts/independent-p07-46494d5-positive-native-review-20261019/review.json`, `artifacts/p07-46494d5-outage-timeline-20261019.json` | | 4. Short qualifier R57 | RED before any browser: M4 endpoint died at launch. Harness locale fault, see below | `artifacts/distributed-fourteen-qualifier-46494d5-r57-diagnosis-20261019.json` | | 4. Short qualifier R58 | RED in setup, zero measurement: all 14 roles started but the fixed 90 s setup deadline expired 10 s after the last start | `artifacts/distributed-fourteen-qualifier-46494d5-r58-run-20261019/`, `artifacts/distributed-fourteen-qualifier-46494d5-r58-setup-diagnosis-20261019.json`, `artifacts/distributed-fourteen-qualifier-46494d5-r58-root-cleanup-check-20261019.json` | | 4. Short qualifier R59 | RED after 304.4 s of measurement: setup passed (82.5 s); 15 of 16 gates pass; `each4BothQualityPeer` fails, as in R54. Receivers 1 to 3 obtained peer media only at low quality | `artifacts/distributed-fourteen-qualifier-46494d5-r59-run-20261019/`, `artifacts/distributed-fourteen-qualifier-46494d5-r59-result-20261019.json`, `artifacts/distributed-fourteen-qualifier-46494d5-r59-path-monitor-20261019/` | Pilot app after P07: `124e3bcc…`, started 07:27:09 UTC, reporting and forwarding off. Docker reports it `unhealthy` whenever no test source is ingesting; the health check requires a publication within 45 seconds, so this is the idle state. Findings for the next agent: - **Harness locale fault (R57).** `owned-chrome.mjs` `identity()` parses `/bin/ps -o lstart=` with a US-order regex and runs raw `ps` on M4. macOS `ssh` forwards `LANG`; with `en_GB.UTF-8` M4 prints `Mon 19 Oct …` and the endpoint throws before writing any receipt. Launch qualifier drivers with `LANG=en_US.UTF-8` and no `LC_*` overrides (verified on M4). A code fix such as pinning `LC_ALL=C` for that `execFile` would change frozen pins and needs its own review cycle. R57's leftover M4 stage was removed by Root after identity, nonce and live-process checks, not by an independent review. - **Setup slowdown (R58).** R54 on `3515d5b` started all 14 roles in 35 s; R58 took 80.6 s and R59 71.5 s. The observer runs on M4, so M1 load cannot slow the M4-only viewer phase. Per viewer, page creation and load took about 1 s in R54 against 2 to 8 s in R58 and 2 to 6 s in R59; click to ready rose similarly. The setup read pass stayed under 0.7 s, control request rates are unchanged, Till was idle and sent less than in R54, and the new playlist retry acts only on failed loads. Earlier "2 to 4 times slower" figures were per-role maxima; netlog medians for R58 were 1.2 to 1.6 times R54. - **Network environment (R59 path monitor).** M1 and M4 both use Wi-Fi and route all default traffic through a full-tunnel VPN. During R59, M4's TCP connect median to the pilot rose from 38 ms to 94 ms in setup and 101 ms in measurement (90th percentile about 240 ms), then returned to 37 ms after the run; M1 rose from 40 ms to 54 ms. This was measured on one run and is consistent with the run's own traffic congesting the path, mostly on M4, which hosts 11 browsers. Relay-only TURN over TLS/TCP sends peer traffic between browsers on the same host out through the VPN and back. Changing the VPN or wiring is the user's decision; launch gates and the external path monitor are recorded in the R59 authorisation and result. - **Both-quality receiver gate (R54, R59).** Contributors served for the whole window without budget limits, but R59 uploaded 182 MB against 15.4 MB of verified peer receipt. Against R54, receivers had far more expired waits (38 to 54 against mostly 10 or fewer), more no-budget decisions and fewer segments obtained after waiting. R43 on `7d7f676` had similar expired waits and passed, so these counts do not decide the gate. - **The gate is marginal on every complete run.** It passed in 2 of 9 runs that completed measurement (R16, R43); R43 and R50 ran the same source and split. Receivers got 1 to 59 of about 170 segments from peers, and all viewers 1.7 to 5.5 per cent of bytes. Per-request records show completed high-quality transfers at 4 to 7 Mbit/s in 0.9 to 1.4 s, but most requests start with only 0.6 to 1.0 s left of a budget capped at 1.5 s (`originFallbackMs`; the demo does not override it), because a holder must first fetch the segment from origin. No high request starting with under 900 ms left completed (0 of 217 in R54 and R59). A timed-out response still arrives in full, since the link protocol has no cancel: in R59 about 155 MB of the 167 MB of unused upload was abandoned responses, sharing the uplink and relay with useful transfers. Receiver 3 started high and had no high peer segment in its first 150 s, so this is not a switch-timing artefact. A network change can shift the odds but not make high-quality peer delivery reliable. Levers and costs, including a read-only UDP probe of the relay: `artifacts/both-quality-peer-gate-diagnosis-46494d5-20261019.json`. - **Peer request floor, local commit `5ae817d`, not pushed.** Peer selection keeps the sizes and payload rates of the last 16 completed transfers on any link; the loader goes to origin, counting `segments.peerSkippedLate`, when the time left is below what the fastest completion at least as large would need for the committed size. Smaller completions never limit a larger request, since a low-only history would otherwise block every first high-quality request; without such a completion there is no limit. It stops requests that could not finish and their wasted upload. It gives high transfers no more time, so a requalification on this source alone would most likely still fail the both-quality gate; any gain from less congestion is unproved. On M4 the swarm suite passed 178 of 178, and Chrome playback and the account journey passed (the first version also passed all four operator cases); a mutation check showed the loader test depends on the floor. A demo cap of 3000 ms for `originFallbackMs` was tried and dropped: it stopped peer delivery in the loopback account-budget journey twice, for a reason not identified, while the floor alone passed. The qualifier projection does not record `peerSkippedLate`. A new source needs CI, deployment, the deployment review, P05, P07 and a rebuilt qualifier before any field result. Evidence: `artifacts/peer-floor-91357aa-local-tests-20261019/SUMMARY.json`. - **Cancel and smaller send buffer, local branch `fix/peer-cancel`, not pushed.** Two commits on `5ae817d`, made in a scratch worktree: `51d992d` (a receiver that starts draining sends `{"t":"cancel","id":n}`; a holder declines with `none` before `meta` or stops at its next chunk and sends EOF early; a short EOF is accepted only after sending cancel; holders count `bytes.uploadsCancelled` and `bytes.uploadCancelledBytes`, with no refund of charged allowance; `docs/NIP-DRAFT.md` and `INTEGRATION.md` updated) and `4178c26` (a holder queues more only while at most 128 KiB is waiting, resuming at 32 KiB, instead of 1 MiB and 256 KiB; without this a 670 KB high segment was queued in one pass and a cancel had nothing left to stop). The Swift kit (`relayswarm-kit` 2f0b26a) is receive-only and never serves, drains or cancels. On M4 all suites passed, including real-Chrome peer-first with no loss of peer share; loopback peers never timed out, so cancel itself is proved only by unit and loader tests. Mutation checks covered each path. The qualifier observer records only `totals.uploaded`; measuring the saving in the field needs the rebuilt qualifier to keep `bytes.uploadCancelledBytes`. Evidence: `artifacts/peer-cancel-4178c26-local-tests-20261019/SUMMARY.json`. - **`4178c26` cycle, in progress (user approved, 19 October).** `feat/broadcaster-pilot` was fast-forwarded to `4178c26` and pushed at 16:18 UTC. CI run 39284440433 passed all nine required jobs (optional soak skipped) during a GitHub Actions incident: `artifacts/ci-4178c26-39284440433-20261019/ci-terminal-success.json`. Fresh consumption PASS (archive `a9b98c50`, package `f82ca82a` with 283 members, demo client 777134 B `a8d22a0b`, TMPDIR removed), from an exact-binding rebase of the executed 46494d5 helpers: `artifacts/clean-consumer-4178c26-20261019/package-review.json`. **Deployed 16:54 UTC, local closure PASS.** App `db17ed0f` (revision 4178c26, image `faa4520b`) replaced `124e3bcc`; the public client is the consumer build (777134 B, `a8d22a0b`); profile unchanged. The packet is an exact rebase of the executed 46494d5 deployment with one appended typed guard branch for the positive P07 handover (kind `P07-parent-crash-finite900-app-transition-v1`, validated by the reviewed qualifier `p07_prerequisite.py`) and its intake test (6 of 6). The inventory went 62 to 62 with three changed `src/browser` files. Live `operator.json` and `account-budget.json` inodes had changed by atomic replacement since P07, which the guards permit; the four lease inodes were unchanged. Result: `artifacts/deployment-4178c26-peer-cancel-result-20261019.json`. **Independent post-cleanup deployment review PASS** (17:00 UTC, one 1.7 s read-only Till read, 116 pins, six predicates): `artifacts/independent-deployment-4178c26-review-20261019/review.json`. The first preparation refused at a missed literal before creating any output (`artifacts/deployment-cleanup-review-4178c26-prepare-attempt1-20261019.json`); the r2 packet fixed it. **P05 attempt 1 RED (17:04 to 17:06 UTC).** The worker stopped after ten exchanges with an AssertionError consistent with a torn read of `request.json` (the actor replaces it by atomic rename while the worker polls it with an identity check); the 4178c26 code is not involved. Restore and cleanup ran: reporting is off, the P05 control directory is gone, browser cleanup is complete, the lease inodes are unchanged, and the live app is now `7ff2b4ec` (same image). Because the run replaced the app, a plain rerun would refuse; the reviewed P05 schema accepts the failed partial run as a `p05-owned-journal-v1` predecessor after an independent cleanup review. Record: `artifacts/p05-4178c26-root-run-attempt1-20261019.json`. **P05 r2 PASS (17:21 to 17:28 UTC, 385 s of 540 s).** Attempt 1 was closed by an independent cleanup-only review (PASS, reporting acceptance false) and bound as a typed `p05-owned-journal-v1` predecessor through one new runner path; the actor is byte-identical to attempt 1. A torn-read retry for the actor was prepared and dropped because the original method-protection test forbids changing the worker lifecycle. Natural expiry 304 s, telemetry restored false, 44 host operations, live app `de1e594d`. Independent review PASS with reporting acceptance true: `artifacts/independent-p05-4178c26-positive-own-review-20261019/review.json`. **P07 attempt 1 RED and pilot outage 17:29:58 to 18:44:08 UTC.** The run reached operator-decision after the parent crash and waited for a root recovery authority that was not placed (no watch was running); it ended without restarting. With the user's choice, the pilot was restored by a guarded operator recovery outside the expired window: fresh complete writer audit, the reviewed `explicit-marker-recovery.mjs` under all four leases (dirty marker and v2 lock removed, leases and publisher state preserved), app recreated from its own compose files with `unless-stopped`. Live app `59ba62eb` (4178c26, image `faa4520b`), lease inodes unchanged, public `/` 200 waiting page (no source running). Records: `artifacts/p07-4178c26-root-run-attempt1-20261019.json`, `artifacts/p07-4178c26-operator-recovery-20261019.json`. Because the live app no longer descends from any harness proof, every next harness run (P07 r2, P05 or the qualifier) needs a typed handover for this recovery before it can start. The R61 qualifier preparation is built (`artifacts/distributed-fourteen-qualifier-4178c26-r61-preparation-20261019`, identity rebase plus a labelled observer field for the cancel counters; two stale topology test cases fail identically on the 46494d5 base) and is not yet bound. Steps that need a clean checkout stash the handover docs and restore them by checksum. **P07 r2 prepared (recorded method change, user-approved).** A new typed handover `p07-negative-operator-recovery-transition-v1` (`artifacts/parent-crash-p07-4178c26-r2-source-preparation-20261019`, index `112351af…`, record `OPERATOR-RECOVERY-HANDOVER.json`) replays attempt 1 and the operator recovery from 26 pinned files and moves only the app namespace and restart policy to `59ba62eb`; the P05 tuple stays exact. Changed: new `current_handover.py`, the P05 wrapper, tests and resealed pure pins; actor, host protocol, observer and all bounds are byte-identical. Pures 14/14 (`artifacts/p07-4178c26-r2-pure-20261019/RESULTS.json`), each of 34 per-fact refusals checked to fail on its own line. Attempt 1 left its Chrome profile and child temporary roots on disk (receipt cleanup `{}`); they were removed under an identity check (`artifacts/p07-4178c26-attempt1-browser-root-removal-20261019.json`). Driver r2 (`artifacts/p07-4178c26-root-driver-r2-source-20261019`, fresh r2 DATA, results, Till control and source names) and native review r2 (`artifacts/p07-4178c26-r2-native-review-source-20261019`, actor pointer only) are built; a dry check passed the whole chain, including the live app fields. The r2 run uses a background recovery watch that places the one-use authority by atomic rename only if all eligibility checks pass. **P07 r2 PASS (19:23:23 to 19:25:08 UTC).** Actor 104 s; the watch passed all 13 checks and placed the authority 5 ms after the actor requested it; kill to healthy 16.0 s; the M1 observer decoded video and audio at both qualities on the new continuity, no fatal errors. Independent native review PASS (`artifacts/independent-p07-4178c26-r2-positive-native-review-20261019/P07-NATIVE-PROOF.json`, sha `54a66394…`). Live app `7d0ae914`, started 19:24:20 UTC, `unless-stopped`, lease inodes unchanged. Record: `artifacts/p07-4178c26-r2-result-20261019.json`. - **R61 is RED on the same single gate (19:30:44 to 19:37:27 UTC).** Source 4178c26, Till app 7d0ae914 unrestarted, 3 roles on M1 and 11 on M4, 302 s measured. The launch waited for the unchanged gate (19:28 refused on M4 load). 15 of 16 gates passed; `each4BothQualityPeer` failed and is weaker than R60: no receiver received high quality from peers (receiver 2 received no peer media), 0 of 425 high-quality peer requests completed, and verified peer media fell to 6.3 MB (R60 14.2 MB). Cancel is active: 353 responses cancelled and 129 MB never sent. `bytes.uploaded` charges the whole segment on acceptance and is not refunded, so its 222 MB includes that 129 MB; from the two counters about 92.9 MB was actually sent (one session per contributor). High-quality requests still start with as little as 24 ms left (p10); the late-request floor cannot limit them without a completed high-quality transfer, and the observer does not record `peerSkippedLate`. The R61 observer change (cancel counters only) is labelled in the authorisation. External path monitors (not harness evidence): M4 median connect rose from 65 to 112 ms during measurement, as in R60, but M1 load1 peaked at 6.6 (R60 51.6), so M1 load does not explain the result. Cleanup confirmed on M1, M4 and Till; docs restored by checksum. Result: `artifacts/distributed-fourteen-qualifier-4178c26-r61-result-20261019.json`. The 7,200 s run stays blocked; the next step is a high-quality delivery change, which needs its own cycle. **Read-only diagnosis (`artifacts/r61-throughput-diagnosis-20261019/DIAGNOSIS.json`), corrected by the structural analysis below.** Holder links peaked at 3.9 Mbit/s (R60 15.2, R59 9.1) and no high-quality request ran faster than 2.75 Mbit/s (R60 5.17). Cancelled responses keep their charge against the 512 000 B/s upload token bucket, so the busiest holder refused 137 requests (R60: 7) after 77 MB of charged bytes were never sent. The first version said the environment did not explain the drop and led with the 128 KiB send buffer; both are corrected below. The concurrent session on this Mac is working on Spotlight indexing, which explains much of M1's load. **Structural analysis (`artifacts/high-quality-peer-structure-analysis-20261019/ANALYSIS.json`, read-only, R59 to R61).** Findings: - *Playback regression in R61.* Every peer-first viewer at high quality stalled: receivers 5 to 8 times (7 to 14 s), high contributors 9 to 15 times on 3 of 4. Origin-only baselines barely stalled; R60 had almost none. The frame/audio gate still passed. The stalls followed quality and peer-first mode, not host: low-quality contributors on M4 stalled once or twice for under a second. That points to the high-quality wait loop rather than the path alone, but the records cannot separate 4178c26 from the slower path. - *The 1.5 s cap, not playback, bounded R60.* At high-quality decisions, R60 receivers had a median 7.9 s of buffer. With the 2 s origin reserve kept, 87% could have waited at least 3.5 s. In R61 the high buffer had collapsed to 3.5 s, so the cap bound only about 15% of decisions there. - *A high segment needs far more than 1.5 s.* About 0.7 s goes on waiting for a holder (budget left at request p50 739 to 783 ms). Typical requests then ramp the same way in R60 and R61, gaining about 0.37 of a segment per second after a slow start. A whole segment needs roughly 2.5 to 3 s from the request. The smaller send buffer lowered the fastest links but not the typical request, so it is one unproved contributor, not the lead cause. - *The environment was worse in R61, contrary to the first diagnosis.* High-quality HTTP fetches by peer-first roles were 40 to 65% slower on 3 of 4 high contributors; low-quality fetches were unchanged. Both runs were without the VPN. Origin timing per request was not recorded, so path capacity and self-inflicted fallback bursts cannot be separated. - *Likely feedback loop (inferred).* A failed high wait costs up to 1.5 s plus the HTTP fetch, close to the 2 s segment in R60 and over it in R61. The buffer then drains toward the reserve, the budget shrinks toward zero, and requests start with little time left. R61 had 96 high requests given under 400 ms (p50 25 ms), 91 of which received nothing. The code charges each accepted request a whole segment before sending. Records carry no holder id, and the timing correlation with refusals (0.38) is no stronger than for other timeouts, so the size of this drain is unproved. - *Gate arithmetic.* Each receiver needs one verified high peer segment in about 150 s at high (about 60 attempts). A 5% per-attempt completion rate gives about 95% per receiver; R60 managed 1%, R59 4%, R61 0%. - *Projection.* From each timeout's own partial rate (pessimistic), a cap of 3 to 5 s would let 18 to 32% of R60's high timeouts finish, but only where the buffer allows it. - *Receiver 2 in R61.* It had four links and no dial or admission failures; its only peer segment arrived before measurement. - *Loopback cap failure.* The 3000 ms cap failure in the loopback journey is still unexplained. - *Process.* Floor, cancel and the smaller buffer were each proved only on loopback, where peers never time out. No local bench reproduces a 160 to 200 ms relayed round trip. The analysis lists the levers and their costs: wait cap, request floor, charge semantics, early give-up, buffer depth, segment size, send buffer, UDP relay addresses and cut-through sending. - **Peer timing bench and candidate `eb8a62f` (20 October, local, not pushed).** The user chose "bench first". - *Bench.* `test/peer-timing-bench.mjs` (dev-only, committed with the candidate): the demo page, two live renditions at field segment sizes (about 208 KB and 668 KB), and Chrome DevTools network emulation set before any peer connection opens (60 ms per page, a peer round trip of about 250 ms; origin 150 ms + 800000 B/s or 200 ms + 530000 B/s). On 4178c26 it reproduces the field: 0 to 1 per cent high-quality completions, the R60 ramp, and the R61 drain when only the origin slows. Loopback with emulated delay, not field evidence. Calibration: `artifacts/peer-timing-bench-calibration-20261019/CALIBRATION.json`. - *Cap alone.* A 3000 ms `originFallbackMs` drained high-quality viewers further and completed no high transfer (EXPERIMENTS.json there). - *Candidate.* Branch `perf/peer-no-drain`, one commit on 4178c26: projected waits bounded by the buffer less the origin reserve (new `maxPeerWaitMs`, 5000), early abandonment, a holder refund of unsent bytes to the per-second rate, first-byte timing and new counters; INTEGRATION.md updated. Five iterations; v5 was reverted. - *Result, 300 s runs, matched settings.* Current code: 0 high and 5 to 8 low peer completions, receivers at 2.5 to 3.0 s of buffer at high decisions. Candidate: 2 to 11 high and 185 to 217 low completions, receivers' median buffer 3.1 to 6.7 s, no stalls in any run. The bench gate passed 1 of 6 candidate runs; each failure left one receiver with no high peer segment. High delivery is bounded by holder uplink: a high viewer needs about 335 kB/s against the demo's 512 kB/s limit. `maxPeerWaitMs` bound the room where the buffer allowed about 5.9 s. Record: `artifacts/peer-timing-bench-candidate-20261019/CANDIDATE.json`. - *Local tests.* Unit 214/214, playback, resume, all four operator cases (both account-budget journeys) and the CI-shape browser runs passed on M1: `artifacts/candidate-3321b3b-local-tests-20261020/SUMMARY.json`. - *Holder upload rate (user's choice, "bench at 1.25 MB/s first").* With contributors at the demo's 1.25 MB/s choice (bench commit `3407eb8`), the candidate passed the bench gate in both regimes (22 and 11 high completions, no rate-limit refusals, no stalls); current code still failed both with no high completion. One run per regime; the slow-origin pass left one receiver with a single high segment. The pilot profile records 512 kB/s, so the field equivalent is a profile change needing fresh consent. Record: `artifacts/peer-timing-bench-upload-1250000-20261020/RESULT.json`. - **`c5672e5` cycle, in progress (user chose "candidate + 1.25 MB/s", 20 October).** The candidate and bench option were squashed to `8279c23`; `feat/broadcaster-pilot` was fast-forwarded from 4178c26 and pushed. CI 39380893462 failed: (1) `test:broadcast:browser`, a code fault: the test's availability instrumentation reads `deadline` in `#peerFirst`, which the change had replaced, so every instrumented peer-first load threw (production builds unaffected); (2) one Windows timing test (`serial peer attempts…`, 120 ms budget against 15.6 ms timer steps), passing 15/15 locally and on Ubuntu/macOS. Record: `artifacts/ci-8279c23-39380893462-20261020/FAILURE-RECORD.json`. Fix `c5672e5` (keeps an initial `deadline` binding; broadcast browser test passes locally) pushed as a fast-forward; CI 39382996962 running. Consumer preparation for c5672e5 is built (exact rebase of the executed 4178c26 helpers, same edit counts): `artifacts/clean-consumer-c5672e5-source-preparation-20261020` (SOURCE-PINS `f50c2228…`). Deployment findings: the runtime inventory excludes `test/`, so it stays 62 with the same three changed files; the existing positive-P07 typed branch (`P07-parent-crash-finite900-app-transition-v1`) accepts the 4178c26 r2 native proof unchanged in a pure check (derives app `7d0ae914`, 18 records), so the deployment is a rebase with predecessor 4178c26, not a new method. The qualifier profile change is `SETTINGS.rate` 512000 to 1250000 in `actor-model.mjs`, to be labelled in R62 with the new counters. CI 39382996962 on c5672e5 then failed only on an over-tight assertion in a new test (first byte `>= 600` against a 600 ms timer); fixed in `5f2ece0` (test only) and pushed. **CI 39384666332 on 5f2ece0 PASS**, all nine required jobs including live relays, soak skipped: `artifacts/ci-5f2ece0-39384666332-20261020/ci-terminal-success.json` (`f56b24e3…`). **Fresh consumption PASS (07:29 UTC, M1, 13 s)**: archive `979522a7` (287 members), package `aff72af3` (284 members), demo client 782466 B `92b3f56f`, standalone `8a1161cb`; supervisor exit 0, TMPDIR removed, docs restored by checksum. Deviation: the offline audit ran once under a plain 15 s timeout, not the recorded wrapper (stated in `analysis/AUDIT-EXECUTION.json`). Review: `artifacts/clean-consumer-5f2ece0-20261020/package-review.json`. **Deployed 07:43 UTC, local closure PASS.** Packet: rebase of the executed 4178c26 deployment (host-common/snapshot rebound, inventory constants regenerated against the 4178c26 map, pure test rebound to the 4178c26 r2 P07; proof-guards, host-entry and namespace adapter exact copies), pure 6/6: `artifacts/deployment-5f2ece0-peer-wait-source-preparation-20261020`. One chained Root run (`artifacts/deployment-5f2ece0-peer-wait-root-chain-20261020.sh`): snapshot, fresh M1/Till reads, stage 07:43:03 to :16, deploy/attest/cleanup to :55, finalise. App `d33b0421` (revision 5f2ece0, image `e088cec7`) replaced `7d0ae914`, started 07:43:42 UTC; client 782466 B `92b3f56f`; profile unchanged (relay TLS/TCP, 32/900); four lease inodes unchanged. Contract `202b5564…`: `artifacts/deployment-5f2ece0-peer-wait-20261020/runtime-contract.json`. **Independent post-cleanup deployment review PASS** (07:47 UTC, one 1.7 s read-only Till read, 115 pins, six predicates; literal rebase of the 4178c26 r2 review protocol with the positive-P07 checks rebound to the 4178c26 r2 app): `artifacts/independent-deployment-5f2ece0-review-20261020/review.json` (`df9fed1c…`). **P05 PASS on the third invocation (07:55 to 08:01:37 UTC, 379 s of 540 s).** Source: identity rebase of the 4178c26 r1 bound copy (no predecessor branch needed). Two earlier invocations refused locally before any host action: attempt 1, the generator had set the actor's two native helpers to 0600 (base 0500), refused at native resource identity; attempt 2, Chrome's hard-link count changed 44 to 43 between Root's executable snapshot and the actor's check (another session's Chrome instance closed). Records: `artifacts/p05-5f2ece0-root-run-attempt1-20261020.json`, `artifacts/p05-5f2ece0-root-run-attempt2-20261020.json`. Attempt 3 (`artifacts/p05-5f2ece0-source-bound-r3-20261020`, launched after the Chrome link count held for 5 s): 45 host operations ok, natural expiry 302.7 s, telemetry false restored, live app `9a265f56` started 08:01:22 UTC. Independent OWN review PASS, reporting acceptance true (one M1 and one Till read, 34 direct pins): `artifacts/independent-p05-5f2ece0-positive-own-review-20261020/review.json` (`5842f8bf…`). **P07 attempt 1 RED before the crash (08:11:32 to 08:12:15 UTC).** Sources (identity rebases of the 4178c26 attempt-1 P07 source, driver and native review, pures 11/11): `artifacts/parent-crash-p07-5f2ece0-source-preparation-20261020` (index `ebd52de1…`). The recovery watch was polling and Chrome's link count steady before launch. The M1 observer played both qualities with decoded progress, then its Node-side `publicState()` fetch of `/session.json` or `/client.js` from the public pilot hit its 5 s/8 s timeout; the run ended before the parent signal. Host operations: prepare, restore-policy, cleanup-source. No crash, no recovery request, watch placed nothing, browser cleanup complete. Live app unchanged: `9a265f56`, unless-stopped. Record: `artifacts/p07-5f2ece0-root-run-attempt1-20261020.json`. The user chose a rerun. Attempt 2 (r2 driver names) refused at actor validation, Chrome hard-link count changed, no host action. Attempt 3 (r3 names, launched only when no other browser process ran and the count held 10 s) failed like attempt 1: both qualities decoded, then `publicState()` timed out about 7.5 s after readiness; no crash, cleanup complete, app `9a265f56` unchanged. In attempt 1 a browser segment in the same window took 7.5 s (others 0.1 to 0.7 s), suggesting a path stall; `publicState()` is byte-identical to the passing 4178c26 r2 observer. Records: `artifacts/p07-5f2ece0-root-run-attempt2-20261020.json`, `artifacts/p07-5f2ece0-root-run-attempt3-20261020.json`. Diagnosis: the r3 timeout was the observer's single 8 s fetch of the 782 KB `/client.js` (the pilot proxy logged the aborted response); a quiet probe of 30 such fetches from M1 had median 0.70 s but one 7.2 s body stall (`artifacts/p07-5f2ece0-path-diagnosis-20261020.json`). M1 was on Wi-Fi. The user paused P07 after attempt 3, then asked to carry on; M1 was still on Wi-Fi, so reruns used the unchanged harness behind local read-only gates. Attempt 4 (r4, link gate passed) refused before any host action: the Till policy/clock read took 1689 ms against the 1000 ms bound (`artifacts/p07-5f2ece0-root-run-attempt4-20261020.json`). **P07 r5 PASS (08:49:32 to 08:51:11 UTC).** Link and SSH gates clean; actor 98 s; the watch placed the authority at 08:50:18; independent native review PASS (`artifacts/independent-p07-5f2ece0-r5-positive-native-review-20261020/P07-NATIVE-PROOF.json`, sha `19869d43…`; review `8547424d…`). The chain wrote the read authorisation with mode 0644, so `produce-review.py` refused after both reads; Root set 0600 (content unchanged) and reran only that step inside the window. Live app `8534fff7` (5f2ece0, image `e088cec7`), started 08:50:23 UTC, `unless-stopped`. Record: `artifacts/p07-5f2ece0-r5-result-20261020.json`. **R62 prepared and bound.** Preparation `artifacts/distributed-fourteen-qualifier-5f2ece0-r62-preparation-20261020` (generator beside it; manifest `3c1c5013…`) is the R61 build rebased to 5f2ece0 with three labelled changes: `SETTINGS.rate` 512000 to 1250000 (the existing 1.25 MB/s option), peer-wait counters (`peerSkippedLate`, `peerProjectedLate`, `peerWaitExtended`, `peerAbandoned`, `peerNoFit`) in each observer sample, and Chrome pins refreshed to 155.0.8059.85 (`6e156f22…`, same bytes on M1 and M4; M4 whole-app strict signature still RED as before; `artifacts/qualifier-chrome-155.0.8059.85-observation-20261020.json`). Local tests equal the R61 base file by file, with the same failing test names (`artifacts/distributed-fourteen-qualifier-5f2ece0-r62-local-tests-20261020.json`). Deployment bound (`1303387c…`); `prepare-run` PASS with the P07 r5 proof (data `4e7ea41f…`, root driver `fa86cb17…`, identical to R61's apart from deployment, archive, contract, review, CI and P07 pins). The R61 root scripts were copied out of the session scratchpad to `artifacts/r61-root-scripts-20261019/`; R62's are in `artifacts/r62-root-scripts-20261020/` (launch gate adds M1 `client.js` <= 0.8 s to the R60 gate). - **R62 is RED, stopped early by the observer's own health read (09:52:51 to 09:58:02 UTC).** The gate waited about 40 minutes while another session's fuzz campaign saturated M1, then met at 09:52:19. At 09:57:41.8, 178 s into the 300 s measurement, the observer on M4 timed out (2 s) reading M1's local `/resource-health` through the SSH tunnel; the sample a second earlier was healthy. The cause is not isolated between a stall on the M4-to-M1 path (M1 on Wi-Fi) and one slow reply from M1's health server: M1's sample lag stayed flat (about 1 s) up to the failure, and M1 was busier than in R61 (load1 median 6.7, maximum 12.3; R61 4.5, 8.0). The run finalised RED, so the receipt holds only the three admission gates that need a completed measurement (all false) and the per-role gates were not evaluated. Admission verifies: 1979 of 1982 returned 200. Partial peer evidence (178 s, not gate-comparable): high-quality peer requests delivered 4 of 18 (R61: 0 of 425 over 300 s); low 93 of 174 (R61: 30 of 169); median budget left at request start 1.36 to 1.39 s (R61: 0.74 to 1.0 s); receivers 1 and 3 received high from peers, receiver 2 low only, receiver 4 none. The new peer-wait counters were recorded in every sample. Cleanup complete on M1, M4 and Till; live app `8534fff7` unchanged. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r62-result-20261020.json`. - **R62 r2 is RED (10:34:29 to 10:38:15 UTC).** The user chose a fresh-name rerun; the r2 preparation is the R62 generator with only names changed (every program byte-identical). At 10:38:04, 107 s into measurement, the actor model refused an unplanned origin-only interval: M4-contributor-high-2's short-lived peer authority lapsed for 0.95 s while its renewal was pending, and the page dropped to off and back, losing its peer links. The M4 path monitor shows M4-wide degradation from 10:37:55 to 10:38:03 (pilot TCP connect 0.7 to 0.95 s against about 40 ms, TURN connect up to 1.1 s, `session.json` 2.06 s) while M1's connects stayed normal; M1 load1 was 69 to 76 from other sessions. Harness uploads were not the cause (aggregate M4 peer upload about 0 MB/s then). R62's own failure also coincided with a smaller M4 spike. M4's default route is a VPN tunnel over Wi-Fi, and M1 was recorded as on Wi-Fi but most likely also used a tunnel (see R63). R61's launch notes record a no-VPN baseline, so the paths differ from R61's. Partial peer evidence was weak (low 11 of 44, high 0 of 8; only receiver 1 received peer media). Cleanup complete; live app `8534fff7` unchanged. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r62-r2-result-20261020.json`. - **R62 r3 is RED on 2 of 16 gates after a complete 304 s measurement (11:35:33 to 11:42:43 UTC).** The user said "carry on regardless"; r3 is the same programs with fresh names. The first gate window (10:44 to 11:30) was never met (M1 load from other sessions, M4 `client.js` over 0.8 s), with no host action; the second met at 11:35:25. Failed: `each4BothQualityPeer` (receivers 1 to 3 received both qualities from peers, receiver 4 high only) and `observedInPlaceRenewal` (M4-contributor-low-1 had no peer links at its first ticket renewal, having lost its last two four seconds earlier). Against R61's full run: high-quality peer requests delivered 28 of 66 (R61 0 of 425), low 149 of 278 (R61 30 of 169), verified peer bytes 50.1 MB (R61 6.3 MB) with fewer uploaded bytes (157 MB against 222 MB). Link churn rose about five-fold (166 links closed against 34; 36 dial timeouts against 0), led by upload drain timeouts (52 against 9) and the matching channel errors, consistent with the 1.25 MB/s limit overdriving relayed links on the current Wi-Fi/VPN paths but not isolated from the network change; `steadyNoChurn` passed. Cleanup complete; live app `8534fff7` unchanged. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r62-r3-result-20261020.json`. The user chose a rerun at 512 kB/s to isolate the rate (R63). - **R63 is RED in setup, before any measurement (12:02:30 to 12:03:45 UTC).** R63 is the R62 preparation without the rate change: `actor-model.mjs` is byte-identical to R61's (`rate:512000`), the Chrome pins and peer-wait counters stay, and local tests match R62's (`artifacts/distributed-fourteen-qualifier-5f2ece0-r63-local-tests-20261020.json`). The gate met at 12:02:22 after 9 checks. M4-contributor-high-1 (M4 profile A) started receive-only at 12:03:19 and was not ready within the page's 12 s default limit (unchanged since R61). Playback never began, a policy read took 2.3 s and one admission verify failed at 3.0 s. Six contributors had started. M4's path degraded through the window. Pilot TCP connects rose from about 120 ms to 1.07 s between 12:03:07 and 12:03:27, and `session.json` took 1.33 s, then timed out. The monitor paused for 8 s while M4 load1 was 3.5 to 4.6. M4 has slowed in every setup since R61 (`session.json` up to 1.6 to 2.3 s against at most 0.53 s in R61's setup), but R63 was the worst (connect p90 850 ms against 187 to 346 ms). Rate is not the setup factor, since three setups at 1.25 MB/s passed. The rate question is still unanswered. - **M1 also routes through a VPN tunnel.** Its default route was Wi-Fi (en1) at 08:43 UTC today. A tunnel system extension process started at 08:59:03, and the route was confirmed through the tunnel at 12:06. Nothing observed the route in between. M4's tunnel extension started at 20:14 UTC on 19 October, after R61 ended. So every R62-series run and R63 most likely sent through a VPN tunnel on both Macs, and R61 on neither. The P07 r5 and R62-series records describe M1 as on Wi-Fi because the tunnel was not checked; P07 r5 passed, and no verdict changes. M1 load1 rose from about 8 at the gate to 22 to 32 during setup (not attributed). - **R63 cleanup.** Both stages are absent with no owned processes. Till keeps only `journal.json`, and the live app `8534fff7` is unchanged (restart count 0). The browser receipt does not prove browser cleanup: only 7 of 14 contexts were acquired (all 7 closed, CDP detached). The outer guardian reports `ok: false` with the worker reaped and the owned group absent. The metadata helper ended by signal with an invalid record. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r63-result-20261020.json`. The user chose "Tunnels off, then rerun". Both tunnels were off by 12:22:14 (M1 en1, M4 en0). - **R63 r2 is RED at the setup progress check, before measurement (12:35:20 to 12:37:06 UTC).** R63 r2 is the R63 programs with fresh names (all 92 byte-identical). Its authorisation adds a Root-side check that refused to launch if the default, origin or TURN route on either Mac was a tunnel; it passed. All 14 roles started. The progress check requires every page to advance frames, media time and decoded audio over 10 s (unchanged since R61). Two high-quality pages on M4 failed it: M4-contributor-high-2 and receiver-3. Their frames and audio stayed flat while media time jumped about 16 s, which suggests the player skipping forward after a stall. The origin-only high-quality page on M4 also stalled. M4's pilot connects rose to 100 to 270 ms, with spikes of 1.2 and 2.2 s, and `session.json` took 1.6 s. What M4's pages pulled from the origin in that window has fallen across the runs: R60 2.90 MB/s, R61 2.32, R62 2.25, R62 r2 1.53, R62 r3 1.87, R63 r2 1.09. M1's three roles were served steadily (0.50 to 0.57 MB/s), which points at M4's side. The fall is not explained by the tunnel alone or by the contributor rate. M4 is a laptop on Wi-Fi only (channel 60, -48 dBm, 780 Mbit/s when checked afterwards). M1 is on Wi-Fi with its Ethernet port not carrying the route. The rate question is still unanswered. Cleanup complete and proved (14 of 14 contexts closed); live app `8534fff7` unchanged. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r63-r2-result-20261020.json`. The user chose to investigate peer startup locally. - **The setup stalls come from M4's origin downloads, not from peer waits (analysis of retained records, no host action).** The stalled high-quality pages on M4 were loading from the origin. Since R61 most of their decisions were "no budget" (buffer already below the origin reserve), and the few bounded peer attempts fell back to the origin. R60's pages tried peers more often and did not stall. In R63 r2's netlog, M4's origin requests went out at once (0 to 1 ms queued), and the time went on transfer: high segments at about 100 to 290 kB/s against the about 325 kB/s real time needs. M1 fetched the same segments from the same origin at 0.65 to 4.2 MB/s. The end-of-measurement netlog windows compare like for like: median per-segment high transfer on M4 was 1.0 to 1.1 MB/s in R60 and 0.23 to 0.72 MB/s in R61 to R62 r3, while M1 stayed at 0.9 to 2.0 MB/s. A single HTTP transfer does not depend on the peer loader, so M4's network path has slowed since R60. The 11 M4 roles need about 2.5 MB/s from the origin, because peers deliver almost nothing during setup (R60 included). M4 has supplied that or less since R61. Each role is its own browser context, so the HTTP/1.1 connection limit is per role and not shared. The R60 to R61 loader changes do not alter how origin requests are made. Fresh test profiles also download Chrome components at startup (4.89 MB against 4.53 MB of media on one M4 browser in R63 r2's last 11 s). Why M4's path slowed is not identified: R60 ran at a different time of day, and other traffic on M4 was not measured. Record: `artifacts/qualifier-setup-stall-analysis-20261020.json`. - **Origin probe (13:09 to 13:11 UTC, outside the harness, read-only).** With the harness idle, M4 is no slower than M1. Six parallel `client.js` streams gave 2.73 MB/s on M4 and 2.05 MB/s on M1 when run separately, and 2.87 and 3.01 MB/s when run together (5.88 MB/s combined, so no shared bottleneck). Each fetch opens a new TLS connection, so these understate capacity. In R63 r2's setup the same path fell to 0.1 to 0.3 MB/s per transfer, with connects up to 1 to 2 s. So M4 congests under the qualifier's own load: 11 pages, about 2.5 MB/s of origin media plus start-up buffering, Chrome component downloads of about 5 MB per browser, and relay and control traffic. R60 carried the same load without congesting, and what differs is not identified. Record: `artifacts/origin-download-probe-20261020.json`. - **R63 r3 is RED at the 90 s setup deadline, before measurement (13:15:14 to 13:17:15 UTC).** The user chose "Rerun now, measure M4": the R63 programs again with fresh names, tunnels off, plus a per-process network sampler on M4 outside the harness. All 14 roles started, but over 75 s (R60 40 s, R61 50 s, R63 r2 54 s), and the deadline expired inside the 10 s progress check. M4's Wi-Fi download sat at a flat 4.0 to 4.4 MB/s for the last minute of setup, which means it was saturated. It took in 311 MB in 85 s, at least 224 MB of it through the two test browsers, but the pages' origin media came to only 57 MB. Another Chrome on M4 used 0.1 to 0.4 MB/s, the harness's observer and SSH session up to about 0.2 MB/s each, and nothing else was significant. In the M4 netlog, a long request that started before the window read 6.86 MB in 8.3 s over QUIC. The origin serves HTTP/1.1 only, so it was not from the origin. A similar one read 5.73 MB in 11 s in R63 r2, while R60's and R61's end-of-run windows show almost no QUIC traffic. Component updates also downloaded. A guess that it was Chrome's on-device AI model went against the evidence: M1's regular Chrome holds that 4 GB model and M4's does not. The harness launches Chrome without `--disable-background-networking` or `--disable-component-update`, so every fresh profile runs its background downloads during setup. The large download's URL is not in the retained window. Cleanup: both stages are absent, the Chrome groups gone and the profiles removed. Till keeps only `journal.json`, and the live app `8534fff7` is unchanged. The observer receipt holds no browser-cleanup fields, because its setup deadline ended it first. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r63-r3-result-20261020.json`. The user chose to identify the download. - **Every fresh test profile downloads about 54 MB of Chrome's own models and updates in its first 90 s (probe at 14:25 UTC, between runs, outside the harness).** One fresh headless Chrome per Mac ran with the harness's exact launch flags, idled for 90 s and was then removed. Both downloaded about 41 MB of Optimization Guide models from Google over QUIC, starting 12 to 14 s after launch; the largest, the passage embedder, is 33.6 MB. About 13 MB of component updates followed from about 60 s. None of it relates to the test. M4 runs two profiles, so about 110 MB lands on its Wi-Fi early in setup. That matches the QUIC downloads in the R63 r2 and r3 netlogs and much of R63 r3's non-media traffic. Whether R60 and R61 profiles downloaded the same is not known. Record: `artifacts/chrome-background-probe-20261020/SUMMARY.json`. - **Flags verified; R64 prepared, not run.** The user chose "Verify flags, then build R64". With `--disable-background-networking`, `--disable-component-update` and `--disable-features=OptimizationGuideModelDownloading,OptimizationHints,OptimizationTargetPrediction`, a fresh profile's background downloads fall from about 54 MB to 0.01 MB on both Macs. The first two flags alone left the 41 MB of models (`artifacts/chrome-background-probe-flags-20261020`, M4; the M1 half of that probe passed the flags as one argument and is invalid). Final probe: `artifacts/chrome-background-probe-flags2-20261020`. R64 is the R63 programs plus one labelled change: those three flags in `model.mjs`, the only one of the 92 programs that differs from R63 (`artifacts/distributed-fourteen-qualifier-5f2ece0-r64-preparation-20261020/R64-METHOD-DELTA.patch`). Local tests equal R62 file by file after one rerun of `netlog-capture`, whose single extra failure did not recur and whose files are byte-identical to R62's (`artifacts/distributed-fourteen-qualifier-5f2ece0-r64-local-tests-20261020.json`). Bind and prepare-run pass, and the root pins the flagged `model.mjs`. The user approved running it. - **R64 cleared setup, then went RED 106 s into measurement (14:54:10 to 14:57:51 UTC).** Setup passed for the first time since R62 r3. All 14 roles started in 36.5 s (R60 39.9 s, R63 r3 75.1 s), every page advanced in the progress check, and peer readiness was green with 43 links. During setup M4 took in 2.49 MB/s with no flat ceiling, and the test browsers received about as much as their pages' origin media (83 MB against 82 MB). So the launch flags removed the background downloads. At 14:57:07.7 the observer's 2 s health read of M1 timed out. M1's load had climbed from about 10 to 144 during the run and was still about 100 afterwards, which points to other work on M1 rather than the harness (its M1 tree stayed at 24 to 25 processes). Partial peer evidence, not gate-comparable: low-quality peer requests 97 of 136 delivered, high 0 of 42, as in R61 and unlike R62 r3's 28 of 66 at 1.25 MB/s. Early link churn does not clearly follow the rate (6.9 closes per minute in R64 and 17.7 in R61 at 512 kB/s, against 9.6 to 31.3 at 1.25 MB/s). The partial evidence points to the 512 kB/s limit, not churn, as what blocks high-quality peer delivery, but the comparison is not matched. - **R64 cleanup is incomplete on M1.** The harness cleanup stopped at `read-endpoint-receipt` (TimeoutExpired) under that load. The runner was reaped, the Chrome group is gone, and nothing references the stage, but three folders remain: the stage (174 KB), the Chrome profile (21.7 MB) and an empty child temp folder. Their records are copied to `artifacts/distributed-fourteen-qualifier-5f2ece0-r64-run-20261020/M1-leftover-stage-evidence/`; at the user's request they were then removed by literal path after inode checks, a manual cleanup deviation (`MANUAL-CLEANUP.json` there). M4 and Till are clean, and the live app `8534fff7` is unchanged. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r64-result-20261020.json`. - **R65 prepared and run after a second gate wait.** The user chose "Matched 1.25 MB/s run": the R64 programs with the contributor limit at 1.25 MB/s, so R65 differs from R62 only in the three launch flags. The first 45-minute gate wait (15:30 to 16:16 UTC) passed none of 123 checks: M1 load1 reached 169 from other projects' builds, test browsers and a virtual machine, and M4's load stayed mostly above 5 from the owner's own apps. Nothing was stopped. At the user's request the gate was re-armed with unchanged limits; it was met at 16:42:08. - **R65 completed the 300 s measurement and is RED on two strict gates (16:42:18 to 16:48:55 UTC).** 14 of 16 gates passed, including steady churn, consent, renewal, admission and resource gates. All 14 roles started in 34.9 s, every page advanced at least 308 frames in the progress check, and M4 took in 2.19 MB/s during setup. `all8ActuallyUploaded` failed: M4-contributor-high-2 served one 666 kB upload during setup and none during measurement, although it was serving with 3 to 4 links and refused nothing. `each4BothQualityPeer` failed: only receiver-3 received high-quality peer media. Receivers 1, 2 and 4 asked for high-quality segments, mostly waited for a holder and fell back to origin; only the four high-quality contributors hold that media. M1's load rose to 18.6 during measurement and the run still completed. - **Matched rate comparison.** On the same method (launch flags, no tunnels), high-quality peer requests completed only at 1.25 MB/s: 9 of 16 in R65's first 106 s of measurement against 0 of 26 in R64, and 36 of 52 over R65's 300 s against 0 of 416 in R61. R64's earlier "0 of 42" included setup records. Link churn did not follow the rate: over the first 106 s, 4.3 closes per minute in R65 and 6.9 in R64; over 300 s, 3.6 in R65 against 32.9 in R62 r3, which ran at the same rate with tunnels and the background downloads. The higher limit is needed for high-quality peer delivery but is not sufficient. Request counts are lower bounds, because each sample carries only the last 16 page records. - **Open question: single transfers run well below the limit.** High-quality payloads ran at a median 2.1 Mbit/s against the 10 Mbit/s limit (low quality 1.5 Mbit/s, R64 1.2), timed from request, so first-byte delay is included. The limiter is one token bucket per contributor with a two-second burst, shared across its links, and a holder queues at most 128 KiB (since `4178c26`). M4's Wi-Fi took in 3.22 MB/s during R65's measurement and 3.17 MB/s in R64's. All 48 links open at the end of R65 were relay to relay over TLS, as the recorded relay-only profile requires, so every peer byte went to Till and back over TLS/TCP. The round trip to the TURN service was about 84 ms from M1 and 102 ms from M4, roughly 170 to 200 ms per link. That path is the leading candidate, not yet tested. The high rendition is about 2.6 Mbit/s, so a single high-quality peer transfer at the observed median runs slower than real time. Addendum: `artifacts/distributed-fourteen-qualifier-5f2ece0-r65-result-addendum-20261020.json`. Cleanup passed on M1, M4 and Till, the live app `8534fff7` is unchanged, and the docs stash was restored with matching checksums. Record: `artifacts/distributed-fourteen-qualifier-5f2ece0-r65-result-20261020.json`. Awaiting the user's decision. - **UDP relay addresses, not chosen.** The relay answered a STUN binding over UDP 3478 from M4; the demo already supports `--turn-url-projection issued`, still relay-only, but that changes the recorded pilot profile and requires fresh Apply and upload consent, so it is the user's decision. - **Local link bench (20 October, 19:10 to 21:24 UTC, local only, no host action; its TCP figure is overstated, see the field probe below).** The user asked to test the transfer rate at about 200 ms locally. Two headless Chrome pages ran the 5f2ece0 PeerLink. Chrome DevTools latency proved lossy (6 to 8% of peer packets), so delay came from a counted UDP relay on loopback. At a 196.5 ms round trip with no loss, a high segment ran at 6.5 Mbit/s and a low one at 2.8 Mbit/s, about 1.0 s and 0.6 s from the request. The pre-4178c26 1 MiB queue reached 8.9 Mbit/s on high segments (1 of 3 runs valid; the others lost packets on loopback). Through a local coturn of Till's image (`coturn/coturn:4.17.2-r0`) at 197 ms, TURN over TCP ran at 1.0 Mbit/s in two checks, with 35 and 39 packets lost and none in netem or Chrome; a third check's link failed with a channel error. coturn's source drops relayed data bound for a TCP/TLS client, without counting or logging it, once 32 KiB is queued (always on), and every R65 link went through a coturn TLS leg. TURN over UDP reached 3.3 Mbit/s, a lower bound, because that cell lost 3.5% between Docker's UDP forwarding and coturn. A UDP relay avoids the drop rule but not field loss: 1% seeded loss alone gave 0.6 Mbit/s, then the holder's 3 s drain deadline closed the link. The pilot's `tls-tcp` projection keeps only the issued TLS address; `issued` keeps UDP, TCP and TLS, so a browser would use UDP where it works. R65's records also show (inferred, no holder identity recorded) receiver-1 waiting on a same-quality link that was never ahead, with neighbour discovery making no checks, while receivers 2 and 4 got haves but no high transfer fitted their budget. Record: `artifacts/link-throughput-bench-20261020/FINDINGS.md`. Awaiting the user's decision. - **Field probe: one TLS relay link through Till runs at 3 to 4 Mbit/s, and UDP relay does not help (20 October, 21:38 to 22:19 UTC).** The user approved the single-link probe ("do it"). Holder Chrome on M1, receiver Chrome on M4 in a fresh profile over SSH, relay-only through the shared TURN service with one issued URL per cell, both Macs on Wi-Fi with no tunnel, one fresh issuer credential per repetition (values not recorded, files deleted). Nothing in the pilot, consent or Till changed. A high segment ran at a median 3.15 and 3.8 Mbit/s over TLS and 4.2 and 3.35 Mbit/s over TCP, 18 of 18 requests each, losing 0.2 to 0.6%. UDP ran at 3.35 Mbit/s with 1.6% loss; in a second cell the holder's 3 s drain deadline closed the link after 7 of 18 requests, and the smoke check lost 7.7%. The path was jittery (ping spread 64 to 149 ms) and background traffic was not controlled; M4's load reached 70 from the owner's work in one cell. Two repetitions completed; a third and a first attempt stopped at the M1 quiet gate. So R65's 2.1 Mbit/s comes from what the qualifier adds (concurrent uploads sharing the house uplink, 11 roles on M4's Wi-Fi, admission, loss under load), not from one TLS link, and switching to UDP relay addresses is not supported. Cleanup proved on both Macs. Record: `artifacts/link-throughput-bench-20261020/FINDINGS.md`. Awaiting the user's decision. - **v0.2.0 published as an experimental GitHub prerelease (21 October, about 00:25 UTC).** The user said "commit push merge ship" and chose a v0.2.0 prerelease. The handover docs and a release-preparation docs commit (`fd046f5`) passed all nine required CI jobs; PR 8 merged as `bf43940` (merge commit, tree identical to `fd046f5`), whose main CI run 39514327948 also passed. Annotated tag `v0.2.0` points to `bf43940`. Assets (tarball, standalone bundle, `SHA256SUMS`) were built from a clean archive with the recipe that rebuilds v0.1.0's bundle byte for byte, then downloaded from the public URLs and verified; see [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#release-verification). Field gates stay open: the qualifier is RED and the pilot still runs `5f2ece0` without the release's clock-skew diagnostics. No npm publish. - **R60 is RED on the same single gate (19 October, 15:34 to 15:40 UTC).** Source 46494d5, Till app 124e3bcc unrestarted, 3 roles on M1 and 11 on M4, 302 s measured, both Macs on the LAN with no VPN carrying the default route. 15 of 16 gates passed; `each4BothQualityPeer` failed (only receiver 2 had both qualities from peers). 3 of 309 high-quality peer requests completed, none of the 236 that started with under 1100 ms left; 14.2 MB verified peer media against 189 MB uploaded. Removing the VPN did not rescue the gate on this source. Launch deviation: R59's M4 connect bound (45 ms) was set on the VPN path; without it both Macs connect in a steady 57 to 71 ms, so the launch used that baseline, recorded in the authorisation. The checkout was detached at 46494d5 for the run and restored (checksums matched). Cleanup confirmed on M1, M4 and Till; the Till control directory keeps its journal like R57 to R59. The app health check fails whenever no source is publishing, which is idle state between runs. Result: `artifacts/distributed-fourteen-qualifier-46494d5-r60-result-20261019.json`. - R58 and R59 cleanup were confirmed by Root fresh read-only checks on M1, M4 and Till; the formal independent cleanup review method (R55 lineage) was not rebased. - Scope: steps 1 to 3 used one M1 Chrome against the live pilot over the real network. They do not test multi-viewer peer delivery (P01). Deviations to keep visible: the CI receipt `artifacts/ci-46494d5-39180173046-20261019/ci-terminal-success.json` was changed from mode 0644 to 0600 (contents unchanged; the frozen P05 index still pins 420). P05 used a bound copy (`artifacts/p05-46494d5-source-bound-20261019`) with `-r2` data/result paths after attempt 1 refused at local input pinning (`artifacts/p05-46494d5-root-run-attempt1-20261019.json`, no host action). Intake pure r1 failed on a Root seal-order fault; r2 and r3 passed. The P07 root driver (`artifacts/p07-46494d5-root-driver-source-20261019`) is new: 24 counted edits to the R4 driver, dropping the negative handover. The OWN and native review sources are identity rebases of the 3f706a9 versions. ## Progress on 21 October 2026 (source 140c256) Source `140c256` is on `fix/holder-discovery` ([PR 9](https://github.com/forgesworn/relayswarm/pull/9), merged as `1d54538` and released as v0.2.1): holder labels in local diagnostics (`368b860`), then the fix that stops a never-ahead holder suppressing neighbour discovery. Paths are relative to a checkout holding the local `artifacts/` tree. | Run | Verdict | Evidence | |---|---|---| | CI, fresh consumer, deployment, deployment review | PASS: nine required jobs in [run 39529800310](https://github.com/forgesworn/relayswarm/actions/runs/39529800310) (attempt 2 reran only the hls.js playback job after a runner apt 403 before any test step); 286 package members from the committed source; independent deployment review | `artifacts/cycle-140c256-record-20261021.json`, `artifacts/ci-140c256-39529800310-20261021/`, `artifacts/clean-consumer-140c256-20261021/package-review.json`, `artifacts/independent-deployment-140c256-review-20261021/review.json` | | P05 reporting lifecycle | PASS, natural expiry 303,923 ms, reporting restored off | `artifacts/cycle-140c256-record-20261021.json` | | P07 parent crash | PASS, independent native review | `artifacts/cycle-140c256-record-20261021.json` | | R66 short qualifier | GREEN, 16 of 16 gates, 302.823 s, including `each4BothQualityPeer` and `all8ActuallyUploaded`; first green fourteen-role qualifier | `artifacts/distributed-fourteen-qualifier-140c256-r66-result-20261021.json` | | R66 wire and cost | Receivers used 31.5% less origin traffic than matched baselines; TURN host carried about 319 MB egress; marginal cost not determined | `artifacts/r66-wire-cost-20261021/HOST-CHECK.json` (its correction governs over `WORKER4-REPORT.md`) | | R37 sustained | RED at the first churn event on a harness assertion about retained renewals | `artifacts/distributed-long-three-eleven-140c256-r37-result-20261021.json` | | R38 sustained | RED after 640,110 ms of measurement; first failure is a harness race in `rejoin()` (read 7 ms after clicking Start, before the page applied its settings; diagnosis confidence high) | `artifacts/distributed-long-three-eleven-140c256-r38-result-20261021.json`, `artifacts/distributed-long-three-eleven-140c256-r38-result-addendum-20261021.json` | | P06 3 MB shared-cap lifecycle | RED, `RED_HIGH_QUALITY_NO_VERIFIED_COMPLETION_BEFORE_SHARED_CAP_REFUSAL`; finite-source cleanup review PASS | `artifacts/p06-140c256-result-20261021.json`, `artifacts/p06-140c256-result-addendum-20261021.json`, `artifacts/p06-140c256-result-addendum-2-20261021.json`, `artifacts/p06-140c256-red-diagnosis-20261021/DIAGNOSIS.md`, `artifacts/p06-140c256-user-decision-20261021.json`, `artifacts/independent-p06-140c256-source-cleanup-review-20261021/review.json` | | P06 6 MB shared-cap lifecycle (`1d54538`) | RED, `RED_LOCAL_SESSION_CAP_BELOW_SEGMENT_NO_ACCOUNT_REFUSAL`; high-quality verified peer media passed (seven of eight 720p reservations verified, 4,689,096 B); finite-source cleanup review PASS | `artifacts/p06-1d54538-6mb-result-20261021.json`, `artifacts/p06-1d54538-6mb-result-addendum-20261021.json`, `artifacts/p06-1d54538-6mb-red-diagnosis-20261021/DIAGNOSIS.md`, `artifacts/independent-p06-1d54538-6mb-source-cleanup-review-20261021/review.json` | | R67 short qualifier (`1d54538`) | RED at controller binding before any browser started: the harness `dependency-pins.json` still pinned the 0.2.0 `package-lock.json` hash (harness defect, no product evidence); source cleanup review PASS | `artifacts/distributed-fourteen-qualifier-1d54538-r67-result-20261021.json`, `artifacts/distributed-fourteen-qualifier-1d54538-r67-result-addendum-20261021.json`, `artifacts/independent-fourteen-qualifier-1d54538-r67-source-cleanup-review-20261021/review.json` | | R68 short qualifier (`1d54538`) | RED, 15 of 16 gates, 303.088 s; `each4BothQualityPeer` FALSE (receiver-1 and receiver-2 received no high-quality peer segment after switching to high); cleanup review PASS with `strict300Passed` false | `artifacts/distributed-fourteen-qualifier-1d54538-r68-result-20261021.json`, `artifacts/distributed-fourteen-qualifier-1d54538-r68-result-addendum-20261021.json`, `artifacts/r68-1d54538-red-diagnosis-20261021/DIAGNOSIS.md`, `artifacts/independent-fourteen-qualifier-1d54538-r68-cleanup-review-20261021/review.json` | | R39 sustained (`1d54538`) | Prepared, not run, superseded: the `rejoin()` applied-state wait and a finite-source intake in the long finaliser; it carried the same stale lock pin, and no GREEN matching qualifier exists | `artifacts/long-1d54538-r39-preparation-record-20261021.json`, `artifacts/long-1d54538-r39-superseded-20261021.json` | | CI on docs commit `304cf8a` | PASS on attempt 2; attempt 1 failed one Windows case in `test/browser-hardening.test.mjs` (known flake) | `artifacts/ci-304cf8a-attempt1-20261021.json` | | Desktop D1 Firefox 152.0.6 (M1) | PASS, six of six checkpoints; 663,828 B verified peer at the receive checkpoint, 413,600 B uploaded | `artifacts/desktop-journeys-140c256-result-20261021.json` | | Desktop D2 Safari 17.6 (M1) | RED: no verified peer download within 45 s, no selected ICE candidate pair; cause not determined; not retried | `artifacts/desktop-journeys-140c256-result-20261021.json` | | Desktop D3 Safari 26.6.2 (M4) | PASS, six of six checkpoints; 667,212 B verified peer, 213,004 B uploaded; first Safari pass | `artifacts/desktop-journeys-140c256-result-20261021.json`; finite-source cleanup review PASS in `artifacts/independent-desktop-140c256-source-cleanup-review-20261021/review.json` | Pilot app after P07: `38eb5c2d`, started 02:59:29 UTC, reporting and forwarding off; served client 787,462 bytes. Repo-tracked summary: [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/140c256-current-delivery-checkpoint-20261021.json). Findings for the next agent: - **R66 was run at the R65 profile** (contributors at 1,250,000 B/s, four neighbours, relay-only TURN over TLS/TCP, no VPN tunnel on either Mac, checked by the authorisation) on the rebuilt source. It is a short desktop-class result; it says nothing about 7,200 s, devices or a separate network. - **TURN is a separate host from the origin.** The origin served about 226 MB less than all-origin delivery over R66's 302 s window, but total egress across both hosts rose by roughly 85 to 100 MB. Do not describe this as a bill saving: the hosts' plan terms are not recorded. - **R38's rejoin race is a harness fault.** `rejoin()` in the long lineage reads the actor straight after clicking Start; the page applies settings asynchronously. A fix needs its own review cycle and a new run. No earlier long run reached a rejoin, so the rejoin itself has no evidence either way. - **P06's role summary fields do not update.** Do not cite `videoQualities`, `verifiedPeerQualities`, `zeroFrameIntervals` or `contributionWithdrawn` for P06 or a416f7e; the observer never assigns `measurementStarted`. Use the raw samples. - **P06 is a design limitation, not a product defect.** The shared allowance behaved as documented in [Account upload budget](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md). About 660 KB high-quality segments did not complete within the receiver's buffer-safe wait on the relay path (about 255 KB/s on the best link), so three accepted reservations consumed the cap before the fourth was refused. - **P06 at 6 MB stops on the page's own cap.** Each uploading page snapshots the smaller of its local allowance and the account's remaining allowance when uploading is applied (`demo/client.mjs`) and refuses locally with `session-allowance` before any account reservation once a segment exceeds its own remainder (`src/browser/hls-swarm.mjs`). The account refusal the stage waits for can only come from a donor whose local remainder lies within the other devices' spend of one segment; at 6 MB that window was narrower than one 720p segment, so no cap size reaches it in this scenario. Two product findings follow: a holder keeps advertising segments it will always refuse, because serving stops only at exactly zero remaining, and the receiver has no back-off against a holder that refuses every request (39 wasted round trips); and the page cap is never refreshed from the account after it is applied. Fixing either is a product cycle. - **R68's both-quality failure is a product mechanism on a one-segment margin.** Receivers switch quality together about 150 s in. In R66 receiver-1 received exactly one high-quality peer segment after switching, so R66 passed by one segment. In R68, with origin media fetches 1.5 to 2 times slower (cause not determined; the pilot server and small control requests were unchanged), receivers 1 and 2 received none. The projection in `src/browser/hls-swarm.mjs` declines a peer request when the holder wait plus first byte exceeds the room left; the holder wait is the viewer's own origin median, so each fallback raises the next estimate, and there is no back-off. With no high-quality holder ahead, HAVE waits expire; transfers of about 670 KB over the relay are abandoned at the deadline; and a spent neighbour replacement resets only on a verified high-quality segment (`src/browser/neighbour-discovery.mjs`). These are findings, not fixes. Holder labels carry no mapping to roles, and the origin-only baselines record no origin latency, so the evidence cannot say which contributor served whom. - **Identity rebases miss bare hash pins.** R67's generator re-pinned path records from the archive but copied `dependency-pins.json` `lockSHA256`, which the controller checks against the checkout. R68's generator refuses stale hashes of changed runtime files, and its authorisation runs the controller's own dependency check first. - **Decisions.** The user chose to record Item 5 and P06 as RED and open and to move on. After one 6 MB run on `1d54538`, the user chose to stop P06. After R67 stopped on the harness pin, the user chose R68; after R68 was RED, the user chose to record Item 5 RED and stop it. ## Next work, in dependency order Position on 21 October 2026: v0.2.1 is a published experimental GitHub prerelease of merge commit `1d54538` (PR 9), deployed to the pilot (app `ce410033`). Its loader source `140c256` passed CI, consumption, guarded deployment and its review, P05, P07 and the short qualifier R66 (GREEN, 16 of 16). The owner decided to publish v0.2.1 with Item 5, P06 and Safari 17.6 RED and open, as v0.2.0 shipped with its qualifier RED. Those items stay RED and open. On the deployed `1d54538` the short qualifier R68 is RED, 15 of 16 gates, so the sustained run has no matching qualifier. Release and deployment evidence is in [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#release-verification). 1. **PR 9 is merged and released as v0.2.1.** The next finite source or deployment chains on the `1d54538` deployment's independent cleanup review. 2. **Item 5, the sustained 7,200 s run (RED, stopped by decision).** It needs a GREEN matching short qualifier on the deployed source. R68 on `1d54538` is RED at `each4BothQualityPeer`, which R66 passed by one segment, so an unchanged re-run measures variance rather than fixing anything. Resuming needs the user's decision on the gate, the scenario or the product mechanism in the R68 findings. The prepared long method (the `rejoin()` applied-state wait and the finite-source intake) is in `artifacts/1d54538-long-r39-builder-source-20261021`. Any new source chains on the R68 source cleanup review. Run 7,200 seconds, 22 churn events, two 3,600-second windows and natural TURN expiry/renewal under unchanged limits. Do not shorten the run or substitute fake credential expiry. 3. **P06, the both-quality shared-cap lifecycle (RED, open, stopped by decision).** The 3 MB run failed at high quality; the 6 MB run passed high quality but cannot reach natural exhaustion because of the page's own cap snapshot. A further attempt needs a scenario change (for example a receiver order of low, high, low) or a product change to the two findings above, both the user's decision. Do not cite the dead role-summary fields. 4. **Remaining browser, device and network coverage (open).** Safari 17.6 desktop is RED with the cause undetermined. Physical iPhone is unavailable; physical Android and device Safari/Firefox need the owner; hard NAT and a separate network need another network. Report each as open until it passes. 5. **Cost.** Marginal cost on the hosts' plans is not determined. Record the plan terms before any cost statement; distinguish saved traffic from actual marginal cost. 6. **Releases.** v0.2.1 is published, its downloaded assets verified and its merge commit deployed. Keep the v0.2.1, v0.2.0 and v0.1.0 tags and assets unchanged. npm publication is out of scope. The short and long builders are prepared source. Review their changes and pure checks before materialising them. Frozen source manifests must remain intact: make a fresh copy when binding new evidence. ## Known failures to retain - Item 5: R37 and R38 are RED. R37 failed at the first churn event on a harness renewals assertion; R38 failed on the `rejoin()` race after 640,110 ms of measurement. The 7,200 s run has not completed on any source; on `1d54538` it did not start because no matching qualifier passed. - The v0.2.1 short qualifier R68 is RED at `each4BothQualityPeer` (one-segment margin; see the R68 findings), and R67 stopped on a harness pin. R66's GREEN on `140c256` is a narrow pass. - CI flakes, each passing on one rerun: `test/browser-hardening.test.mjs` on the hosted Windows runner (docs commit `304cf8a`) and on macOS (PR head `55c0f68`), and the account-budget TURN renewal browser case (main run 39601445318). - P06 on `140c256` is RED with high-quality delivery unverified before the shared cap refused a reservation (same class as the a416f7e third run). On `1d54538` at 6 MB it is RED at natural exhaustion (page cap below a segment, no account refusal) after high-quality peer media passed. Public shared-account API and the focused LOW lifecycle passed earlier. - Safari 17.6 on the desktop is RED on `140c256` (no verified peer download, no selected candidate pair, cause not determined). Earlier Safari REDs (f393abf, 2dd156e) and Firefox and Safari results at a023 stay history. - Earlier short-qualifier REDs R54 to R65 stay on record as history. R66 is the first green run and does not change them. - Simulator playback/resume passed but did not reproduce the physical iPhone's stopped-video fault. It cannot close physical iPhone recovery acceptance. ## Evidence and prepared sources Paths below are relative to this checkout. `artifacts/` contains local evidence and private operational material; it is not generally available in a fresh GitHub clone. An agent on another machine needs the relevant reviewed evidence as well as this document. Do not publish credentials or copy the whole private artifact tree into a public handover. | Purpose | Local path | |---|---| | Mutable session checkpoint; includes historical values | `artifacts/resume-20261016-root-checkpoint/checkpoint.json` | | Exact-source CI receipt (current, 4178c26) | `artifacts/ci-4178c26-39284440433-20261019/ci-terminal-success.json` | | Fresh consumption (current) | `artifacts/clean-consumer-4178c26-20261019/package-review.json` | | Actual deployment, lifecycle and cleanup (current) | `artifacts/deployment-4178c26-peer-cancel-20261019/` | | Independent deployment review (current) | `artifacts/independent-deployment-4178c26-review-20261019/review.json` | | Positive P05 and independent review (current) | `artifacts/p05-4178c26-run-r2-20261019/`, `artifacts/independent-p05-4178c26-positive-own-review-20261019/review.json` | | P07 attempt 1 (RED) and operator recovery | `artifacts/p07-4178c26-root-run-attempt1-20261019.json`, `artifacts/p07-4178c26-operator-recovery-20261019.json` | | P07 r2 actor source, run and native review (PASS) | `artifacts/parent-crash-p07-4178c26-r2-source-preparation-20261019/SOURCE-PINS.json`, `artifacts/p07-4178c26-r2-result-20261019.json`, `artifacts/independent-p07-4178c26-r2-positive-native-review-20261019/` | | Short qualifier R61 (RED), preparation and result | `artifacts/distributed-fourteen-qualifier-4178c26-r61-preparation-20261019/`, `artifacts/distributed-fourteen-qualifier-4178c26-r61-result-20261019.json` | | Previous candidate 46494d5: CI, deployment, P05, P07 and R57 to R60 | `artifacts/ci-46494d5-39180173046-20261019/`, `artifacts/deployment-46494d5-live-playlist-retry-20261019/`, `artifacts/p07-46494d5-run-20261019/`, `artifacts/distributed-fourteen-qualifier-46494d5-r60-result-20261019.json` | | Long qualification, source only | `artifacts/46494d5-long-r35-builder-source-20261019/SOURCE-PINS.json` | | Final recovery unit results | `artifacts/recovery-root-unit-final-r2-20261019/RESULTS.json` | | Full-controller retry results | `artifacts/demo-live-playlist-retry-final-full-chain-green-20261019/RESULTS.json` | | Real Chrome recovery/cancellation/deadline binding | `artifacts/network-retry-real-browser-20261019/treatment-final-r2/COMMITTED-COMPONENT-BINDING.json` | | Older actual P05 pass and independent review | `artifacts/p05-3f706a9-run-20261018/`, `artifacts/independent-p05-3f706a9-positive-own-review-20261018/` | | Older actual P07 failure and cleanup | `artifacts/p07-3f706a9-run-r4-20261019/` | Recorded runtime anchors for recognising drift: ```text source: 4178c2602e6ca04dadf8b9d760de852888bcbe32 image: sha256:faa4520b24b665ac0fb59b56ee00af87ba99aacccf8ecb27c18acde05048988d client: 777134 bytes client SHA-256: a8d22a0b549440ca6a10ebfa1ce010972dc8e5c3a4707ebe521e78f553fad155 runtime-contract.json SHA-256: c4150172693e000f2c9ae7b74207b007eb202c098871f6cc298846c12798305b live app after P07 r2: 7d0ae914e13d3d2a7c9e8ebeaa62269f80fba802fb81afd614604fe60c1828ea (started 2026-10-19T19:24:20Z) ``` Prepared review/test directories include their own README, manifests and bounds. Read them before execution. Null future results or synthetic pure-test inputs are not live proof. Use current provenance and private input pins; do not run an old bound command against a replacement container. ## Working constraints and reporting - Other jobs on M1/M4 must keep running. Do not kill unrelated processes, ask the owner to pause their work, or raise resource/process limits to make tests pass. - The physical iPhone is currently unavailable. Continue independent work and leave that acceptance item explicitly open; do not repeat unlock/cable requests. - Preserve explicit upload/reporting consent, spent quota, private publisher and account state, permanent lease inodes, and the independent router/proxy. - The recorded pilot uses relay-only TLS/TCP TURN through the existing service, admission address limits of 32 tickets and 900 requests, and four demo neighbours. The SDK default remains six. Recheck the runtime contract rather than silently changing this profile or treating it as six-neighbour capacity. - Restore any test-owned temporary privacy, reporting or network changes. Stop owned fixtures/browsers/emulators and remove owned scratch after retaining evidence. Leave the permanent pilot/router/proxy running intentionally. - Keep the original acceptance windows and cleanup reserves. Failure or resource pressure calls for diagnosis, not relaxed requirements or erased fatal records. - Preserve supported-media boundaries. A custom ABR engine, DRM/SAMPLE-AES, durable media storage and an accepted RelaySwarm NIP are not existing features. - Report each result with source, runtime, topology/device, duration, verdict, evidence path and cleanup. Separate implementation, local tests, CI, deployment, physical acceptance and publication. Report actual progress and remaining gates plainly; do not present another preparation pass as completed field acceptance. Start with `git status --short --branch`, refresh `origin`, and confirm the PR head before relying on this snapshot. For documentation edits, update authored Markdown and `llms.txt`, then run `npm run docs:generate` and `npm run check:docs`. Node 22.13+ is required; CI uses Node 24. Preserve all unrelated work and follow the repository's resource-cleanup instructions. --- Source: [docs/BROADCASTING.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md) # Broadcaster source workflow [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md) · [Container deployment](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md) · [Evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) This guide describes the v0.2.1 broadcaster workflow, persistent publisher state and operator/reporting controls. Install [v0.2.1](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/GETTING-STARTED.md); the immutable v0.1.0 assets do not include these additions. Publication of a guide does not establish deployed playback or platform acceptance. ## Local source and dependencies Use Node 24 and ffmpeg with libx264 and AAC. RTMPS input/forwarding additionally requires a DNS hostname and FFmpeg major version 5 or later built with GnuTLS, or major version 8 or later built with OpenSSL. Install the source dependencies and the pinned MediaMTX router: ```sh npm ci npm run broadcast:install ``` The installer downloads MediaMTX 1.21.2 for macOS/Linux x64 or arm64, checks the archive against a platform-specific pinned SHA-256 before extraction, and prints the executable path. Its owner-controlled cache is `artifacts/tools/mediamtx-v1.21.2`; a private receipt records the extracted binary digest. A cached receipt is trusted local state, not independent upstream attestation. On another platform supply your own compatible router executable. Start the bundled local router and broadcaster from the repository root: ```sh npm run broadcast -- \ --mediamtx artifacts/tools/mediamtx-v1.21.2/mediamtx \ --state-dir artifacts/broadcast ``` Configure OBS Custom streaming with server `rtmp://127.0.0.1:1935/live` and an empty stream key. Supply **both H.264 video and AAC audio**. The bundled router listens only on loopback, refuses a second publisher for `live`, and exposes its RTSP read path at `rtsp://127.0.0.1:8554/live`. The launcher reads that path over TCP. Without `--mediamtx`, run the router separately or provide `--input` for an existing supported network source. Supported input schemes are RTSP, RTMP, RTMPS and SRT. RTSPS is rejected because verified TLS behaviour is not portable across supported FFmpeg versions; scheme acceptance does not prove compatibility with every source. The launcher first binds a waiting listener and prints its address, normally `http://localhost:8787`. The root page returns HTTP 200 and checks again every three seconds. Before both HLS renditions publish, other endpoints return bounded HTTP 503 responses with `Retry-After: 3`; there is no session, relay or operator API on the waiting listener. Once output is ready, the launcher replaces that listener with the player on the same port. A waiting page proves HTTP availability, not media playback. Stop with Ctrl-C for orderly listener, worker and router shutdown. An external OBS workstation can use an authorised SSH tunnel rather than a public plaintext RTMP listener: ```sh ssh -N -L 1935:127.0.0.1:1935 deploy@your-host ``` OBS then targets its own loopback address. The container router uses an internal app/router network plus a separate normal bridge needed for its loopback RTMP port publication; RTSP has no published host port. Container ingest mappings and the existing/new HTTPS proxy choices are in the [deployment guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md). Remote browsers require configured TLS or an explicit `--public-url https://your-hostname` behind an HTTPS proxy. The public origin must match browser Origin headers. Configure repeated `--relay wss://...` options if using external relays; otherwise the server supplies its own bounded relay at `/relay`. `--stun` accepts a STUN URL. Alternatively, `--ice-config FILE` loads private host-provided STUN/TURN browser credentials; the [field guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#use-separate-devices-and-networks) gives the bounded format and disclosure boundary. No TURN deployment is supplied. For an existing short-lived credential issuer, use `--turn-credentials-url https://issuer.example/turn` instead of `--stun` or `--ice-config`. The optional [renewal adapter](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#optional-turn-credential-renewal) is off by default. It obtains separate viewer credentials, refreshes active peer sessions and retains consent and spent allowances. It supplies no TURN deployment; expired credentials leave playback on origin until fresh Apply. Admission defaults to 12 tickets per minute for each socket address. Viewers behind a reverse proxy can share that address. Set `--admission-per-address-tickets 32` when the operator intends that capacity; accepted values are integers 1–120, default 12. The launcher validates the value before creating state or starting services. This changes no global issuance, request, expiry or consent limit, and does not trust forwarded-address headers. Choosing a limit does not establish a passing multi-viewer qualification. Admission also defaults to 600 requests per minute for each socket address, shared by challenge, ticket and verification requests. Configure `--admission-per-address-requests 900` only when the operator intends that allowance; accepted values are integers 1–10,000, default 600. Validation runs before state creation or service startup. Behind Caddy or another reverse proxy, viewers can share one backend socket address; forwarded-address headers remain untrusted. The global request limit remains 2,048 per minute, global ticket issuance remains 120 per minute, and all other admission limits remain unchanged. The pilot plans an explicit 900 after observing 637 startup admission requests within a minute, allowing headroom over that observation. This setting has not yet been deployed or qualified; configuring it does not prove field capacity or resolve the separate delayed-response observations. The broadcaster and demo accept `--ice-transport-policy all|relay`, default `all`. Choose `relay` explicitly to restrict peer ICE to relayed candidates; provide usable TURN configuration or the existing credential adapter. The choice does not force TLS: by default the adapter preserves all validated issuer URLs. It never falls back to `all`, changes the peer deadline or grants upload consent. Playback keeps its existing origin fallback. A changed demo session policy stops peers and requires fresh Apply and upload consent. This option does not establish improved delivery, measured privacy or field acceptance. With the optional credential issuer, `--turn-url-projection tls-tcp` selects secure TCP configuration independently of the ICE candidate policy. Default `issued` preserves the existing descriptor and issued URLs. The adapter retains its original raw cache/lease, preserves explicit secure TCP URLs, and appends `?transport=tcp` only where a valid `turns:` URI left transport unspecified. It excludes plain TURN and explicit UDP; it changes no host, port, credentials, issuer TTL or refresh boundary. The client enforces the projected response too. No supported result means origin fallback, never unrestricted retry. Changing selection stops peers and requires fresh Apply/upload consent. This is an application-selected URI, not the unchanged issuer response or a capability proof; see the [API contract and primary standards](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#optional-tls-over-tcp-url-projection). No existing issuer/service configuration is changed by this option. ## Output and recovery Add `--account-budget` to offer the optional shared upload allowance. It keeps `account-budget.json` in the private state directory and supports explicit Nostr sign-in. Website account authentication uses the JavaScript host callback, not a viewer-supplied account identifier. The Compose template enables the offer through `ACCOUNT_BUDGET_ENABLED=1`; viewers still choose whether to connect an account and separately opt into uploading. Preserve the ledger and its permanent lease files. See [shared upload allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md). The encoder produces two fixed H.264/AAC renditions: | Rendition | Frame shape/rate | Target video rate | Audio | |---|---|---|---| | low | 640 × 360, 30 fps | 700 kbps | AAC, 128 kbps, 48 kHz stereo | | high | 1280 × 720, 30 fps | 2,500 kbps | AAC, 128 kbps, 48 kHz stereo | Scaling preserves aspect ratio and pads to the fixed frame shape. Each rendition uses a two-second segment target and a twelve-segment live playlist: approximately **24 seconds of listed media**, not a 120-second playlist. ffmpeg retains an additional deletion tail; prior process generations have a separate two-minute pruning grace by default. These durations are storage/publication policy, not a measured end-to-end latency guarantee. Both renditions belong to one supported codec/frame-rate family; this is a fixed ladder, not a general encoding service. The HLS worker and optional forwarding worker retry independently, with bounded exponential delay. Each HLS process generation uses a distinct segment directory and a persisted discontinuity sequence. Variant/master publication uses atomic file replacement. A directory watch on the current generation starts publication when ffmpeg renames a playlist into place; a 250 ms interval remains the fallback. Source loss leaves the last published playlists available while workers reconnect; old HTTP availability does not establish fresh media or successful decoder recovery. Inspect publication age in operator status. Use a dedicated canonical state directory owned by the launching user, preferably mode **0700**, with no symlink components or group/world writes. New directories use 0700. The launcher keeps `publisher.json` and `operator-token` as owner-only **0600**, regular, single-link files. The publisher file contains a private signing key and its signed redistribution authorisation; neither secret is delivered in browser sessions or operator status. Existing malformed/mismatched publisher state is rejected rather than replaced. Restarting with the same state retains publisher identity, swarm ID and authorisation; starting with another state directory creates another identity. Only one pipeline may use a media directory. `/state/media/.broadcast-lock` in the container, or `STATE_DIR/media/.broadcast-lock` natively, is acquired exclusively. Orderly close removes it. An unclean exit may leave it and the next start fails closed. Stop all possible users of that volume/directory and establish exclusive ownership before manual stale-lock removal; never infer safety from a PID in a different namespace or delete locks automatically. See [operations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md#restart-and-recovery). ## Optional RTMPS forwarding Create a private, owner-controlled directory outside the checkout. In it, use a private editor to write one line containing the complete RTMPS ingest URL to a regular, single-link file owned by the launching user, mode **0600**. Keep the parent mode **0700** and use its canonical path. Start with: ```sh npm run broadcast -- \ --mediamtx artifacts/tools/mediamtx-v1.21.2/mediamtx \ --state-dir artifacts/broadcast \ --youtube-url-file /absolute/private/directory/youtube-url ``` The file supplies the URL without putting the stream key in environment variables or launcher arguments. For RTMPS input or forwarding, the pipeline first checks the selected executable’s version/build configuration with a five-second, 32 KiB output budget, before creating media state or workers. Direct callers of the argument builders must perform equivalent capability validation themselves. Forwarding has its own ffmpeg process and source reader, copies the H.264/AAC tracks into FLV, requires RTMPS, explicitly enables TLS certificate/hostname verification and sets a 15-second output I/O timeout. It does not transcode for a platform's separate compatibility rules. A forwarding outage cannot block the HLS process, although both still depend on the same source and host resources. Trusted host/container administrators can inspect ffmpeg's process arguments, which contain the full ingest URL. The implementation consumes upstream stderr without publishing credentials in logs, metrics or browser sessions. Protect the host, secret file and process-inspection permissions accordingly. Restart the broadcaster to read a changed URL. A process marked running/connecting or repeated restarts is **not** evidence that YouTube accepted the stream or that viewers can play it; confirm that separately in an authorised platform test. ## Verification boundary The source includes native process/publication tests and actual Chrome fixtures. The dated [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) retains the authorised OBS and private YouTube tests; that YouTube broadcast was stopped and deleted. Current deployed `8f482b4` playback passed its ordinary short check, while both-quality peer delivery and the fourteen-role qualification remain red. Complete physical-device, separate-network/hard-NAT, sustained-operation and final release acceptance remain open. Earlier passes retain their original source and scope. The broadcast browser fixture uses loopback Chrome, synthetic media and explicit RTC/fake-media fixture flags. Its receipt adds bounded observations of existing media request events: at most four pages, 512 shared object labels, 256 retained rows and 64 tracked active requests per page. Labels correlate the same private pathname/range within one run; they do not reveal paths, queries or parsed playlist sequence/continuity. Fixed media/rendition categories and numeric cached Playwright timings distinguish request start, response and completion. Unavailable values remain null; evictions, overflow and pending requests remain explicit. The unpopulated native epoch placeholder is null; zero remains valid for relative timings. Snapshots before and after browser close are separate observations. The recorder adds no requests or body reads and changes no playback deadline or assertion. It is diagnostic evidence, not ordinary network or physical-device qualification. --- Source: [docs/CORE-PACKAGING.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/CORE-PACKAGING.md) # Native core release packaging The v0.4.0 release uses this workflow to prepare native core assets. It creates no tag or GitHub release, publishes nothing to npm, and leaves `core/apple/Package.swift` using `path:`. A binary URL dependency remains a separate release decision. ## Triggers and permissions The existing [test workflow](https://raw.githubusercontent.com/forgesworn/relayswarm/main/.github/workflows/test.yml) calls [native packaging](https://raw.githubusercontent.com/forgesworn/relayswarm/main/.github/workflows/core-packages.yml) on a tag push, or when explicitly dispatched with `core_packages: true`. Ordinary branch pushes and pull requests do not run the release-packaging jobs. Their existing validation jobs retain their normal behaviour. The packaging-only dispatch skips the ordinary test matrix, builds Apple and Android artefacts, uploads them to Actions and verifies their checksums and source commit. Build/download jobs have read-only repository permission. The attachment job requires **both** a tag-push event and the caller's publish flag; a dispatch cannot attach assets, including when dispatched at a tag. On a tag push, attachment requires an already existing GitHub release for that tag. It fails if the release does not exist, and never creates one. Uploads omit `--clobber`, so existing release assets are not replaced. Both platforms must build and pass the combined verification before attachment. The caller grants write permission only to the reusable workflow; only its attachment job uses that permission. ## Dry run From the candidate checkout: ```sh gh workflow run test.yml --ref -f core_packages=true gh run view gh run download --pattern 'relayswarm-core-*' --dir artifacts/core-release-download node scripts/package-core-release.mjs verify artifacts/core-release-download ``` The entry point already exists on the default branch, so the dispatch can test a new reusable-workflow file on an unmerged candidate branch. Use a fresh empty download directory and check out the exact dispatched commit before verification. The verifier rejects mismatched source commits, missing or unexpected assets and invalid checksums. Actions artefacts are retained for 30 days; a successful dispatch is not a release or publication. ## Assets | File | Content | |---|---| | `relayswarm-core.xcframework.zip` | The binary XCFramework at the archive root, arm64 for iPhone, iOS simulator and macOS | | `relayswarm-core.xcframework.zip.checksum` | Actual `swift package compute-checksum` result for that archive | | `relayswarm-core-swift-bindings.zip` | Handwritten Swift facade and unchanged local-path `Package.swift` | | `relayswarm-core.aar` | Kotlin bindings and native libraries for arm64-v8a, armeabi-v7a and x86_64 | | `SHA256SUMS-apple`, `SHA256SUMS-android` | Digests of each platform's assets and metadata | | `BUILD-METADATA-apple.json`, `BUILD-METADATA-android.json` | Source commit, package version, Node and Rust versions | Extract both Apple archives into one directory to obtain the existing local Swift package. Its minimums are macOS 14 and iOS 16. The build compiles the Swift wrapper against the actual XCFramework before archiving it. The SwiftPM checksum describes the binary archive, not the bindings archive. The Android minimum is API 26 and consumers need Kotlin 2.2 or later; JNA is not required. Each ABI contains Rust and JNI shared libraries. The builder checks each library's machine, 16 KiB load alignment for 64-bit libraries and system-library dependencies. Packaging checks the manifest, classes, consumer rules and all six libraries. ## Local build and scope ```sh npm ci node scripts/package-core-release.mjs apple node scripts/package-core-release.mjs android node scripts/package-core-release.mjs verify ``` Apple needs macOS/Xcode and the three Rust Apple targets. Android needs the SDK/NDK, SDK platform 36, cargo-ndk 4.1.2, Kotlin and the three Rust Android targets, as the existing builders require. Each build uses the worktree's own `core/target`; it sets no separate target directory or incremental policy. Source paths are remapped for native builds and checked before archiving. Source commits and hashes bind each platform's outputs to the same checkout. These checks cover build/packaging and local or CI consumption. They do not prove physical-device, mobile battery, public-NAT or field acceptance, and add no native WebRTC adapter, client application or transport dependency. ## JavaScript and WASM downloads From a clean release commit after `npm ci`, run `npm run release:build`. It checks the committed WASM source stamp, audits the npm package file list, bundles the browser loader without external imports and writes the tarball, separate module, source metadata and `SHA256SUMS` under `artifacts/release`. It creates no tag or release. Verify fresh consumption before uploading those files to the same release as the source-matched native assets. --- Source: [docs/CORE-SIGNATURE-BUDGET.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/CORE-SIGNATURE-BUDGET.md) # Core signature verification budget Measured 24 October 2026 at source `cd92d3690b9e32b7f5932ea0b703f42a41a13eb9`. This is an isolated experiment; the shipping Rust, JavaScript and committed WASM module are unchanged. The [raw measurements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/core-signature-budget-20261024.json) include asset hashes, per-round timings and tool versions. ## Recommendation Keep signature verification in the core for now, with the WASM module served as a separate compressed asset. Delegating checks to the already-bundled `nostr-tools` saved about 3% of the combined compressed client/module bytes, but the measured imported-verifier path took longer per commitment. It also adds a host import to the currently import-free module. This result supports retaining one verifier across browser and native targets; it does not establish which isolated Schnorr implementation is intrinsically faster. ## Asset sizes Both variants use the demo's minified browser ESM build, the same pinned Rust release configuration (`opt-level=z`, LTO, no `wasm-opt`) and a separately fetched module. Compression is gzip level 9 and Brotli quality 11. Totals sum the two separately compressed assets; they exclude HTTP headers and cache effects. The rebuilt baseline module is byte-identical to the committed module. | Asset | Core checks: raw / gzip / Brotli bytes | Imported nostr-tools checks: raw / gzip / Brotli bytes | |---|---:|---:| | Demo client | 823,969 / 261,901 / 216,987 | 824,082 / 261,922 / 216,961 | | WASM module | 406,612 / 150,394 / 122,190 | 369,884 / 137,844 / 112,356 | | Combined | 1,230,581 / 412,295 / 339,177 | 1,193,966 / 399,766 / 329,317 | The prototype saves 36,615 raw bytes, 12,529 gzip bytes or 9,860 Brotli bytes across the pair. The client already includes `nostr-tools` for relay/session verification; moving commitment checks does not remove it from the baseline. ## Verification time Apple M1, macOS arm64, headless Chrome 155.0.8059.85, Node 24.21.0 for building and Rust 1.94.1, nostr-tools 2.24.1 and esbuild 0.28.2. Each variant passed all 140 shared commitment/delegation/revocation vectors through Node/WASM and through actual Chrome before timing. | Direct-author commitment | Core mean / median / p95 ms | Imported nostr-tools mean / median / p95 ms | |---|---:|---:| | Schema 2, 970-byte event | 0.521 / 0.500 / 0.600 | 0.850 / 0.800 / 1.000 | | Schema 3, 64 piece hashes, 5,422-byte event | 0.649 / 0.600 / 0.700 | 1.038 / 1.000 / 1.200 | These measure the complete `verifySegmentCommitment` browser call, including JSON marshalling, validation, signature checks and returned-content decoding. The schema-3 event commits to a 4 MiB segment; the segment payload is not hashed or transferred in this timing. Each profile/variant has 50 warm-up calls and 600 timed calls in six alternating-order rounds of 100. The vector timestamp is fixed for replay. Timings exclude network transfer, module compilation and player startup; Chrome's timer resolution limits individual-call precision. ## Experiment boundary The baseline keeps BIP-340 checks inside `event::verify_event`. In the isolated prototype, the WASM implementation of that function serialises the event to a host import. The host parses it and calls `nostr-tools/pure.verifyEvent`, returning the verdict; native Rust keeps its existing implementation. The prototype browser adapter supplies that import. Both demo clients are built with identical esbuild settings. Temporary source edits are restored after the experiment, and neither experimental module nor adapter is shipped. Every callback parses a fresh event object, so `nostr-tools` cannot reuse an object's cached verification symbol. The timing includes this JSON callback cost and all checks the current core invokes. A different import format, authorisation cache or direct JavaScript verifier could change the result; those alternatives were not measured. Timing covers two direct-author profiles, while the conformance check covers all 140 shared vectors. This is one desktop loopback measurement. It does not measure mobile battery, physical iPhone/Android devices, public NAT, player-level latency or field load. It changes no release, tag, package dependency or production verification path. --- Source: [docs/NATIVE-REALTIME.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NATIVE-REALTIME.md) # Native operator real-time backend Experimental, initiator-only transport for opaque datagrams. It does not capture, encode, decrypt, record or play media. The existing browser adapter, NIP-44 session, application admission and media queues remain separate. `src/node/native-realtime.mjs` loads no native dependency on import. A dedicated operator supplies a source-built **node-datachannel 0.33.4** addon whose native library identifies itself as **0.24.5-forgesworn-turn-close.1**. Both versions are checked. The stock npm binary is refused. Browser consumers load no native code; explicit preparation belongs to the operator build. ## API and ownership ```js import { createRequire } from 'node:module'; import { readPreparedNativeRealtime } from './scripts/build-native-realtime.mjs'; const directory = '/absolute/path/to/prepared-native'; const { receipt } = await readPreparedNativeRealtime(directory); const binding = directory + '/native-addon.node'; const nodeDataChannel = createRequire(binding)(binding); import { createNativeRealtimeBackend } from './src/node/native-realtime.mjs'; const backend = await createNativeRealtimeBackend({ nodeDataChannel, packageVersion: receipt.bindingVersion, maxPacketLifeTimeMs: 250, maxPeers: 16, }); // Pass backend.RTCPeerConnectionImpl to RealtimePeer on the operator side, // with initiator:true and the same explicit finite lifetime. The browser // installs its answerer before the operator starts sending an offer. // ICE servers and all/relay policy remain explicit application inputs. backend.closeOwnedPeers(); // Only at dedicated process exit, after every call has closed: backend.disposeForProcessExit(); ``` The factory returns `RTCPeerConnectionImpl`, `closeOwnedPeers`, `snapshot` and `disposeForProcessExit`. `closeOwnedPeers` closes all peers it created and refuses new ones. It does not call the dependency's process-global cleanup. `disposeForProcessExit` also invokes that global cleanup exactly once; it is unsuitable as the cleanup operation for one call in a shared native process. The facade implements the subset used by `RealtimePeer`: offer creation, local offer application, remote answer application, trickled ICE, state and data-channel events, bounded binary sends, buffering observations and close. It is not a complete browser RTCPeerConnection polyfill. Native automatic channel negotiation has already applied an offer when `createOffer` resolves. ## Initiator boundary The upstream 0.33.4 polyfill caches channel reliability attributes from constructor options. For an incoming channel it supplies no options, so those attributes describe defaults rather than the actual remote DCEP mode. The native binding exposes no reliability getter. This adapter therefore **refuses remote offers, answer creation and all incoming channels**. It creates one exact `relayswarm-live-v1` channel locally, requesting unordered delivery and the configured finite lifetime. Its exposed attributes describe that local native request. The actual browser answerer independently checks the remote channel's negotiated DCEP values and refuses mismatches. The operator must not select this backend as an answerer or relabel unknown remote channels to pass the shared policy gate. ICE starts with no default STUN server. The host must supply `iceServers` and `iceTransportPolicy`; relay policy is not downgraded. TURN credentials use the native structured ICE API, preserving opaque colons, slashes and plus signs instead of interpolating them into URI user-info. DTLS fingerprint verification remains enabled. Native logging is initialised at `None`; there is no per-call log writer in this module. Host/provider logging is separate. The pinned native libjuice backend supports **TURN over UDP only**. This facade refuses TURN/TCP and TURN/TLS configuration before allocating a peer, including under `all` policy, so unsupported servers cannot be silently ignored in favour of a direct connection. This limit belongs to the native backend; it is not a claim that the browser or Spry lacks those transports. Native `send(false)` means the message was accepted into a buffer, not refused. The shared datagram link checks native `bufferedAmount` before sending. This facade preserves the standard void-send behaviour and treats native exceptions as failure. Finite transport expiry and receiver observations remain relevant; accepted-send counters alone do not prove delivery. ## Qualification ```sh node --test test/native-realtime.test.mjs node scripts/build-native-realtime.mjs --output target/realtime-native E2E_NATIVE_ARTIFACT=/absolute/path/to/target/realtime-native \ node test/native-realtime-browser.mjs E2E_NATIVE_BINDING=/absolute/path/to/target/realtime-native/native-addon.node \ python3 test/native-turn-lifecycle.py ``` The browser command verifies the explicit prepared receipt and binary, then fails on missing, altered or mismatched inputs. There is no successful skipped mode. An optional `E2E_CHROMIUM_EXECUTABLE` selects a host-installed test browser. It exercises the real native initiator against a real Chromium answerer through encrypted RelaySwarm signalling and verifies actual browser DCEP reliability, binary datagrams containing NUL/255 in both directions and rejection of an unexpected incoming channel. Its finite process closes peers, relay, browser and native runtime. It captures no camera, microphone, screen or media recording. Initial macOS arm64 loopback qualification passed on the development Mac and M4 with Node 24, package 0.33.4 and native library 0.24.5. The M4 run used an isolated temporary source copy and existing dependencies without changing shared installations. [Retained observations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/evidence/native-realtime-loopback-20261024.json) record the exact gate. This is not Linux runtime acceptance, public-NAT performance, multi-participant media acceptance or a release. ### Stock TURN allocation-release finding The stock 0.33.4/0.24.5 native backend failed a separate allocation-release gate against an authenticated synthetic loopback TURN server. Both the raw binding and this facade obtained a relay candidate, returned from close and process-global cleanup, and released their local UDP socket while the process was still alive. Neither sent `Refresh(lifetime=0)`. Socket ownership cleanup therefore does not establish prompt release of a server allocation. [Retained observations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/evidence/native-turn-close-stock-20261024.json) keep that failure distinct from the passing browser/datagram gate. `test/native-turn-release.py` reproduces the check with fixture credentials; it contacts no live relay and exits unsuccessfully when release is missing. It requires an explicit exact `E2E_NATIVE_PACKAGE_ROOT`; `PROBE_MODE=facade` selects the owned wrapper and `E2E_NATIVE_BINDING` can explicitly select a separately built sidecar. A native-source correction needs independent identity, source/patch/binary receipts and release qualification. Reissuing credentials, increasing quota or restarting a relay does not repair teardown. ## Dependency and licence boundary This adapter's original source follows RelaySwarm's MIT licence. The native dependency is separately **MPL-2.0**; the combined distribution must not be labelled MIT-only. Binary packaging must retain its licence/notices and make the covered source, including any modifications, available as required by that licence. The prepared artifact includes the reviewed dependency licence inventory, exact source revisions, complete patches and hashes of its emitted files. Modified MPL-covered files are libjuice `src/agent.c`, `src/agent.h` and libdatachannel `include/rtc/version.h`; SCTP source is unchanged. Primary pinned sources: - [node-datachannel 0.33.4 package](https://registry.npmjs.org/node-datachannel/0.33.4) - [Native binding source and licence](https://github.com/murat-dogan/node-datachannel/tree/v0.33.4) - [Pinned native build configuration](https://github.com/murat-dogan/node-datachannel/blob/v0.33.4/CMakeLists.txt) - [libdatachannel 0.24.5 source and licence](https://github.com/paullouisageneau/libdatachannel/tree/v0.24.5) - [Buffered-send contract](https://github.com/paullouisageneau/libdatachannel/blob/v0.24.5/include/rtc/channel.hpp) ### Source-built allocation teardown Explicit preparation builds only pinned source inputs with at most two jobs. Each invocation owns fresh source and derived directories; it never trusts an existing OpenSSL/CMake cache or modifies an installed npm prebuild. The receipt and library version identify a modified binary. Preparation downloads sources; importing the verifier or starting an operator never does. The libjuice change sends explicit authenticated `Refresh(lifetime=0)` on the existing allocation socket before destroying it. Receive processing remains alive for stale-nonce challenges; a single closing loop owns retries and transaction IDs. Each agent has a 500ms deadline and at most six requests per allocation. A 438 updates the nonce and starts a fresh transaction. Validated success with explicit lifetime zero, or allocation-mismatch 437, completes release. Success validation uses upstream transaction IDs and MESSAGE-INTEGRITY; upstream error handling does not require error-response integrity. This patch does not introduce a general TURN response-source validation change. Release is best effort under packet loss or partition: an unreachable server can retain its allocation until expiry. Eight serial fully blackholed agents can consume approximately four seconds plus scheduling overhead. This bound is per agent, not per process. No credential rotation or quota increase is a substitute for cleanup. `test/native-turn-lifecycle.py` uses only authenticated synthetic loopback TURN with a cap of eight and one unchanged fixture credential. It checks normal and dropped-request `8 → 0 → 8 → 0` reuse, delayed 350ms stale-nonce challenges, invalid-HMAC and wrong-transaction success replies, lost/late acknowledgements, and bounded whole-process cleanup when all release packets are blackholed. [The retained macOS arm64 lifecycle run](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/evidence/native-turn-lifecycle-20261024.json) passed all eight scenarios. Normal, dropped-first-two and delayed-nonce cases each released and reused eight slots twice. All-eight blackhole cleanup returned in 4254ms while the fake server correctly retained eight allocations. [Patched native/browser qualification](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/evidence/native-realtime-patched-loopback-20261024.json) also passed actual unordered 250ms DCEP and binary exchange. These are synthetic loopback gates; Linux runtime and public Spry lifecycle acceptance remain separate. Every accepted release request must carry the correct HMAC, realm, username, nonce and original client UDP tuple. Blackhole allocation retention is an expected limitation, reported separately from successful release. Neither native implementation, operator independence nor absent call logs establishes an Online Safety Act exemption. --- Source: [docs/NIP-DRAFT.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NIP-DRAFT.md) # RelaySwarm experimental protocol draft This is a local specification of the implemented RelaySwarm session and browser object contracts. It is **not an accepted Nostr NIP**. Session wire version 3, commitment schemas 1 to 3, browser object framings 1 and 2 and native object framing have separate version boundaries. Schema 3 and framing 2 are experimental and off by default. The original `poc.mjs` uses older plaintext signalling and must not be described as this encrypted contract. ## Session events Every event uses NIP-01 canonical serialisation and a valid BIP-340 signature. The swarm identifier is exactly one `x` tag. Signal events have exactly one `p` recipient tag. Presence events must not contain recipient tags. Senders use throwaway Nostr identities; presence does not establish a trusted media author. | Contract | Implemented value | |----------|-------------------| | Presence kind | `24170` | | Signal kind | `24171` | | Session version | JSON field `v: 3` | | Signal encryption | Pairwise NIP-44 v2; mandatory | | Sender event age | At most 120 seconds old; at most 30 seconds ahead | | Presence JSON limit | 16 KiB UTF-8 | | Signal ciphertext limit | 64 KiB UTF-8 | | Decrypted signal limit | 8 KiB UTF-8 | | Relay frame limit | 1 MiB | Presence content has this shape: ```json {"v":3,"role":"watcher","transports":[{"type":"webrtc","publicKey":"<64 lowercase hex characters>"}],"have":[],"open":true} ``` `role` and transport `type` are lowercase tokens, up to 32 characters, matching `[a-z0-9][a-z0-9-]*`. `transports` is required and contains at most eight entries. A capability may carry `obj`, its browser object framing version, an integer from 1 to 15; absent reads as 1, and other values reject the presence. v0.2.1 accepts the field and discards it. `have` is required and contains at most 32 lowercase 64-character hexadecimal object keys. `open` is optional and advisory. An optional opaque `ticket` is a non-empty string of at most 2 KiB UTF-8; admission is the host's responsibility. A browser WebRTC capability uses the peer's Nostr public key. A native `hyperdht-v1` capability uses its DHT transport public key. Signal plaintext has this shape, then the whole JSON object is NIP-44 encrypted: ```json {"v":3,"type":"offer","transport":"webrtc","requestId":"","payload":{"sdp":""}} ``` `type` and `transport` use the same token rule. `requestId` is 8–64 ASCII characters from `[a-zA-Z0-9_-]`. `payload` is an object. Browser offers, answers and rejects must match the pending counterparty, transport and request ID. SDP appears in `payload.sdp`. Browser admission is checked before revealing an answer and again after asynchronous negotiation. Native `dial` and `ready` payloads bind the transport public key, expected SHA-256 and exact object size; see [Native transport](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NATIVE-TRANSPORT.md). A peer must not reinterpret a missing version or an unsupported version as plaintext. RelaySwarm's current session rejects version 2. The NIP-44 encryption version is not the RelaySwarm session version. ## Browser object exchange A WebRTC data channel carries JSON text controls and binary chunks. At most one response is in flight in each direction. A binary chunk is at most 16 KiB. | Message | Meaning | |---------|---------| | `{"t":"have","keys":[""]}` | Complete advertised key set, capped at 256 | | `{"t":"have","add":[""],"del":[]}` | Bounded key-set update | | `{"t":"want","id":1,"k":""}` | Request one object | | `{"t":"meta","id":1,"size":262181}` | Exact response size; chunks follow | | Binary messages | Response bytes, serialised between `meta` and `eof` | | `{"t":"eof","id":1}` | Response complete | | `{"t":"none","id":1}` | Object unavailable or serving declined | | `{"t":"cancel","id":1}` | Receiver no longer wants the response | Control text is capped at 64 KiB. Object size is limited by the host's configured segment cap, at most 16 MiB. `meta` cannot override the independently verified commitment size. Repeated headers, excessive chunks, empty chunks and response size overflow close the link. Timeout or cancellation resolves the request without extending its deadline. On a known ordered, fully reliable channel, the receiver may discard the remaining response while keeping the link busy until a matching, size-validated `eof`, or `none` before any metadata. No new request can reuse untagged chunks during that interval. Such a receiver sends `cancel` for the request. A holder that honours it answers with `none` before `meta`, or stops sending chunks and sends `eof` early; only after sending `cancel` does a receiver accept an `eof` with fewer bytes than `meta` announced. A holder ignores `cancel` for a request it is not queuing or sending, and peers that do not implement it ignore the message and send the response in full. The existing bounded drain timeout closes an incomplete response; unknown or partially reliable channels close immediately. Host stop and admission withdrawal still close immediately. Upload queues and backpressure retain their original bounds. Framing 2 adds a piece range `"p":[start,end]` to `want` and `meta`, with `end` exclusive and `0 <= start < end <= 64`. Pieces are those of commitment schema 3, whose piece size is a function of the object size alone, so both sides derive the byte offsets without exchanging them. A holder that has the object answers with `meta` echoing the same range and `size` equal to the range's exact byte length, then those bytes; a range past the held object's last piece is answered with `none`. A malformed range closes the link. The requester closes the link when `meta` omits or changes the range or its size differs, which is how a framing 1 holder that ignores `p` and sends the whole object is detected. A requester sends `p` only to a holder whose current presence advertises `obj: 2` or higher, and a viewer advertises framing 2 only while every one of its links can serve ranges. A holder charges a ranged response against upload allowances by the bytes it sends. Requests without `p` behave exactly as in framing 1. Optional `contribution` and `fetching` controls coordinate serving and short fetch leases; they are advisory and never authorise media or spend upload allowance. An object key identifies the host's canonical media URL/range within a swarm; it is **not** the content digest. The local publisher uses SHA-256 over `swarmId + "\n" + path`, appending `#start-end` for an exclusive-end byte range. Hosts with CDN aliases or query-bearing URLs must define their trust policy explicitly. A peer's `have` claim or `meta` message never establishes provenance. ## Signed media commitments Commitments use kind `24172`, one `x` swarm tag and one `e` tag naming the stable stream authorisation event. That event is signed by the trusted media author, has kind `30311`, one `d` identifier and explicit `["relayswarm","redistribute","1"]` consent. Schema 1 uses domain `relayswarm-segment-v1` and binds the stream event ID, swarm, object key, numeric rendition, sequence, discontinuity, part index or `null`, SHA-256, exact size and expiry. Schema 2 uses `relayswarm-segment-v2` and adds `playlist`, `mediaType` and `encryption`; its `rendition` is the exact playlist identity. This avoids treating player level indices, which codec filtering can renumber, as trusted media identities. Content must equal the canonical field order emitted by `commitmentContent` in [segment-commitment.mjs](https://raw.githubusercontent.com/forgesworn/relayswarm/main/src/browser/segment-commitment.mjs). Schema 3 uses `relayswarm-segment-v3` and adds `pieceSize` and `pieces` to the schema 2 fields, after `encryption`. `pieceSize` must equal `ceil(max(65536, ceil(size / 64)) / 16384) * 16384`: at least 64 KiB, at most 64 pieces, a multiple of 16 KiB. `pieces` holds exactly `ceil(size / pieceSize)` lowercase SHA-256 digests, one per piece in order; the last piece may be short. A receiver may verify and keep each piece as it arrives, from any source, and still requires the whole object to match `sha256` and `size` before delivery to the player. The local publisher signs schema 3 instead of schema 2, never both, when its `pieceCommitments` option is set. v0.2.1 and RelaySwarmKit v0.5.0 reject schema 3, so their viewers load those segments from origin. The receiver independently matches every context field. Commitments are at most 120 seconds old, at most 30 seconds ahead and expire within 300 seconds of verification. The local publisher normally signs for 60 seconds. Size is positive and within the host's segment cap. The actual received bytes must match the signed size and SHA-256 before delivery to the player. Schema 2 permits alternate audio and complete LL-HLS parts. Delta playlists require a bounded previously verified catalogue; a cold delta cannot establish omitted contexts. Init maps remain HTTP assets. Identity AES-128 requires an explicit publication policy and signs ciphertext plus exact key URI/IV metadata. Content keys stay on the HTTP path and are never peer objects. SAMPLE-AES, DRM, subtitle and I-frame rendition publication are unsupported. ## Scoped commitment delegation Kind `24173`, domain `relayswarm-commitment-delegation-v1`, authorises one commitment public key under the trusted author's signature. Its canonical content binds `streamEventId`, `swarmId`, `delegatePubkey`, `notBefore`, `expiresAt`, `renditions`, `mediaTypes`, `allowParts` and `maxSegmentBytes`. Scopes contain at most 40 exact rendition identifiers. Delegation expires no later than one hour after issuance. A delegated commitment includes `["delegation",""]`, matches every scope restriction and cannot outlive the delegation. Kind `24174`, domain `relayswarm-commitment-revocation-v1`, revokes an exact delegation ID under the same author's signature, stream and swarm. Hosts supply a bounded current revocation view or explicit revoked IDs. Verifiers do not query relays and absence from a supplied view does not prove global absence of revocation. Replacing the trusted stream authorisation also invalidates scopes bound to its old event ID. A delegate is not authorised to sign live metadata. ## Live metadata and stable authorisation The local publisher keeps the minimal commitment authorisation stable across restarts. A separate full NIP-53 kind `30311` advertisement uses address `live-`, so renewing live status does not replace the event to which commitments and delegations bind. Its signed tags include `streaming`, `status`, `starts`, `expiration`, `relays`, `relayswarm-authorisation` and `relayswarm-swarm`. Ended advertisements include `ends`. The RelaySwarm-specific linking tags are experimental extensions. Advertisements expire within five minutes and require HTTPS/WSS endpoints. Loopback HTTP/WS requires explicit test opt-in. Discovery pins the linked stable authorisation using `streamAuthorisations`, checks the same author and host-selected swarm, and preserves the host's allowed origins, relay and ICE policies. Event-suggested endpoints cannot expand those policies. The latest ended, withdrawn or unsafe update suppresses older live metadata. The host must obtain current metadata; a stable signature alone does not prove that a stream is still live. `previousEvent` gives immediate lifecycle updates a later creation timestamp within the allowed clock tolerance, avoiding an addressable event ID tie. Standard NIP-53 fields are described in the [upstream draft](https://github.com/nostr-protocol/nips/blob/master/53.md). ## Historical Swift baseline and current interoperability On 13 October 2026, `test/interop-swift.mjs` tested public RelaySwarmKit revision [`7eb042ee0fc0e960780c61d755a2ec50f1a8be40`](https://github.com/forgesworn/relayswarm-kit/tree/7eb042ee0fc0e960780c61d755a2ec50f1a8be40) with its pinned secp256k1 dependency and macOS arm64 libdatachannel binary. | Gate | Measured result | |------|-----------------| | Unmodified Kit `SwarmSignaller` ↔ RelaySwarm v3 | Incompatible in both directions | | Kit NIP-44/signatures ↔ JavaScript | Compatible in the exercised encrypted session | | Explicit Swift v3 fixture adapter ↔ JavaScript session | Encrypted presence/offer/answer journey passed | | Kit libdatachannel ↔ JavaScript werift/production `PeerLink` | 262,181-byte transfer in 17 chunks passed | | Independent Swift commitment verification | 12 schema/context/signature/expiry cases passed | | Corrupted bytes over the real WebRTC channel | Rejected against the signed commitment | | Plaintext and malformed encrypted session probes | Rejected by the fixture adapter | | Published Swift v3 client, physical devices, NAT variety | Not proved at that baseline checkpoint | | Kit ↔ HyperDHT native transport | Unsupported by the inspected Kit | The test adapter uses unchanged pinned toolkit crypto, relay and WebRTC components, but adds a separate strict v3 envelope parser and browser object receiver inside this repository. Its passing journey **does not establish compatibility of the Kit client at that revision**. That baseline Kit uses presence version 2, signal version tags and top-level `type`/`sdp`, and retains a plaintext fallback. Current RelaySwarm accepts none of those as v3 sessions. Run `node test/interop-swift.mjs --evidence artifacts/relayswarm-swift-interop-current.json` on macOS arm64 with Swift and authenticated read-only `gh` access. It fetches exact public component sources into an owned scratch package, compiles with four jobs, records source hashes and results, then removes its downloads/build and fixture services after success. The named receipt is retained. A failed build keeps owned scratch for diagnosis and reuse; remove it once its evidence is recorded. No external repository is edited. ### Historical Kit migration requirements These requirements guided the subsequent RelaySwarmKit upgrade: 1. Update `Sources/RelaySwarmSignalling/Swarm.swift` to emit/require `v:3`, transport, request ID and nested payloads; require NIP-44 for every signal. Remove automatic plaintext fallback from the default API. If legacy support remains, expose it through a separately named opt-in API and never negotiate down from v3. 2. Extend presence with bounded transport capabilities, object keys, optional upload availability and opaque host admission tickets. Apply the v3 age, recipient uniqueness, payload and byte limits before dispatch. 3. Update `Sources/RelaySwarmTransport/SwarmHost.swift` so answers preserve the pending request ID and transport, with admission before disclosing SDP. Supply bounded `have`/`want`/`meta`/binary/`eof` framing rather than assuming arbitrary host broadcasts are authenticated HLS objects. 4. Add an independent signed commitment module covering schemas 1 and 2, current author/delegation/revocation trust, exact fragment context and byte verification. Preserve receive-only/upload-consent semantics in the consuming application; a verified commitment is not viewer consent to serve. 5. Run this real interop journey against the updated public APIs, without the fixture adapter, and add Swift negative tests for version downgrade, misrouted/replayed events, context confusion, chunk floods and cancellation. Release and pin that tested Kit revision before publishing compatibility claims. HyperDHT support would be a separate transport implementation. The concrete [Kit review proposal](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/interop/README.md) includes an exact-source patch and SHA-256 manifest. Its full local SDK suite passed 25 tests with one public-relay test skipped. The later authorised upgrade adds public signed-media APIs and is published as [Kit v0.5.0](https://github.com/forgesworn/relayswarm-kit/releases/tag/v0.5.0) at `2f0b26ace4096a5dca87baf715274f91c331ac3a`. PR and merged-head CI passed 39 tests with one opt-in public-relay skip. The production browser sender and current `SwarmGuest`, `MediaDataChannel` and `SignedMediaTransfer` APIs completed author/delegate transfers of 108,950 fMP4 HLS bytes; corruption, tampering and pre-request/during-transfer revocation each returned zero bytes. No wire adapter was used. The exact source/receipt boundary and remaining physical/NAT/playback responsibilities are in the [interop guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/interop/README.md). --- Source: [docs/OPERATIONS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/OPERATIONS.md) # Pilot operator controls [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Broadcaster](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/BROADCASTING.md) · [Container deployment](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md) · [API](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md) · [Evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) These controls belong to **v0.2.1** and are absent from v0.1.0 assets. It adds bounded admission, durable reporting and crash supervision; final production acceptance remains open. See [production features](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) and [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). Before the first broadcast is ready, the root returns an HTTP 200 waiting page with a three-second refresh. Other endpoints return HTTP 503 with `Retry-After: 3`, including the authenticated status route; the waiting listener exposes no session, relay or operator API. The launcher replaces it with the player on the same port when both renditions publish. Waiting-page reachability does not establish fresh media, successful decoding or a verified public deployment. ## Credentials and HTTP routes The broadcaster creates its private `operator-token` in `--state-dir`. The demo can instead take `--operator-token-file FILE`, the `RELAYSWARM_OPERATOR_TOKEN` environment variable, or the `startDemoServer` JavaScript option `operatorToken`. Prefer a private file; supplying both JavaScript token sources is rejected. Tokens must contain 32–256 non-whitespace characters. Token files require an owner-controlled canonical parent, a 0600 regular single-link file and matching ownership; symlinks and unsafe permissions are rejected. The token is never in the player page, `/session.json`, public policy or operator status. Keep it separate from publisher signing secrets and forwarding credentials. The [deployment guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md#operator-access-and-private-identity) shows private header-file extraction and curl commands without printing the token or placing it in arguments. | Route | Method/authentication | Result | |---|---|---| | `/operator/status` | GET, `Authorization: Bearer TOKEN` | Policy, origin HTTP counters, publisher work/cache metrics, report aggregate, bounded request diagnostics and optional redacted broadcast worker/publication status | | `/operator/policy` | POST, bearer token, `application/json` | Accepts only `{"mode":null}`, `{"mode":"off"}`, `{"mode":"shadow"}` or `{"mode":"peer-first"}`; returns incremented policy revision | | `/delivery-policy.json` | GET, public | Mode, revision and reporting availability; no token or publisher secret | | `/delivery-policy.json?session=1` | GET, public, advertised by the current source | Policy plus the same public session snapshot as `/session.json`; no extra authentication or credentials | | `/reports` | POST, explicit server enablement and same-origin browser request | Accepts only bounded numeric measurement fields | | `/operator/admission` | POST, bearer token | Revokes a key or rotates the ticket epoch | | `/admission/challenge`, `/admission/ticket`, `/admission/verify` | POST, same-origin | Bounded key-possession challenge, short-lived ticket and live verification | Unconfigured operator controls return 503; absent/incorrect credentials return 401. Cross-site Origin/Fetch-Metadata requests are rejected. Operator bodies are capped at 2,048 bytes and reject unknown fields/invalid modes; wrong methods and content types are rejected. Authentication is not a replacement for HTTPS, host protection or restricting administrative exposure at the reverse proxy. The bearer token grants policy/status access, not media-source credentials or shell access. ## Policy and viewer consent `mode: null` leaves mode choice to the viewer. `off` requests origin-only playback. `shadow` or `peer-first` selects behaviour **only after the viewer has chosen a peer mode**: viewer origin-only selection and `Use origin only` always win. A policy can never opt the viewer into uploading. Valid publisher-signed redistribution authorisation is also required by the browser engine; operator policy is not an authorisation bypass. The page checks policy and publisher session every two seconds, with at most three independent checks pending. Authority expires five seconds after a check was issued; response arrival cannot extend it. v0.2.1 advertises `deliveryPolicySession: "inline-v1"` and returns both public snapshots in one response from `/delivery-policy.json?session=1`. Older server descriptors retain the two parallel requests. Missing or malformed advertised session data fails closed; it does not trigger a legacy fallback. Bare policy and operator responses keep their existing shapes. Programmatic hosts can use `startDemoServer({policySessionSnapshot: false})` for the legacy contract. Disablement is cooperative browser behaviour, not immediate revocation of already delivered media. An observed operator OFF takes effect before session validation or admission work. Expired authority restores origin loading and clears upload/reporting consent; later success cannot restore those opt-ins. Playback's video instance remains running; origin availability still determines whether playback continues. Same-manifest identity changes rejoin without resetting page counters. A changed manifest fails to origin rather than guessing. The combined response reduces request count; it has no new deployed field qualification and does not guarantee uninterrupted authority. ## Upload and measurement limits The page offers 10 MB, 100 MB (default) or 1 GB of cumulative **media payload** allowance, plus a separate upload rate choice. Web Locks and origin storage reserve payloads atomically across settings, rejoining, reloads and tabs. Interrupted sends are not refunded; oversized next segments do not spend the smaller balance. Exhaustion stops contribution while playback continues. Storage failure disables uploading. Consent is requested anew after reload; the viewer can explicitly raise or reset the allowance. This local allowance covers one browser profile at the origin. The current source also offers an optional [shared account allowance](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md), using explicit Nostr sign-in or the integrating website's authenticated account. Devices using one identity and ledger share cumulative reservations in addition to their local allowances. Account connection, linking, settings changes and resets leave uploading off until fresh viewer consent. Keep the private ledger through upgrades; disconnecting or reloading does not refund its charges. Neither allowance counts complete physical wire traffic. The deployed `44b21d6` pilot offers Nostr sign-in; no website resolver is configured there. The library option is `maxUploadBytesPerSession`; omission means unlimited and zero means no media uploads. Its metrics expose configured cap, remaining allowance and exhaustion. Host applications that recreate a swarm must carry their own cumulative allowance forward, as the page does. Rate limits use a token bucket with up to a two-second burst. Signalling, transport overhead, commitment fetches and shadow downloads are additional traffic; an upload media cap is not a wire-traffic limit. Server `origin` counters separate `/media/` requests/body bytes from commitment requests/body bytes. Media counts include playlists, init segments, ranges and error responses; HEAD contributes no response body. Body bytes are bytes handed to HTTP responses, not confirmed physical-wire totals or network overhead. Browser resource timings have their own scope and exclude native-HLS requests. Verified peer payload records media accepted from peers; shadow mode adds peer traffic alongside origin loading. None of these counters alone establish net traffic/cost savings. Publisher metrics include signing/hashing/cache activity, concurrent work and rejections. Broadcast metrics include worker states/restarts, rendition shape, generation and last publication time; they contain no input/output URLs or stream keys. A running process does not prove a fresh source, successful decoding or platform acceptance. ## Diagnosing control-path timeouts v0.2.1 adds a numeric `Server-Timing: rs-app;dur=...` header to session, policy, admission, report and commitment responses. It measures handler entry to response headers. It excludes queueing before the handler, network transport and response-body receipt. Media responses are not instrumented. Authenticated status includes `requestDiagnostics`: seven fixed route labels, 128 active observations, a 30-second observation expiry and the latest 120 one-second windows. Histograms distinguish headers from terminal outcomes (finished, cancelled or expired). A server finish means handing the response to the HTTP stack, rather than confirmation that the browser received it. Event-loop delay, scheduler drift and utilisation accompany each completed window. The sampler is unreferenced and closes with the server. No request identities, IPs, URLs, query strings, headers, bodies or credentials are stored in these aggregates. Downloaded page receipts include `controlTimings`, with at most 64 numeric observations and 64 pending observations, measuring headers and JSON-body time separately. Application-header duration is included when available. Caller signals, timeouts and single-request behaviour remain unchanged. These local timings are not submitted as numeric reports and do not grant upload or reporting consent. Durations above one minute are clipped and counted. For matched probes, run the following **on the server hosting the loopback endpoint**, using its configured public origin: ```sh node scripts/probe-control-path.mjs \ --public-origin https://trial.example \ --loopback-origin http://127.0.0.1:8787 \ --duration 60000 --interval 5000 --timeout 5000 ``` The probe is bounded to five minutes, verifies public TLS, retains numeric observations only and discards response bodies after a byte limit. Its fresh HTTP/1.1 connections differ from browser HTTP/2. Pair these observations with actual failure timestamps; the instrumentation cannot retroactively diagnose an earlier incident or establish a network cause from a healthy later sample. ## Optional numeric reporting Reporting is **off by default**. Enable it server-side using `--telemetry` or `startDemoServer({telemetry:true})`; each viewer must then check the separate reporting opt-in. The page sends cumulative numeric snapshots every fifteen seconds after playback starts. Downloadable field receipts remain separate and are not submitted. Reports use `{v:1, reportId, sequence, values}`. The temporary page ID is 32 hex characters; sequence increases for new cumulative snapshots. Values contain exactly `durationMs`, `peerBytes`, `uploadedBytes`, `originMediaRequests`, `originMediaBytes`, `stalls`, `stallMs` and `fatalErrors`, non-negative safe integers up to 10¹². No account, browser version, device/network labels or peer IP addresses are accepted. Infrastructure still sees connection addresses; there is no third-party report endpoint. The collector permits 240 requests per ten seconds, caps bodies at 2,048 bytes and requires same-origin requests. Retention defaults to 256 page IDs for five minutes; `reportCapacity` and `reportTtlMs` bound it. With `operatorState` (CLI `--operator-state`) enabled, private state survives restart and expiry is applied after reopening. Retries are idempotent, stale sequences do not add traffic again, and decreased counters are refused. The pending durable write queue defaults to 64; overload returns 503. Reports remain untrusted observations, not unique-viewer totals or billing evidence. Broadcasters enable private operational persistence automatically. ## Resources and admission boundary The HTTP example caps active media responses at 32, connections at 128, header size at 8 KiB and request/header timeouts at ten seconds. Commitment requests have a separate 240-per-ten-second budget. Publisher defaults permit eight concurrent commitment operations and 512 entries in each hash/commitment cache; playlist/catalogue/segment bounds are documented in the [API](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md). Cancellation releases media file handles and response slots even while lookup/opening is pending. The [container package](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md) sets CPU, memory, process and log limits, loopback ingest/player mappings and private network boundaries. Its healthcheck requires a recent publication and publishing worker state; it becomes unhealthy without input or during a prolonged source outage. Compose restart policies recover container exits, not unhealthy status alone. Measure actual host capacity before broadening a pilot. The candidate demo supplies a bounded ticket issuer and live revocation checks. The embedded relay rejects unadmitted presence/signals and caps aggregate messages. Open issuance establishes bounded keys, not unique people or paid subscriptions; broader Sybil and real-network acceptance remain separate gates. ## Restart and recovery Preserve the dedicated state directory/volume to retain publisher identity and operator credentials. Shut down normally so workers, file handles and the exclusive `.broadcast-lock` are released. Do not run two pipelines against one media directory, mount the state into unrelated services, or delete private state during an upgrade. On supported local POSIX storage, permanent publication/worker lease inodes and a guardian permit automatic parent-crash recovery after all worker groups are reaped. A dirty guardian marker or legacy pre-lease lock requires explicit operator inspection. Never delete lease database files to force acquisition. A namespace-local PID is insufficient evidence; retain private backups and leave uncertain ownership closed. The [deployment guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/deploy/README.md#exclusive-volume-ownership-and-crash-recovery) describes the recovery boundary. macOS durable state requires a writable APFS or HFS block filesystem with ownership enabled. RelaySwarm checks the exact directory and device identities through the system `df`, `diskutil` and `plutil` tools under one five-second deadline. Unsupported or changing identities, unavailable metadata and unconfirmed tool exit refuse acquisition. Publisher state contains the signing secret; a whole-volume backup can also contain generated media. Use access-controlled encrypted backups. Forwarding credentials live in a separate private file and are read at launch; trusted process administrators can inspect ffmpeg's full URL arguments. Never put these secrets in a browser receipt, repository, public status response or issue attachment. --- Source: [docs/PERFORMANCE.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PERFORMANCE.md) # Hot-path performance review [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) · [Changelog](https://raw.githubusercontent.com/forgesworn/relayswarm/main/CHANGELOG.md) Measured 24 October 2026, comparing the v0.4.3 source `6f63fb2f8ae20a51953c80853816311f25980bf0` with the changes listed below. The loader and publisher rows were measured against the earlier `ed845ceccca192320f5b40b004ad54b7ffb2417c`; v0.4.3 changes neither the loader's copy and hash paths nor the publisher. The host was a 4-vCPU x86-64 Linux VM with Node 22.22.0 and Rust 1.94.1. Every figure is an in-memory micro-benchmark: no browser, network, relay, device or player is involved, and timer resolution and shared-host noise move single runs by 10–30%. Ranges are medians from repeated runs. Compare runs on one host before and after a change; do not compare absolute numbers across machines. `npm run bench:hot-paths` reproduces the link, verification, multi-holder and native-receive rows. It does not measure playback, field networks or battery. ## Changes and measurements ### Peer links and the WebAssembly boundary | Path | Before | After | |---|---:|---:| | Core-backed link moving one 4 MiB object, both ends on one thread | 6.6–9.7 ms | 4.7–5.4 ms | | Core module memory after two (or four) 4 MiB receives | 29.6 MiB | 17.3 MiB | | Serving one 4 MiB schema-3 object as 16 piece ranges | 6.6–7.2 ms, 2.5 MiB module memory | 5.2–5.9 ms, 2.2 MiB | | Multi-holder piece hashing in the core | 8.4–8.7 ms/MiB | 3.7 ms/MiB | | Final whole-object check of a 4 MiB multi-holder transfer | 35–38 ms | 15–16 ms | The JavaScript reference link moved the same object in 2.0–2.7 ms before and after; it was not changed. v0.4.3 already passes only a requested range into the module when serving; the range row shows the remaining frame copies. - A link frame is moved, not copied, into the module's result buffer, and a resolved object is written into it once. The browser shell reads each event out of module memory separately, so a resolved object is copied once into a buffer of its exact size instead of copying the frame and then the object. The frame format is unchanged, so either module works with either shell. - A receive whose size the caller expected from a signed commitment reserves that size once, on the first byte. A size only the remote declared still grows as bytes arrive, so `meta` alone holds no memory. - The `sha2` crate is compiled at `opt-level = 3` while the rest of the module stays at `"z"`. The module grew from 411,690 to 415,896 bytes (152.0 to 153.4 KB gzip), including the verdict memory below. - The multi-holder transfer output is copied once, from module memory into its own buffer. ### Commitment verification | Fresh commitment per segment, same stream event | Before | After | |---|---:|---:| | JavaScript verifier, author-signed | 3.6–6.1 ms | 1.8–2.0 ms | | WebAssembly verifier, author-signed | 0.80 ms | 0.51 ms | | JavaScript verifier, delegate-signed with four revocations | 14.3–15.0 ms | 2.0–2.3 ms | | WebAssembly verifier, delegate-signed with four revocations | 2.7–2.9 ms | 0.63–0.67 ms | Both verifiers recheck the unchanged stream event, delegation and every supplied revocation for every segment. Each now remembers up to 512 Schnorr signatures it has proved, keyed by the recomputed event hash, public key and signature. The hash is recomputed on every call, so a changed field is a different key, and every other check (size bound, kind, tags, times, scope and revocation matching) still runs on every call. Only proofs are remembered; a failed signature is checked again. Both verifiers pass all 140 shared vectors cold and again with every accepted signature remembered. ### Signalling and the native path - `RelaySwarmSession` derives each peer's NIP-44 conversation key once, in a 256-entry least-recently-used map cleared by `close()`. Fifty signals to one peer took 333 ms before and 162 ms after; the remainder is event signing. Signals stay pairwise encrypted. - `RelayPool` gains `readyOnFirstRelay`. The installed native client uses it, so a relay that accepts TCP but never answers no longer holds discovery for the whole peer deadline. With one such relay and one healthy relay, a native fetch with a 4 s peer deadline completed over HyperDHT in about 0.2 s; before, it exhausted the deadline and the peer attempt failed. - The native client starts Nostr discovery while the DHT bootstraps, and waits for both before dialling. - The native receiver fills one buffer of the trusted size and hashes as bytes arrive, instead of keeping every chunk and joining them. A 16 MiB object in 1,452-byte reads took 88–94 ms before and 23–24 ms after; in whole frames it took 22–24 ms before and 19 ms after, and peak memory is one object, not two. The size, chunk budget and digest checks are unchanged. ### Browser loader Synchronous `load()` time per segment, with every counter identical before and after: | Case | Before | After | |---|---:|---:| | Shadow mode, unsampled, not serving, 2 MiB / 8 MiB | 1.92 / 3.90 ms | 0.12 / 0.14 ms | | Peer-first HTTP fallback, not serving, 2 MiB / 8 MiB | 0.68 / 1.90 ms | 0.23 / 0.19 ms | - Shadow mode copies origin bytes only for a sampled comparison or when serving is enabled (`serve: true`), and hashes them only for a sampled comparison. With the default 0.25 sample rate and serving off, three in four segments previously paid a copy and a SHA-256 they never used. - Peer-first skips whole-segment copies when serving is not enabled or the object is already held. With serving enabled, bytes are still copied and the held-segment store decides when it runs, so a load that starts on cellular or without allowance and finishes with serving allowed is still held. - The core-backed neighbour discovery keeps its decoded candidate list until a hint or clear changes it. With 64 candidates, `hinted` fell from 123–428 µs to 45–52 µs and `choose` from 150–399 µs to 70–78 µs. - Trace-only clones are skipped when request tracing is off. ### Publisher and demo origin | Path | Before | After | |---|---:|---:| | Catalogue refresh, live, two renditions of 12 segments | 1.1–1.3 ms | 0.8–0.9 ms | | Catalogue refresh, two renditions of 1,800 segments | 12.8–13.7 ms | 0.9–1.0 ms | | Commitment, 1,800-segment renditions with cache churn | 31–32 ms | 5.5–6.1 ms | | 16 / 32 / 64 simultaneous requests for one new segment, limit 8 | 8 / 24 / 56 refused (503) | none refused, one signature | | Account-allowance reservation at capacity (CPU) | 65 ms | 40 ms | | Demo page assets, first visit / revalidation | 1.27 MB / 1.27 MB | 385 KB / 0 bytes (304) | | Demo relay fan-out, 64 clients with two subscriptions | 430 µs per event | 53 µs per event | - Media playlists are read concurrently, each read sized from its stat size, and a refresh whose master and media playlists are byte-identical to the previous read returns the previous parse. Every refresh still reads and stat-checks every playlist; a playlist with `EXT-X-SKIP` is always parsed, because a delta depends on the previous catalogue. - Identical concurrent commitment requests join the one in flight without taking a slot. Each joined caller is then checked against a catalogue read and a file stat made after it arrived, as a separate request would be, so a context that left the playlist or a replaced segment is refused rather than answered from the earlier check. Each caller receives its own copy, and a failure reaches every joined caller and is not kept. The demo's 240-per-10-second request budget is unchanged and still counts joined and cached requests. - Account-allowance validation builds its account and grant indexes once, making it linear in the bounded state. - The demo serves its page, style sheet, client bundle and WebAssembly module with Brotli or gzip, a strong ETag per encoding, `cache-control: no-cache` and 304 revalidation. Every other route keeps `no-store`, and the security headers are sent on 200 and 304 responses. - The demo relay serialises each event once per fan-out, with byte-identical frames, and evicts history without copying it. ## Not changed These were measured or reviewed and left alone, with the reason. - Per-chunk link overhead is 5–9 µs in the core-backed link and 2–4 µs in the JavaScript link, about 1–2 ms per 4 MiB at both ends. - Peer selection takes about 2 µs per choice with six links, and scheduler ticks about 13 µs. - Incoming relay events are deduplicated before signature verification, and every bounded map in the session and relay pool stays bounded. ## Later changes (25 October 2026) Measured on the same host against `5ed12be` (main after the changes above), with in-memory or local-filesystem harnesses rather than a real encoder or browser. | Path | Before | After | |---|---:|---:| | Encoder playlist rename to republished playlist, both renditions | mean 135 ms, max 216 ms | mean 6 ms, max 28 ms | | Allowance reservations, 8 at once | 571/s, slowest tenth 16 ms | 2,770/s, 5 ms | | Allowance reservations, 32 at once | 436/s, slowest tenth 65 ms | 1,985/s, 20 ms | | Allowance reservations, 64 at once | 399/s, slowest tenth 149 ms | 1,426/s, 56 ms | - The broadcast publisher watches the current generation's rendition directories and publishes when the encoder renames `index.m3u8` into place. A new generation wakes it so the watch is in place before the first playlist. Events only wake the loop, which rereads and validates the files as before; segment events are ignored, events without a filename wake it at most every 10 ms, and the 250 ms interval remains the fallback. Blocking playlist reloads already watch the published playlists, so they release correspondingly sooner. The figures include the harness's own writes. `close()` during a publication no longer waits for another interval. - The allowance ledger still applies operations one at a time in arrival order, each on its own copy of the state and checked for cancellation before and after it applies. Operations that queue while a write is in flight now share the next durable write and its two fsyncs. Once one of them has changed the state, every later outcome in the batch, refusals and reads included, is held until the write completes and released in arrival order; if that write fails, every operation in it is refused and none is kept. This host's fsync is fast, so slower storage gains more. A single reservation is unchanged. ## Follow-ups Ranked by expected effect. None is implemented here. 1. Count only signatures, not joined or cached requests, against the demo's commitment budget, which otherwise caps a server near 48 viewers. 2. Keep a per-relay retry count so a relay that accepts and then drops each connection backs off instead of being redialled every 1–2 s. 3. Reduce per-reservation CPU at large ledger states: each operation still clones and validates the whole state. --- Source: [docs/PRODUCTION-FEATURES.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-FEATURES.md) # Production feature work [Documentation](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/README.md) · [Delivery requirements](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) · [Evidence](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) · [Protocol draft](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/NIP-DRAFT.md) These changes belong to v0.2.1, the published experimental prerelease. They are absent from the earlier v0.1.0 assets. Production acceptance remains a separate gate; consult the delivery checklist for its current state. ## Browser delivery and media Connected viewers exchange bounded contributor/rendition interests and short origin-fetch leases. A contributor fetches fresh live media from HTTP while other interested viewers may wait for verified peer availability within their playback deadline. Peer claims are advisory: lack of availability, expiry, invalid signatures or insufficient playback buffer use the HTTP loader. Measured HTTP latency raises the origin reserve; peer transfer estimates cannot spend the time retained for fallback. hls.js retains bitrate selection. Commitment, admission and persistent-reservation host callbacks receive an operation-specific signal. A deadline aborts that signal and stops waiting for the result. Host callbacks must honour the signal to cancel their I/O. The bundled demo passes it to its HTTP requests; stopped or expired operations fence late results. The demo retains fatal/native decoder records and allows one deferred attempt to recover a fatal append/MediaSource-reset error. It restores the HTTP loader, stops contribution, clears upload consent and retries the current live/VOD position. Advancing playback must be observed within ten seconds; repeated failure, user cancellation or publisher changes stop recovery. Budget state is preserved. A recovered outcome does not erase the fatal error or establish the cause of an earlier unrelated failure. The same single repair budget also covers a reproduced nonfatal live stall: successful playlists advance to a new continuity outside the current buffer, while decoded frames and playback time remain stopped for ten seconds. The demo restarts loading at the fresh live position through hls.js's public API. Actual rolling-playlist tests retain the failing control, recovered video, cancelled held requests and a ten-second no-progress failure. This does not establish the cause of the older hosted MSE append error. For an established live main playlist, the demo extends HTTP 502/503/504 retries within one fixed 60-second window from the first eligible failure; the 32nd eligible failure refuses another retry. Quality changes do not renew the window; a successful playlist update does. Scheduled extended retries are checked again before dispatch, so hiding or replacing the player, or reaching the deadline, prevents new retry I/O. Startup, VOD, other HTTP errors, request timeouts, fragments and keys retain their original policies. Permanent outages can therefore take longer to become fatal. Fatal records, peer deadlines, account allowances and upload consent remain unchanged. The publisher supports exact local playlist identities for mixed codec and frame-rate variants, alternate audio, fMP4 maps, complete low-latency parts and warm delta playlists. Schema 1 remains valid for its original contexts. Schema 2 binds the exact playlist, media type and encryption context rather than relying on a player's filtered level number. Init maps and keys remain on HTTP. A part-capable host explicitly enables `swarmParts`; the demo exposes that choice through `mediaCapabilities.parts`. Its 500 ms part reserve is specific to the tested one-second-part/three-second-hold-back configuration; the library default remains 2,000 ms and measured HTTP latency can raise it. AES-128 ciphertext publication requires `allowEncryptedMedia: true`. A commitment binds the local key path and IV; it neither publishes the key to peers nor grants rights to redistribute protected media. DRM/SAMPLE-AES, subtitles, I-frame variants, remote/query-bearing publisher assets and cold delta reconstruction remain unsupported. Preload hints do not authorise incomplete bytes for peer delivery. ## Signing and discovery An author can sign a short-lived commitment delegation scoped to a stream, swarm, delegate, rendition/media types, parts and maximum size. The signing server can then operate with the delegate secret and the signed authorisation without retaining the author's secret. Clients enforce scope, expiry and the host's current revocation view. They do not infer that an offline revocation list proves the absence of a newer revocation. Full signed NIP-53 advertisements use a separate addressable identifier and link the persistent commitment authorisation. Live/ended updates carry an explicit streaming URL, relays, start time and bounded expiry. They do not change the stable commitment identity. Discovery can require host-pinned authorisations; event-selected relays and ICE servers do not replace host endpoint policy. `/stream.json` exposes the current signed advertisement. ## Admission and upload allowance The demo issues short-lived swarm/key-bound tickets after a signed one-use possession challenge. Issuance, challenges and verification have separate bounds. Revocation and epoch rotation are authenticated operator actions; browser admission is checked again before connections, signalling and media uploads. The embedded relay refuses unadmitted presence and signals and has both connection and aggregate message bounds. These controls constrain work and participating keys; they do not establish unique people or make an open ticket endpoint a subscription service. Proxy headers do not establish a trusted client address. The browser saves media reservations under an origin-wide Web Lock and origin storage record. Reloads and concurrent tabs share spent bytes; upload consent and signing keys are never saved. Blocked, corrupt or unavailable storage disables contribution. Viewers may deliberately increase or reset the allowance. The quota covers reserved media payload, including interrupted sends, rather than complete connection traffic. An optional private account ledger adds reservations shared across devices. The example supports explicit Nostr sign-in and a host-supplied authenticated website account. Linking requires both proofs, adds recorded spend and retains the lower limit. Connection and account changes leave upload consent off; grants and identities stay outside swarm traffic and receipts. See the [account allowance guide](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/ACCOUNT-UPLOAD-BUDGET.md) for persistence, privacy, failure behaviour and the remaining acceptance scope. ## Operations and recovery Opt-in reports carry a temporary page report identifier and sequence alongside numeric cumulative values. Retries are idempotent, older snapshots do not double-count, and decreasing counters are rejected. Private bounded state retains policy, origin counters and the latest reports across orderly restart. Origin counters use a short write debounce; they are observations rather than an exact crash-proof billing ledger. Retention limits apply after reopening. Broadcaster publication and worker supervision use two permanent SQLite lease inodes on supported local POSIX filesystems. A worker guardian owns encoder and forwarder process groups. On parent termination it kills and waits for those workers before releasing its lease. An independent dirty marker is written before launch and cleared only after cleanup. A killed guardian or host catastrophe leaves recovery closed for explicit operator inspection; PID namespace guesses and timed stale-lock deletion are not used. Distributed volumes and Windows private-state ACLs are unsupported. Node 22.13+ is required. ## Installed native client The installable package supplies `relayswarm-native` and the `relayswarm/native-client` API. An application supplies a trusted descriptor with digest, size, swarm, relay endpoints, allowed seeders and an optional HTTPS origin. A bounded HyperDHT/Noise attempt precedes automatic verified HTTP fallback. Redirects are refused. Exact size and SHA-256 are checked before bytes are returned or a new output file is published. Cancellation does not start fallback, and existing output files are never replaced. Connections require the expected Noise key and acknowledged handshake writes within one connection deadline. Final completion checks the absolute transfer deadline even when synchronous work delays an abort timer. Discovery accepts valid presence within its configured age bound while encrypted signals retain their shorter subscription window. The receiver subscribes before announcing receive-only native presence, with no held objects and `open: false`. A seeder coalesces live replies globally to at most one per second, using one timer and no requester map; close cancels a pending reply. Relay history is optional for ephemeral events. This public readiness metadata links the temporary Nostr identity and native public key; only an exact signed dial can grant a transfer. This entry point requires installed Node; it is not a self-contained binary. The original `native-poc.mjs` remains a separate two-peer proof, with its original failure-reporting behaviour. Neither client is durable media storage. --- Source: [docs/PRODUCTION-READINESS.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md) # Production delivery requirements This checklist tracks the production work requested on 13 October 2026. It retains the full scope of the feature review. Implementation, automated tests, publication, deployment and physical acceptance are separate requirements. An entry remains open until the evidence described below exists. ## Current deployed pilot: 21 October 2026 Exact `140c256` (PR 9) passed all nine required CI jobs, fresh 286-member consumption of the committed source, guarded deployment with independent review, P05 reporting acceptance (natural expiry after 303,923 ms) and P07 parent-crash recovery with an independent native review. The fourteen-role short qualifier R66 is GREEN, 16 of 16 gates, the first green fourteen-role qualifier, though it passed `each4BothQualityPeer` by one high-quality peer segment. PR 9 merged as `1d54538`, published as experimental prerelease v0.2.1 and deployed through the guarded cycle with its own independent review: the pilot app is `ce410033`, the served client is 787,462 bytes, and reporting and forwarding remain off. Several items are RED. v0.2.1's own short qualifier R68 is RED, 15 of 16 gates: receivers switching to high quality received no high-quality peer segment, a product mechanism on a one-segment margin (see [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint)). The sustained 7,200 s run (Item 5) has not completed and is stopped by decision: R37 and R38 failed on harness faults with no product evidence either way, and on `1d54538` it cannot start without a matching qualifier. The P06 3 MB both-quality shared-cap lifecycle failed again as in the a416f7e third run: three accepted 720p reservations were charged but none completed as verified peer media over the relay path before the fourth was refused as exhausted. It is a design limitation under relay throughput, one high-quality holder and a 3 MB cap, with the allowance behaving as documented. Desktop Firefox 152.0.6 and Safari 26.6.2 passed their journeys (macOS arm64 desktop scope only); Safari 17.6 is RED with the cause not determined. Physical devices, hard NAT, a separate network and marginal cost on the hosts' plans remain open. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint), the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/140c256-current-delivery-checkpoint-20261021.json) and the [delivery checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Previous deployed pilot: 19 October 2026 Exact `3f706a9` passed all nine required CI jobs, fresh 280-member consumption, guarded HTTPS deployment and independent verification-source cleanup. The browser client remains 773,458 bytes. Nostr accounts are enabled; the authenticated host-supplied account API is implemented, with no website resolver configured. Reporting and forwarding remain off. P05 durable reporting acceptance now passes: trusted opt-in, duplicate idempotence, same-volume restart persistence and natural expiry after 304.105 seconds. Reporting-off restoration and full browser/source cleanup also passed independent review. P07 crash acceptance remains RED. The latest test passed the parent-only crash, strict writer audit, guarded marker recovery and server restart, while preserving the original restart policy and permanent leases. The browser exhausted its playlist retry budget on HTTP 502 responses before the server returned; post-restart playback was not proved. An unchanged-source browser regression also reproduces stopped playback after a 35-second HTTP 503 outage. Browser and finite-source cleanup passed, and the acceptance window was not extended. Retry and origin-only reconfiguration corrections are being verified; see the [recovery checkpoint](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3f706a9-parent-crash-recovery-checkpoint-20261019.json). The matching fourteen-viewer qualifier remains unproved, so the two-hour run is still ineligible. Both-quality shared-budget lifecycle, device/network coverage, matched benefit and final release remain open. Other work must keep running and the original resource limits remain unchanged. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint), the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3f706a9-current-delivery-checkpoint-20261019.json) and the [delivery checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical a02d5ec checkpoint Exact `a02d5ec` passed all nine required CI jobs, fresh 278-member consumption, guarded HTTPS deployment and independent verification-source cleanup. Private state, permanent leases and the proxy were preserved. Nostr accounts are enabled; the authenticated host-supplied API is implemented. Reporting and forwarding remain off. The demo selects four neighbours; the SDK default is six. R55 stopped during its sixth browser setup, with zero measurement. Independent finite cleanup passed; the expected fourteen-viewer cohort was incomplete. The earlier R54 both-quality peer failure remains RED, and the two-hour run remains ineligible. M4 subsequently became unreachable from this Mac; other work must keep running and the original resource limits remain unchanged. A single-browser reporting retry remained RED after 85.580 s. The server enabled reporting, but reused the same policy revision after changing its startup telemetry setting. The browser refused that conflict and kept opt-in disabled; no report request was sent. Reporting was restored to off, and full browser and finite-source cleanup passed independent review. Restart durability, natural report expiry and subsequent crash-recovery acceptance remain open. The source revision correction passes focused operator and bundled-client regressions; its CI, deployment and acceptance rerun remain pending. P01–P12 source surfaces are implemented; production acceptance and release remain incomplete. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint), the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/a02d5ec-current-delivery-checkpoint-20261018.json) and the [delivery checklist](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/PRODUCTION-READINESS.md#delivery-checklist). ## Historical 3515d5b checkpoint Exact `3515d5b` passed all nine required CI jobs, fresh 277-member consumption, guarded HTTPS deployment and independent verification-source cleanup. Private state, permanent leases and the proxy were preserved. Nostr accounts are enabled; the authenticated host-supplied API is implemented. Reporting and forwarding remain off. The demo selects four neighbours; the SDK default is six. R54 completed 303.647 seconds of measurement but remains RED. Fifteen gates passed, including all fourteen viewers, eight contributors, both-quality decode, consent, resources, renewal and admission. Only every receiver's both-quality peer coverage failed: receiver 2 lacked measured LOW peer bytes; receiver 3 lacked measured HIGH peer bytes. Provider observations recorded zero refusals and a peak of 731 admission calls per aligned minute against the selected 900-request address limit. Independent finite cleanup passed; it does not change the failed qualification. P01–P12 source surfaces are implemented. Matching short qualification, two-hour/churn/natural expiry, both-quality account lifecycle, durable-report and crash-recovery acceptance, browser/device/network breadth, matched wire/cost benefit and final release/download checks remain open. Long eligibility requires a matching successful short qualifier. Other work must keep running; the original resource limits remain unchanged. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) and the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3515d5b-current-delivery-checkpoint-20261018.json). ## Historical c0f337d checkpoint Exact `c0f337d` passed all nine required CI jobs, fresh 276-member consumption and guarded HTTPS deployment. Private state, permanent leases and the independent proxy were preserved. Nostr accounts are enabled, with an implemented host-supplied authenticated account API; reporting and forwarding remain off. R52 stopped after 156.325 s on an unknown/future resource timestamp. A separate controlled millisecond-domain regression and eight-check correction pass; R52's exact failed clock values remain unknown. R53 used the corrected monitor and stopped after 17.135 s on admission refusal. Twelve HTTP 429 responses and the provider's 900-success/refusal/reset pattern support address-budget exhaustion, without a retained server error body. Both runs passed independent finite cleanup. Neither is a successful short qualifier. The local replay-drop/callback-diagnostic candidate passes sixteen focused and 194 combined tests, including an original-source replay regression. Its effect on field admission load remains unproved. It explicitly selects four demo neighbours; the SDK default remains six. The same fourteen-viewer/eight-contributor/both-quality gates and original resource bounds remain required. This profile is not yet deployed or field-qualified and does not establish six-neighbour capacity. P01–P12 source surfaces are implemented. The successful matching short qualifier, two-hour/churn/natural-expiry run, both-quality account lifecycle, durable-report/crash-recovery acceptance, browser/device/network breadth, matched wire/cost benefit and final release/download acceptance remain open. The long run is ineligible until a matching short qualifier passes. Other work on the Macs must keep running; resource limits remain unchanged. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) and the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/c0f337d-current-delivery-checkpoint-20261018.json). ## Historical 44b21d6 checkpoint Exact `44b21d6` passed all nine required CI jobs, fresh 273-member consumption and guarded HTTPS deployment. Bounded rendition-neighbour discovery and cold-peer deadline allocation are deployed, with the existing deadlines and resource limits. The pilot selects 900 address requests per minute; the default remains 600 and the global capacity 2,048. Private state, permanent leases and the independent proxy were preserved. Deployment and finite-source cleanup passed independent fresh reviews. R30 remains RED after 36.188 s of measurement. All fourteen roles started, but one contributor recorded an 82 ms origin-only interval before recovering. The continuity requirement remains unchanged. A delayed session check and subsequent renewal timings fit the interruption; exact request/clock joins and the downstream cause remain unproved. All fourteen contexts and owned processes, profiles, tunnels and source were closed and independently checked. The defined P01–P12 source feature surfaces are implemented. Matching capacity, 7,200 s/22-churn, natural expiry, physical/browser breadth, difficult networks, matched wire/cost benefit and final release/download acceptance remain open. The long run requires a matching successful short qualifier first. v0.1.0 remains published and 0.2.0 the source candidate. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) and the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/44b21d6-current-delivery-checkpoint-20261016.json). ## Historical afbf052 checkpoint Exact `afbf052` passed all nine required CI jobs, fresh 271-member consumption and guarded HTTPS deployment. The TURN cache correction is deployed with its original limits; private state, permanent leases and the independent proxy were preserved. Verification-source cleanup passed independent review. R20 remains setup RED with zero measurement. All twelve intended peers had available TURN and peer-first mode in their latest preflight snapshots, but HTTP 429 admission refusals and delayed control bodies stopped qualification. The unchanged counter replay reproduces the observed 37 refusals above the shared 600-request window. Configurable operator request budgeting passes local checks; its default and the global limit remain unchanged. Idle control probes were healthy, without reproducing loaded-browser delays. All R20 owned cleanup passed; no previous acceptance verdict is changed. The defined P01–P12 source feature surfaces are implemented. Matching capacity, 7,200 s/22-churn, natural expiry, physical/browser breadth, difficult networks, matched wire/cost benefit and final release/download acceptance remain open. v0.1.0 remains published and 0.2.0 the source candidate. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) and the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/afbf052-current-delivery-checkpoint-20261016.json). ## Historical a416f7e checkpoint Exact `a416f7e` is deployed: nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38775128822), fresh 269-member consumption and normal HTTPS attestation pass. Private state, permanent leases and the EE proxy were preserved; owned verification-source cleanup passed all five guards with actual exit 255. Deployment is separate from field, capacity and release acceptance. Nostr plus an authenticated host-supplied resolver API is the selected account scope; no named website or human wallet is required. The public cross-Mac API trial passed its shared-cap/fencing checks. The focused LOW browser component passed seven gates in 74.412 s, including verified low media, real reservations, reload/new-key/spend retention, reconnect with upload off, fresh consent, serving-state Disconnect and LAST 10 MB Settings without fixture resume. The original both-quality/exhaustion trial remains RED with no high verified completion; the component does not replace it. Native iOS 26.5 Simulator Start/Home/return/Resume passed clock/pixels/frame59/61, zero media/page errors, consents off and cleanup. Return was still playing, so the physical stopped-video fault remains unreproduced. Original 4+10 R10 cap33 RED remains; new 3+11 R12 measured 97.691 s before runtime admission refusal, with healthy resource/reader gates and all cleanup. Cause remains unknown; the remembered-admission source correction passed 12 focused regressions and 137 swarm tests after the original-source regression RED. New CI/deployment and field repair remain unproved. No matching 300 s/7,200 s/22-churn, natural expiry, physical or matched-cost acceptance exists. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) and the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/a416f7e-current-delivery-checkpoint-20261015.json). The full P01–P12/37-review scope and final release remain open. ## Historical 5334091 checkpoint The pilot at this checkpoint was exact `5334091`, with all nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38741613596), 267-member fresh consumption and guarded deployment passing. The ordinary public check passed playback, contribution and low/high verified peer delivery over 60.034 s: two fragments/868,936 bytes, 5.8896% of receiver media payload. This does not establish sustained reliability, matched wire savings or cost. The separate forced-early Internet TURN check passed 90.043 s; natural expiry remains unproved. Reporting/forwarding and website authentication remain off. The latest fourteen-role attempt stopped at 33 observed processes against the unchanged 32-process M1 cap, before any measurement window. Endpoint/profile cleanup was recovered separately after the original M4 receipt-read failure; browser-context closure remains unknown. No 300 s qualifier or two-hour/churn acceptance exists. The cross-Mac account test identified a valid challenge rejected over a 16 ms clock difference; issuer-lifetime and explicit playback recovery corrections are in the unreleased source, pending field acceptance. See the [checkpoint record](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/5334091-public-and-account-checkpoint-20261015.json) and [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint). The full P01–P12 scope remains open; v0.1.0 is the published prerelease. ## Historical 3e52294 checkpoint Exact `3e52294` passed all nine required [CI jobs](https://github.com/forgesworn/relayswarm/actions/runs/38701249959), fresh 262-member package/standalone consumption and guarded pilot deployment. Normal HTTPS matched the 757,269-byte client to the image and read both fresh playlists. The pilot now uses relay-only ICE, TLS/TCP TURN projection and admission limit 32, with Nostr account allowances and no configured website resolver. Private state, permanent leases, identity and the independent EE proxy were preserved. Reporting/forwarding remain off. Owned verification-source cleanup passed all five guards and retained actual exit 255; capacity is unproved. A separate rebuilt diagnostic candidate passed the 90.031 s Internet TURN renewal cohort with 40 verified fragments/4,631,756 bytes, including 23 fragments and 2,656,252 bytes after the renewed transport boundary. Independent unchanged strict state machine replay also passes that same cohort. Two local Chrome pages and synthetic HLS/local rendezvous used genuine Internet TURN; the first local lease was 60 s against real 3,600 s credentials. This is not deployed public playback, exact-standalone Internet qualification, natural expiry or a product-fix claim. Earlier Internet and ordinary public REDs remain RED. The latest ordinary public journey measured **60.038 s**: playback and contribution passed, but the receiver verified zero peer fragments/bytes at either quality. Seven requests reached matching metadata and partial payload without EOF before closure. Four-player media errors/stalls were zero and all owned cleanup passed. The [result summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/3e52294-ordinary-public-20261015.json) retains the unchanged gates, resource limits and unresolved delivery cause. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#current-delivery-checkpoint) for exact image, client and retained deployment/Internet/cleanup provenance. The complete P01–P12 and 37-review-item scope remains open: ordinary public peer delivery, complete Safari/physical and hard-NAT journeys, host website resolver integration, natural expiry/reconnection and cross-device budget field evidence, fourteen-role capacity, 7,200 s/22 churn, matched wire/cost and immutable release/download acceptance. A separate completed 37-row ledger is not claimed. v0.1.0 remains the published release; 0.2.0 is a source candidate. The remaining checkpoint sections before the delivery checklist are historical. Their deployment and pending-work statements belong to their named source/date; they do not override the current 44b21d6 summary or reclassify retained REDs. ## Historical complete-playlist blocking reload candidate The example origin now supports bounded blocking reload for compatible complete live playlists, consistently across all renditions. The [API contract](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/API.md#example-origin-http-playlists) keeps raw media, peer deadlines, origin reserve and playback holdback unchanged. Independent review addressed shared directory-watch replacement/rearm races, observed-change reauthorisation and response-slot retention until transmission finishes. All 49 focused tests pass, including five actual loopback HTTP cases; worker reaping and group/birth absence passed. This focused guard has no resource sampler. The [source-check summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/blocking-playlist-reload-source-checks-20261014.json) records exact file hashes and scope. Exact `dd953eeffb36f16674b8afaa01d29cbe2a7f0deb` then passed one fully serial [paired browser journey](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/blocking-playlist-reload-paired-browser-20261014.json) with blocking reload enabled and disabled. Both passed low/high peer delivery and producer-restart sharing under the original guards. Candidate: six verified loads/3,245,444 bytes in 29.285 s; control: six loads/3,079,252 bytes in 28.715 s. The candidate served 17 blocked reloads, with no blocked requests or watchers left after actual server close. All seven worker and six supervisor cleanup flags passed; the original resource bounds held. Each donor stalled once in both runs; baseline/consumer had no stalls and all fatal/native errors were zero. Candidate players each recovered from one HTTP 503 playlist error during restart; control players had none. Its cause remains unproved and is retained as a transient restart risk. This single injected, headless loopback pair does not establish a reliability improvement, causality, ordinary public/physical acceptance or sustained benefit. Required hosted CI and the remaining field gates are separate from these local results. The preceding exact `fc39e32` check passed eight of nine required jobs in [CI 38640084885](https://github.com/forgesworn/relayswarm/actions/runs/38640084885). The broadcast failed initial low-quality peer delivery, before high-quality or restart checkpoints. Healthy connections and late donor availability did not establish a runtime fault or a polling cause. That failure remains separate from the older all-green 7a check below; this capability is not yet a proved fix. Release, deployment and the remaining field gates stay open. ## Earlier source checkpoint: 7a Exact `7a5de06a97baf14c00e3a420944b75a730042c85` passed all nine required jobs on attempt 1 of [CI 38625083620](https://github.com/forgesworn/relayswarm/actions/runs/38625083620); optional soak skipped. The injected loopback broadcast passed both qualities and restart sharing: six verified loads/3,240,180 bytes, including one high CC1 fragment/791,856 bytes with 1,291.1 ms deadline spare. One stall per donor and the absence of full broadcast API/OS cleanup proof remain explicit. The optional credential adapter was off; this PASS does not repair or relabel da9 RED. Fresh exact-7a offline production-only package/consumer/ESM passes cover 239 exact-source members, eleven imports, installed CLI, sequential ledger replay and independent-process verified native/fallback. Assets remain unpublished; earlier smoke failures and source histories are retained. Mock-issuer browser renewal passes separately. Actual existing-service forced-renewal R3/R4 remain RED: R3 lacks the failed sample; R4 records three constructor refusals under the original two-lifetime-PC cap after initial glare. Refresh 2/new 3,600 s credentials were accepted with consent/spend retained, but no post-renewal transport/media or strictly selected positive TLS sample was proved. Owned client/fixture cleanup passed; shared allocation absence was not inspected. No runtime-failure or server-quota cause is inferred. The separate M4 Safari 26.6.2 tooling check returned driver ready, then timed out creating a session before any page/application test. Owned driver, wire workers and scratch cleanup passed; exact session destruction remains unknown. The M4 resource observation was before the blocked request, not continuous. The [7a summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/7a5de06-ci-consumer-and-renewal-checkpoint-20261014.json) retains exact hashes and scope. Last-attested pilot 8f is unchanged; ordinary sharing, complete Safari/physical, sustained/churn, expiry/reconnection, wire/cost, immutable release/download and full P01–P12 acceptance remain open. Earlier source `a2c99a9` passed eight of nine required CI jobs; its loopback broadcast test recovered playback after producer restart but failed the unchanged new-discontinuity peer-fragment gate. The [retained failure](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/a2c99a9-ci-restart-failure-20261014.json) and [current observations](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#earlier-source-checks-restart-sharing-failures) are separate from the deployed checkpoint below. No playback-latency or deadline change has been made to increase sharing. The instrumented `d283071` run also failed the unchanged sharing gate. Native request timings confirm matched donor requests started after receiver completion; the [summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/d283071-ci-observations-20261014.json) separates that result from its macOS cancellation-test precondition correction. ## Cached TURN credential correction The follow-up client preserves its original lease when the credential endpoint returns the same cached material. It does not rebuild peers or increment the refresh counter, and uses the existing bounded retry. One deterministic da9 reproduction is retained; the corrected eleven lifecycle and four page-VM cases pass with worker/group/birth absence. The focused guard has no resource sampler. Exact-7a CI/package and separate RED Internet-renewal attempts are recorded above; the [correction summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/turn-cached-lease-fix-20261014.json) does not replace the source-bound da9 evidence below or close field acceptance. ## Optional TURN renewal candidate Exact `da9ac9202fd8794a68d6d707a1ab5d8109bbbb34` completed [CI 38620173084](https://github.com/forgesworn/relayswarm/actions/runs/38620173084) with eight required PASS/media FAIL; optional soak skipped. The unchanged post-restart peer gate remains RED despite recovered origin playback. All 31 consumer discontinuity-1 decisions had zero peer budget: 1,159–1,202 ms playable ahead versus the unchanged 2,000 ms reserve. Donors were ahead in the retained object timings; this does not establish a correctness repair or justify a playback-policy change. One stall per donor is retained; broadcast recorder cleanup does not prove actor/API or OS reaping. The off-by-default [credential adapter](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/FIELD-TEST.md#optional-turn-credential-renewal) has eleven server/owned-HTTP, ten lifecycle and four page-VM passes. Separate real Chrome mock-issuer rollover fixtures pass locally (47.010 s) and in CI (50.433 s), preserving consent/spend and verifying new-swarm peer payload, link/restart/reset and scoped cleanup. They use 15 s fake credentials and loopback host WebRTC, not an actual TURN relay. Existing-service Internet renewal was pending at da9; the later exact-7a RED attempts appear above. Sustained expiry/reconnection remains unproved. Exact-da9 fresh offline production-only consumption passes all 237 package members, eleven documented imports, installed CLI, sequential durable ledger replay, independent-process native/fallback and rebuilt ESM. The first smoke failure remains separate; corrected R2 passes do not rewrite it. Assets remain unpublished. The pilot is still 8f, v0.1.0 remains published, and all P01–P12 acceptance remains open. See the [da9 summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/da9ac92-ci-and-consumer-checkpoint-20261014.json) for exact assets, CI and scope limits. ## Earlier completed CI source checks: 07 Exact `07ea96becce44fec6baa0b41f7719e0e99ee4031` passed all nine required jobs on attempt 1 of [CI 38616043417](https://github.com/forgesworn/relayswarm/actions/runs/38616043417); the optional soak was skipped. The broadcast diagnostic passed four checkpoints with six verified loads/3,125,876 bytes. All 239 observation rows and four final extractions were retained without drops/unknowns/unlabelled objects. Each donor recorded one stall; baseline/consumer recorded none, with zero fatal/native/append failures. Declared injected/headless loopback fixture scope applies, and the raw receipt does not prove full actor/API or OS cleanup. The earlier abb Windows failure and 426 media failure remain. Fresh package proof belongs to 426; fresh 07 package/consumer/ESM has not run. The pilot remains 8f and published release v0.1.0; all P01–P12/release acceptance stays open. Exact 07 retains the static TURN lifecycle gap below; its CI does not qualify the later optional renewal candidate. See the [07 summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/07ea96b-ci-checkpoint-20261014.json). ## Earlier source checks: 426 [Exact 426 CI](https://github.com/forgesworn/relayswarm/actions/runs/38607468217) finished with eight required jobs passing and the media job RED at its 30 s first low-quality peer-load gate. Fresh production-only package/ESM, eleven imports, durable ledger replay and installed native/fallback checks pass at that exact source. Later candidates maintain bounded queued/accepted HAVE test observations; their separate results above make no playback repair claim. A separate injected Mac diagnostic passed in 33.759 s: six total peer loads/ 3,107,076 bytes, with only the last high object observed after restart and 366.123 ms deadline spare. Its Chrome/platform/injection differ from failed CI. One existing shared-service TLS-relay check passed 90.005 s measured/105.150 s whole, with 34 complete verified peer fragments/3,956,272 receiver bytes. Both pages had positive selected TLS pairs in 67/91 samples, constructed four PCs in total, and had no active PC in the final seven samples. Video/time continued; this is not continuous TLS, both-quality, physical, hard-NAT, server quota or matched-cost acceptance. Client cleanup and separate issued-credential removal passed; the shared service and network rules were unchanged. See [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#earlier-source-checkpoint-426-on-14-october-2026) and the [scope summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/42608f7-source-and-tls-checkpoint-20261014.json). Static ICE configuration has no supported credential renewal: the observed 3,600 s issuer TTL does not prove fresh allocations/reconnections throughout the 7,200 s goal. Existing-allocation behaviour at expiry is unproved; the short TLS pass does not close this lifecycle gate. The deployed pilot remains 8f; all P01–P12 and release gates remain open. ## Historical deployed checkpoint: 8f The deployed application is `8f482b4528a671acfe9f1afc336cce5743aaaefd`. All nine required jobs passed on attempt 1 of [CI run 38578315372](https://github.com/forgesworn/relayswarm/actions/runs/38578315372); the optional soak was skipped. Fresh production-only package/standalone proofs and guarded deployment passed, preserving private state and the independent EE HTTP/1.1 proxy. The pilot offers Nostr; a host supplies its website resolver. Exact assets and receipts are in [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#historical-deployed-checkpoint-8f-on-14-october-2026) and the [8f summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/8f482b4-current-checkpoint-20261014.json). The ordinary 60.119 s cross-Mac check passed playback but failed contribution and both-quality peer payload, with zero peer channels/bytes. Six dials reached remote SDP installation and ICE checking before timeout. The 120 populated whole-journey budget geometries matched the existing formula. Original cleanup failures, later exact absence/removal and successful source cleanup remain separate. A further interpreter capture refused before workload because its remote clock was 68 ms ahead; no clock or freshness limit changed. The temporary SSH TURN fixture was removed after its scoped test. Fresh Till metadata found no known running TURN service on that host while the image remains cached. The later existing shared-service TLS check above is separate; hard-NAT, provider-policy and full field acceptance remain open. No current same-topology 300 s qualifier, two-hour/churn, complete physical/Safari, hard-NAT, matched wire/cost or immutable-release/download pass exists. Full P01–P12 remains open, PR 8 is open and v0.1.0 remains published. Documentation updates do not change the deployed application source. No separate 37-row ledger was located and no 37-item completion is asserted. ## Previous deployed checkpoint: df51 The deployed application is `df51cbed1ebb3bd09ef1b521c451d6b47989a664`. All nine required jobs passed on attempt 1 of [CI run 38554223220](https://github.com/forgesworn/relayswarm/actions/runs/38554223220); the optional soak was skipped. Fresh production-only package/standalone checks and guarded pilot deployment passed. Both shared account methods are implemented; the pilot offers Nostr sign-in, while integrating websites supply their own authenticated account resolver. Private state and the independent EE H1 proxy were preserved. Exact assets and evidence are in [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md#previous-deployed-checkpoint-df51-on-14-october-2026) and the [df51 summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/df51cbe-current-checkpoint-20261014.json). The ordinary 60.110 s check passed playback but failed contribution and both-quality peer payload: no channel opened and verified peer bytes were zero. A separate 60.027 s heap/native-stats diagnostic observed positive ICE check request counters and zero replies in retained snapshots. It narrows the failure stage, without proving its cause or ordinary qualification. Original M4 cleanup failure/unknown, later exact absence/removal and successful source cleanup are kept separate. No production connectivity fix is established. The full P01–P12 checklist remains open. No current same-topology 300 s qualifier, two-hour/churn, complete physical/Safari, hard-NAT, matched wire/cost or release pass exists. Earlier references to 37 review items have no separately located row-by-row ledger; no 37-item completion is asserted. PR 8 remains open and v0.1.0 remains the published RelaySwarm release. ## Previous deployed checkpoint: 2dd The deployed application checkpoint is `2dd156e64f86e6f18b616e7d87159aee1c43eac2`. All nine required jobs passed on attempt 1 of [CI run 38525990386](https://github.com/forgesworn/relayswarm/actions/runs/38525990386). The optional CI soak was skipped; it is not a new sustained pass. The normal-TLS public client is 734,604 bytes, SHA-256 `34259c97f1317c3ae4668c2634df6d57287ca8a40b4c8a249088c0400f3c1a61`; the image is `sha256:200807d127f0e8cac781b1d9bd36ddfb0541285cc3eae2db96590d5410dc189c`. Guarded deployment preserved publisher identity and private state. The permanent HTTP/1.1 proxy retains independent EE provenance; a later documentation commit does not change the recorded application source. The ordinary four-role public check remains **RED** over 60.049 s: playback passed, but contribution and both-quality verified payload failed. The receiver accepted 15 low-quality loads/3,169,304 bytes and no high-quality peer payload; both contributors retained consent/serving, while the high donor uploaded zero. All 358 fixed-route controls finished HTTP 200/H1; HTTP 200 does not prove an admitted response body. There were no new measured stalls, fatal/native/page errors or zero-frame intervals. The high donor's earlier 1,247 ms stall remains recorded. Actor/provider/controller/outer and actual source-cleanup-v2 proofs passed; source exit 255 is retained. No connectivity cause or fix was established. The fourteen-role R7/R9/R10/R11 attempts remain RED: respectively an unknown resource-probe timeout, process-limit failures under their original declared limits, and zero-peer readiness before measurement. Safari 17 R2/R4/R5 remain bootstrap-only; physical iPhone USB R2 produced no page evaluation and unknown lockdown closure. Original cleanup failures and later exact-ownership recovery are recorded separately. No new long, physical, hard-NAT or cost pass exists. See [current 2dd evidence summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/2dd156e-current-checkpoint-20261014.json) and [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md) for exact assets, counters and boundaries. The full P01–P12 and 37-item scope remains open. ## Previous f393 checkpoint The previous deployed application checkpoint was `f393abf3d55215bdf58241a4a2af74245d646117`. All nine required jobs passed on their first attempt in [CI run 38511479806](https://github.com/forgesworn/relayswarm/actions/runs/38511479806). The optional twelve-viewer CI soak was skipped, not a new sustained pass. The permanent HTTP/1.1 proxy retains independent EE provenance. The normal-TLS served client is 734,441 bytes, SHA-256 `4fdb2861b08f42e4c82788a5940e0b2b436be52af84bc264998d41cf81938fcb`. Fresh production-only package and standalone ESM checks passed; exact image, package and source hashes are recorded in [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). These local assets remain unpublished and do not prove downloaded-release acceptance. [Both ordinary cross-machine short checks](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-ordinary-cross-machine-20261014.json) passed playback, contribution and both-quality verified payload. Forward M1 contributors → M4 receiver measured 60.050 s: 28 loads/12,763,132 bytes (13 low/2,732,956; 15 high/10,030,176), with zero link closures and one outgoing dial superseded by a crossed offer. Reverse M4 contributors → M1 receiver measured 60.023 s: 17 loads/8,179,316 bytes (seven low/1,476,364; ten high/6,702,952). It retained two initial donor dial timeouts after admitted remote SDP installation/ICE checking, two receiver request-timeout link closures followed by replacement connections, and two donor channel-error closures. Numeric PC IDs do not identify remote roles; these records do not establish the underlying routing or request-budget cause. No connectivity fix is claimed. All roles recorded zero stalls/fatal/native/page errors or frame-freeze intervals, and both contributors retained consent/serving in each run. Forward controls: 383 HTTP/1.1 responses, 382 finished and one commitment GET cancelled after HTTP 200 headers. Reverse controls: 387 HTTP/1.1 responses, 386 finished and one admission verification still pending after HTTP 200 in the final observer snapshot; its terminal result is unknown. HTTP 200 does not prove an admitted response body. Each run retained a pre-measurement media abort. Start/upload consent was trusted; dropdowns were programmatic, with no native-menu claim. No extra RTC/media/permission flags or whole-heap inspection were used. All actor/provider/controller cleanup passed. Source cleanup v2 matched stable identity, helper/input pins and start/cleanup journal receipt hashes; the reverse review did not independently reread the raw remote journal. VPN Connected was observed before and after each run only, not continuously. Bounded local transport metrics are now deployed; they add observation without changing transport policy. The earlier ordinary sharing reds below remain unexplained. [Distributed fourteen-role qualification](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f393abf-distributed-qualification-20261014.json) remains RED; sustained 7,200-second/22-churn, physical/native-input, hard-NAT, matched field-benefit, cost and immutable-release gates remain open across the full P01–P12 and 37-review-item scope. The previous deployed 0e checkpoint passed its own nine-job first-attempt [CI run 38500343145](https://github.com/forgesworn/relayswarm/actions/runs/38500343145), production-only package and standalone checks. The ordinary 60.013 s public check passed all three playback/contribution/verified- peer gates with 19 loads/6,285,968 peer bytes across both qualities and zero recorded stalls/fatal/native/page errors. The [180.015 s renewal check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/0e68847-public-renewal-180-20261014.json) passed all four declared gates with 90 peer loads/39,608,780 bytes (45 low loads/ 9,488,548 bytes; 45 high/30,120,232). Each contributor retained one completed pre-measurement stall (550/2,372 ms); no new stall occurred during measurement. All 1,009 controls finished HTTP 200/H1 before cleanup. Passive sampled session, peer-set/link counters, consent and monotonic quota held across successful own- ticket renewal for all three peer actors; direct PC object identity is not proved. Programmatic dropdowns/trusted Start and upload, one browser/four contexts and host/host links bound this evidence. Setup/nonfatal media aborts remain retained. The later cross-machine public HLS check was red for sharing over 60.060 s: playback progressed without recorded stalls/fatal/native/page errors, but both contributors uploaded zero and the receiver opened zero links/received zero peer bytes after two dial timeouts. Its 323 controls ultimately finished HTTP 200/H1; verification status alone does not prove admission. No ICE/transport cause is established. Separate loopback-origin raw RTC exchanged 8,192 bytes each way cross-machine but failed in both same-M4 topologies; this does not prove public- origin HLS or a NAT class. A separate public-origin raw M1-offer → M4-answer case passed in 7.972 s: both exact 0e public clients exchanged one verified 8,192-byte message each way, gathering completed and each SDP had one mDNS-form and one IPv4-form candidate. Both apps remained unstarted with no media/admission/ upload consent, and all cleanup passed. M4 VPN remained connected in a read-only 03:14:35 UTC receipt; no settings changed or mDNS/VPN cause was proved. The HLS sharing red remains separate. A separate reverse M4-offer → M1-answer raw case passed in 7.566 s, again with one hash-matched 8,192-byte message each way, complete gathering and one mDNS-form/one IPv4-form candidate per actual SDP. Apps remained unstarted with no media/admission/upload consent; all cleanup passed. Neither raw case proves the hosted HLS rendezvous/admission journey or its failure cause; investigation continues. All owned completed-run browsers/readers/sources are closed; the installed app awaits ingest. Fourteen-role/7,200-second/22-churn, complete physical journeys, hard NAT, cost and immutable release/download gates remain open. The earlier 0e ordinary restored-VPN cross-machine HLS check remained sharing-red for 60.020 s: four high-only verified loads/2,697,988 bytes, low zero, despite both contributors retaining consent/serving; playback and all recorded error/ stall/withdrawal counts passed. High's 4,038,428 accepted/reserved bytes are not receiver delivery or wire bytes. A preceding whole-heap-instrumented 60.074 s check on the same finite source passed with 22 loads/10,151,436 bytes across both qualities. These sequential results establish no heap/VPN cause. Separate same-M4 raw RTC passed with the owner-disconnected VPN (6.517 s/8,192 bytes each way), then failed after restoration (27.113 s); it is not HLS/admission/NAT proof. Both ordinary-run VPN observations were Connected; all browser/provider/source cleanup passed. Named receipts and precise counters are in [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). Documentation checkpoint `8c09478` passed all nine required CI jobs in [run 38506350320](https://github.com/forgesworn/relayswarm/actions/runs/38506350320); that documentation-only checkpoint did not change the then-deployed 0e runtime. The later f393 deployment above includes bounded local transport metrics; see [integration](https://raw.githubusercontent.com/forgesworn/relayswarm/main/INTEGRATION.md#metrics). All earlier reds and full scope remain. The earlier deployed application was `fa79c2260431cf7901921fab4eaca251c4988f4b`, with independent EE proxy provenance and all nine jobs green in [CI run 38496983011](https://github.com/forgesworn/relayswarm/actions/runs/38496983011). The [fresh public short check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/fa79c22-permanent-public-short-20261014.json) passed all three gates over 60.011 s with 13,206,248 verified peer bytes at both qualities and zero recorded stalls/errors/withdrawals. All actors/source closed. M4's zero-churn local check still hit the admission address cap and completed no peer links; raw two-context RTC also failed. The later 0e renewal evidence is recorded above; fourteen-role, sustained, device/network/cost and release gates remain open; see [status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). The preceding deployed checkpoint was `ee1510d429ac85f3738c03f10a09b753ec4eb037`, with permanently committed HTTP/1.1 and all nine required jobs green in [CI run 38492003110](https://github.com/forgesworn/relayswarm/actions/runs/38492003110) after one failed-job retry. The [fresh ordinary short check](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/ee1510d-permanent-public-short-20261014.json) passed all three gates over 60.014 s with 13,188,200 verified peer bytes across both qualities. The high contributor retained one 143 ms pre-measurement stall; all owned actors/source were cleaned. A separate fourteen-viewer local check stopped red after admission 429s blocked ticket renewal; the new heartbeat optimisation still needs fresh cohort/deployment acceptance. Two-hour, physical, varied-network, cost and release gates remain open. See [current status](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/STATUS.md). The preceding deployed checkpoint was source `2e1bdeb724eb45e37f7b97604e4f396a73985719`. All nine required jobs passed in [CI run 38483497575](https://github.com/forgesworn/relayswarm/actions/runs/38483497575); the optional long soak was skipped. Fresh offline production-only consumption passed ten documented imports, exact packaged demo/renewal/recovery bytes, the installed CLI, separate-process verified native transfer and HTTP fallback. The unpublished tarball contains 190 files, is 847,937 bytes and has SHA-256 `21103ad4dc0701ed41d07f4393560053a480963995bbe4682bfda76bf4b0c0e1`. The standalone ESM remains 114,201 bytes, SHA-256 `01de11837fbd08098bf98b6e8be945866ef766f76629030fec89de2318170d19`. Local artifacts do not prove downloaded-release acceptance. The guarded app-only deployment passed the 51-file UID-1000 image preflight, clean writer drain, stable identity/private lease/shared-service preservation and normal-TLS exact-client/fresh-playlist attestation. Image is `sha256:e73b4a0bb57ca37950abab2ae5c9f22c63a1ab4128880b9c85883d438701d87a`; public client is 728,315 bytes, SHA-256 `c264287acad81090c8952f99946f75f844e8f5fa718e907899dc77cacf04ef59`. Reporting remained off. The maintained no-store real-HTTP renewal regression passed, but the deployed ordinary four-role Chrome 155.0.8059.40 check recorded red for contribution and verified peers: 60.013 s of requested video/native-audio decode passed, with zero fatal/native/page errors or stalls, while both contributors uploaded zero and the receiver verified zero peer bytes. Authority-expiry timing is retained; the underlying missing-response cause remains unproved. A subsequent sequential comparison used Chrome 155.0.8059.41 and the same finite source/client. Adding only `--disable-http2` passed all three short gates in 60.009 s: the receive-only actor accepted 2,806,464 verified peer bytes at both qualities, and both contributors retained consent/serving. Successful fixed-route responses reported HTTP/1.1; the high contributor's one stall is retained. A fresh default-browser check on the same source measured 60.015 s: playback passed but both contributors withdrew, uploaded zero, and the receiver verified zero peer bytes; successful requests used HTTP/2. These sequential same-desktop checks isolate a useful transport diagnostic, not a proven HTTP/2 implementation cause or default production acceptance. No quota resets, automatic reconsent, fake media or permission overrides were used. Browser/provider cleanup passed in all three windows. The independently bounded source remained Root-owned and separate from observer cleanup. Named evidence: `artifacts/public-cdp-2e1bdeb-run-20261014`, `artifacts/public-cdp-2e1bdeb-http1-diagnostic-r2-run-20261014` and `artifacts/public-cdp-2e1bdeb-http1-window-default-run-20261014`. The later temporary server-H1 trial used ordinary Chrome 155.0.8059.41 with no browser transport override and unchanged app/client source. Its 60.009 s measurement retained a partial red result: playback passed and both contributors kept consent/serving, but only high delivered peer media (10,082,816 verified bytes in 15 loads); low delivered zero. Contribution and both-quality peer gates therefore failed. All 385 successfully completed fixed-route responses in the four pre-cleanup CDP ledgers reported HTTP/1.1, with no ledger records dropped. Fatal/native/page errors and sampled zero-frame intervals were zero; the high contributor's one stall is retained. This short diagnostic does not establish sustained benefit, a named HTTP/2 defect or permanent H1 readiness. The first trial preparation failed before proxy mutation because the image's file-capability binary could not execute with all capabilities dropped. That setup red remains retained. The isolated r2 preflight passed after copying and hash-verifying the same public binary bytes without capability attributes in private tmpfs; non-root/no-network/no-shared-mount/cap-drop/NNP bounds stayed in place. This setup correction is not a product or transport fix. Browser/provider cleanup passed despite the overall red outcome. Explicit controller finish and audit restored the original H1/H2 file and complete runtime at the same inode, proved the watchdog absent, and separate source cleanup removed the exact owned source (retained exit code 255). Named evidence is `artifacts/public-cdp-server-h1-trial-r2-run-20261014`, `artifacts/caddy-http1-trial-2e1bdeb-r2-preparation-20261014` and `artifacts/public-proxy-http1-trial-source-2e1bdeb-r2-preparation-20261014`. No permanent protocol change was made or authorised by this partial trial. A subsequent r3 trial retained ordinary Chrome 155.0.8059.41 and the same application/client, with only temporary server H1 and bounded read-only metrics. All three gates passed in 60.010 s: the receive-only actor accepted 13,205,308 verified peer bytes in 30 loads, comprising 3,151,444 low and 10,053,864 high bytes. Both contributors kept consent/serving throughout; fatal/native/page errors, stalls, sampled zero-frame intervals and contribution withdrawals were zero. All 407 successfully completed fixed-route CDP responses reported HTTP/1.1. No browser transport override, quota reset or reconsent was used. Browser/provider cleanup, controller finish/audit and exact source removal passed. The original H1/H2 file/runtime and inode were restored and the watchdog was absent. Evidence is retained under `artifacts/public-cdp-server-h1-trial-metrics-r3-run-20261014`, `artifacts/caddy-http1-trial-2e1bdeb-r3-preparation-20261014` and `artifacts/public-proxy-http1-trial-source-2e1bdeb-r3-preparation-20261014`. This one-minute ordinary-browser result supports selecting H1 as a deployment mitigation; it does not establish a specific HTTP/2 implementation fault or replace the r2 partial red. Permanent H1 has not been deployed: it still requires a new clean commit, all nine exact-source CI jobs, guarded actual application of the proxy change, and fresh default-browser short and full two-hour gates. Decoded audio bytes do not prove audible output. Prior red outcomes, sustained load, full physical/hard-NAT/cost gates, v0.2.0 publication and downloaded-release acceptance remain open. The earlier deployed checkpoint is source `f9990b36956282f3d4e849b55bd64a79eb440151`, whose nine required jobs passed in [CI run 38449139246](https://github.com/forgesworn/relayswarm/actions/runs/38449139246). The earlier a023 two-hour load/churn run retains its separate source and scope. The later proxy-only protocol correction passed pinned-binary validation and a guarded live reload, while subsequent public contribution remained red. The earlier candidate checkpoint `cee92281b20aa5e60fc39d0e0cb2a368daa83747` passed all nine required jobs in [CI run 38471147105](https://github.com/forgesworn/relayswarm/actions/runs/38471147105). Its fresh offline production-only package/all ten documented imports, exact packaged demo/recovery, installed CLI separate-process verified native transfer and peer-absence origin fallback passed. The tarball is 823,201 bytes, SHA-256 `b847aa0d57f68975aa69bdc70589f1aa5066b757e748001ccb7bb967853a3d3a`; the standalone ESM is 114,201 bytes, SHA-256 `01de11837fbd08098bf98b6e8be945866ef766f76629030fec89de2318170d19`. These local artifacts are unpublished; the optional soak at this head was skipped. Its runtime/dependency inputs were unchanged from f999/6b2, whose original timed-fixture CI failure is retained separately. The passive f999 CDP observation retained a 60.015 s playback pass with contribution/peer failure and no proven transport cause; its owned-resource cleanup passed, and it does not close sustained acceptance. The [13 October acceptance summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/current-source-acceptance-summary-20261013.json) retains receipt identities and limits. v0.2.0 release and final downloaded-asset acceptance remain pending; passing CI does not close the full checklist. The [f999 public field summary](https://raw.githubusercontent.com/forgesworn/relayswarm/main/spikes/results/f999-public-field-summary-20261013.json) records the later short/partial-long, TCP relay and Android checks separately. ## Delivery checklist Current state cells below use the checkpoint above; historical component evidence retains its narrower scope. A passing component check does not close the other requirements for production acceptance. | ID | Requirement | Evidence required | Current state | |---|---|---|---| | P01 | Reliable live-edge peer delivery and adaptive quality | Unmodified live playlists, simultaneous viewers, quality changes and bounded fallback; paired origin baseline | 21 October, `140c256`: nine-job CI, 286-member consumption, guarded deployment and its review pass. Short qualifier R66 GREEN, 16 of 16 gates including `each4BothQualityPeer` (302.823 s, 1,250,000 B/s contributors, relay-only TURN over TLS/TCP). Receivers used 31.5% less origin traffic than matched baselines; total egress across the origin and TURN hosts rose by roughly 85 to 100 MB, and marginal cost is not determined. On deployed `1d54538` (v0.2.1, runtime identical apart from version fields) R68 is RED, 15 of 16 gates: `each4BothQualityPeer` failed (receivers switching to high got no high-quality peer segment; R66 had passed it by one segment). The sustained 7,200 s/churn run (Item 5) is RED and stopped by decision: harness faults in R37 and R38, and no matching qualifier on `1d54538` | | P02 | Resolve intermittent MSE playback failure | Reproduction or supported diagnosis, regression and repeated concurrent hosted playback without fatal media errors | Exact later-retained sparse-AAC bytes reproduce the low-only failure; recovery restored video/audio in 403 ms with the original fatal retained; f999 maintained regression, required CI and repeated short concurrent public playback pass without fatal/native errors; original missing bytes do not establish historical causation, and sustained contribution remains separately open | | P03 | Wider HLS media support | Signed exact-context tests and actual playback for fMP4, alternate audio, supported encryption, parts/deltas and mixed variants | Current Chrome fixture and exact-source CI evidence pass; physical/browser coverage is recorded separately under P12 | | P04 | Production admission and adversarial resource defence | Key-bound expiring tickets, revocation, bounded issuance and verification; flood/exhaustion/withholding regressions | Exact3f selects four demo neighbours and address budget900, retaining SDKdefault6/default600/global2048. Historical R54 admission checks pass with0refusals/unknowns and provider peak731/alignedminute; full field capacity remains unqualified | | P05 | Durable operational measurements | Private persistence, cumulative-report deduplication, restart recovery, explicit reporting consent and bounded retention | Real-browser acceptance PASS on `3f706a9` and again on `140c256` (natural expiry after 303,923 ms; reporting restored OFF; independent review). Other browser/load requirements remain under P12 | | P06 | Persistent upload budgets and their device/account scope | Atomic persistent reservations, failure handling and actual reload/multiple-tab tests; a shared account cap across devices; uploading still requires new consent | Nostr and authenticated host-supplied account API supported; Nostr-only pilot valid, no named website/human wallet required. Public cross-Mac shared-cap API PASS and focused LOW lifecycle PASS (74.412 s/seven gates) cover low verified media/reservations, reload/new key/spend, reconnect OFF/fresh consent and state withdrawal. The 3 MB both-quality shared-cap lifecycle is RED and open on `140c256` (21 October): low verified peer media reached the receiver, three accepted 720p reservations (659,128, 673,604 and 659,692 B) were charged without completing as verified peer media, and the fourth was refused as exhausted at 2,625,232 of 3,000,000 B. Same class as the a416f7e third run; a design limitation under relay throughput (about 255 KB/s best link), one high-quality holder and a 3 MB cap, with the allowance behaving as documented. No re-run on this source. On deployed `1d54538` at a user-chosen 6 MB starting allowance, high-quality verified peer media passed (seven of eight 720p reservations) but the lifecycle stayed RED at natural exhaustion: each page's cap snapshot refused locally before the account could. P06 is stopped by decision. Desktop Firefox 152.0.6 and Safari 26.6.2 explicit-upload and reload-retains-usage checkpoints pass within desktop scope. Complete shared-media/physical acceptance remains open | | P07 | Safe broadcaster crash recovery | Concurrent-process exclusion, forced process termination/restart, stable identity, monotonically separate generations and private state | `140c256` actual parent-crash test PASS with independent native review (21 October), following the earlier `5f2ece0` pass. Guardian/host catastrophe still requires operator inspection | | P08 | Delegated signing and stream advertisements | Author-scoped expiring delegation, rejection/revocation tests, complete signed NIP-53 live/ended advertisements and host endpoint policy | Scope/revocation/discovery and exact-source CI evidence pass; caller-owned author trust/revocation freshness and operational advertisement policy remain explicit host responsibilities | | P09 | Native application delivery | Installable executable entry point, independent-process native transfer, verified HTTP fallback and clean-consumer package test | Exact `140c256` fresh 286-member consumption/install/import/native/HTTP smoke checks pass. Consumer semver resolutions differ from root lock; standalone ESM is root-lock bound. Final publication and downloaded-release acceptance remain open | | P10 | Protocol compatibility | Maintained wire/commitment specification, conformance fixtures and successful independent-client journeys | Published Kit v0.5.0 and actual independent public-SDK/browser author/delegate/adversarial journeys pass, including exact-source CI; standards acceptance is not claimed and physical integration is recorded under P12 | | P11 | Current release and production deployment | All required checks on the final source, immutable release assets/checksums, exact deployed revision, fresh media and rollback/restart verification | Exact `140c256` nine-job CI, 286-member consumption, guarded deployment/HTTPS with independent review, P05 and P07 pass; private state, permanent leases and proxy preserved. v0.2.1 is published from merge commit `1d54538` (nine-job main CI, 287-member consumption, downloaded assets verified) by owner decision while Item 5, P06 and Safari 17.6 are RED; the merge commit is deployed with guarded deployment/HTTPS and independent review (app `ce410033`). Final acceptance remains open | | P12 | Real-world acceptance | Physical Android/iPhone, Safari/Firefox, separate networks/hard NAT, hours of load/churn/cost measurements and authorised OBS/external-platform playback | 21 October, `140c256`, macOS arm64 desktop scope (one 1,800 s finite source, three owned Chrome 155 actors per browser, relay-only TURN over TLS/TCP): Firefox 152.0.6 PASS and Safari 26.6.2 PASS (first Safari pass), all six checkpoints each; Safari 17.6 RED (no verified peer download in 45 s, no selected candidate pair, cause not determined, not retried). R66 short qualifier GREEN on `140c256`; R68 RED on deployed `1d54538` (15 of 16, `each4BothQualityPeer`). Sustained 7,200 s/churn/natural-expiry (Item 5) RED, stopped by decision; marginal cost not determined. Physical iPhone (unavailable), physical Android and device Safari/Firefox (need the owner), hard NAT and a separate network (need another network) remain open. Prior Simulator/account/LOW lifecycle/Internet TURN passes retain original scopes | ## Evidence rules The existing pilot is a useful deployment starting point. A waiting page or a running encoder does not prove media playback. Emulator and loopback receipts do not prove physical-device or difficult-NAT behaviour. Peer media bytes are not net wire-data or financial savings. A NIP draft and related codebase are not proof of external standards acceptance or protocol interoperability. Record the exact source, browser/device, topology, measurement window and receipt path for each acceptance result. Preserve failing results until their cause and regression are established. A completed duration can still fail its acceptance gate. Connection counts do not establish accepted media payload. Temporary-policy diagnostics do not establish default-device behaviour. Update this table as evidence arrives; do not mark the overall work complete while a required entry remains open. --- Source: [docs/REALTIME-TRANSPORT.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/REALTIME-TRANSPORT.md) # Experimental real-time transport The source-only `relayswarm/realtime-peer` export carries opaque datagrams over an explicitly selected WebRTC peer. It reuses `RelaySwarmSession` wire version 3's signed pairwise NIP-44 signalling with a separate `webrtc-live` transport token. HLS `PeerLink` and the loader keep their ordered reliable protocol unchanged. This module is not included in the immutable v0.2.1 release or its browser bundle. This is a transport component for a new call adapter, not an SFU, codec, media-key service or room implementation. The application must authenticate and encrypt media before sending it, authorise recipients, reassemble bounded fragments, enforce frame deadlines and request video recovery after loss. DTLS protects each link but does not by itself hide media from a forwarder which terminates that link. No logging, recording, discovery announcement, credential issuer or automatic peer/service selection is added here. ## API ```js import { RealtimePeer } from 'relayswarm/realtime-peer'; // pool and session are host-selected and connected/started already. // Resolve the selected peer's key through the application's trust policy. const peer = new RealtimePeer({ session, peerPubkey: selectedPeerPubkey, initiator: true, iceServers: deviceSelectedIceServers, iceTransportPolicy: 'relay', onDatagram: bytes => admitToBoundedFrameReceiver(bytes), onClose: reason => handleTransportClosure(reason), signal: cancellation.signal, }); await peer.start(); // also available as peer.ready const sent = peer.send(alreadyEncryptedFragment, { deadlineMs: performance.now() + 100, }); if (!sent) requestApplicationRecovery(); // Bounded counters and generic states; no SDP, addresses, credentials or payloads. const counters = peer.snapshot(); peer.close(); ``` Construct the receiving side with `initiator: false` and its explicit sender key, then start it before the initiator. Both sides can be given the same `requestId` (8 to 64 URL-safe ASCII characters) when the host already has a fresh negotiation capability. Otherwise the initiator generates a random ID and the receiver binds to the first offer from its pinned peer. Replacement uses a new peer instance. Caller admission remains necessary: knowing a Nostr public key is not proof of room entitlement. `start()` returns the same `ready` promise, resolving with its `RealtimeDatagramLink`. The native connection is available as `peer.pc` for caller read-only statistics. `send(Uint8Array | ArrayBuffer, { deadlineMs })` returns a boolean. `deadlineMs` uses the same monotonic millisecond clock as the optional injected `now()` callback; omitted deadlines have no transport expiry. Once SCTP accepts bytes, the application cannot recall them. A receiver must still reject an expired complete frame. `RealtimeDatagramLink` can wrap an application-negotiated `pc`/`channel` directly. It requires the label `relayswarm-live-v1` and `ordered: false`. The default mode requires `maxRetransmits: 0` and `maxPacketLifeTime: null`. An explicit `maxPacketLifeTimeMs` option (integer 1 to 1000) instead requires `maxRetransmits: null` and exactly the selected `maxPacketLifeTime` value. Both endpoints must select the same mode and lifetime. Ordered, reliable, different-lifetime and different-mode channels are refused; there is no automatic switch or HLS fallback. The same constraints apply to channels received by `RealtimePeer`. Snapshots name the selected delivery mode and lifetime without exposing credentials or payloads. Peer snapshots also retain a generic close reason, current/pre-close native connection/ICE/gathering/signalling/channel states, candidate counts and description-presence booleans. The pre-close state remains available after the underlying connection has been closed. These are in-memory observations on explicit request; no logger or history writer is added. For a media forwarding service, explicitly selecting 50 ms lifetime bounds unsent and retransmission eligibility in a correctly implemented backend. Zero retries alone does not impose an unsent queue deadline. Negotiated flags do not prove backend conformance; use the guarded Node correction below. ## Bounds and lifetime - Default datagrams are at most 16 KiB; the configurable hard maximum is 64 KiB. Larger media frames need application fragmentation. - Default SCTP buffered-data allowance is 256 KiB, configurable up to 4 MiB. A send that would exceed the allowance is dropped, without an application transport queue, retry or deferred send. - Async receive callbacks are capped at 16 in flight by default on the link. Additional datagrams are dropped; callback rejection closes with a generic reason. A synchronous admission callback can hand bytes to a separately bounded receiver. Closing cannot cancel an already-running callback, so callers must check their own cancellation before applying async results. - Each peer accepts at most 128 ICE candidates per direction, at most 4 KiB per candidate and 6 KiB SDP. Candidate-before-description and replica reordering are retained only inside those bounds. The default connection deadline is 15 seconds (configurable up to 60 seconds). - Abort, timeout, native/channel failure or explicit close removes listeners, clears candidate queues, closes channel/connection and rejects unfinished readiness with a generic error. The caller owns the shared session/pool; closing one peer does not close those shared resources. - `iceServers` and `iceTransportPolicy` are supplied by the host. The policy defaults to `relay` with no ICE servers. No root TURN secret or default service is supplied. An empty relay configuration cannot establish a path. ## Verification scope Run `npm run test:realtime`. The tests exercise bounds, late data, protocol refusal, cancellation, timeout, pinned peers/IDs, candidate reordering and an actual `RelayPool`/NIP-44 session exchange through an in-memory relay. The native peer connection in these unit tests is a fixture, so they do not prove browser SCTP behaviour, WAN/NAT traversal, real media playback or a complete Spry/Sapflow/KithMoot call. Those require the consuming adapter's integration tests. This component establishes no legal exemption for the combined offering. `npm run test:realtime:native` additionally runs an actual Chromium initiator against a Node werift 0.24.3 answerer, with real WebRTC and encrypted session signalling over a loopback relay. Both directions carry generated datagrams and the native incoming channel must be unordered with zero retransmits. The qualifier requires the matching Playwright Chromium installation (or `E2E_CHROMIUM_EXECUTABLE`). It passed on the development Mac. It does not exercise TURN, remote networks, audiovisual decoding or phone devices. The original uncorrected Node qualifier role is **answerer only**. Werift 0.24.3's outgoing DCEP encoding overwrites the unordered channel bit when maxRetransmits is set; an initiating werift peer therefore fails the strict receiver check. Do not weaken that check to make a Node initiator pass. The browser initiates each connection to an independent Node forwarding operator. The receiver accepts the browser's correctly encoded unordered channel and sends on that channel. Always pass explicit ICE configuration to the Node implementation. Werift otherwise supplies a default STUN service; it selects the first supplied STUN and TURN URL rather than establishing browser-like multi-server fallback. Source inspection maps relay policy to its `forceTurn` option; that inspection is not a live TURN qualification. Operator wrappers must also disable/reject inherited dependency debugging (`DEBUG`) before opening connections: dependency diagnostics can include ICE credentials. The transport module itself adds no logger. ## Guarded Node backend build The opt-in `relayswarm/realtime-werift-build` module corrects one exact werift 0.24.4 ESM source revision during an esbuild Node build. It neither edits installed packages nor changes another application's dependency. The exported `weriftRealtimeRevision` records the reviewed upstream file SHA-256 values. Unknown metadata/source, browser builds, external-package builds and unsupported werift subpath imports are refused. There is no uncorrected fallback. ```js import { build } from 'esbuild'; import { realtimeWeriftPlugin } from 'relayswarm/realtime-werift-build'; await build({ entryPoints: ['operator-entry.mjs'], // imports RTCPeerConnection from werift outfile: 'operator.mjs', platform: 'node', format: 'esm', bundle: true, // Supply the normal createRequire shim if bundled dependencies require it. plugins: [await realtimeWeriftPlugin({ packageRoot: reviewedWeriftDirectory })], }); ``` The changes preserve unordered DCEP mode bits, recognise zero retransmits, capture lifetime in monotonic seconds when the data-channel send is enqueued, discard expired application-queue data, and refuse expired SCTP data before first send or retransmission. A single timer per association expires queued media even without a window-opening event. Abandonment identifies the exact DATA chunk and its message fragments rather than another message with the same chunk type. Flight-byte accounting follows abandonment and retransmission. The latest FORWARD TSN control skip is retained until cumulative acknowledgement and retried using the unchanged control timer if lost; expired media is not retransmitted. Association closure cancels its added expiry timer. The upstream MIT notice is retained explicitly in the generated bundle, alongside dependency legal comments. The published npm package omitted its licence file; the notice comes from the [upstream repository licence](https://github.com/shinyoshiaki/werift-webrtc/blob/develop/LICENSE). The guard does not independently pin all transitive dependencies: retain the consuming application's lockfile and build provenance as separate inputs. Correction revision 2 also releases a successfully allocated TURN lease on shutdown. It aborts the scheduled positive refresher, settles outstanding transactions, sends authenticated Refresh with lifetime zero to the already resolved server, handles stale nonce with fresh transaction IDs, then closes the socket in all outcomes. Up to three attempts share a 900 ms release budget; a server which cannot acknowledge release still owns allocation expiry. Closing is idempotent. Peer/server requests cannot resume after close and register another transaction after asynchronous address resolution. Failed allocation also closes its newly created transport. These corrections do not increase server quotas or replace them with fresh-credential churn. Run the conformance tests with the reviewed installation supplied explicitly: ```sh WERIFT_REALTIME_PACKAGE_ROOT=/path/to/reviewed/node_modules/werift npm run test:realtime:backend ``` Without that variable the conformance command fails; it cannot turn green by skipping the backend cases. With the reviewed source, the tests build the corrected module and exercise actual serialised SCTP packets through a finite in-memory lossy transport. They prove zero-retry loss recovery, expiry behind a zero receive window, correct message selection, fragmented-message loss and lifetime-unit/application-queue handling. They also cover wall-clock rollback, lost control-skip recovery and expiry timer cleanup. The packet fixture accelerates the retransmission trigger; production retry timers, ICE consent and native resource limits remain unchanged. This is SCTP wire proof, not WAN or physical device qualification. The same suite additionally runs the actual corrected TURN client against an authenticated loopback UDP fixture. It verifies nonce/authenticated release, lost requests, an unresponsive server, refresher/request cancellation, failed allocation and two successive batches of eight sockets reusing one credential under an eight-allocation limit. These control-plane tests do not replace the consuming application's public-server allocation/readback gate. The Chromium-to-native qualifier can consume the generated module explicitly: ```sh E2E_REALTIME_BACKEND_MODULE=/path/to/corrected-backend.mjs E2E_REALTIME_LIFETIME_MS=50 npm run test:realtime:native ``` That path is a mandatory explicit selection when qualifying finite-lifetime native forwarding. An omitted backend path retains the historical direct upstream diagnostic; it does not establish corrected loss/expiry behaviour. --- Source: [docs/TRANSFER-WORKER.md](https://raw.githubusercontent.com/forgesworn/relayswarm/main/docs/TRANSFER-WORKER.md) # Dedicated transfer worker This unreleased experimental opt-in moves schema-3 piece verification and transfer scheduling into one dedicated worker per swarm, for mixed and explicit peer-only transfers. Both execution paths share the same small transfer facade and compiled Rust module. Piece hashes, the whole-object hash, planner, probe caps and returned commands remain Rust's decisions; there is no additional JavaScript verifier. ## Host integration and packaging Bundle the companion entry from the same SDK revision as the main adapter and reviewed WASM module. From this repository, using its installed dependencies: ```sh npx --no-install esbuild src/browser/core-transfer-worker-runtime.mjs --bundle --platform=browser --format=esm --outfile=public/relayswarm-transfer-worker.mjs ``` Serve that generated file and configure its URL explicitly: ```js const swarm = createHlsSwarm({ ...approvedStreamOptions, mode: "peer-first", coreWasm: "/vendor/relayswarm-core.wasm", multiHolder: true, transferWorkerUrl: "/relayswarm-transfer-worker.mjs", }); swarm.attach(hls); ``` `transferWorkerUrl` requires peer-first mode, `coreWasm` and `multiHolder`. The host's normal explicit peer/upload consent still applies. A relative `import.meta.url` inside a bundled main library does not guess an adjacent asset. Existing browser worker/module capabilities and the host's content policy must permit the supplied URL; refusal goes to HTTP. Installed-package bundlers can resolve the entry as `relayswarm/transfer-worker`, for example from a companion entry containing `import "relayswarm/transfer-worker"`. The SDK release build emits `relayswarm-transfer-worker-VERSION.mjs` with metadata and a checksum alongside the browser bundle. Existing immutable release downloads do not contain this unreleased feature. `loadCore(...)` exposes its already compiled `module`, a `WebAssembly.Module`. The swarm warms the worker asynchronously from that module, without a second WASM fetch or holding session/player startup. While the worker is warming or after a worker failure, configured peer-first loads use ordinary HTTP before any metadata or coordinated wait. They do not quietly retry a large Rust transfer on the main thread. The synchronous/native transfer API and unconfigured swarms retain their existing path. Once the worker is ready, schemas 1/2 retain their existing path too. The companion imports only the shared transfer facade. It receives a cloned compiled module, numeric scheduler inputs, commitment digests and media bytes. Native peer connections and signalling keys remain in the main host. It performs no media fetch, creates no peer connection and selects no player. ## Bounds, cancellation and observations The default bridge permits two active objects, 16 MiB per object, 32 MiB of active object sizes, 32 pending calls and 32 MiB of pending media payload. The loader respects its configured segment limit up to the bridge's 32 MiB per-object maximum. Initialisation and every call have a five-second safety deadline; the existing HLS peer floor and absolute origin backstop remain in force independently. Queue or handle exhaustion sends that load to HTTP. There is no automatic worker retry or unbounded queue. Media input is copied into an owned transferable buffer so the caller retains its original bytes for caching, accounting and tracing. Verified output is transferred back. This moves CPU work and retains an input-copy cost; it does not prove lower total CPU time or network use. Per-transfer free/cancel immediately fences its replies, rejects pending calls and queues Rust handle cleanup; other active transfers continue. Acknowledgements or operation deadlines still own that queued work, because only terminating the worker can interrupt a synchronous WASM call. Swarm stop, worker failure, malformed results or a genuine operation deadline terminate the worker and reject pending work. The normal pending HTTP arm of a cached-peer race remains owned by its loader. The loader keeps generation/abort guards and complete-object acceptance. An explicit clock check fences worker replies at the absolute backstop even when its timer has not run; the mixed path retains its origin reserve. Late worker replies cannot credit peer bytes or call the player. Only first-verified-copy contributions in an accepted complete object reach `onPeerDelivery`. `metrics().core.transferWorker` reports state/reason and, once available, active objects, pending calls and pending media bytes. It contains no native connection references. The low-level [`createCoreTransferWorker`](https://raw.githubusercontent.com/forgesworn/relayswarm/main/src/browser/core-transfer-worker.mjs) bridge also accepts a compiled `module` and explicit `workerUrl`, with bounded limits, a lifecycle `signal` and `onFailure`. Its `transfer(config, { signal })` returns asynchronous `start`, `progress`, `delivered`, `failed` and `tick` methods with the synchronous core's arguments and frames. `free`/`cancel` release one handle; `stop` terminates the worker. `WorkerImpl` on the HLS options is a constructor injection point for tests or an equivalent host worker transport. ## Explicit peer-only cached race When no safe serial wait remains, `zeroBudgetPeerRace` starts one normal whole-object HTTP request immediately. The competing Rust transfer is created with `peerOnly: true`: there is no origin lane, origin estimate or ignored origin command inside it. Fast whole-HTTP history cannot strand ranges behind work that performs no I/O. Candidate identity stays inside the initial cached snapshot and current HAVE by default. Cold holders receive bounded one-piece calibration. Remaining unverified, uncovered pieces stay pending until verified progress refills bounded peer requests. Failed or corrupt holders return only unfinished work to that pool. No speculative serial-recovery abandonment kills this already-parallel arm; the real HTTP winner, peer floor and host cancellation own its lifetime. At the floor, Rust cancels peers and fails this transfer while normal HTTP continues. Piece and whole-object hashes, request size, holder, worker queue and upload allowance bounds remain in force. Normal mixed transfers retain their origin lane and existing abandonment rules. The optional capability mask is `2` (alongside bounded-probe mask `1`). Low-level callers request `peerOnly: true` in transfer creation, then supply `origin: null` at start. Existing constructor/C/native signatures remain compatible. A synchronous core without the capability declines before allocation; a worker declines that handle without retiring healthy mixed transfers. HLS retains its already-running HTTP arm. No synthetic origin latency is substituted. Ranged requests are charged by their actual bounded size under unchanged rate and session limits. Unlike a whole-object upload, an entire large media object need not fit one two-second rate bucket. The temporary whole-object fallback was hash-safe but lost the same-M4 native first-load comparison; that failed control is retained. New mode qualification still requires the unchanged native three-load win/HTTP-win/win assertion and physical playback evidence; the capability alone is not a performance guarantee. ### Optional late HAVE With `zeroBudgetPeerRace` and the separate experimental `lateHaveRace: true`, an already-running whole HTTP load can race an object advertised later on a connection accepted at load entry. This uses the existing key-filtered HAVE notifications. FETCH is not cached data; no neighbour search or new connection is admitted. The first actual matching holder snapshot is frozen once, and failure or corruption does not start a second arm. Key hashing, HAVE observation, commitment verification and peer delivery all consume the same original `maxPeerWaitMs` window. HTTP never waits and no origin range is created. Its success or exposed progressive chunk cancels the observation and worker handle; swarm stop preserves pending normal HTTP, while loader abort or destroy cancels both arms. Upload and worker bounds remain unchanged. The zero-budget `have-after-wait` diagnostic marks a real later HAVE, not deferred HTTP. A peer winner can still leave partial HTTP traffic; the host must measure that traffic before claiming network savings. ## Focused verification ```sh node --test test/core-transfer-worker.test.mjs test/core-transfer.test.mjs node --test --test-name-pattern='transfer worker:' test/browser-hardening.test.mjs node --test --test-name-pattern='^late-HAVE race' test/browser-hardening-core.mjs ``` The bridge fixture uses a real Node worker thread with the committed WASM, comparing every six-MiB mixed/corrupt transfer frame and final bytes against the synchronous core. It covers independent cleanup, limits, stale replies, deadlines, worker errors and stop. Loader checks cover a six-MiB verified contribution with exact observations, HTTP during held initialisation with a real FETCH/no HAVE, delayed replies within and past the origin reserve, ordinary HTTP surviving peer shutdown, and genuine worker failure with no peer credit or synchronous retry. These are protocol/lifecycle checks; physical HLS continuity and net network benefit remain separate acceptance gates.