OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-overlay commits / 1f8cec2

0.3.11: attachProtocol must not no-op SILENTLY
attachProtocol returned silently on every guard: if (this.closing || this.closed || !this._protocol) return A host that wraps the call in try/catch (the atproto daemon does) sees NO exception and concludes the attach succeeded. `peerCount` then reports 0 whether the protocol was never built or it attached with no peers — the two are indistinguishable from outside. That ambiguity sent a live investigation at the content layer for days while byte transfer had simply never been wired up, and it defeated instrumentation added at the CALL SITE, which could only ever catch exceptions this path does not throw. Now logs once per distinct reason: closing / protocol-not-built / channel-unavailable (createChannel returning null for a duplicate, or a channel the remote already closed). Attach is load-bearing — byte resolution gates signing — so a no-op here has to say so. Suite 213/213. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1f8cec2dc0122d3ef105470377999b952867fa5c
by plankatron <fleeky@gmail.com> · 2026-07-26T19:58:48.000Z

Changed files (2) +27 -3

lib/overlay.js +26 -2
……@@ -159,9 +159,33 @@ export class HyperOverlay extends ReadyResource {
159159 // channel MUST be created synchronously — protomux will not pair a channel
160160 // opened after the remote's (verified). The stack is built at ready, so
161161 // this._protocol is always present by the time connections arrive.
162 // INSTRUMENTED: this used to `return` silently on every guard, which is unobservable from the host.
163 // A host wrapping the call in try/catch (the atproto daemon does) sees NO exception and concludes the
164 // attach succeeded, while `peerCount` reports 0 either way — `_protocol` being null and "attached but
165 // no peers" are indistinguishable from outside. That ambiguity sent a live investigation at the
166 // content layer for days when byte transfer was simply never wired up. Attach is load-bearing (byte
167 // resolution gates signing), so a no-op here must say so exactly once per reason.
162168 attachProtocol (mux) {
163 if (this.closing || this.closed || !this._protocol) return
164 return this._protocol.attach(mux)
169 if (this.closing || this.closed) return this._logAttachSkip('closing')
170 if (!this._protocol) return this._logAttachSkip('protocol-not-built')
171 const peer = this._protocol.attach(mux)
172 // attach() returns null for a duplicate channel, or one the remote already closed.
173 if (!peer) this._logAttachSkip('channel-unavailable')
174 return peer
175 }
176
177 _logAttachSkip (reason) {
178 if (!this._attachSkips) this._attachSkips = new Set()
179 if (this._attachSkips.has(reason)) return null
180 this._attachSkips.add(reason)
181 try {
182 console.error(JSON.stringify({
183 msg: 'hyper-overlay: attachProtocol did NOT attach — this connection will move NO bytes for this overlay',
184 reason,
185 overlayKey: this._key ? this._key.toString('hex').slice(0, 16) : null
186 }))
187 } catch {}
188 return null
165189 }
166190
167191 get peerCount () { return this._protocol ? this._protocol.peerCount : 0 }
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "hyper-overlay",
3 "version": "0.3.10",
3 "version": "0.3.11",
44 "description": "Content-addressed P2P file distribution over Protomux — FastCDC chunking, multi-source fetch, resumable transfers, zero blob duplication. Files live on disk; the overlay is a thin index and transfer protocol.",
55 "type": "module",
66 "main": "index.js",