Repository navigation
docs(sync): the relay never carried the ledger, and half of what it holds is readable - #113
Merged
Merged
Conversation
lessevv
force-pushed
the
docs/relay-what-it-actually-holds
branch
from
September 13, 2026 16:29
ef596a5 to
d1ddd23
Compare
…olds is readable Two sentences about the relay have been in this specification since the founding commit and neither is true of the product. The first is that op-log entries wait in the relay when a peer is asleep. They do not. An operation travels only inside a mutually-authenticated session between two paired devices; the mobile sync pass reaches a relay for key material only, and says so in its own comment. Where neither device can reach the other, the changes wait on the device that made them. The relay setting's own help string has said exactly that since 2026-09-05, and a test pins it -- including that it must not promise a pull the phone cannot make. Since then the specification and the shipped string have been contradicting each other outright, and the shipped string was the honest one. The second is that what a relay holds is opaque ciphertext. Half of it is. An epoch wrap is sealed to the receiving device's X25519 key and cannot be opened. A pairing frame is not sealed at all: it is JSON handed to the mailbox as written, and between the two frame types and the addressing that carries them a relay operator reads both device identifiers, the responder's Ed25519 and X25519 public keys, the pairing token's hash, and the name the responder's device goes by -- on a phone often one a person chose. Only the confirming frame is signed; the accepting one is not, so "signed but not encrypted" is true of one of the two and not of both. None of that is a defect in the design. A pairing frame is public-key material exchanged before any shared secret exists, and the safety number both readers compare is what makes a swapped key fail. It is a defect in the description: a reader who believes a relay holds only ciphertext concludes that nominating one reveals nothing. ADR-0033 records the ruling and retires the term "zero-knowledge relay" rather than redefining it -- a house definition cannot repair a word whose outside meaning is the overclaim, and the property that is actually true is narrower, checkable and already written down: no cryptography on a blob, and never looking inside one. The thing is a pairing relay. ADR-0016 and ADR-0004 keep their bodies and get notes naming the claims that no longer hold; ADR-0016 keeps its filename too, because its title is a fact about what was decided in June. Seventeen further pages carried the claim downstream of that term, including the FAQ the public site renders live and the roadmap line it pulls into its milestones. E3-R24 pins what may cross a relay and that both halves of what it holds must be described; G1-R22 pins saying so in the product's own copy. No existing requirement changes meaning: E3-R7 and E3-R14 were accurate and stand as written. Signed-off-by: Wessel Verheij <info@nightworks.io>
lessevv
force-pushed
the
docs/relay-what-it-actually-holds
branch
from
September 13, 2026 16:29
d1ddd23 to
d50a0c9
Compare
|
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.



Why
The public site says the sync relay "only ever holds encrypted data it cannot read" and that changes wait in it when a device is asleep. Both sentences come from this repository, and both are false of the product.
beatrax-app/website#5corrects the site's own copy, but/faqrenders this repo's90-appendix/faq.mdlive at build time — so until this lands,/faq(English, from the spec) and/nl/faq(Dutch, corrected in the website PR) contradict each other on the same page.Verified against
beatrax@origin/mainrather than taken on report:MobileSyncTriggerService::syncOnce()reaches the relay leg after the LAN leg, and its own comment says it "carries no ops — only epoch wraps".PairingPeerOutboxserves only pairing frames out ofrelay_mailbox. No op-log delivery path touches a relay.GdkRotationService::deliverWrap()doessodium_crypto_box_seal()first, so the key is sealed to the recipient.PairingPeerOutbox::queueFor()doesjson_encode($frame)and hands the raw blob toRelayMailbox::deliverIfUnderQuota()— no encryption.PairingFrame::buildResponderAccept()carriestoken_hash, the responder's device id, its Ed25519 and X25519 public keys as hex, andresponder_name.buildConfirm()carries both device ids and a signature. Every mailbox row is addressed sender → recipient regardless, so both identifiers are visible either way.PAIR_CONFIRMonly.PAIR_RESPONDER_ACCEPTcarries nosig_hex.DeviceNameDetector::detect()— a neutral platform label on desktop ("Mac", "PC", "Linux"), and on a phone the OS-reported name, whichNativeDeviceNamedocuments as "the user-set device name first ("Wessel's S24")". Deliberately never the hostname.The product's own copy was already right: the
relay_endpoint_helpstring inModules/Sync/Resources/lang/en/devices.phpsays pairing and key exchange only, transactions LAN-only, andTheRelayHelpPromisesNoPullThePhoneCannotMakeTestpins it. The specification and the shipped string have been contradicting each other, and the shipped string was the honest one.The term
ADR-0033rules that "zero-knowledge relay" is retired, not redefined. Whatever a reader takes "zero-knowledge" to mean — a proof system, or the industry's looser "the operator cannot read it even if it wants to" — neither survives a plaintext pairing frame. A house definition cannot repair a word whose outside meaning is the overclaim, and the reader being misled is the one who never opens the glossary. The property that is true is narrower and already written down asE3-R7: no cryptography on a blob, and never looking inside one. That is a statement about what the relay does; "zero-knowledge" is a statement about what it could do.The thing is a pairing relay. "zero-knowledge relay" and "zero-knowledge sync" join the glossary's Deliberately not used table, alongside "cloud sync" and "server", which were retired on exactly this ground.
ADR-0016andADR-0004keep their bodies and get notes naming the claims that no longer hold —ADR-0031already refused to editADR-0016in place, and that refusal is right.ADR-0016keeps its filename too: its title is a fact about what was decided on 2026-06-15, and renaming it would edit the history this repository keeps decisions for. That is deliberate and is recorded inADR-0033so it is not later mistaken for an oversight.Sites corrected
The three that were reported, plus fourteen more found by sweeping the whole repository for
relay,zero-knowledgeandstore-and-forward:90-appendix/faq.md×2 (rendered live by the site)00-overview/glossary.md00-overview/roadmap.md×200-overview/vision.md×200-overview/decisions/0016-*.md00-overview/decisions/0004-*.md10-functional/features/e-sync/e3-transport.mdE3-R2410-functional/features/e-sync/e2-device-pairing.md10-functional/features/e-sync/e5-mobile-peer.md10-functional/features/g-ux/g1-privacy.md×2G1-R22added10-functional/features/g-ux/g5-plain-language.md10-functional/journeys/j5-adding-a-device.md×310-functional/journeys/j2-daily-use.md20-architecture/system-context.md20-architecture/data-flow.md40-quality/security.md×290-appendix/data-retention.md30-repos/website.md·60-brand/surface-mapping.mdRequirements
No existing requirement changes meaning.
E3-R7(no cryptography on a blob, never look inside one) andE3-R14(document the metadata, claim no traffic-analysis resistance) were accurate as written and are untouched, as areG1-R15,G5-R5,REPO-R41,E2-R15andE5-R19.Two are added, for facts nothing previously required anyone to state:
E3-R24— an op-log entry MUST NOT be delivered over a relay; a relay MUST carry only pairing frames and sealed key-epoch wraps, and what it holds MUST be documented in both halves.G1-R22— the product's own copy MUST state that no transaction crosses a relay, and describe what one holds in both halves rather than only the sealed one.Neither is marked (Open): both describe shipped behaviour, so no manifest entry is needed and
manifest_check.pyis clean.Gates
integrity.pyclean ·manifest_check.pyclean (373 goals) ·typosclean ·markdownlint-cli20 issues in 160 files ·lychee0 errors ·commit_lint.pyanddco_check.pyclean againstorigin/main.gen_summary.pypicks upADR-0033for the mdbook build.Not merged, and auto-merge not armed
This is public-facing copy about privacy. The owner decides when it goes live.
Paired with
beatrax-app/website#5, which corrects the site's own strings and the Dutch FAQ. With both merged,/faqand/nl/faqsay the same thing: transactions never cross a relay; a relay exists only to finish pairing and exchange keys; the key handover is sealed to the receiving device and the pairing messages are not.