// arborist/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="arborist mesh init --group <name>\nthen mesh enable\n(creates epoch 0; founder = sole admin)", shape=box, style="rounded,filled", fillcolor="#d6ffd6"];
    a_add    [label="arborist 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="arborist mesh kick\n--member-id <id>\n--reason '...'", shape=box, style="rounded,filled", fillcolor="#d6ffd6"];
    a_rotate [label="arborist 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];
}
