219 files, 2.0 MB, untracked in souveraine/docs and existing nowhere else. The volume is at 100% with no snapshots.
814 lines
34 KiB
HTML
814 lines
34 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Seed-ID vs Matrix — Protocol Comparison</title>
|
||
<style>
|
||
:root {
|
||
--bg: #0d0d14;
|
||
--surface: #16161f;
|
||
--surface2: #1e1e2a;
|
||
--border: #2a2a3e;
|
||
--text: #d0d0e0;
|
||
--text-dim: #7a7a8e;
|
||
--accent-souv: #7c5cf0;
|
||
--accent-matrix: #0dbd8b;
|
||
--accent-souv-dim: #5a3eb8;
|
||
--accent-matrix-dim: #08946b;
|
||
--red: #e55550;
|
||
--amber: #e5a050;
|
||
--green: #50c878;
|
||
}
|
||
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', system-ui, sans-serif;
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
line-height: 1.6;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* ── Hero ─────────────────────────────────────────── */
|
||
.hero {
|
||
background: linear-gradient(135deg, #0d0d14 0%, #1a1035 50%, #0a1a15 100%);
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 80px 24px 60px;
|
||
text-align: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.hero::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background:
|
||
radial-gradient(ellipse 600px 300px at 25% 60%, rgba(124, 92, 240, 0.06) 0%, transparent 70%),
|
||
radial-gradient(ellipse 600px 300px at 75% 40%, rgba(13, 189, 139, 0.06) 0%, transparent 70%);
|
||
}
|
||
.hero h1 {
|
||
font-size: clamp(2rem, 5vw, 3.2rem);
|
||
font-weight: 700;
|
||
letter-spacing: -0.03em;
|
||
position: relative;
|
||
}
|
||
.hero .vs {
|
||
background: linear-gradient(90deg, var(--accent-souv), var(--accent-matrix));
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
.hero p {
|
||
color: var(--text-dim);
|
||
max-width: 620px;
|
||
margin: 16px auto 0;
|
||
font-size: 1.05rem;
|
||
position: relative;
|
||
}
|
||
|
||
/* ── Layout ───────────────────────────────────────── */
|
||
.container { max-width: 1100px; margin: 0 auto; padding: 48px 24px; }
|
||
|
||
/* ── Section headers ──────────────────────────────── */
|
||
.section-title {
|
||
font-size: 1.4rem;
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
.section-sub {
|
||
color: var(--text-dim);
|
||
font-size: 0.9rem;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
/* ── Dimension header row ─────────────────────────── */
|
||
.dim-row {
|
||
display: flex;
|
||
gap: 16px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.dim-label {
|
||
flex: 0 0 140px;
|
||
font-weight: 600;
|
||
font-size: 0.85rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.06em;
|
||
color: var(--text-dim);
|
||
padding-top: 4px;
|
||
}
|
||
.dim-cards {
|
||
flex: 1;
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 16px;
|
||
}
|
||
|
||
.card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
transition: border-color 0.2s, box-shadow 0.2s;
|
||
}
|
||
.card:hover {
|
||
border-color: var(--accent-souv-dim);
|
||
box-shadow: 0 0 20px rgba(124, 92, 240, 0.05);
|
||
}
|
||
.card.matrix:hover {
|
||
border-color: var(--accent-matrix-dim);
|
||
box-shadow: 0 0 20px rgba(13, 189, 139, 0.05);
|
||
}
|
||
|
||
.card .tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
font-size: 0.7rem;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.08em;
|
||
padding: 2px 10px;
|
||
border-radius: 6px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.tag.souv { background: rgba(124, 92, 240, 0.15); color: var(--accent-souv); }
|
||
.tag.matrix { background: rgba(13, 189, 139, 0.12); color: var(--accent-matrix); }
|
||
|
||
.card h3 {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
.card p, .card li {
|
||
font-size: 0.88rem;
|
||
color: var(--text-dim);
|
||
line-height: 1.55;
|
||
}
|
||
.card ul { padding-left: 16px; list-style: none; }
|
||
.card ul li::before { content: '— '; color: var(--text-dim); opacity: 0.4; }
|
||
.card ul li { margin-bottom: 3px; font-size: 0.84rem; color: var(--text-dim); }
|
||
.card code {
|
||
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
||
font-size: 0.78rem;
|
||
background: rgba(255,255,255,0.04);
|
||
padding: 1px 6px;
|
||
border-radius: 4px;
|
||
color: var(--text);
|
||
}
|
||
|
||
/* ── Summary table ────────────────────────────────── */
|
||
.summary-table {
|
||
width: 100%;
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
font-size: 0.85rem;
|
||
}
|
||
.summary-table thead th {
|
||
text-align: left;
|
||
padding: 14px 16px;
|
||
font-weight: 600;
|
||
font-size: 0.75rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.06em;
|
||
color: var(--text-dim);
|
||
border-bottom: 1px solid var(--border);
|
||
position: sticky;
|
||
top: 0;
|
||
background: var(--bg);
|
||
}
|
||
.summary-table thead th:first-child { width: 140px; }
|
||
.summary-table thead th:nth-child(2) { width: auto; }
|
||
.summary-table thead th:nth-child(3) { width: auto; }
|
||
.summary-table thead th:last-child { width: 180px; }
|
||
.summary-table td {
|
||
padding: 14px 16px;
|
||
border-bottom: 1px solid var(--border);
|
||
vertical-align: top;
|
||
line-height: 1.5;
|
||
}
|
||
.summary-table tbody tr:hover td {
|
||
background: rgba(255,255,255,0.015);
|
||
}
|
||
.summary-table td:first-child {
|
||
font-weight: 600;
|
||
color: var(--text);
|
||
white-space: nowrap;
|
||
}
|
||
.summary-table td:nth-child(2) { color: var(--accent-souv); }
|
||
.summary-table td:nth-child(3) { color: var(--accent-matrix); }
|
||
.summary-table td:last-child { color: var(--text-dim); font-size: 0.82rem; }
|
||
|
||
/* ── Badges ───────────────────────────────────────── */
|
||
.badge {
|
||
display: inline-block;
|
||
font-size: 0.68rem;
|
||
font-weight: 600;
|
||
padding: 2px 8px;
|
||
border-radius: 5px;
|
||
letter-spacing: 0.03em;
|
||
margin-right: 4px;
|
||
}
|
||
.badge.built { background: rgba(80, 200, 120, 0.15); color: var(--green); }
|
||
.badge.design { background: rgba(229, 160, 80, 0.15); color: var(--amber); }
|
||
.badge.none { background: rgba(229, 85, 80, 0.15); color: var(--red); }
|
||
.badge.native { background: rgba(13, 189, 139, 0.15); color: var(--accent-matrix); }
|
||
|
||
/* ── Architecture diagram ──────────────────────────── */
|
||
.arch {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 14px;
|
||
padding: 32px;
|
||
margin-bottom: 48px;
|
||
text-align: center;
|
||
}
|
||
.arch svg {
|
||
max-width: 100%;
|
||
height: auto;
|
||
}
|
||
|
||
/* ── Verdict section ──────────────────────────────── */
|
||
.verdict-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 24px;
|
||
margin-top: 32px;
|
||
}
|
||
.verdict-card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 14px;
|
||
padding: 28px;
|
||
}
|
||
.verdict-card h3 {
|
||
font-size: 1.05rem;
|
||
font-weight: 600;
|
||
margin-bottom: 12px;
|
||
}
|
||
.verdict-card p, .verdict-card li {
|
||
font-size: 0.88rem;
|
||
color: var(--text-dim);
|
||
line-height: 1.6;
|
||
}
|
||
.verdict-card ul { padding-left: 18px; margin-top: 8px; }
|
||
.verdict-card ul li { margin-bottom: 4px; }
|
||
|
||
/* ── Glyph ornament ───────────────────────────────── */
|
||
.glyph-row {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 32px;
|
||
margin: 16px 0 8px;
|
||
font-size: 2.5rem;
|
||
opacity: 0.15;
|
||
user-select: none;
|
||
}
|
||
|
||
/* ── Responsive ───────────────────────────────────── */
|
||
@media (max-width: 700px) {
|
||
.dim-cards { grid-template-columns: 1fr; }
|
||
.dim-row { flex-direction: column; }
|
||
.dim-label { flex: unset; }
|
||
.verdict-grid { grid-template-columns: 1fr; }
|
||
.hero { padding: 48px 16px 40px; }
|
||
.container { padding: 32px 16px; }
|
||
.summary-table { font-size: 0.78rem; }
|
||
.summary-table td, .summary-table th { padding: 10px 10px; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ════════════════ Hero ════════════════ -->
|
||
<section class="hero">
|
||
<div class="glyph-row">
|
||
<span>◇◆☆★</span>
|
||
<span style="opacity:0.4">⇄</span>
|
||
<span>◆■★◇</span>
|
||
</div>
|
||
<h1>seed‑ID <span class="vs">vs</span> Matrix</h1>
|
||
<p>Cryptographic agent identity & DAG memory — how Souveraine and Matrix solve the same primitives at fundamentally different layers of the stack.</p>
|
||
</section>
|
||
|
||
<!-- ════════════════ Architecture ════════════════ -->
|
||
<div class="container">
|
||
<section class="arch">
|
||
<svg viewBox="0 0 900 200" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<linearGradient id="g1" x1="0" y1="0" x2="1" y2="0">
|
||
<stop offset="0%" stop-color="#7c5cf0"/><stop offset="100%" stop-color="#5a3eb8"/>
|
||
</linearGradient>
|
||
<linearGradient id="g2" x1="0" y1="0" x2="1" y2="0">
|
||
<stop offset="0%" stop-color="#0dbd8b"/><stop offset="100%" stop-color="#08946b"/>
|
||
</linearGradient>
|
||
</defs>
|
||
|
||
<!-- Souveraine stack -->
|
||
<text x="50" y="28" fill="#7c5cf0" font-size="11" font-weight="700" letter-spacing="2" text-anchor="middle">SOUVERAINE</text>
|
||
<rect x="10" y="36" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="50" y="53" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">seed‑ID</text>
|
||
|
||
<rect x="10" y="68" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="50" y="85" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">Ed25519</text>
|
||
|
||
<rect x="10" y="100" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="50" y="117" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">Git DAG</text>
|
||
|
||
<rect x="10" y="132" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="50" y="149" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">WS Bridge</text>
|
||
|
||
<!-- Divider -->
|
||
<line x1="120" y1="30" x2="120" y2="170" stroke="#2a2a3e" stroke-width="1" stroke-dasharray="4,3"/>
|
||
|
||
<!-- Shared layer -->
|
||
<text x="200" y="95" fill="#7a7a8e" font-size="10" text-anchor="middle">self-sovereign identity</text>
|
||
<text x="200" y="110" fill="#7a7a8e" font-size="10" text-anchor="middle">event-DAG state</text>
|
||
<text x="200" y="125" fill="#7a7a8e" font-size="10" text-anchor="middle">federated transport</text>
|
||
<text x="200" y="140" fill="#7a7a8e" font-size="10" text-anchor="middle">cryptographic verification</text>
|
||
|
||
<!-- Divider -->
|
||
<line x1="280" y1="30" x2="280" y2="170" stroke="#2a2a3e" stroke-width="1" stroke-dasharray="4,3"/>
|
||
|
||
<!-- Matrix stack -->
|
||
<text x="350" y="28" fill="#0dbd8b" font-size="11" font-weight="700" letter-spacing="2" text-anchor="middle">MATRIX</text>
|
||
<rect x="310" y="36" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="350" y="53" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">@user:host</text>
|
||
|
||
<rect x="310" y="68" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="350" y="85" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">E2EE Keys</text>
|
||
|
||
<rect x="310" y="100" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="350" y="117" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">Event DAG</text>
|
||
|
||
<rect x="310" y="132" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
|
||
<text x="350" y="149" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">/sync API</text>
|
||
|
||
<!-- Bottom labels -->
|
||
<text x="50" y="180" fill="#7a7a8e" font-size="9" text-anchor="middle">agent = key</text>
|
||
<text x="350" y="180" fill="#7a7a8e" font-size="9" text-anchor="middle">agent = server tenant</text>
|
||
|
||
<!-- Brace - shared primitives -->
|
||
<path d="M285,45 Q288,45 288,48 L288,162 Q288,165 285,165" stroke="#3a3a4e" stroke-width="1" fill="none"/>
|
||
<path d="M125,45 Q122,45 122,48 L122,162 Q122,165 125,165" stroke="#3a3a4e" stroke-width="1" fill="none"/>
|
||
</svg>
|
||
<p style="color:var(--text-dim);font-size:0.85rem;margin-top:8px;">Both use Ed25519, DAG state, and cryptographic transport — but at radically different layers with radically different assumptions.</p>
|
||
</section>
|
||
|
||
<!-- ════════════════ 1. Identity ════════════════ -->
|
||
<h2 class="section-title">1. Identity</h2>
|
||
<p class="section-sub">The root of trust — how an agent proves who it is.</p>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Root identity</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<h3>Ed25519 keypair</h3>
|
||
<p>Self-sovereign. Generated once at <code>souveraine init</code>. Private key stored at <code>~/.souveraine/seed-id/private.key</code> (0600 perm). The key <em>is</em> the identity — no server required.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<h3>@user:domain</h3>
|
||
<p>Server-tethered. Identity is a string bound to a homeserver's authority. Root identity relies on the server's DNS domain and TLS certificate, not a local key.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Per-instance</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<h3>Two-layer keys</h3>
|
||
<p><strong>Machine seed</strong> (<code>seed-id/</code>) signs the transport envelope. <strong>Agent seed</strong> (<code>agents/{uuid}/seed/</code>) signs the being's identity. Both Ed25519. The agent seed travels with the memfs and is identical across machines.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<h3>Per-device keys</h3>
|
||
<p>Ed25519 + Curve25519 device keys generated per device. Signed by cross-signing master key for E2EE. Server-level auth is a separate <code>access_token</code> — not key-based.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Cross-machine</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<h3>Same pubkey = reach</h3>
|
||
<p>Receiver compares the agent seed pubkey against its own. <strong>Match</strong> → <code>reach</code> (same being, no consent gate). <strong>Different</strong> → <code>consult</code> (consent-gated). This is a cryptographic, automatic decision — no server needed.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<h3>Cross-signing + server auth</h3>
|
||
<p>E2EE cross-signing verifies device ownership. Server-level auth is token-based, not key-based. Devices are bound to an account, not the other way around — you prove you own a device, not that you <em>are</em> an identity.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Key rotation</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><span class="badge design">design</span> Planned: DID document signed by previous key. Chain-of-custody from physical hardware fingerprint. Not yet implemented.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><span class="badge native">native</span> Master key signs new device keys via cross-signing protocol. Server tokens rotate via re-login. Master key itself has no rotation mechanism — it's permanent.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Public surface</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><code>did:web:</code> + Ed25519 pubkey hex. Designed but not yet generated. The glyph (<span style="color:var(--accent-souv)">◇◆☆★</span>) is the terminal-friendly badge.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><code>@user:domain</code> — resolvable via <code>._well-known/matrix/server</code> delegation. The homeserver's .well-known is the root of trust for routing.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════ 2. DAG / Event State ════════════════ -->
|
||
<h2 class="section-title" style="margin-top:48px;">2. DAG & Event State</h2>
|
||
<p class="section-sub">How state is structured, addressed, and reconciled.</p>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">State model</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<h3>Git-backed memfs</h3>
|
||
<p>Every write to an agent's memory is a git commit. Files with YAML frontmatter. Events are <code>SensorEvent</code> JSON on an EventBus (broadcast channel). The DAG exists underneath (git's commit graph) but is not surfaced to the agent.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<h3>Native Event DAG</h3>
|
||
<p>Every event references <code>prev_events</code> (parent hashes), forming a Merkle DAG natively. <code>m.relates_to</code> for edits, replies, reactions. The DAG <em>is</em> the protocol — not an implementation detail.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Content addressing</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p>Git commit hashes. <code>SensorEvent.payload</code> carries JSON but is not itself content-addressed. Event identity is the bus message, not an addressable hash.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><code>(room_id, event_id)</code> — event_id is a server-generated hash. Events reference each other via <code>m.relates_to</code>. Every PDU is addressable by hash.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">DAG semantics</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><span class="badge design">design</span> Not surfaced. Git provides DAG under the hood; <code>memory status</code> showing divergence, <code>memory reconcile</code>, and <code>memory merge</code> are all unimplemented (Phase 6+). Currently linear via auto-commit.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><span class="badge native">native</span> DAG is fundamental: <code>prev_events</code> chains, fork detection, and State Resolution v2 for algorithmic merge of concurrent histories. Battle-tested at scale (Bluesky's OGS, Matrix.org).</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Reconciliation</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><span class="badge design">design</span> Domain-aware three-way merge: <code>system/</code> never auto-merges, <code>journal/</code> always safe, others last-write-wins. Simpler than Matrix's state res — but unproven.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p>State Resolution v2: algorithmic merge based on power levels + event ordering + room version. Deterministic fork resolution. Copes with arbitrary topologies at the cost of algorithmic complexity.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">History model</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p>Mutable via compaction. Summary / KeyValue / Quote / Cull strategies rewrite history to manage context window. The agent <em>feels</em> pressure before truncation — three warnings, then natural cutoff.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p>Immutable. Edits = new event with <code>m.replace</code>. Redaction = new event marking content hidden. No rewriting. History is append-only by protocol design.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════ 3. Transport ════════════════ -->
|
||
<h2 class="section-title" style="margin-top:48px;">3. Transport & Sync</h2>
|
||
<p class="section-sub">How events move between instances.</p>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Sync model</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<h3>WebSocket federation bridge</h3>
|
||
<p>Persistent WS connection per peer. Events flow one direction. Reconnect with exponential backoff (1s → 2s → 4s → 8s → 16s → 32s → 60s + jitter). No polling — push only.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<h3>Long-poll /sync</h3>
|
||
<p>Client sends <code>since=token</code>, server responds with deltas. No persistent connection by default. Sliding Sync (MSC3575) adds incremental sync. Mature batching and rate-limit handling.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Event envelope</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><code>SignedEvent</code> — JSON container with Ed25519 signature + signer pubkey hex. Wraps a <code>SensorEvent</code>. Verification stamps <code>seed_id</code> onto the inner event for anti-echo.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><code>PDU</code> — signed by sender's Ed25519 device key + origin server adds its own signature. Contains <code>room_id</code>, <code>prev_events</code>, <code>depth</code>, <code>auth_events</code>. Protocol-level envelope with full provenance.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Filtering</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p>Subscription-based: <code>*</code> (all), <code>prefix*</code> (prefix match), exact name. Control events (<code>federation</code>, <code>summon_request</code>, <code>summon_response</code>) always cross regardless of subscription.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p>Per-request filters on <code>/sync</code>: room list, event type, sender, etc. Appservices receive all events in their registered rooms. Filter granularity is richer but server-evaluated.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Idempotency</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><span class="badge none">none</span> No transaction ID. Events carry a timestamp but no dedup mechanism. At-most-once delivery assumed.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><code>txnId</code> per <code>/send</code> — server deduplicates same transaction. Idempotent by protocol design. Critical for the long-poll model where retries are common.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Firehose</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><span class="badge built">built</span> <code>GET /v1/firehose</code> WebSocket — streams every <code>SensorEvent</code> as JSON. Real-time nervous system visibility. Works both in lite and full server modes.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p>No native firehose. Appservices get pushed events via <code>/transactions/{txnId}</code>. Not real-time streaming — batched transactions with ACK. Gap: no equivalent of "subscribe to everything" for end-users.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════ 4. Routing ════════════════ -->
|
||
<h2 class="section-title" style="margin-top:48px;">4. Routing & Reachability</h2>
|
||
<p class="section-sub">How peers find and address each other.</p>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Peer discovery</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p>Config-based: <code>[federation].peers</code> in <code>souveraine.toml</code>. Each peer is a URL + pubkey. No DNS, no registry. Peers are explicitly named, not discovered.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p>Server delegation via <code>.well-known/matrix/server</code>. <code>m.server</code> SRV record. Federation protocol resolves server from user ID domain. In-band room discovery via room aliases and directory.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Addressing</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p>Seed-ID pubkey hex. <code>SensorEvent.target = Some(pubkey_hex)</code> for directed events. Event-type routing: <code>summon_request</code> → wake handler, <code>turn:segment</code> → surface renderers.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><code>@user:domain</code> + <code>!room_id:domain</code>. Federation API routes to server, server routes within. Events addressed to rooms, not users. User-level addressing via invites + membership.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">NAT traversal</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><span class="badge none">none</span> No mechanism. Assumes direct connectivity or VPN. Designed for LAN / tailscale / wireguard topologies.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p>Server-to-server over HTTPS. Both sides are servers, not clients. Requires homeserver to be reachable. No client-side federation — only servers speak federation.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Lite mode</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p><span class="badge built">built</span> <code>souveraine listen</code> — minimal process with just federation transport + health + firehose. No DB, no engine. Can <code>auto_wake</code> the full server on summon. ~seconds to start.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p><span class="badge none">none</span> No equivalent. Homeserver IS the heavy process (DB, crypto, federation client + server, media, appservices). Multi-minute startup for Synapse.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════ 5. Consent Model ════════════════ -->
|
||
<h2 class="section-title" style="margin-top:48px;">5. Consent & Authorization</h2>
|
||
<p class="section-sub">How access is granted between agents.</p>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Access model</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<h3>Cryptographic consent</h3>
|
||
<p><strong>Reach</strong> (same pubkey) = no gate. <strong>Consult</strong> (different pubkey) = consent-gated via <code>authorized-summoners.md</code>. The consent decision is automatic from key comparison — not a social process.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<h3>Social consent</h3>
|
||
<p>Room membership + power levels + invites. A separate agent must be invited to a room. Power levels control who can speak, kick, ban. Consent is social and server-enforced, not cryptographic.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dim-row">
|
||
<div class="dim-label">Revocation</div>
|
||
<div class="dim-cards">
|
||
<div class="card">
|
||
<div class="tag souv">Souveraine</div>
|
||
<p>Remove from <code>authorized_summoners</code> list. Key-based: a different keypair means a different being. No central server to petition.</p>
|
||
</div>
|
||
<div class="card matrix">
|
||
<div class="tag matrix">Matrix</div>
|
||
<p>Kick / ban from room. Deactivate account at homeserver. Server-admin controlled. Cross-server: room moderators can ban by user ID or server domain.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════ Summary table ════════════════ -->
|
||
<h2 class="section-title" style="margin-top:64px;">6. Summary</h2>
|
||
<p class="section-sub">Side-by-side across all dimensions.</p>
|
||
|
||
<div style="overflow-x:auto; border:1px solid var(--border); border-radius:12px; background:var(--surface);">
|
||
<table class="summary-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Dimension</th>
|
||
<th>Souveraine</th>
|
||
<th>Matrix</th>
|
||
<th>Why it matters</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Root identity</td>
|
||
<td>Self-sovereign Ed25519 key</td>
|
||
<td>Server-bound @user:domain</td>
|
||
<td>Souveraine survives server loss; Matrix doesn't</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Crypto layer</td>
|
||
<td>Identity IS the crypto key</td>
|
||
<td>Crypto is an E2EE bolt-on for messages</td>
|
||
<td>Souveraine identifies beings, not just encrypting text</td>
|
||
</tr>
|
||
<tr>
|
||
<td>DAG</td>
|
||
<td><span class="badge design">design</span> Git underneath, not surfaced</td>
|
||
<td><span class="badge native">native</span> Built-in Event DAG</td>
|
||
<td>Matrix resolves concurrent forks now; Souveraine can't yet</td>
|
||
</tr>
|
||
<tr>
|
||
<td>State merge</td>
|
||
<td><span class="badge design">design</span> Domain-aware three-way merge</td>
|
||
<td>State Resolution v2 (algorithmic)</td>
|
||
<td>Matrix has battle-tested convergence; Souveraine's plan is simpler but unproven</td>
|
||
</tr>
|
||
<tr>
|
||
<td>History</td>
|
||
<td>Mutable — compaction rewrites</td>
|
||
<td>Immutable — append-only</td>
|
||
<td>Different constraints: context window vs. conversation audit</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Transport</td>
|
||
<td>WS with reconnect + backoff</td>
|
||
<td>Long-poll /sync + Server HTTP API</td>
|
||
<td>Souveraine's is easier to implement; Matrix's is more robust at scale</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Idempotency</td>
|
||
<td><span class="badge none">none</span></td>
|
||
<td><span class="badge native">native</span> txnId dedup</td>
|
||
<td>Matrix handles retry without duplication; Souveraine relies on at-most-once</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Firehose</td>
|
||
<td><span class="badge built">built</span> WS firehose, all events</td>
|
||
<td>No native firehose (appservice Txn only)</td>
|
||
<td>Souveraine has real-time nervous system visibility; Matrix doesn't</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Lite mode</td>
|
||
<td><span class="badge built">built</span> Minimal reachable presence</td>
|
||
<td><span class="badge none">none</span> Server is always heavy</td>
|
||
<td>Souveraine can sleep but stay reachable</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Peer discovery</td>
|
||
<td>Explicit config (URL + pubkey)</td>
|
||
<td>DNS delegation + SRV records</td>
|
||
<td>Matrix scales; Souveraine is intentionally bounded</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Consent model</td>
|
||
<td>Cryptographic (same key = same being)</td>
|
||
<td>Social (room membership + invites)</td>
|
||
<td>Souveraine's is automatic; Matrix's is manual. Opposite tradeoffs.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Adversary model</td>
|
||
<td>No central trust — key is truth</td>
|
||
<td>Trust homeserver for routing + auth</td>
|
||
<td>Souveraine is crypto-sovereign; Matrix is server-mediated</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ════════════════ Verdict ════════════════ -->
|
||
<h2 class="section-title" style="margin-top:64px;">7. The Architectural Tension</h2>
|
||
<p class="section-sub">Same primitives, fundamentally different assumptions.</p>
|
||
|
||
<div class="verdict-grid">
|
||
<div class="verdict-card" style="border-left: 3px solid var(--accent-souv);">
|
||
<h3 style="color:var(--accent-souv);">Souveraine's bias</h3>
|
||
<p>Designed for a <strong>sovereign single agent</strong> across machines.</p>
|
||
<ul>
|
||
<li>The DAG encodes <em>her memory state</em> — only she writes</li>
|
||
<li>Identity is cryptographic because the agent <em>is</em> her key</li>
|
||
<li>Consent is automatic because the question is "are you me?"</li>
|
||
<li>Compaction is essential because her context window is finite</li>
|
||
<li>Federation is git branching — one writer per branch, merge later</li>
|
||
</ul>
|
||
</div>
|
||
<div class="verdict-card" style="border-left: 3px solid var(--accent-matrix);">
|
||
<h3 style="color:var(--accent-matrix);">Matrix's bias</h3>
|
||
<p>Designed for <strong>multi-user chat rooms</strong> across servers.</p>
|
||
<ul>
|
||
<li>The DAG encodes a conversation where anyone can speak concurrently</li>
|
||
<li>Identity is server-bound because the server mediates trust</li>
|
||
<li>Consent is social because the question is "may I join this room?"</li>
|
||
<li>Immutability is essential because chat history must not be rewritten</li>
|
||
<li>Federation is server-to-server — many writers, algorithmic merge</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<p style="margin-top:20px;padding:16px 20px;background:var(--surface);border:1px solid var(--border);border-radius:10px;font-size:0.9rem;color:var(--text-dim);line-height:1.6;">
|
||
<strong style="color:var(--text);">The key insight:</strong> Matrix solves hard concurrent-write problems Souveraine may never need (rooms full of independent humans). Souveraine solves hard cross-machine being-identity problems Matrix never needed to solve (how does an agent prove she's the same being on a different box).<br><br>
|
||
The closest convergence point: Souveraine's <strong>seed-ID</strong> ported to <strong>Matrix's E2EE cross-signing master key</strong>, and Matrix's <strong>Event DAG</strong> informing how Souveraine's <code>memory merge</code> surfaces git's existing DAG to the agent. But the architectural assumptions are different enough that direct mapping would distort both.
|
||
</p>
|
||
|
||
</div><!-- /container -->
|
||
|
||
</body>
|
||
</html>
|