Conversation
Three conformant implementations could not, until now, serve a single request. The site advertised transparent JSON fallback and per-request negotiation; both were described in the spec and absent from the code. spec/negotiation-v1.md defines the exchange. A client advertises the fingerprints it holds in Hyperfly-Accept, most preferred first; a server serves the first one it can and otherwise answers JSON with a Hyperfly-Offer naming an artifact the client could fetch. Steady state costs no extra round trip, a cold client bootstraps in one, and every response carries Vary: Hyperfly-Accept because the same URL yields either representation and a shared cache would otherwise hand one peer's binary to a peer that cannot read it. CodecRegistry is the piece that makes profiles operable rather than theoretical. Retraining changes the fingerprint, so a deployment holding one codec per route turns every rollout into a cutover in which in-flight clients fall back to JSON until the fleet converges — the incentive being never to retrain, which quietly defeats the feature. Holding the outgoing codec beside the incoming one makes rotation a transition, and letting the client's preference decide lets it migrate itself without the server tracking who holds what. Artifacts are served from .well-known and are content-addressed, so a hit is immutable and cacheable forever while a miss is a 404 rather than an error. A client derives its codec from the parsed artifact and verifies the fingerprint it computes equals the one it requested, so a server cannot induce it to hash bytes it has not understood. Request bodies get 415 rather than a guess, because a body already sent has no safe fallback. apps/interop is the demonstration the golden vectors imply but cannot give: a Bun server and a Python client walking the whole protocol over real HTTP. The client starts empty, is offered an artifact, fetches it, checks it, and then reads 258 bytes where it first received 2447 — with both representations carrying an identical value. CI now runs it on every push. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_hf1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the gap between "three conformant implementations" and "you can serve a request."
What was missing
The site advertises transparent JSON fallback and negotiated per request. Both were spec prose with no implementation. And
spec/plan-columnar-v3.md§6.4 recommends a fingerprint-keyed registry that did not exist — without it profiles are operationally unusable: retraining changes the fingerprint, so a rolling deploy means every request between mismatched peers falls back to JSON, and the only safe move is never to retrain.The protocol —
spec/negotiation-v1.mdHyperfly-Accept: <fp>[, <fp>], most preferred first. Server serves the first it holds, else JSON +Hyperfly-Offer.Vary: Hyperfly-Accepton every response — the same URL yields either representation, so a shared cache would otherwise serve one peer's binary to a peer that cannot read it..well-known/hyperfly/{fingerprint}serves the canonical artifact,immutablebecause it is content-addressed. A client derives the codec from parsed content and verifies the fingerprint it computes, so a server cannot induce it to hash bytes it has not understood.415rather than a guess: a body already sent has no safe fallback.Hyperfly-Acceptis bounded (32 entries) and malformed entries are dropped, not fatal.The proof
apps/interop— a Bun server and a Python client over real HTTP, starting from a client that holds nothing:The golden vectors prove three implementations agree on bytes; this proves two of them agree on a conversation. CI runs it on every push, in a job with both runtimes.
Also:
hyperfly/httpsubpath export with a Fetch adapter (respond/discovery/readBody) covering Hono, Workers, Bun.serve and Next route handlers, plus the Python equivalents.TS 194 tests, Python 138, Rust 9, all green.
🤖 Generated with Claude Code