arborist/docs/diagrams/mesh-group-decisions.dot
russell@unturf.com c7275b5618
docs: mesh multiplayer protocol with dot diagrams
Adds docs/mesh.md and five graphviz diagrams covering the federation
layer: identity stack, epoch state machine, per-member secret envelope,
gossip wire contract, and operator decision tree. Pins the protocol
contract for the upcoming HTTP wire (mesh sync, mesh serve).

Makefile gets a 'docs' target with pattern rule so PNG renders are
incremental from .dot sources.
2026-04-28 12:54:36 -04:00

50 lines
2.7 KiB
Text

// aborist/mesh — group operator decision tree.
//
// When a group steward (admin) faces a roster question, this diagram
// shows which CLI verb solves it and what guarantee comes out the
// other side.
//
// Render: dot -Tpng docs/diagrams/mesh-group-decisions.dot -o /tmp/x.png
digraph mesh_group_decisions {
rankdir=TB;
bgcolor="white";
node [fontname="Helvetica"];
edge [fontname="Helvetica", fontsize=10];
start [label="group steward has a question", shape=ellipse, style="filled", fillcolor="#eeeeee"];
q_first [label="is mesh\ninitialized\nyet?", shape=diamond, style="filled", fillcolor="#fff7d6"];
q_role [label="is the question\nabout people\nor secrets?", shape=diamond, style="filled", fillcolor="#fff7d6"];
q_who [label="add, remove,\nor refresh?", shape=diamond, style="filled", fillcolor="#fff7d6"];
q_admin [label="are you\nadmin in\ncurrent epoch?", shape=diamond, style="filled", fillcolor="#fff7d6"];
a_init [label="aborist mesh init --group <name>\nthen mesh enable\n(creates epoch 0; founder = sole admin)", shape=box, style="rounded,filled", fillcolor="#d6ffd6"];
a_add [label="aborist mesh add\n--member-id <id>\n--sign-pub <hex>\n--dh-pub <hex>\n[--role admin]", shape=box, style="rounded,filled", fillcolor="#d6ffd6"];
a_kick [label="aborist mesh kick\n--member-id <id>\n--reason '...'", shape=box, style="rounded,filled", fillcolor="#d6ffd6"];
a_rotate [label="aborist mesh rotate\n--reason '...'\n(any current member)", shape=box, style="rounded,filled", fillcolor="#d6ffd6"];
g_admin [label="permission denied\n(only admins of the\ncurrent epoch may add or kick)", shape=box, style="rounded,filled", fillcolor="#ffe0e0"];
g_add [label="new member can decrypt\nepoch+1 forward;\ncannot reach prior epochs", shape=note, style="filled", fillcolor="#ffffff"];
g_kick [label="kicked member's prior\nsignatures stay valid forever;\nopaque to gossip from epoch+1 on", shape=note, style="filled", fillcolor="#ffffff"];
g_rot [label="fresh secret on the same roster;\nuse on suspected secret leak\nor scheduled hygiene", shape=note, style="filled", fillcolor="#ffffff"];
start -> q_first;
q_first -> a_init [label="no"];
q_first -> q_role [label="yes"];
q_role -> q_who [label="people"];
q_role -> a_rotate [label="just rotate the secret"];
q_who -> q_admin [label="add or kick"];
q_who -> a_rotate [label="refresh secret only"];
q_admin -> a_add [label="yes (admin) -> add"];
q_admin -> a_kick [label="yes (admin) -> kick"];
q_admin -> g_admin [label="no"];
a_add -> g_add [arrowhead=none, style=dotted];
a_kick -> g_kick [arrowhead=none, style=dotted];
a_rotate -> g_rot [arrowhead=none, style=dotted];
}