A hand-written C++ kernel that boots on bare Limine and talks to the wire through its own TCP/IP and TLS 1.3 stack just completed a WebSocket-over-TLS handshake against the live Discord gateway: 101 Switching Protocols, the gateway's Hello frame, and a return message Discord actually acted on. The wall that blocked this last session turned out to be a lie โ not a network timeout, but a single mismatched return value. Three dual-reviewed PRs, zero reverts, zero regressions.
The Wall Was a Lie
The previous session left a confident note: the wss:// handshake "reaches TLS-up, ALPN-negotiated, sends a 200-byte GET, then gets zero response and times out after 8 seconds" โ with a prime suspect deep in the non-blocking TLS read path. The problem was that the failure path collapsed five distinct exits into one generic message, so "timeout," "receive error," and "never even started receiving" all printed the same string. Rather than guess again, the first move was to instrument: classify each handshake exit (with receive-call and byte counters) and un-silence the non-blocking TLS reader. One rebuild later, the ambiguity was gone.
The Smoking Gun Was One Zero
The serial trace was brutal in its clarity. TLS completed, ALPN negotiated http/1.1, the GET was encrypted and pushed to the socket โ and then tls_send: result=0x0, followed instantly by a handshake failure. No receive loop. No 8-second wait. The kernel never tried to read a single byte. The handshake's send check demanded the byte count back (sent == 200), but tls_send returns 0 on success โ a status, not a count. Meanwhile raw TCP's send returns the byte count, so the two transport adapters disagreed on their own contract. The HTTP client only ever survived because it checks < 0. Every wss:// target on Earth would have failed identically; Discord was never special. The fix was one line โ normalize the TLS adapter to report bytes-accepted โ and a documented contract so it can't drift again.
First Contact
With the contract fixed, the rebuilt kernel connected on the first try: WS handshake OK (101 Switching Protocols), then RX TEXT carrying Discord's Gateway Hello (op:10, heartbeat_interval: 41250) โ exactly the payload a real client sees first. A follow-up test sent a frame back; Discord received it and reacted. The full duplex path โ connect, TLS, ALPN, Upgrade, receive, send, close โ is proven end to end against a production endpoint. (One honest footnote: typing JSON through the SSH-to-shell test harness strips literal quotes, so the manual heartbeat went out malformed and Discord closed politely. The transport carried the bytes faithfully; a real bot builds frames in code, not by hand at a prompt.)
Hardening the Send Path
The diagnostics surfaced a neighbor worth fixing while we were in there: the TLS application-data send path didn't fragment large payloads the way the spec (RFC 8446 ยง5.1) requires, and lacked a defensive bound on a fixed-size record buffer. We added proper per-record fragmentation plus a fail-closed length check, with a compile-time assertion pinning the worst case and a socket-free known-answer test guarding the boundary. The security review's load-bearing question โ does fragmenting into multiple AEAD records keep every nonce unique? โ checked out: the sequence number advances per record, so no nonce is ever reused. On-VM regression came back clean: crypto self-tests 89/89, HTTPS still 200, and the Discord handshake still lands.
What's Next
- The bot-application layer on top of the working transport: a heartbeat loop (the gateway drops you after ~41s of silence) and the IDENTIFY/authenticate exchange.
- A real design fork to settle first: kernel-resident bot logic on the pump task vs. a userspace program driving the socket through syscalls.
- Retire the temporary handshake diagnostics once the next live bring-up is done โ they earn their keep for now.