summaryrefslogtreecommitdiffstats
path: root/docs/invite-pairing-v1.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/invite-pairing-v1.md')
-rw-r--r--docs/invite-pairing-v1.md26
1 files changed, 23 insertions, 3 deletions
diff --git a/docs/invite-pairing-v1.md b/docs/invite-pairing-v1.md
index 56fccbe..290c756 100644
--- a/docs/invite-pairing-v1.md
+++ b/docs/invite-pairing-v1.md
@@ -1,6 +1,8 @@
# MeshBay — Invitation and Pairing (design)
-> Status: **proposal, not implemented.** Written 2026-08-13.
+> Status: **implemented and deployed** (2026-08-14). Written 2026-08-13 as a proposal;
+> §9bis records what shipped, what departed from the plan, and what a browser found
+> that the automated run could not.
> Supersedes the invite flow described in `meshbay-draft-v5.md` §5.1 and the
> Phase 12.1 milestone in `devel-phases-next.md`, if adopted.
>
@@ -86,7 +88,7 @@ signature ceremony, no operator required to be online when someone joins.
```
operator (SSH) meshbay-node operator pair
node prints PAIR-CODE: K7M2-QX4P (also written to data_dir/pair-code)
-operator (SPA) Settings → "Pair this browser with my node" → types the code
+operator (SPA) group → Members tab → "Pair this browser" → types the code
SPA → node join_request {role_hint: operator, code, pk_ed25519, pk_x25519, sig}
node code valid, unused, unexpired → pins the keys, role = operator
node writes the pin to its roster DB, prints it in `status`
@@ -120,7 +122,7 @@ platform.
```
bob (SPA) opens the group; client has no GEK for it
bob → node handshake {token, group_id, nonce_c} (pre-proof window)
-node → bob handshake_challenge {nonce_s}
+node → bob handshake_challenge {nonce_s, node_pk} ← bob signs over both
bob → node join_request {group_id, pk_ed25519, pk_x25519, code, sig}
node 1. rate-limit + attempt count on this connection
2. code matches a pending invite for this user_id and group
@@ -414,6 +416,24 @@ DataChannel, the operator gets a code, and a member who has never held the group
key redeems it in the pre-proof window and receives the key wrapped for a key only
they can open.
+### What a browser found that the harness could not
+
+The design was exercised end to end by `QE/deploy/e2e.py` and passed. It was then tried in
+a browser and failed four times, each for a different reason, none of them the pairing code:
+
+| Symptom | Cause |
+|---|---|
+| No code ever requested, "no GEK available" | the browser held no identity keys — session restore never re-read the encrypted bundle sitting in its own localStorage |
+| "No nodes available" | the node had gone deaf: its hub socket sat in CLOSE-WAIT because the WebRTC offer handler was awaited inside the read loop (a Phase 11 bug) |
+| "Not a member of this group" | the token predated being added to the group; `groups` is baked in at sign-in, and nothing refreshed it |
+| "Handshake incomplete — reconnect and retry" | `joinGroup()` read `node_pk` and `nonce_node` before they were assigned |
+
+The common thread is worth keeping: **e2e.py is a second implementation of the client**,
+written in the right order by construction, so it proves the protocol and nothing about
+`app.js`. Three of those four were ordering or plumbing mistakes it could never see. Hence
+`packages/meshbay-hub/tests/test_spa_ordering.py`, which asserts on source order — inelegant,
+and the only thing that catches them.
+
### Deliberate departures from this document
| Written | Built | Why |