Design doc §28: update to reflect v0.6.0 shipped state
Mostly a framing refresh — the underlying architecture description matches what v0.6.0 actually does. Per-subsection status badges so a reader can see at a glance what's shipped, what's partial, and what's deferred: - §28.1 two-layer identity: Shipped - §28.2 persona types: Shipped (minus ephemeral — folded into §28.4) - §28.3 multi-device: Partial (export/import works; no QR linking UX) - §28.4 ephemeral rotating DM IDs: Deferred + connection-model rationale written out - §28.5 CDN holder sets: Shipped, with drop-migration note - §28.6 DM privacy: Shipped (2 of 3 mechanisms; comment-as-intro machinery exists but no dedicated UX yet) - §28.7 user-facing: split into Shipped and Not-yet items - §28.8 key safety: Shipped (unchanged content) - §28.9 phase-by-phase rollout: each phase tagged Shipped v0.6.0 except Phase 6 (Deferred) Final paragraph replaces the old "beta and stable are separate networks" language with the hard-fork framing and a link to the upgrade path on the download page. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d0d055839a
commit
b789ab5a19
1 changed files with 37 additions and 34 deletions
|
|
@ -1704,63 +1704,66 @@ END</code></pre>
|
|||
|
||||
<!-- 28. Identity Architecture (Planned) -->
|
||||
<section id="identity-architecture">
|
||||
<h2>28. Identity Architecture <span class="badge badge-planned">Planned</span></h2>
|
||||
<p>The 0.6.x beta line introduces a separation between <strong>network identity</strong> (per-device routing/connection key) and <strong>posting identity</strong> (the face/persona authoring content). This is the architectural foundation for multi-device, multi-persona, and DM-level traffic-graph privacy.</p>
|
||||
<h2>28. Identity Architecture <span class="badge badge-partial">Mostly Shipped (v0.6.0)</span></h2>
|
||||
<p>v0.6.0 separates <strong>network identity</strong> (per-device routing/connection key) from <strong>posting identity</strong> (the face/persona authoring content). This is the architectural foundation for multi-device, multi-persona, and DM-level traffic-graph privacy. Five of the original six phases shipped as v0.6.0; ephemeral rotating DM IDs (§28.4) are deferred pending connection-model design work.</p>
|
||||
|
||||
<h3>28.1 Two layers of identity</h3>
|
||||
<h3>28.1 Two layers of identity <span class="badge badge-complete">Shipped</span></h3>
|
||||
<p>Each device has ONE network key — used for QUIC connections, endpoint ID, mesh routing. It's never linked on the wire to any posting key.</p>
|
||||
<p>Each user can hold MANY posting keys simultaneously — no "active" persona, no switching. Each posting key is a persona (Public, Private, Work, Family, per-conversation ephemeral, etc). Posts are signed with the posting key chosen at compose time.</p>
|
||||
<p>Each user can hold MANY posting keys simultaneously — no "active" persona, no switching. Each posting key is a persona (Public, Private, Work, Family, etc). Posts are signed with the posting key chosen at compose time. On first launch after upgrading, the existing identity becomes the default posting key (same bytes as the network key for upgraders, so all prior signed content keeps verifying).</p>
|
||||
<p><strong>Privacy invariant:</strong> peers cannot determine which network IDs belong to a given posting ID, which posting IDs belong to the same network ID, or which posting IDs belong to the same user. These associations are private to the device owner.</p>
|
||||
|
||||
<h3>28.2 Persona types</h3>
|
||||
<h3>28.2 Persona types <span class="badge badge-complete">Shipped</span></h3>
|
||||
<ul>
|
||||
<li><strong>Public posting IDs</strong> — main persona(s), openly associated with "you"</li>
|
||||
<li><strong>Private posting IDs</strong> — smaller-context personas for close contacts or specific groups</li>
|
||||
<li><strong>Contextual / ephemeral posting IDs</strong> — per-relationship, per-thread, or one-off; auto-generated and isolated</li>
|
||||
<li><strong>Contextual posting IDs</strong> — per-relationship or per-group; user creates one per context and sticks with it</li>
|
||||
</ul>
|
||||
|
||||
<h3>28.3 Multi-device is a special case</h3>
|
||||
<p>"Two devices holding the same posting key" is a trivial case of the multi-key model. Link happens out-of-band between the user's own devices (QR / file / copy-paste bundle). The network sees no cross-device message announcing the relationship. Each device pulls content for its posting IDs via the normal CDN — the fact that two network nodes hold the same posting key is only discoverable if an observer has private knowledge (which they shouldn't).</p>
|
||||
<h3>28.3 Multi-device is a special case <span class="badge badge-partial">Partial</span></h3>
|
||||
<p>"Two devices holding the same posting key" is a trivial case of the multi-key model. Link happens out-of-band between the user's own devices via the existing identity export/import bundle — the export includes all posting identities so they restore on the second device. The network sees no cross-device message announcing the relationship; each device pulls content for its posting IDs via the normal CDN. The fact that two network nodes hold the same posting key is only discoverable if an observer has private knowledge (which they shouldn't).</p>
|
||||
<p>In-app QR / file-share flows for easy linking between an existing device and a new one are not wired yet — today it's manual export-then-import.</p>
|
||||
|
||||
<h3>28.4 Ephemeral rotating IDs for DM threads</h3>
|
||||
<p>DM threads and group messages use per-thread unique posting IDs that rotate per message. Each encrypted message includes a handshake field — the next posting ID to use. Observer sees a stream of distinct posting IDs with no cryptographic tie between them, defeating thread-level traffic correlation.</p>
|
||||
<p>Desync recovery: receivers accept messages signed by any of the last N ephemeral IDs (sliding window). Message history (which can't be searched by rotating ID) is kept in a local <strong>encrypted-to-self archive</strong> — the archive is implemented as normal encrypted posts with recipient = user's own archive persona, replicating across the user's linked devices via self-follow.</p>
|
||||
<h3>28.4 Ephemeral rotating IDs for DM threads <span class="badge badge-planned">Deferred</span></h3>
|
||||
<p>The intent: DM threads and group messages use per-thread unique posting IDs that rotate per message. Each encrypted message would include a handshake field — the next posting ID to use. Observer sees a stream of distinct posting IDs with no cryptographic tie between them, defeating thread-level traffic correlation. Desync recovery via a sliding window of the last N accepted IDs. Message history kept in a local encrypted-to-self archive that replicates across linked devices via self-follow.</p>
|
||||
<p><strong>Why deferred:</strong> the current connection model is per-network-ID (peers establish QUIC sessions keyed by stable NodeId; holder-set learning assumes durable addressable authors). Ephemeral authors that come into existence per-thread need a crisper design for how a freshly generated posting ID becomes reachable fast enough to receive replies before the next rotation. The pieces needed to implement rotation (per-file holder sets, merged pull with recipient-match, per-posting-ID signing) are all in place — what's missing is the cold-contact discovery semantics for ephemeral recipients.</p>
|
||||
|
||||
<h3>28.5 CDN restructure: per-file holder sets</h3>
|
||||
<p>The current upstream/downstream tree (which assumed a single author network endpoint) is replaced by a flat per-file holder set with header-diff propagation.</p>
|
||||
<p>Each file (post, blob, manifest) has its own holder set. Each holder tracks up to 5 peers it recently interacted with about that specific file. When a new post is created, the creator updates the headers of recent prior posts (their manifests now reference the new post), then pushes the header diff to the up-to-5 known holders of each updated prior post. Recipients apply the header diff, see the reference to the new post, and pull it through normal sync.</p>
|
||||
<p>Notifications thus route via network-ID peers who happen to hold related files — not via any tree rooted at the author. Content always arrives via pull, never pushed directly.</p>
|
||||
<h3>28.5 CDN: per-file holder sets <span class="badge badge-complete">Shipped</span></h3>
|
||||
<p>The earlier upstream/downstream tree (which assumed a single author network endpoint) is replaced by a flat per-file holder set with header-diff propagation.</p>
|
||||
<p>Each file (post, blob, manifest) has its own holder set (up to 5 most-recent peers, LRU-capped). When a new post is created, the creator updates the headers of recent prior posts (their manifests now reference the new post), then pushes the header diff to each updated prior post's holder set. Recipients apply the header diff, see the reference to the new post, and pull it through normal sync.</p>
|
||||
<p>Notifications thus route via network-ID peers who happen to hold related files — not via any tree rooted at the author. Content always arrives via pull, never pushed directly. Four legacy tables (<code>post_upstream</code>, <code>post_downstream</code>, <code>blob_upstream</code>, <code>blob_downstream</code>) were dropped in v0.6; a one-way migration seeds <code>file_holders</code> from them on first launch.</p>
|
||||
|
||||
<h3>28.6 DM privacy model</h3>
|
||||
<p>Three complementary mechanisms eliminate the "A messaged B" traffic signal:</p>
|
||||
<h3>28.6 DM privacy model <span class="badge badge-complete">Shipped</span></h3>
|
||||
<p>Two of the three originally-planned mechanisms shipped in v0.6.0 and eliminate the "A messaged B" traffic signal for follower-to-follower and cold-contact-via-pull scenarios:</p>
|
||||
<ol>
|
||||
<li><strong>CDN-only propagation.</strong> Direct <code>PostPush</code> for encrypted posts is removed. All encrypted posts propagate via the file-holder CDN, indistinguishable from any other encrypted content.</li>
|
||||
<li><strong>Merged pull + recipient-match.</strong> Pull sync's query is extended so peers return posts matching <code>author ∈ query_list</code> OR <code>recipient ∈ wrapped_keys</code>. Client always includes its own NodeId alongside follows. The search pattern is indistinguishable from routine pull — no "searching for DMs" traffic fingerprint.</li>
|
||||
<li><strong>Comment-as-introduction for cold contact.</strong> Any public post with open comments serves as a message-request surface. Comments flow via engagement diffs through the post's holder network, reaching the author's linked devices via normal pull.</li>
|
||||
<li><strong>CDN-only propagation.</strong> Direct <code>PostPush</code> for encrypted posts is removed. All encrypted posts propagate via the file-holder CDN, indistinguishable on the wire from any other encrypted content.</li>
|
||||
<li><strong>Merged pull + recipient-match.</strong> Pull sync's query is a uniform list of NodeIds; server returns posts matching <code>author ∈ query_list</code> OR <code>wrapped_key.recipient ∈ query_list</code>. Client always includes its own NodeId alongside follows. No distinguishable "searching for DMs" traffic fingerprint — the query looks identical to a routine follow-pull.</li>
|
||||
<li><strong>Comment-as-introduction for cold contact.</strong> Any public post with open comments serves as a message-request surface. The machinery exists (engagement diffs flow through the post's holder network); a dedicated UX affordance for "start a conversation by commenting" is still on the todo list.</li>
|
||||
</ol>
|
||||
|
||||
<h3>28.7 What the user sees</h3>
|
||||
<ul>
|
||||
<li>One merged incoming feed (all content to all personas), with filter-by-persona pills</li>
|
||||
<li>Reply/comment defaults to the persona whose key decrypted the post (override available)</li>
|
||||
<li>Persona picker only appears at post-creation time, with contextual defaults</li>
|
||||
<li>DMs to different personas appear as distinct conversation threads in the inbox</li>
|
||||
<li>"New conversation with Alice" can offer a fresh per-thread ephemeral ID</li>
|
||||
<li>One merged incoming feed (all content to all personas), with filter-by-persona pills <span class="badge badge-complete">Shipped</span></li>
|
||||
<li>Per-post "(you) as <persona>" label on own posts authored by a non-default persona <span class="badge badge-complete">Shipped</span></li>
|
||||
<li>Persona picker at post-creation time, auto-hidden with a single persona <span class="badge badge-complete">Shipped</span></li>
|
||||
<li>Settings → Personas to create, delete, and set default <span class="badge badge-complete">Shipped</span></li>
|
||||
<li>Reply/comment default persona = whichever key decrypted the post <span class="badge badge-planned">Not yet</span></li>
|
||||
<li>Contextual compose defaults (e.g., posting to a circle auto-picks that circle's last-used persona) <span class="badge badge-planned">Not yet</span></li>
|
||||
<li>DMs to different personas as distinct inbox threads <span class="badge badge-planned">Not yet</span></li>
|
||||
</ul>
|
||||
|
||||
<h3>28.8 Key/collision safety</h3>
|
||||
<h3>28.8 Key/collision safety <span class="badge badge-complete">Shipped</span></h3>
|
||||
<p>Posting keys and network keys are ed25519 seeds (256 bits of entropy). Birthday paradox reaches 50% collision at ~2<sup>128</sup> keys generated — not a concern even at aggressive rotation rates across a global userbase. The operational risk is weak RNG during key generation; we rely on the platform CSPRNG everywhere.</p>
|
||||
|
||||
<h3>28.9 Phased rollout</h3>
|
||||
<h3>28.9 Rollout status</h3>
|
||||
<ol>
|
||||
<li><strong>Phase 1</strong> — Remove direct <code>PostPush</code> for encrypted posts (keeps existing CDN tree). Encrypted DMs propagate via ManifestPush like any other content.</li>
|
||||
<li><strong>Phase 2</strong> — File-holder model + header-diff propagation replaces upstream/downstream. Diverse lateral holder networks per file.</li>
|
||||
<li><strong>Phase 3</strong> — Merged pull + recipient-match search. DM search becomes indistinguishable from follow-pull.</li>
|
||||
<li><strong>Phase 4</strong> — Posting-key / network-key split. Local-only linked-devices hints. Multi-persona plumbing.</li>
|
||||
<li><strong>Phase 5</strong> — Multi-persona UX.</li>
|
||||
<li><strong>Phase 6</strong> — Ephemeral rotating IDs for DM threads + local self-archive.</li>
|
||||
<li><strong>Phase 1</strong> <span class="badge badge-complete">Shipped v0.6.0</span> — Direct <code>PostPush</code> for encrypted posts removed. Encrypted DMs propagate via ManifestPush like any other content.</li>
|
||||
<li><strong>Phase 2</strong> <span class="badge badge-complete">Shipped v0.6.0</span> — File-holder model + header-diff propagation replaces upstream/downstream. Legacy tables dropped with a one-way seed migration.</li>
|
||||
<li><strong>Phase 3</strong> <span class="badge badge-complete">Shipped v0.6.0</span> — Merged pull + recipient-match search. DM search indistinguishable from follow-pull. <code>post_recipients</code> index added.</li>
|
||||
<li><strong>Phase 4</strong> <span class="badge badge-complete">Shipped v0.6.0</span> — Posting-key / network-key split plumbing. <code>posting_identities</code> table; seed migration copies network key in as default persona for upgraders.</li>
|
||||
<li><strong>Phase 5</strong> <span class="badge badge-complete">Shipped v0.6.0</span> — Multi-persona UX (Settings page, compose picker, feed filter pills, per-post persona labels).</li>
|
||||
<li><strong>Phase 6</strong> <span class="badge badge-planned">Deferred</span> — Ephemeral rotating IDs for DM threads + local self-archive. See §28.4 for the open design question.</li>
|
||||
</ol>
|
||||
<p><strong>Beta and stable are separate networks.</strong> The 0.6.x beta line does not interoperate with 0.5.3 stable. This is an explicit simplification — no dual-writing legacy tables, no mixed-version wire handlers, no cross-network testing matrices. Users can cross tracks via the existing export/import identity bundle.</p>
|
||||
<p><strong>v0.6 is a hard network fork from v0.5.</strong> The two versions do not interoperate. This was an explicit simplification once the user base was small enough to migrate everyone directly — no dual-write tables, no legacy message handlers, no mixed-network testing. Users cross via the existing export/import identity bundle; see the <a href="download.html">download page</a> for the upgrade path.</p>
|
||||
</section>
|
||||
|
||||
<!-- Appendix A: Timeouts -->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue