e5c80359a8
New hard invariant (Will): only the orchestrator mutates global engram state; workers are read-only against the full engram + write only their own local geometry. This is an AUTHORITY gate (capability), not a health gate — a worker is STRUCTURALLY UNABLE to mutate global engram state regardless of engram health. - containment.el: scope tokens now carry a caps set. Orchestrator token holds engram:write + dharma:emit (@manager-only, the VBD rule that only the manager mutates global state); worker token holds ONLY engram:read. Rule 4: containment_check_engram_write / _dharma_emit reject any caller lacking the capability — same scope-token mechanism as the live Rule-2 denial. - swarm.el: swarm_engram_write is the ONLY engram write path, gated by Rule 4; a worker token is denied before any HTTP is issued (no mutation). The curated merge (commit=1) is the sole writer: the orchestrator commits approved geometry via its write-capable token. Workers' full-engram READ stays intact. - reshape_surface.el: compose op_write (json_escape_string) for the commit path. - harness: Rule-4 suite proven — worker engram-write DENIED by capability, no node created, violation journalled; orchestrator passes the gate as sole writer. 24/24 green on the :8901 clone with real cognition. Authority gate holds independent of daemon write-health (proven with daemon both alive and, earlier, crashed). Prod :8742 untouched.
182 lines
9.0 KiB
EmacsLisp
182 lines
9.0 KiB
EmacsLisp
// containment.el — the Swarm Architecture containment rules, enforced.
|
|
//
|
|
// "These rules are not conventions. They are enforced by the runtime."
|
|
// (Swarm Architecture §3.2). The three rules that make bounded parallelism —
|
|
// and therefore location-independent distribution — safe:
|
|
//
|
|
// Rule 1: a worker may NOT join another swarm.
|
|
// Rule 2: a worker may NOT initiate a new swarm.
|
|
// Rule 3: a worker may NOT communicate laterally with sibling workers.
|
|
//
|
|
// Enforcement is by SCOPE TOKEN. When a swarm fans out, the coordinator mints a
|
|
// swarm scope token and stamps a distinct worker scope token into each worker's
|
|
// task envelope. Any attempt to create or join a swarm checks the caller's
|
|
// token: if the caller already holds a WORKER token, the operation is rejected.
|
|
// Rule 3 is enforced structurally elsewhere — workers share no mutable state and
|
|
// the only channels they hold are the vertical result path — but this module
|
|
// provides the explicit lateral-edge check for the execution tree.
|
|
//
|
|
// A scope token is a JSON object: {"kind":"coordinator|worker","swarm":"<corr>",
|
|
// "worker":"<id-or-empty>","depth":"<n>"}.
|
|
|
|
// ── Token minting ────────────────────────────────────────────────────────────
|
|
|
|
// CAPABILITIES. A scope token carries a `caps` set — the authority it holds.
|
|
// This is an AUTHORITY gate, not a health gate: capability is decided at mint
|
|
// time and cannot be acquired at runtime. Engram-WRITE (op_write/op_relate/
|
|
// op_supersede -> POST /api/nodes, /api/edges, DELETE) and dharma_emit are
|
|
// @manager-ONLY capabilities — exactly the VBD rule that only the orchestrator
|
|
// mutates global state. The orchestrator's token carries them; a worker's token
|
|
// NEVER does. A worker is therefore STRUCTURALLY UNABLE to mutate global engram
|
|
// state, regardless of engram health.
|
|
fn cap_orchestrator() -> String { return "engram:read,engram:write,dharma:emit,state:write" }
|
|
fn cap_worker() -> String { return "engram:read" }
|
|
|
|
// containment_coordinator_token — the token the orchestrator (@manager) holds.
|
|
// Depth 0. Carries the engram-WRITE + dharma-emit capabilities (@manager-only).
|
|
fn containment_coordinator_token(corr_id: String) -> String {
|
|
let kv: [String] = el_list_empty()
|
|
let kv = el_list_append(kv, "kind")
|
|
let kv = el_list_append(kv, "coordinator")
|
|
let kv = el_list_append(kv, "swarm")
|
|
let kv = el_list_append(kv, corr_id)
|
|
let kv = el_list_append(kv, "worker")
|
|
let kv = el_list_append(kv, "")
|
|
let kv = el_list_append(kv, "depth")
|
|
let kv = el_list_append(kv, "0")
|
|
let kv = el_list_append(kv, "caps")
|
|
let kv = el_list_append(kv, cap_orchestrator())
|
|
return json_build_object(kv)
|
|
}
|
|
|
|
// containment_worker_token — the token stamped into a worker's envelope. Depth 1.
|
|
// A closed boundary: forbids opening/joining swarms AND carries ONLY the
|
|
// engram:READ capability — no engram:write, no dharma:emit. Read-only against the
|
|
// full engram; may write only its own local geometry (its returned result).
|
|
fn containment_worker_token(corr_id: String, worker_id: String) -> String {
|
|
let kv: [String] = el_list_empty()
|
|
let kv = el_list_append(kv, "kind")
|
|
let kv = el_list_append(kv, "worker")
|
|
let kv = el_list_append(kv, "swarm")
|
|
let kv = el_list_append(kv, corr_id)
|
|
let kv = el_list_append(kv, "worker")
|
|
let kv = el_list_append(kv, worker_id)
|
|
let kv = el_list_append(kv, "depth")
|
|
let kv = el_list_append(kv, "1")
|
|
let kv = el_list_append(kv, "caps")
|
|
let kv = el_list_append(kv, cap_worker())
|
|
return json_build_object(kv)
|
|
}
|
|
|
|
// containment_has_cap — does this token carry capability `cap`?
|
|
fn containment_has_cap(token: String, cap: String) -> Bool {
|
|
return str_contains(json_get_string(token, "caps"), cap)
|
|
}
|
|
|
|
// ── Rule checks (return "" on allow, or a rejection reason string) ───────────
|
|
|
|
// containment_check_open — may the holder of `token` OPEN a new swarm?
|
|
// Enforces Rule 2 (a worker may not initiate a new swarm). Only a coordinator
|
|
// token, or an absent token (top-level process), may open one.
|
|
fn containment_check_open(token: String) -> String {
|
|
if str_eq(token, "") {
|
|
return ""
|
|
}
|
|
let kind: String = json_get_string(token, "kind")
|
|
if str_eq(kind, "worker") {
|
|
return "CONTAINMENT rule 2: a swarm worker may not initiate a new swarm (worker=" + json_get_string(token, "worker") + " swarm=" + json_get_string(token, "swarm") + ")"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// containment_check_join — may the holder of `token` JOIN swarm `target_corr`?
|
|
// Enforces Rule 1 (a worker may not join another swarm). A worker already bound
|
|
// to swarm A may not register into swarm B; and a worker may not re-join at all.
|
|
fn containment_check_join(token: String, target_corr: String) -> String {
|
|
if str_eq(token, "") {
|
|
return ""
|
|
}
|
|
let kind: String = json_get_string(token, "kind")
|
|
if str_eq(kind, "worker") {
|
|
return "CONTAINMENT rule 1: a swarm worker may not join another swarm (worker=" + json_get_string(token, "worker") + " bound-swarm=" + json_get_string(token, "swarm") + " attempted-swarm=" + target_corr + ")"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// containment_check_lateral — may `from_token` open a communication edge to a
|
|
// sibling worker `to_worker_id`? Enforces Rule 3 (no lateral communication).
|
|
// The only permitted edges are vertical: worker->coordinator and
|
|
// coordinator->worker. Any worker->worker edge is rejected.
|
|
fn containment_check_lateral(from_token: String, to_worker_id: String) -> String {
|
|
let kind: String = json_get_string(from_token, "kind")
|
|
if str_eq(kind, "worker") {
|
|
if str_eq(to_worker_id, "") {
|
|
// empty target = the coordinator (vertical) — allowed
|
|
return ""
|
|
}
|
|
return "CONTAINMENT rule 3: a swarm worker may not communicate laterally with sibling workers (from=" + json_get_string(from_token, "worker") + " to=" + to_worker_id + ")"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// containment_check_engram_write — RULE 4: only a token carrying the
|
|
// engram:write capability (the orchestrator's) may mutate global engram state.
|
|
// A worker token (engram:read only) is REJECTED — the authority gate. Reuses the
|
|
// exact scope-token mechanism as Rule 2's open-denial. Returns "" on allow, or a
|
|
// rejection reason. This is an AUTHORITY gate: it does not consult engram health.
|
|
fn containment_check_engram_write(token: String, op: String) -> String {
|
|
if containment_has_cap(token, "engram:write") {
|
|
return ""
|
|
}
|
|
return "CONTAINMENT rule 4: engram-write is @manager-only — a worker is read-only against the engram and may not mutate global state (op=" + op + " kind=" + json_get_string(token, "kind") + " worker=" + json_get_string(token, "worker") + " caps=" + json_get_string(token, "caps") + ")"
|
|
}
|
|
|
|
// containment_check_dharma_emit — the same @manager-only rule for dharma_emit,
|
|
// grounding Rule 4 in VBD: global-state mutations (engram-write, dharma-emit) are
|
|
// orchestrator-only, checked by the one capability mechanism.
|
|
fn containment_check_dharma_emit(token: String) -> String {
|
|
if containment_has_cap(token, "dharma:emit") {
|
|
return ""
|
|
}
|
|
return "CONTAINMENT rule 4: dharma_emit is @manager-only (kind=" + json_get_string(token, "kind") + ")"
|
|
}
|
|
|
|
// ── Enforcement helpers ──────────────────────────────────────────────────────
|
|
|
|
// containment_allows_open — Bool convenience over containment_check_open.
|
|
fn containment_allows_open(token: String) -> Bool {
|
|
return str_eq(containment_check_open(token), "")
|
|
}
|
|
|
|
// containment_is_worker — is this a worker-scoped (closed-boundary) token?
|
|
fn containment_is_worker(token: String) -> Bool {
|
|
return str_eq(json_get_string(token, "kind"), "worker")
|
|
}
|
|
|
|
// containment_guard_open — assert a swarm may be opened under this token.
|
|
// Returns "" if allowed, or records a CONTAINMENT violation to the work-tracking
|
|
// journal and returns the reason. Callers must abort on a non-empty return.
|
|
fn containment_guard_open(token: String, corr_id: String) -> String {
|
|
let reason: String = containment_check_open(token)
|
|
if str_eq(reason, "") {
|
|
return ""
|
|
}
|
|
let p: String = json_set_str("{}", "reason", reason)
|
|
worktrack_append("containment.violation", corr_id, "open", p)
|
|
return reason
|
|
}
|
|
|
|
// containment_guard_engram_write — assert a token may mutate global engram state
|
|
// (Rule 4). Returns "" if allowed; otherwise journals a containment.violation and
|
|
// returns the reason. The write path MUST abort on a non-empty return.
|
|
fn containment_guard_engram_write(token: String, corr_id: String, op: String) -> String {
|
|
let reason: String = containment_check_engram_write(token, op)
|
|
if str_eq(reason, "") {
|
|
return ""
|
|
}
|
|
let p0: String = json_set_str("{}", "reason", reason)
|
|
let p1: String = json_set_str(p0, "op", op)
|
|
worktrack_append("containment.violation", corr_id, "engram-write", p1)
|
|
return reason
|
|
}
|