feat(orchestrator): hierarchy view from council offices with a separate agent order

The Agents views gain a Hierarchie view: an org chart of the chair and
the line offices read from the council claims. The operator appoints,
hands over and recalls an office there; the page signs each change with
the passkey and a host unit (client/offices.py, offices path unit)
verifies the signature, removes a live holder itself and runs a plain
council.py claim for the successor. council.py loses the --operator
flag, so no agent can override a live holder.

The agent order is now separate from task priority: rasci.py agents
order stores it in agent-order.json beside the register through the
nofollow helpers and never writes a --prio pin. It only breaks ties of
equal task rank, also among the queue grants. The Hierarchie view edits
it as a drag list.

Host units run the installed skill scripts, so orchestrator.sh keeps the
offices unit off while the installed council.py, nofollow.py or rasci.py
differ from the tree. Job files, council files and hub records are read
with O_NOFOLLOW and O_NONBLOCK and size caps; nofollow.rewrite replaces
a claim without creating directories, so a beat never revives a released
office.

🎯 Fix: 92 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: 79 %
🛡️ Security: 100 %
🏆 Score: 100
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Veen-BirkenbachandClaude Opus 5.5 committed 2026-11-07 17:46:39 +00:00
1 parent 8e180be256
commit 4540494c30
53 files changed
+1821 -211

No files matched your search

+9 -1
View File
@@ -3,7 +3,8 @@ import {mkdtempSync, readFileSync, rmSync, writeFileSync} from "node:fs";
import {tmpdir} from "node:os";
import {join} from "node:path";
// Args: <chromium binary> <plan.json>; the plan lists steps {width, height, url, wait, probe, shot, media} and an optional
// Args: <chromium binary> <plan.json>; the plan lists steps {width, height, url, wait, keys, probe, shot, media}, keys
// being real key presses (Enter, Tab) on the focused element before the probe, and an optional
// authenticator {credentialId, privateKey, rpId}: base64 id and PKCS#8 key of a passkey the page may sign with.
// Prints {results, errors}: one probe value per step and every uncaught page exception.
const [binary, planFile] = process.argv.slice(2);
@@ -14,6 +15,7 @@ const profile = mkdtempSync(join(tmpdir(), "cdp-"));
const flags = ["--headless", "--no-sandbox", "--disable-gpu", "--use-angle=swiftshader", "--enable-unsafe-swiftshader", "--no-first-run", "--no-default-browser-check", "--hide-scrollbars", `--user-data-dir=${profile}`, "--remote-debugging-port=0", "about:blank"];
const browser = spawn(binary, flags, {stdio: ["ignore", "ignore", "pipe"]});
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const KEYS = {Enter: [13, "\r"], Tab: [9, ""]};
const address = await new Promise((resolve, reject) => {
let text = "";
@@ -79,6 +81,12 @@ try {
await page("Page.navigate", {url: step.url});
}
await sleep(step.wait);
for (const key of step.keys || []) {
const [code, text] = KEYS[key];
await page("Input.dispatchKeyEvent", {type: "keyDown", key, code: key, windowsVirtualKeyCode: code, text});
await page("Input.dispatchKeyEvent", {type: "keyUp", key, code: key, windowsVirtualKeyCode: code});
await sleep(250);
}
let value = null;
if (step.probe) {
const {result, exceptionDetails} = await page("Runtime.evaluate", {expression: step.probe, awaitPromise: true, returnByValue: true});
+99 -3
View File
@@ -19,11 +19,13 @@ sys.path.insert(0, str(HERE.parent))
from hub_case import HubCase
from hub_support import ASK, iso, verifier
from test_hub_cleanup import DONE_TIP, FAKE_PKGMGR, host
from test_hub_offices import COUNCIL_SCRIPT
from test_hub_offices import host as office_host
OUT = Path(os.environ.get("E2E_OUT", "/tmp/orchestrator-phase4-shots"))
WIDTHS = ((1920, 1080), (1366, 768), (390, 844))
VIEWS = ("orbit", "chord", "swimlane", "tree", "3d")
SCREENS = ["stream", "stream/inbox", "stream/rules", *(f"{tab}/{view}" for tab in ("agents", "artifacts") for view in VIEWS)]
SCREENS = ["stream", "stream/inbox", "stream/rules", *(f"{tab}/{view}" for tab in ("agents", "artifacts") for view in VIEWS), "agents/hierarchy"]
HELPERS = """
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const until = async (check, ms) => {
@@ -78,9 +80,57 @@ PROBE = """(async () => {@HELPERS@
marks: all("#main svg.chart .node").length,
note: text(document.querySelector("#main .space-note")),
canvas: Boolean(document.querySelector("#main .graph3d canvas")),
org: all("#main .org-chart .org-row[data-office]").map((row) => [row.dataset.office, text(row.querySelector(".org-holder"))]),
toggles: all("#main .org-toggle").map((button) => [name(button), button.getAttribute("aria-expanded")]),
order: all("#main .agent-order li").map((item) => item.dataset.name),
wide: document.documentElement.scrollWidth > window.innerWidth + 1,
};
})()""".replace("@HELPERS@", HELPERS)
ORG_OPEN = """(async () => {@HELPERS@
const row = await until(() => document.querySelector('#main .org-row[data-office="identity/oidc"]'), 8000);
if (!row) {
return {error: text(document.getElementById("main"))};
}
const toggle = all("#main .org-toggle").find((button) => name(button) === "Zuklappen: identity");
toggle.focus();
return {focused: document.activeElement.dataset.focus, offices: all("#main .org-row[data-office]").map((entry) => entry.dataset.office)};
})()""".replace("@HELPERS@", HELPERS)
ORG_FOLDED = """(async () => {@HELPERS@
const toggle = document.activeElement;
const folded = {focused: toggle.dataset.focus, expanded: toggle.getAttribute("aria-expanded"), label: name(toggle), hidden: document.getElementById(toggle.getAttribute("aria-controls")).hidden, seen: all("#main .org-row[data-office]").filter((entry) => entry.offsetParent !== null).map((entry) => entry.dataset.office)};
toggle.click();
await sleep(200);
const before = all("#main .agent-order li").map((item) => item.dataset.name);
all("#main .agent-order li")[1].querySelector('[data-focus^="up:"]').focus();
return {...folded, again: toggle.getAttribute("aria-expanded"), before};
})()""".replace("@HELPERS@", HELPERS)
ORDER_MOVED = """(async () => {@HELPERS@
const after = all("#main .agent-order li").map((item) => item.dataset.name);
const focused = document.activeElement.dataset.focus || null;
const save = all("#main .agent-order button").find((button) => text(button) === "Reihenfolge speichern");
const disabled = save.disabled;
save.click();
const toast = await until(() => all("#toasts .toast").find((box) => text(box).startsWith("Priorität")), 8000);
return {after, focused, disabled, toast: text(toast)};
})()""".replace("@HELPERS@", HELPERS)
OPEN_TAKEOVER = """(async () => {@HELPERS@
document.querySelector('#main [data-focus="takeover:identity/oidc"]').click();
await sleep(400);
return {title: text(document.querySelector(".sheet-head .panel-title")), options: all(".sheet-box select option").map((option) => option.value), work: document.querySelector('.sheet-box input[aria-label="Arbeit"]').value, focused: document.activeElement.tagName};
})()""".replace("@HELPERS@", HELPERS)
CONFIRM_TAKEOVER = """(async () => {@HELPERS@
all(".sheet-box button").find((button) => name(button) === "Übergeben").click();
const done = await until(() => document.querySelector(".sheet-box [data-result]"), 30000);
return {result: done ? done.dataset.result : null, text: text(done), toasts: all("#toasts .toast").map(text)};
})()""".replace("@HELPERS@", HELPERS)
AFTER_TAKEOVER = """(async () => {@HELPERS@
document.querySelector(".sheet-head button").click();
const row = await until(() => {
const found = document.querySelector('#main .org-row[data-office="identity/oidc"] .org-holder');
return found && !text(found).endsWith("Stage") ? found : null;
}, 15000);
return {holder: text(row)};
})()""".replace("@HELPERS@", HELPERS)
ACTIONS = """(async () => {@HELPERS@
const press = async (key) => {
document.dispatchEvent(new KeyboardEvent("keydown", {key, bubbles: true}));
@@ -174,6 +224,8 @@ class TestOrchestratorE2E(HubCase):
self.claim("s1", "Skills session")
self.write_council({
"work/s2/claim.json": {"office": "work/s2", "session": "s2", "runtime": "claude", "name": "Stage", "since": iso(now - 7200), "beat": now - 2000, "work": "x"},
"chair/claim.json": {"office": "chair", "session": "s1", "runtime": "claude", "name": "Skills session", "since": iso(now - 7200), "beat": now, "work": "allocate"},
"identity/oidc/claim.json": {"office": "identity/oidc", "session": "s2", "runtime": "claude", "name": "Stage", "since": iso(now - 7200), "beat": now - 2000, "work": "oidc line"},
"rasci.json": {"work/stage": {"title": "Stage line", "status": "running", "worker": "Stage (this session)", "roles": {"Stage (this session)": "RA"}}},
"radio-silence.json": {"since": now - 60, "until": now + 3600, "by": "Docs", "text": "disk full"},
"news.jsonl": self.jsonl([
@@ -253,15 +305,20 @@ class TestOrchestratorE2E(HubCase):
self.assertEqual([probe["chips"] for probe in probes if probe["hash"] == "#stream"], [["Für dich", "Funk", "Arbeit", "Transkripte"]] * len(WIDTHS))
self.assertEqual((stream["menus"], stream["custom"]), (["Filter"], True))
self.assertEqual(by_hash["#stream/inbox"]["inbox"], 2)
for tab in ("agents", "artifacts"):
for tab, own in (("agents", ["Hierarchie"]), ("artifacts", [])):
with self.subTest(tab=tab):
self.assertEqual(by_hash[f"#{tab}/orbit"]["views"], ["Orbit", "Chord", "Swimlane", "Tree", "3D"])
self.assertEqual(by_hash[f"#{tab}/orbit"]["views"], ["Orbit", "Chord", "Swimlane", "Tree", "3D", *own])
self.assertEqual(by_hash[f"#{tab}/3d"]["layouts"], ["Kraft", "Zeit", "Spawn-Tiefe"])
self.assertTrue(by_hash[f"#{tab}/3d"]["canvas"], by_hash[f"#{tab}/3d"]["note"])
self.assertRegex(by_hash[f"#{tab}/3d"]["note"], r"^\d+ Knoten · \d+ Kanten · Kraft$")
agents = by_hash["#agents/orbit"]
self.assertEqual(agents["toolbar"], ["Funk an alle", "Mayday aufheben", "Priorität", "Tag/Nacht"])
self.assertEqual(agents["toAll"], [["newsletter", True], ["broadcast", False], ["pan-pan", False], ["security", False], ["mayday", False]])
hierarchy = by_hash["#agents/hierarchy"]
self.assertEqual([office for office, _ in hierarchy["org"]], ["chair", "identity/oidc", "work/s1", "work/s2"])
self.assertEqual(hierarchy["toggles"], [["Zuklappen: Operator", "true"], ["Zuklappen: Chair", "true"], ["Zuklappen: identity", "true"], ["Zuklappen: Präsidenten", "true"]])
self.assertEqual(hierarchy["toolbar"], agents["toolbar"])
self.assertGreaterEqual(len(hierarchy["order"]), 2)
self.assertEqual(by_hash["#agents/tree"]["spawn"][0], ["operator", None])
self.assertIn(["twig", "true"], by_hash["#agents/tree"]["spawn"])
self.assertIn(["twig", "false"], by_hash["#agents/tree"]["spawn"])
@@ -363,6 +420,45 @@ class TestOrchestratorE2E(HubCase):
["branch", "tree", "--format", "json", "--output", str(self.tree_file)],
])
def test_chromium_folds_the_hierarchy_by_keyboard_reorders_agents_and_hands_an_office_over_with_a_signature(self):
signer = self.pin()
trust = verifier.Trust(approvers=self.approvers, replay=self.replay / "offices.json", origin=self.origin)
runner = office_host.Offices(trust, self.council, COUNCIL_SCRIPT, self.outside / "home")
jobs, results = self.offices / "jobs", self.offices / "results"
self.beside(lambda: any(jobs.iterdir()) and office_host.cycle(jobs, results, runner))
private = "".join(line for line in signer.pem.read_text(encoding="utf-8").splitlines() if not line.startswith("-----"))
authenticator = {"credentialId": base64.b64encode(signer.raw_id).decode(), "privateKey": private, "rpId": "localhost"}
local = f"http://localhost:{self.port}/"
steps = [
{"width": 1366, "height": 768, "url": f"{local}#agents/hierarchy", "wait": 1200, "probe": ORG_OPEN, "shot": self.shot("1366-hierarchy-open")},
{"width": 1366, "height": 768, "url": None, "wait": 0, "keys": ["Enter"], "probe": ORG_FOLDED, "shot": None},
{"width": 1366, "height": 768, "url": None, "wait": 0, "keys": ["Enter"], "probe": ORDER_MOVED, "shot": self.shot("1366-hierarchy-order")},
{"width": 1366, "height": 768, "url": None, "wait": 0, "probe": OPEN_TAKEOVER, "shot": self.shot("1366-hierarchy-takeover")},
{"width": 1366, "height": 768, "url": None, "wait": 0, "probe": CONFIRM_TAKEOVER, "shot": self.shot("1366-hierarchy-takeover-result")},
{"width": 1366, "height": 768, "url": None, "wait": 0, "probe": AFTER_TAKEOVER, "shot": self.shot("1366-hierarchy-after")},
]
data = self.drive(steps, authenticator)
(OUT / "chromium-hierarchy.json").write_text(json.dumps(data, indent=1), encoding="utf-8")
self.assertEqual(data["errors"], [])
opened, folded, moved, sheet, confirmed, after = data["results"]
self.assertNotIn("error", opened)
self.assertEqual(opened["focused"], "toggle:dimension:identity")
self.assertEqual((folded["focused"], folded["expanded"], folded["label"], folded["hidden"], folded["again"]), ("toggle:dimension:identity", "false", "Aufklappen: identity", True, "true"))
self.assertNotIn("identity/oidc", folded["seen"])
before = folded["before"]
self.assertEqual(moved["after"], [before[1], before[0], *before[2:]])
self.assertEqual((moved["focused"], moved["disabled"]), (f"down:{before[1]}", False))
self.assertTrue(moved["toast"].startswith("Priorität"), moved)
self.assertIn(("rasci.py", ["agents", "order", ",".join(moved["after"])]), [(Path(script).name, args) for script, args in self.scripts.calls])
self.assertEqual((sheet["title"], sheet["options"], sheet["work"], sheet["focused"]), ("identity/oidc: Übergeben", ["s1"], "oidc line", "SELECT"))
self.assertEqual((confirmed["result"], confirmed["text"]), ("done", "identity/oidcerledigt"), confirmed)
self.assertIn("Übergeben: erledigtidentity/oidc: erledigt", confirmed["toasts"])
self.assertNotIn("error", after)
claim = json.loads((self.council / "identity" / "oidc" / "claim.json").read_text(encoding="utf-8"))
self.assertEqual((claim["session"], claim["work"]), ("s1", "oidc line"))
written = [json.loads(path.read_text(encoding="utf-8")) for path in results.glob("*.json")]
self.assertEqual([[(item["office"], item["action"], item["status"]) for item in result["items"]] for result in written], [[("identity/oidc", "takeover", "done")]])
@unittest.skipUnless(shutil.which(os.environ.get("FIREFOX", "firefox")), "no Firefox")
def test_firefox_walks_every_screen_at_three_widths(self):
shots = [(width, height, screen, OUT / f"firefox-{width}-{screen.replace('/', '-')}.png") for width, height in WIDTHS for screen in SCREENS]
+2 -1
View File
@@ -43,6 +43,7 @@ class HubCase(unittest.TestCase):
self.tree_file = base / "tree" / "branch-tree.json"
self.timers = base / "timers"
self.cleanup = base / "state" / "cleanup"
self.offices = base / "state" / "offices"
self.approvers = base / "config" / "approvers.json"
self.replay = base / "replay"
for path in (self.pages, self.state, self.outside, self.projects, self.tree_file.parent, self.timers):
@@ -64,7 +65,7 @@ class HubCase(unittest.TestCase):
transcripts=self.projects,
scripts=self.scripts,
templates=HUB / "templates",
places=server.Places(tree_file=self.tree_file, timers=self.timers, vendor=HUB / "vendor", cleanup=self.cleanup),
places=server.Places(tree_file=self.tree_file, timers=self.timers, vendor=HUB / "vendor", cleanup=self.cleanup, offices=self.offices),
model=server.Model(url="", model="", key=""),
engines=self.engines,
approvers=self.approvers,
+57 -1
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import argparse
import importlib.util
import json
import os
import subprocess
@@ -9,6 +11,7 @@ import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
REPO_ROOT = Path(__file__).resolve().parents[1]
COUNCIL = REPO_ROOT / "skills" / "kvb-org-organize" / "scripts" / "council.py"
@@ -30,7 +33,7 @@ class TestCouncil(unittest.TestCase):
json.dumps({"sessionId": sid, "name": name}), encoding="utf-8"
)
def _run(self, sid: str, *args: str, stdin: str = "") -> subprocess.CompletedProcess:
def _run(self, sid: str, *args: str, stdin: str = "", cwd: str | None = None) -> subprocess.CompletedProcess:
env = {
"PATH": "/usr/bin:/bin",
"HOME": str(self.home),
@@ -43,6 +46,7 @@ class TestCouncil(unittest.TestCase):
text=True,
env=env,
input=stdin,
cwd=cwd,
check=False,
)
@@ -74,6 +78,58 @@ class TestCouncil(unittest.TestCase):
self.assertEqual(self._run("s1", "release", "work/x").returncode, 0)
self.assertFalse((self.root / "work/x").exists())
def test_no_flag_lets_an_agent_take_over_or_release_a_live_holder(self):
self._run("s1", "claim", "security/gui", "--work", "w")
before = (self.root / "security/gui/claim.json").read_text(encoding="utf-8")
for args in (("takeover", "security/gui", "--work", "w2"), ("takeover", "security/gui", "--work", "w2", "--operator"), ("release", "security/gui"), ("release", "security/gui", "--operator")):
with self.subTest(args=args):
self.assertIn(self._run("s2", *args).returncode, (2, 3))
self.assertEqual((self.root / "security/gui/claim.json").read_text(encoding="utf-8"), before)
def test_no_office_operation_follows_a_planted_link(self):
outside = Path(self.tmp.name) / "outside"
(outside / "gui").mkdir(parents=True)
(outside / "gui" / "keep.txt").write_text("x", encoding="utf-8")
(outside / "gui" / "claim.json").write_text(json.dumps({"session": "s1", "runtime": "claude-code", "beat": 1.0}), encoding="utf-8")
self.root.mkdir()
(self.root / "security").symlink_to(outside)
for args in (
("takeover", "security/gui", "--work", "w"),
("release", "security/gui"),
("claim", "security/new", "--work", "w"),
("claim", "security/gui", "--work", "w"),
):
with self.subTest(args=args):
self.assertNotEqual(self._run("s2", *args).stdout.split(" ")[0], "elected")
self.assertEqual(sorted(path.name for path in outside.rglob("*")), ["claim.json", "gui", "keep.txt"])
(self.root / "work").mkdir()
(self.root / "work" / "x").symlink_to(outside / "gui")
self.assertEqual(self._run("s2", "takeover", "work/x", "--work", "w").returncode, 3)
self.assertTrue((outside / "gui" / "keep.txt").exists())
def test_a_claim_from_the_root_directory_records_no_workdir_or_branch(self):
self.assertEqual(self._run("s2", "claim", "work/y", "--work", "appointed", cwd="/").returncode, 0)
row = json.loads((self.root / "rasci.json").read_text(encoding="utf-8"))["work/y"]
self.assertEqual((row["worker"], row["description"], row["status"]), ("Two", "appointed", "running"))
self.assertNotIn("workdir", row)
self.assertNotIn("branch", row)
def test_a_vacant_office_is_taken_over_without_a_council_root_or_group(self):
self.assertEqual(self._run("s1", "takeover", "work/x", "--work", "w").stdout, "elected work/x\n")
self.assertEqual(self._run("s1", "takeover", "security/gui", "--work", "w").stdout, "elected security/gui\n")
def test_a_beat_racing_a_release_never_brings_the_office_back(self):
spec = importlib.util.spec_from_file_location("council_beat_race", COUNCIL)
council = importlib.util.module_from_spec(spec)
spec.loader.exec_module(council)
self.root.mkdir()
council.ROOT = self.root
released = {"session": "s1", "runtime": "claude-code", "beat": 1.0}
council.claims = lambda: [("work/gone", dict(released))]
with mock.patch.dict(os.environ, {"CLAUDE_CODE_SESSION_ID": "s1"}):
self.assertEqual(council.cmd_beat(argparse.Namespace(session=None)), 0)
self.assertEqual(sorted(self.root.rglob("*")), [])
def test_gate_blocks_unclaimed_edits_in_a_git_worktree_only(self):
repo = Path(self.tmp.name) / "repo"
(repo / ".git").mkdir(parents=True)
+11 -4
View File
@@ -69,7 +69,11 @@ class TestHubBoard(HubCase):
"rasci.json": {"work/a": {"worker": "A", "status": "running", "prio": 2}, "work/b": {"worker": "B session", "status": "queued", "prio": 1}, "work/c": {"worker": "C", "status": "done"}},
})
state = self.snapshot()
self.assertEqual((state["silence"]["by"], state["night"], state["priority"]), ("Docs", "evening", ["B session", "A"]))
self.assertEqual((state["silence"]["by"], state["night"]), ("Docs", "evening"))
self.assertEqual(state["agent_order"], ["B session", "A", "Gatekeeper", "Skills session"])
self.write_council({"agent-order.json": {"agents": ["Gatekeeper", "Nobody", "A", "A"], "set": "2026-11-07T10:00:00+00:00"}})
self.assertEqual(self.snapshot()["agent_order"], ["Gatekeeper", "A", "B session", "Skills session"])
register = (self.council / "rasci.json").read_text(encoding="utf-8")
def board(action: str, payload: object) -> tuple[int, dict | None]:
status, _, body = self.post_json(f"/api/board/{action}", payload, self.guard(self.host))
@@ -81,11 +85,14 @@ class TestHubBoard(HubCase):
status, result = board("broadcast", {"text": "main is green", "class": "newsletter"})
message_id = self.tool("operator_message", {"id": self.snapshot()["messages"][-1]["id"]})["structuredContent"]["id"]
self.assertEqual(self.scripts.calls[-1], (skill_scripts.RADIO, ["post", "--session", "Operator", f"[kvb-orchestrator msg {message_id}] main is green"]))
self.assertEqual(board("order", {"agents": ["A", "B session"]})[0], 200)
self.assertEqual(self.scripts.calls[-1], (skill_scripts.RASCI, ["order", "A,B session"]))
for payload in ({"agents": ["A,B"]}, {"agents": ["A", "A"]}, {"agents": []}, {"agents": ["-x"]}, {"agents": "A"}, {"text": "x"}):
self.assertEqual(board("order", {"agents": ["Gatekeeper", "A", "B session"]})[0], 200)
self.assertEqual(self.scripts.calls[-1], (skill_scripts.RASCI, ["agents", "order", "Gatekeeper,A,B session"]))
calls = len(self.scripts.calls)
for payload in ({"agents": ["A,B"]}, {"agents": ["A", "A"]}, {"agents": []}, {"agents": ["-x"]}, {"agents": "A"}, {"text": "x"}, {"agents": ["A", "Nobody"]}, {"agents": ["C"]}):
with self.subTest(payload=payload):
self.assertEqual(board("order", payload)[0], 400)
self.assertEqual(len(self.scripts.calls), calls)
self.assertEqual((self.council / "rasci.json").read_text(encoding="utf-8"), register)
calls = len(self.scripts.calls)
self.assertEqual(board("evening", {})[0], 200)
self.assertEqual(self.scripts.calls[calls:], [
+15 -2
View File
@@ -9,10 +9,14 @@ from hub_support import NAV
NAV_PROBE = """
const N = require(process.argv[1]);
const hashes = ["", "#stream", "#stream/inbox", "#stream/rules", "#stream/nope", "#agents/chord", "#agents/3d", "#agents", "#agents/nope",
"#artifacts/tree", "#artifacts/orbit", "#graph", "#graph/swimlane", "#graph/orbit", "#tree", "#bogus", "#agents%2Fswimlane"];
"#artifacts/tree", "#artifacts/orbit", "#graph", "#graph/swimlane", "#graph/orbit", "#tree", "#bogus", "#agents%2Fswimlane",
"#agents/hierarchy", "#artifacts/hierarchy", "#graph/hierarchy", "#tree/hierarchy"];
console.log(JSON.stringify({
tabs: N.TABS.map(([id, label]) => [id, label, (N.SUBS[id] || []).map(([sub, name]) => [sub, name])]),
views: N.VIEWS.map(([id, label]) => [id, label]),
agents: N.viewsOf("agents").map(([id, label]) => [id, label]),
artifacts: N.viewsOf("artifacts").map(([id, label]) => [id, label]),
icon: N.ICONS.hierarchy,
routes: hashes.map((hash) => N.route(hash)),
hashes: [["stream", null], ["inbox", null], ["rules", null], ["agents", "chord"], ["artifacts", "3d"]].map(([screen, view]) => N.hashOf(screen, view)),
tabOf: ["stream", "inbox", "rules", "agents", "artifacts"].map((screen) => N.tabOf(screen)),
@@ -30,7 +34,12 @@ class TestNavModule(unittest.TestCase):
self.assertEqual(self.data["tabs"], [["stream", "Stream", [["inbox", "Inbox"], ["rules", "Regeln"]]], ["agents", "Agents", []], ["artifacts", "Artifacts", []]])
def test_agents_and_artifacts_offer_five_views_in_order(self):
self.assertEqual(self.data["views"], [["orbit", "Orbit"], ["chord", "Chord"], ["swimlane", "Swimlane"], ["tree", "Tree"], ["3d", "3D"]])
shared = [["orbit", "Orbit"], ["chord", "Chord"], ["swimlane", "Swimlane"], ["tree", "Tree"], ["3d", "3D"]]
self.assertEqual((self.data["views"], self.data["artifacts"]), (shared, shared))
def test_only_agents_add_the_hierarchy_after_3d(self):
self.assertEqual(self.data["agents"][-2:], [["3d", "3D"], ["hierarchy", "Hierarchie"]])
self.assertEqual(self.data["icon"], "bi-diagram-2")
def test_hashes_route_and_the_old_ones_redirect(self):
stream = {"screen": "stream", "view": None, "redirect": None}
@@ -52,6 +61,10 @@ class TestNavModule(unittest.TestCase):
{"screen": "artifacts", "view": "tree", "redirect": "#artifacts/tree"},
stream,
{"screen": "agents", "view": "swimlane", "redirect": None},
{"screen": "agents", "view": "hierarchy", "redirect": None},
{"screen": "artifacts", "view": None, "redirect": None},
{"screen": "agents", "view": "hierarchy", "redirect": "#agents/hierarchy"},
{"screen": "artifacts", "view": "tree", "redirect": "#artifacts/tree"},
])
def test_every_screen_has_its_own_hash_and_tab(self):
+324
View File
@@ -0,0 +1,324 @@
from __future__ import annotations
import importlib.util
import json
import os
import re
import secrets
import shutil
import subprocess
import sys
import tempfile
import time
import unittest
from pathlib import Path
from unittest import mock
from hub_case import HubCase
from hub_support import HUB, ORIGIN, REPO_ROOT, key, signing, verifier
OFFICES = HUB / "client" / "offices.py"
OFFICES_SPEC = importlib.util.spec_from_file_location("kvb_orchestrator_offices_runner", OFFICES)
host = importlib.util.module_from_spec(OFFICES_SPEC)
OFFICES_SPEC.loader.exec_module(host)
COUNCIL_SCRIPT = REPO_ROOT / "skills" / "kvb-org-organize" / "scripts" / "council.py"
SINCE = "2026-11-07T08:00:00+00:00"
def office_claim(office: str, session: str, name: str, runtime: str) -> dict:
return {"office": office, "session": session, "runtime": runtime, "name": name, "since": SINCE, "beat": time.time(), "work": f"{office} work"}
def unblock(fifo: Path) -> None:
try:
os.close(os.open(fifo, os.O_WRONLY | os.O_NONBLOCK))
except OSError:
pass
class TestHubOffices(HubCase):
def setUp(self):
super().setUp()
self.write_council({
"chair/claim.json": office_claim("chair", "s1", "Maintainer", "claude-code"),
"identity/oidc/claim.json": office_claim("identity/oidc", "s2", "Skills", "claude-code"),
"work/hub/claim.json": office_claim("work/hub", "s3", "Stage", "claude-code"),
"cluster/gate/claim.json": office_claim("cluster/gate", "s2", "Skills", "claude-code"),
})
self.snapshot()
def sign(self, items: list[dict]) -> tuple[int, bytes]:
status, _, body = self.post_json("/api/sign", {"items": items}, self.guard(self.host))
return status, body
def test_the_chair_is_the_holder_of_the_chair_office(self):
state = self.snapshot()
self.assertEqual([(node["id"], node["kind"]) for node in state["graph"]["nodes"][:2]], [("Operator", "operator"), ("s1", "chair")])
self.assertEqual({claim["office"]: claim["kind"] for claim in state["claims"]}, {"chair": "chair", "cluster/gate": "cluster", "identity/oidc": "line", "work/hub": "work"})
code = re.sub(r'<script nonce="[^"]+" id="state" type="application/json">.*?</script>', "", self.index(), flags=re.DOTALL)
self.assertNotIn("Maintainer", code)
def test_a_fifo_or_link_at_a_council_file_never_blocks_or_feeds_the_state(self):
fifos = [self.council / "work" / "fifo" / "claim.json", self.council / "agent-order.json"]
fifos[0].parent.mkdir(parents=True)
for fifo in fifos:
os.mkfifo(fifo, 0o600)
self.addCleanup(unblock, fifo)
planted = self.outside / "claim.json"
planted.write_text(json.dumps(office_claim("security/gui", "s9", "Linked", "claude-code")), encoding="utf-8")
(self.council / "security" / "gui").mkdir(parents=True)
(self.council / "security" / "gui" / "claim.json").symlink_to(planted)
offices = [claim["office"] for claim in self.snapshot()["claims"]]
self.assertEqual(offices, ["chair", "cluster/gate", "identity/oidc", "work/hub"])
def test_a_vacant_chair_draws_no_chair_node_and_the_operator_grants(self):
shutil.rmtree(self.council / "chair")
now = time.time()
self.write_council({
"rasci.json": {"work/hub": {"title": "Hub", "status": "running", "worker": "Stage", "workdir": "/repo/hub", "roles": {"Stage": "RA"}}},
"queue-history.jsonl": self.jsonl([{"id": "q1", "kind": "gate", "workdir": "/repo/hub", "start": now - 10, "end": now - 5, "exit": 0}]),
})
state = self.snapshot()
self.assertEqual([node["kind"] for node in state["graph"]["nodes"]].count("chair"), 0)
self.assertIn({"source": "Operator", "target": "s3", "class": "grant", "count": 1}, state["graph"]["edges"])
def test_signing_an_office_needs_a_known_session_the_current_holder_and_one_line_per_dimension(self):
for name, item in (
("appoint a vacant line", signing.office_item("appoint", "security/gui", "", "s3", "GUI line")),
("take over the chair", signing.office_item("takeover", "chair", "s1", "s2", "allocate")),
("recall a president", signing.office_item("recall", "work/hub", "s3", "", "")),
("take over a line in the own dimension", signing.office_item("takeover", "identity/oidc", "s2", "s3", "oidc")),
):
with self.subTest(name=name):
status, body = self.sign([item])
self.assertEqual(status, 200, body)
self.assertEqual(json.loads(body)["payload"]["items"], [signing.item_hash(item)])
bad = (
("capital office", signing.office_item("appoint", "Chair", "", "s3", "w"), 400),
("three levels", signing.office_item("appoint", "a/b/c", "", "s3", "w"), 400),
("climbing office", signing.office_item("appoint", "../x", "", "s3", "w"), 400),
("bare group", signing.office_item("appoint", "work", "", "s3", "w"), 400),
("unknown session", signing.office_item("appoint", "security/gui", "", "s9", "w"), 400),
("pseudo session", signing.office_item("appoint", "security/gui", "", "name:Docs", "w"), 400),
("the operator", signing.office_item("appoint", "security/gui", "", "Operator", "w"), 400),
("unknown action", {**signing.office_item("appoint", "security/gui", "", "s3", "w"), "action": "fire"}, 400),
("empty work", signing.office_item("appoint", "security/gui", "", "s3", " "), 400),
("two lines of work", signing.office_item("appoint", "security/gui", "", "s3", "a\nb"), 400),
("long work", signing.office_item("appoint", "security/gui", "", "s3", "x" * 301), 400),
("recall with a successor", signing.office_item("recall", "work/hub", "s3", "s2", ""), 400),
("extra key", {**signing.office_item("recall", "work/hub", "s3", "", ""), "command": "rm -rf ~"}, 400),
("missing key", {key_name: value for key_name, value in signing.office_item("recall", "work/hub", "s3", "", "").items() if key_name != "holder"}, 400),
("number", {**signing.office_item("recall", "work/hub", "s3", "", ""), "holder": 3}, 400),
("held office", signing.office_item("appoint", "identity/oidc", "", "s3", "w"), 409),
("holder changed", signing.office_item("takeover", "chair", "s2", "s3", "w"), 409),
("vacant recall", signing.office_item("recall", "security/gui", "", "", ""), 400),
("option as session", signing.office_item("appoint", "security/gui", "", "--all", "w"), 400),
("successor is the holder", signing.office_item("takeover", "chair", "s1", "s1", "w"), 400),
("second line of a dimension", signing.office_item("appoint", "identity/saml", "", "s2", "w"), 400),
)
for name, item, expected in bad:
with self.subTest(name=name):
self.assertEqual(self.sign([item])[0], expected)
item = signing.office_item("appoint", "security/gui", "", "s3", "GUI line")
self.assertEqual(self.sign([item, item])[0], 400)
def test_a_signed_office_becomes_a_job_without_any_command(self):
item = signing.office_item("takeover", "chair", "s1", "s2", "allocate")
signer = self.pin()
proof = signer.proof(self.prepare([item])["payload"], self.origin)
self.assertEqual(self.post_json("/api/offices", {"items": [item], "proof": None}, self.guard(self.host))[0], 400)
self.assertEqual(self.post_json("/api/offices", {"items": [item], "proof": proof}, {"Host": self.host})[0], 403)
self.assertEqual(self.post_json("/api/offices", {"items": [{**item, "holder": "s3"}], "proof": proof}, self.guard(self.host))[0], 409)
status, _, body = self.post_json("/api/offices", {"items": [item], "proof": proof}, self.guard(self.host))
self.assertEqual(status, 202, body)
job_id = json.loads(body)["id"]
written = self.offices / "jobs" / f"{job_id}.json"
job = json.loads(written.read_text(encoding="utf-8"))
self.assertEqual(sorted(job), ["created", "id", "items", "proof", "v"])
self.assertEqual(job["items"], [{key_name: item[key_name] for key_name in ("action", "office", "holder", "session", "work")}])
self.assertEqual(job["proof"], proof)
self.assertNotIn("command", written.read_text(encoding="utf-8"))
self.assertEqual((written.stat().st_mode & 0o777, (self.offices / "jobs").stat().st_mode & 0o777), (0o600, 0o700))
self.assertEqual(json.loads(self.get(f"/api/offices/{job_id}")[2])["status"], "queued")
self.assertEqual(self.get("/api/offices/0000000000000000")[0], 404)
self.assertEqual(self.get("/api/offices")[0], 405)
result = {"id": job_id, "finished": time.time(), "items": [{**job["items"][0], "status": "done", "reason": ""}]}
(self.offices / "results" / f"{job_id}.json").write_text(json.dumps(result), encoding="utf-8")
self.assertEqual(json.loads(self.get(f"/api/offices/{job_id}")[2])["status"], "done")
class TestHostOffices(unittest.TestCase):
def setUp(self):
tmp = tempfile.TemporaryDirectory()
self.addCleanup(tmp.cleanup)
base = Path(tmp.name)
self.council = base / "council"
self.council.mkdir(mode=0o700)
self.home = base / "home"
sessions = self.home / ".claude" / "sessions"
sessions.mkdir(parents=True)
for sid, name in (("s1", "One"), ("s2", "Two")):
(sessions / f"{sid}.json").write_text(json.dumps({"sessionId": sid, "name": name}), encoding="utf-8")
self.jobs, self.results = base / "jobs", base / "results"
self.jobs.mkdir()
self.results.mkdir()
self.approvers = base / "config" / "approvers.json"
self.trust = verifier.Trust(approvers=self.approvers, replay=base / "replay" / "offices.json", origin=ORIGIN)
self.signer = key(-7, "main")
self.signer.pin(self.approvers, ORIGIN)
self.runner = host.Offices(self.trust, self.council, COUNCIL_SCRIPT, self.home)
def proof(self, items: list[dict], signer) -> dict:
hashes = [signing.item_hash(signing.office_item(**item)) for item in items]
return signer.proof(signing.approval_payload(hashes, secrets.token_hex(16), int(time.time()) + 600), ORIGIN)
def run_job(self, items: list[dict], proof: object) -> dict:
job_id = secrets.token_hex(8)
(self.jobs / f"{job_id}.json").write_text(json.dumps({"v": 1, "id": job_id, "created": "x", "items": items, "proof": proof}), encoding="utf-8")
self.assertEqual(host.cycle(self.jobs, self.results, self.runner), 1)
self.assertEqual(list(self.jobs.iterdir()), [])
return json.loads((self.results / f"{job_id}.json").read_text(encoding="utf-8"))
def signed(self, item: dict) -> dict:
return self.run_job([item], self.proof([item], self.signer))
def holder(self, office: str) -> dict | None:
path = self.council / office / "claim.json"
return json.loads(path.read_text(encoding="utf-8")) if path.exists() else None
def files(self) -> list[str]:
return sorted(str(path.relative_to(self.council)) for path in self.council.rglob("*"))
def test_appoint_take_over_and_recall_run_the_council_script_for_the_operator(self):
appoint = {"action": "appoint", "office": "chair", "holder": "", "session": "s1", "work": "allocate"}
self.assertEqual([(entry["status"], entry["code"]) for entry in self.signed(appoint)["items"]], [("done", 0)])
self.assertEqual({key_name: self.holder("chair")[key_name] for key_name in ("session", "runtime", "name", "work")}, {"session": "s1", "runtime": "claude-code", "name": "One", "work": "allocate"})
takeover = {"action": "takeover", "office": "chair", "holder": "s1", "session": "s2", "work": "allocate more"}
self.assertEqual(self.signed(takeover)["items"][0]["status"], "done")
self.assertEqual((self.holder("chair")["session"], self.holder("chair")["name"]), ("s2", "Two"))
asleep = {"action": "appoint", "office": "security/gui", "holder": "", "session": "s9", "work": "gui line"}
self.assertEqual(self.signed(asleep)["items"][0]["status"], "done")
self.assertEqual((self.holder("security/gui")["session"], self.holder("security/gui")["runtime"]), ("s9", "other"))
recall = {"action": "recall", "office": "chair", "holder": "s2", "session": "", "work": ""}
self.assertEqual(self.signed(recall)["items"][0]["status"], "done")
self.assertIsNone(self.holder("chair"))
president = {"action": "appoint", "office": "work/new", "holder": "", "session": "s1", "work": "build it"}
self.assertEqual(self.signed(president)["items"][0]["status"], "done")
row = json.loads((self.council / "rasci.json").read_text(encoding="utf-8"))["work/new"]
self.assertEqual((row["worker"], row["description"], "workdir" in row, "branch" in row), ("One", "build it", False, False))
def test_every_doubtful_item_is_refused_and_changes_nothing(self):
appoint = {"action": "appoint", "office": "chair", "holder": "", "session": "s1", "work": "allocate"}
self.signed({"action": "appoint", "office": "identity/oidc", "holder": "", "session": "s2", "work": "oidc"})
rule = self.signer.proof(signing.rule_payload(secrets.token_hex(8), ["office"], "", "*", "*", int(time.time()) + 600), ORIGIN)
outside = self.council.parent / "outside"
(outside / "gui").mkdir(parents=True)
cases = (
("bad signature", appoint, self.proof([appoint], key(-7, "intruder")), "no valid operator signature"),
("missing signature", appoint, None, "no signature"),
("rule instead of approval", appoint, rule, "no valid operator signature"),
("other item signed", appoint, self.proof([{**appoint, "session": "s2"}], self.signer), "does not list this item"),
("holder changed", {**appoint, "office": "identity/oidc"}, self.proof([{**appoint, "office": "identity/oidc"}], self.signer), "holder changed"),
)
for name, item, proof, reason in cases:
with self.subTest(name=name):
before = self.files()
result = self.run_job([item], proof)
self.assertEqual([entry["status"] for entry in result["items"]], ["refused"])
self.assertIn(reason, result["items"][0]["reason"])
self.assertEqual(self.files(), before)
(self.council / "security").symlink_to(outside)
linked = {**appoint, "office": "security/gui"}
result = self.signed(linked)
self.assertEqual(result["items"][0]["status"], "refused")
self.assertIn("link", result["items"][0]["reason"])
self.assertEqual(list(outside.rglob("*")), [outside / "gui"])
(self.council / "security").unlink()
self.council.chmod(0o777)
result = self.signed(appoint)
self.assertEqual(result["items"][0]["status"], "refused")
self.assertIn("others can write", result["items"][0]["reason"])
self.council.chmod(0o700)
self.assertIsNone(self.holder("chair"))
def test_the_runner_passes_no_flag_and_checks_the_holder_in_the_removal_itself(self):
self.signed({"action": "appoint", "office": "chair", "holder": "", "session": "s1", "work": "allocate"})
takeover = {"action": "takeover", "office": "chair", "holder": "s1", "session": "s2", "work": "allocate"}
recall = {"action": "recall", "office": "chair", "holder": "s1", "session": "", "work": ""}
self.assertNotIn("--operator", self.runner.command(takeover)[0])
swapped = {**self.holder("chair"), "session": "s9"}
(self.council / "chair" / "claim.json").write_text(json.dumps(swapped), encoding="utf-8")
with mock.patch.object(host, "holder_of", return_value="s1"):
for item in (takeover, recall):
with self.subTest(action=item["action"]):
result = self.signed(item)["items"][0]
self.assertEqual(result["status"], "refused", result)
self.assertIn("holder changed", result["reason"])
self.assertEqual(self.holder("chair"), swapped)
self.assertEqual(self.files(), ["chair", "chair/claim.json"])
def test_a_claim_council_would_not_read_is_never_reported_recalled(self):
(self.council / "chair").mkdir()
(self.council / "chair" / "claim.json").write_text(json.dumps({"session": "s1"}), encoding="utf-8")
result = self.signed({"action": "recall", "office": "chair", "holder": "s1", "session": "", "work": ""})["items"][0]
self.assertNotEqual(result["status"], "done", result)
self.assertEqual(self.files(), ["chair", "chair/claim.json"])
def test_a_job_that_is_a_link_a_fifo_or_too_large_runs_nothing(self):
appoint = {"action": "appoint", "office": "chair", "holder": "", "session": "s1", "work": "allocate"}
linked, fifo, large = (secrets.token_hex(8) for _ in range(3))
planted = self.council.parent / "planted.json"
planted.write_text(json.dumps({"v": 1, "id": linked, "created": "x", "items": [appoint], "proof": self.proof([appoint], self.signer)}), encoding="utf-8")
(self.jobs / f"{linked}.json").symlink_to(planted)
os.mkfifo(self.jobs / f"{fifo}.json", 0o600)
(self.jobs / f"{large}.json").write_text(" " * (host.READ_LIMIT + 1), encoding="utf-8")
self.assertEqual(host.cycle(self.jobs, self.results, self.runner), 3)
for job_id in (linked, fifo, large):
with self.subTest(job=job_id):
result = json.loads((self.results / f"{job_id}.json").read_text(encoding="utf-8"))
self.assertEqual(result["items"], [])
self.assertIn("unreadable job", result["error"])
self.assertEqual((list(self.jobs.iterdir()), self.files()), ([], []))
self.assertTrue(planted.is_file())
def test_a_signature_runs_once_and_a_malformed_job_nothing(self):
appoint = {"action": "appoint", "office": "chair", "holder": "", "session": "s1", "work": "allocate"}
proof = self.proof([appoint], self.signer)
self.assertEqual(self.run_job([appoint], proof)["items"][0]["status"], "done")
self.signed({"action": "recall", "office": "chair", "holder": "s1", "session": "", "work": ""})
again = self.run_job([appoint], proof)
self.assertEqual(again["items"][0]["status"], "refused")
self.assertIn("already used", again["items"][0]["reason"])
for name, items in (
("command smuggled in", [{**appoint, "command": "rm -rf ~"}]),
("climbing office", [{**appoint, "office": "../x"}]),
("unknown action", [{**appoint, "action": "fire"}]),
("option as session", [{**appoint, "session": "--all"}]),
("two lines of work", [{**appoint, "work": "a\nb"}]),
("recall with work", [{"action": "recall", "office": "chair", "holder": "s1", "session": "", "work": "x"}]),
("no items", []),
):
with self.subTest(name=name):
result = self.run_job(items, None)
self.assertEqual(result["items"], [])
self.assertIn("malformed job", result["error"])
self.assertIsNone(self.holder("chair"))
def test_the_unit_runs_the_script_once_over_the_job_directory(self):
appoint = {"action": "appoint", "office": "chair", "holder": "", "session": "s1", "work": "allocate"}
job_id = secrets.token_hex(8)
(self.jobs / f"{job_id}.json").write_text(json.dumps({"v": 1, "id": job_id, "created": "x", "items": [appoint], "proof": self.proof([appoint], self.signer)}), encoding="utf-8")
(self.jobs / "stray.tmp").write_text("x", encoding="utf-8")
trust = ["--approvers", str(self.approvers), "--replay", str(self.trust.replay)]
command = [sys.executable, str(OFFICES), "--port", ORIGIN.rsplit(":", 1)[1], "--jobs", str(self.jobs), "--results", str(self.results), *trust, "--council", str(self.council), "--script", str(COUNCIL_SCRIPT)]
done = subprocess.run(command, capture_output=True, text=True, timeout=60, check=False, env={"PATH": "/usr/bin:/bin", "HOME": str(self.home)})
self.assertEqual(done.returncode, 0, done.stderr)
self.assertEqual(list(self.jobs.iterdir()), [])
result = json.loads((self.results / f"{job_id}.json").read_text(encoding="utf-8"))
self.assertEqual(result["items"][0]["status"], "done", result)
self.assertEqual((self.results / f"{job_id}.json").stat().st_mode & 0o777, 0o600)
self.assertEqual(self.holder("chair")["session"], "s1")
if __name__ == "__main__":
unittest.main()
+2 -2
View File
@@ -175,7 +175,7 @@ class TestHubSpeech(HubCase):
args = {
"--bind": "127.0.0.1", "--listen-port": "0", "--public-port": "1", "--council": str(self.council), "--pages": str(self.pages), "--state": str(self.state),
"--host-state": str(HOST_STATE), "--skills": str(self.outside), "--transcripts": str(self.projects), "--templates": str(HUB / "templates"),
"--tree-file": str(self.tree_file), "--timers": str(self.timers), "--vendor": str(HUB / "vendor"), "--cleanup": str(self.cleanup),
"--tree-file": str(self.tree_file), "--timers": str(self.timers), "--vendor": str(HUB / "vendor"), "--cleanup": str(self.cleanup), "--offices": str(self.offices),
"--llm-key-file": os.devnull, "--llm-url": "", "--llm-model": "",
"--piper": str(self.engines.piper), "--voices": str(self.engines.voices), "--operator-voice": "en_US-test-high:9", "--whisper": str(self.engines.whisper),
"--whisper-model": str(self.engines.whisper_model), "--scratch": str(self.engines.scratch), "--approvers": str(self.approvers),
@@ -185,7 +185,7 @@ class TestHubSpeech(HubCase):
argv = [part for pair in given.items() for part in pair]
return subprocess.run([sys.executable, str(HUB / "server.py"), *argv], capture_output=True, text=True, timeout=60, check=False)
for name in ("--piper", "--voices", "--operator-voice", "--whisper", "--whisper-model", "--scratch", "--approvers", "--vendor", "--cleanup"):
for name in ("--piper", "--voices", "--operator-voice", "--whisper", "--whisper-model", "--scratch", "--approvers", "--vendor", "--cleanup", "--offices"):
with self.subTest(name=name):
done = run({key: value for key, value in args.items() if key != name})
self.assertEqual(done.returncode, 2, done.stderr)
+23 -12
View File
@@ -68,10 +68,10 @@ class TestHubState(HubCase):
self.assertEqual(self.status(review_id), "pending")
def test_state_is_empty_without_council_files(self):
empty = {"reviews": [], "operator": [], "register": [], "radio": [], "claims": [], "grants": []}
empty = {"reviews": [], "operator": [], "register": [], "radio": [], "claims": [], "grants": [], "agent_order": []}
state = self.snapshot()
self.assertEqual({key: state[key] for key in empty}, empty)
self.assertEqual([(node["id"], node["kind"]) for node in state["graph"]["nodes"]], [("Operator", "operator"), ("name:Maintainer", "chair")])
self.assertEqual([(node["id"], node["kind"]) for node in state["graph"]["nodes"]], [("Operator", "operator")])
self.assertEqual(state["graph"]["edges"], [])
self.index()
self.write_council({"rasci.json": "{not json", "queue-history.jsonl": "[" * 100000 + "\n", "work/x/claim.json": "[1]"})
@@ -129,6 +129,8 @@ class TestHubState(HubCase):
]
claim = {"office": "work/hub", "session": "s1", "runtime": "claude", "name": "Skills", "since": "2026-11-05T10:00:00+00:00", "beat": now, "work": "build the hub"}
gate = {"office": "cluster/gate", "session": "s2", "runtime": "codex", "name": "Gatekeeper", "since": "2026-11-05T09:00:00+00:00", "beat": now, "work": "gate"}
chair = {"office": "chair", "session": "s3", "runtime": "claude-code", "name": "Maintainer", "since": "2026-11-05T08:00:00+00:00", "beat": now, "work": "allocate"}
line = {"office": "identity/oidc", "session": "s1", "runtime": "claude", "name": "Skills", "since": "2026-11-05T10:00:00+00:00", "beat": now, "work": "oidc line"}
history = [
{"id": "q1", "kind": "gate", "signature": "make test", "workdir": "/repo/.worktrees/hub/sub", "start": now - 15, "end": now - 5, "exit": 0, "minutes": 0.2},
{"id": "q2", "kind": "deploy", "signature": "make deploy", "workdir": "/elsewhere", "start": now - 15, "end": now - 5, "exit": 0, "minutes": 0.2},
@@ -139,6 +141,8 @@ class TestHubState(HubCase):
"news.jsonl": self.jsonl(news),
"work/hub/claim.json": claim,
"cluster/gate/claim.json": gate,
"chair/claim.json": chair,
"identity/oidc/claim.json": line,
"work/broken/claim.json": "not json",
"queue-history.jsonl": self.jsonl(history),
})
@@ -147,7 +151,7 @@ class TestHubState(HubCase):
set(state),
{
"now", "since", "until", "first", "alarm_since", "reviews", "asks", "decisions", "messages", "operator",
"register", "priority", "radio", "claims", "grants", "night", "silence", "graph",
"register", "agent_order", "radio", "claims", "grants", "night", "silence", "graph",
"inbox", "pending", "rules", "approvers", "jobs", "views", "llm", "people", "settings", "media", "speech",
"badges", "kinds",
},
@@ -168,7 +172,8 @@ class TestHubState(HubCase):
"limit": phrasing.SPEECH_LIMIT, "rate": engines.STT_RATE, "seconds": engines.STT_SECONDS,
})
self.assertAlmostEqual(state["now"] - state["since"], view.RADIO_WINDOW)
self.assertEqual((state["night"], state["silence"], state["priority"]), ("day", None, ["Skills session", "subagent general-purpose (default)"]))
self.assertEqual((state["night"], state["silence"]), ("day", None))
self.assertEqual(state["agent_order"], ["Skills session", "subagent general-purpose (default)", "Gatekeeper", "Maintainer", "Skills"])
radio = [(row["from"], row["to"], row["class"], row["text"]) for row in state["radio"]]
self.assertEqual(radio, [
("Skills", ["Maintainer"], "post", "ready"),
@@ -178,12 +183,17 @@ class TestHubState(HubCase):
("Docs", ["Skills"], "pan-pan", "PAN-PAN slow"),
("Maintainer", ["Skills", "Docs"], "security", "rotate"),
])
self.assertEqual([(row["office"], row["agent"], row["runtime"]) for row in state["claims"]], [("cluster/gate", "Gatekeeper", "codex"), ("work/hub", "Skills", "claude")])
self.assertEqual([(row["office"], row["agent"], row["runtime"], row["kind"], row["dimension"], row["line"]) for row in state["claims"]], [
("chair", "Maintainer", "claude-code", "chair", "", ""),
("cluster/gate", "Gatekeeper", "codex", "cluster", "", ""),
("identity/oidc", "Skills", "claude", "line", "identity", "oidc"),
("work/hub", "Skills", "claude", "work", "", ""),
])
self.assertEqual([(row["to"], row["kind"], row["id"]) for row in state["grants"]], [("Skills", "gate", "q1")])
self.assertEqual([row["task"] for row in state["operator"]], ["operator/push"])
nodes = {node["id"]: node for node in state["graph"]["nodes"]}
moon = "subagent general-purpose (default) @ s1"
self.assertEqual(list(nodes), ["Operator", "name:Maintainer", "name:Docs", "s2", "s1", moon])
self.assertEqual(list(nodes), ["Operator", "s3", "name:Docs", "s2", "s1", moon])
self.assertEqual([nodes[key]["kind"] for key in nodes], ["operator", "chair", "session", "session", "session", "subagent"])
self.assertEqual([nodes[key]["label"] for key in nodes][:5], ["Operator", "Maintainer", "Docs", "Gatekeeper", "Skills"])
self.assertEqual((nodes[moon]["parent"], nodes[moon]["label"]), ("s1", "subagent general-purpose (default)"))
@@ -191,17 +201,18 @@ class TestHubState(HubCase):
self.assertEqual(skills, [("operator/push", False, "A"), ("work/hub", True, "R"), ("work/sub", False, "A")])
self.assertEqual([(task["task"], task["letters"]) for task in nodes["Operator"]["tasks"]], [("operator/push", "R")])
self.assertEqual([task["task"] for task in nodes[moon]["tasks"]], ["work/sub"])
self.assertEqual([claim["office"] for claim in nodes["s1"]["claims"]], ["work/hub"])
self.assertEqual([claim["office"] for claim in nodes["s1"]["claims"]], ["identity/oidc", "work/hub"])
self.assertEqual([claim["office"] for claim in nodes["s3"]["claims"]], ["chair"])
self.assertEqual((state["people"]["s1"]["now"], state["radio"][0]["source"], state["grants"][0]["target"]), ("Skills", "s1", "s1"))
edges = {(edge["source"], edge["target"], edge["class"]): edge["count"] for edge in state["graph"]["edges"]}
self.assertEqual(edges, {
("name:Docs", "*", "mayday"): 1,
("name:Docs", "s1", "pan-pan"): 1,
("name:Maintainer", "*", "newsletter"): 1,
("name:Maintainer", "name:Docs", "security"): 1,
("name:Maintainer", "s1", "grant"): 1,
("name:Maintainer", "s1", "security"): 1,
("s1", "name:Maintainer", "post"): 2,
("s3", "*", "newsletter"): 1,
("s3", "name:Docs", "security"): 1,
("s3", "s1", "grant"): 1,
("s3", "s1", "security"): 1,
("s1", "s3", "post"): 2,
})
def test_state_needs_the_host(self):
+13 -1
View File
@@ -13,6 +13,7 @@ from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
SCRIPT = REPO_ROOT / "scripts" / "orchestrator.sh"
HOST_SCRIPTS = ("kvb-org-organize/scripts/council.py", "kvb-org-organize/scripts/nofollow.py", "kvb-org-rasci/scripts/rasci.py")
OLD = "kvb-hub"
NEW = "kvb-orchestrator"
STUB = r'''#!/usr/bin/env python3
@@ -97,6 +98,8 @@ class TestOrchestratorMigration(unittest.TestCase):
self.other = {"matcher": "Bash", "hooks": [{"type": "command", "command": "other-hook"}]}
legacy = {"matcher": "Bash", "hooks": [{"type": "command", "command": f"python3 {share}/{OLD}/client/permission_hook.py --port 8737"}]}
self.write(self.home / ".claude" / "settings.json", json.dumps({"model": "x", "hooks": {"PermissionRequest": [self.other, legacy], "Stop": [self.other]}}), 0o640)
for script in HOST_SCRIPTS:
self.write(self.home / ".claude" / "skills" / script, (REPO_ROOT / "skills" / script).read_text(encoding="utf-8"))
def write(self, path: Path, text: str, mode: int = 0o644) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
@@ -127,7 +130,7 @@ class TestOrchestratorMigration(unittest.TestCase):
self.assertIn(f"{share / NEW}/client/permission_hook.py", hooks[1]["hooks"][0]["command"])
self.assertEqual(settings.stat().st_mode & 0o777, 0o640)
self.assertIn(f"{OLD}/client", (self.home / ".claude" / f"settings.json.before-{NEW}-migration").read_text(encoding="utf-8"))
self.assertEqual((first["images"], first["mcp"], first["enabled"]), ([f"{NEW}:local"], {NEW: "http://127.0.0.1:8737/mcp"}, [f"{NEW}-runner.service"]))
self.assertEqual((first["images"], first["mcp"], first["enabled"]), ([f"{NEW}:local"], {NEW: "http://127.0.0.1:8737/mcp"}, [f"{NEW}-offices.path", f"{NEW}-runner.service"]))
self.assertIn(["docker", "compose", "--file", str(share / OLD / "compose.yml"), "down", "--remove-orphans"], first["calls"])
before = snapshot(self.home)
@@ -137,6 +140,15 @@ class TestOrchestratorMigration(unittest.TestCase):
legacy_calls = [call for call in second["calls"][len(first["calls"]) :] if any(OLD in arg for arg in call)]
self.assertEqual(legacy_calls, [["docker", "image", "inspect", f"{OLD}:local"], ["claude", "mcp", "get", OLD]])
def test_the_offices_unit_waits_for_the_installed_skill_scripts_of_this_tree(self):
self.install()
stale = self.home / ".claude" / "skills" / HOST_SCRIPTS[2]
stale.write_text(stale.read_text(encoding="utf-8") + "\n", encoding="utf-8")
done = subprocess.run(["bash", str(SCRIPT), "install"], env=self.env, capture_output=True, text=True, timeout=120, check=False)
self.assertEqual(done.returncode, 0, done.stderr)
self.assertIn("run 'make install' to enable", done.stderr)
self.assertNotIn(f"{NEW}-offices.path", json.loads(self.state.read_text(encoding="utf-8"))["enabled"])
def test_install_ships_no_bytecode_from_the_tree(self):
planted = REPO_ROOT / "orchestrator" / "client" / "__pycache__" / "planted.cpython-0.pyc"
planted.parent.mkdir(exist_ok=True)
+10 -1
View File
@@ -27,6 +27,7 @@ BASE = {
"silenced": False,
"slot_limits": {"test": 5, "deploy": 1},
"ranks": {"work/a": 0, "work/b": 1, "work/c": 2},
"agents": {},
"now": NOW,
}
CHILD = (
@@ -62,7 +63,7 @@ def history_row(seq: int, **fields: object) -> dict:
def job(seq: int, **fields: object) -> dict:
return {
"id": f"j{seq}", "seq": seq, "kind": "test", "task": "work/a", "need_gb": 1, "hotfix": None,
"workdir": f"/w{seq}", "status": "waiting", "enqueued": NOW, **fields,
"workdir": f"/w{seq}", "name": "s1", "status": "waiting", "enqueued": NOW, **fields,
}
@@ -98,6 +99,14 @@ class TestEvaluate(unittest.TestCase):
tied = job(4, task="work/c", enqueued=NOW - 2 * HOUR)
self.assertEqual(list(self.decide([tied, fresh])), ["j1", "j4"])
def test_the_agent_order_breaks_ties_of_equal_rank_only(self):
entries = [job(1, name="Beta"), job(2, name="Alpha"), job(3, task="work/b", name="Alpha"), job(4, name="Stranger")]
self.assertEqual(list(self.decide(entries)), ["j1", "j2", "j4", "j3"])
self.assertEqual(list(self.decide(entries, agents={"Alpha": 0, "Beta": 1})), ["j2", "j1", "j4", "j3"])
tied = [job(5, task="work/b", name="Beta", enqueued=NOW - HOUR), job(6, name="Alpha")]
self.assertEqual(list(self.decide(tied)), ["j5", "j6"])
self.assertEqual(list(self.decide(tied, agents={"Alpha": 0, "Beta": 1})), ["j6", "j5"])
def test_the_slot_limit_counts_active_jobs_per_kind(self):
verdicts = self.decide([job(1, kind="deploy", status="active"), job(2, kind="deploy"), job(3)])
self.assertEqual(verdicts, {"j2": "all 1 deploy slots taken", "j3": None})
+65 -11
View File
@@ -36,7 +36,7 @@ class TestRasci(unittest.TestCase):
json.dumps({"sessionId": sid, "name": name}), encoding="utf-8"
)
def _run(self, *args: str, script: Path = RASCI, sid: str = "s1", timeout: float | None = None) -> subprocess.CompletedProcess:
def _run(self, *args: str, script: Path = RASCI, sid: str = "s1", timeout: float = 120) -> subprocess.CompletedProcess:
env = {
"PATH": "/usr/bin:/bin",
"HOME": str(self.home),
@@ -312,28 +312,82 @@ class TestRasci(unittest.TestCase):
self.assertEqual([line.split("\t")[1] for line in self._out(*args)],
["work/a"] if args == ("artifacts",) else [])
def test_order_pins_the_agents_in_the_operators_order(self):
def _ranked(self) -> list[str]:
return [line.split(" | ")[2].split(":")[0] for line in self._out("show")[2:] if line.startswith("| ")]
def test_agents_order_breaks_ties_only_and_never_touches_the_task_pins(self):
self._run("set", "work/a1", "--worker", "Alpha", "--prio", "1")
self._run("set", "work/a2", "--worker", "Alpha", "--prio", "2")
self._run("set", "work/b1", "--worker", "Beta", "--prio", "3")
self._run("set", "work/b1", "--worker", "Beta", "--prio", "1")
self._run("set", "work/b2", "--worker", "Beta", "--prio", "2")
self._run("set", "work/c1", "--worker", "Gamma")
self._run("estimate", "work/c1", "One", "--value", "8", "--complexity", "2")
self._run("set", "work/d1", "--worker", "Delta")
self._claim("security/gui", "s9", "Epsilon", "line")
self.assertEqual(
self._out("agents"),
["1\tAlpha\t2\twork/a1, work/a2", "2\tBeta\t1\twork/b1", "3\tGamma\t1\twork/c1"],
["1\tAlpha\t1\twork/a1", "2\tBeta\t2\twork/b1, work/b2", "3\tGamma\t1\twork/c1", "4\tDelta\t1\twork/d1", "5\tEpsilon\t0\t-"],
)
self.assertEqual(self._ranked(), ["work/a1", "work/b1", "work/b2", "work/c1", "work/d1"])
register = (self.root / "rasci.json").read_text(encoding="utf-8")
self.assertEqual(
self._out("order", "Gamma, Beta"), ["pinned 2 tasks of 2 agents; the others rank by WSJF after them"]
self._out("agents", "order", "Gamma, Beta,Epsilon"),
["agent order: Gamma, Beta, Epsilon; the others follow by register rank; task --prio pins unchanged"],
)
self.assertEqual((self.root / "rasci.json").read_text(encoding="utf-8"), register)
stored = json.loads((self.root / "agent-order.json").read_text(encoding="utf-8"))
self.assertEqual(stored["agents"], ["Gamma", "Beta", "Epsilon"])
self.assertEqual(
self._out("agents"),
["1\tGamma\t1\twork/c1", "2\tBeta\t1\twork/b1", "3\tAlpha\t2\twork/a1, work/a2"],
["1\tGamma\t1\twork/c1", "2\tBeta\t2\twork/b1, work/b2", "3\tEpsilon\t0\t-", "4\tAlpha\t1\twork/a1", "5\tDelta\t1\twork/d1"],
)
self.assertTrue(self._out("show")[2].startswith("| 1 | 4 | work/c1 |"))
self.assertNotIn("prio: 1", self._out("get", "work/a1"))
for args in (("order", "Gamma,Nobody"), ("order", "Beta,Beta"), ("order", " , ")):
self.assertEqual(self._ranked(), ["work/b1", "work/a1", "work/b2", "work/c1", "work/d1"])
self.assertIn("prio: 1", self._out("get", "work/a1"))
for args in (("agents", "order", "Gamma,Nobody"), ("agents", "order", "Beta,Beta"), ("agents", "order", " , "), ("agents", "sort")):
with self.subTest(args=args):
self.assertEqual(self._run(*args).returncode, 2)
self.assertEqual(json.loads((self.root / "agent-order.json").read_text(encoding="utf-8")), stored)
def test_the_old_order_command_stores_the_agent_order_and_says_so(self):
self._run("set", "work/a1", "--worker", "Alpha", "--prio", "3")
self._run("set", "work/b1", "--worker", "Beta")
done = self._run("order", "Beta,Alpha")
self.assertEqual(done.returncode, 0, done.stderr)
self.assertIn("rasci: `order` is now `agents order`", done.stderr)
self.assertIn("no longer writes --prio pins", done.stderr)
self.assertEqual(json.loads((self.root / "agent-order.json").read_text(encoding="utf-8"))["agents"], ["Beta", "Alpha"])
self.assertIn("prio: 3", self._out("get", "work/a1"))
self.assertNotIn("prio: 1", self._out("get", "work/b1"))
def test_a_broken_agent_order_file_ranks_like_none(self):
self._run("set", "work/a1", "--worker", "Alpha")
self._run("set", "work/b1", "--worker", "Beta")
for text in ("{not json", json.dumps({"agents": "Beta"}), json.dumps({"agents": [1, "Beta"]}), json.dumps([1])):
with self.subTest(text=text):
(self.root / "agent-order.json").write_text(text, encoding="utf-8")
self.assertEqual(self._ranked(), ["work/a1", "work/b1"])
def test_the_agent_order_never_reads_or_writes_through_a_link_fifo_or_deep_nesting(self):
self._run("set", "work/a1", "--worker", "Alpha")
self._run("set", "work/b1", "--worker", "Beta")
outside = Path(self.tmp.name) / "outside.json"
outside.write_text(json.dumps({"agents": ["Beta"]}), encoding="utf-8")
order = self.root / "agent-order.json"
order.symlink_to(outside)
self.assertEqual(self._ranked(), ["work/a1", "work/b1"])
order.unlink()
order.write_text("[" * 100000, encoding="utf-8")
self.assertEqual(self._ranked(), ["work/a1", "work/b1"])
order.unlink()
os.mkfifo(order, 0o600)
self.assertEqual(self._run("agents", timeout=20).stdout.splitlines(), ["1\tAlpha\t1\twork/a1", "2\tBeta\t1\twork/b1"])
order.unlink()
lock = self.root / "rasci.lock"
lock.unlink(missing_ok=True)
planted = Path(self.tmp.name) / "planted.lock"
lock.symlink_to(planted)
refused = self._run("agents", "order", "Beta,Alpha")
self.assertEqual(refused.returncode, 2, refused.stderr)
self.assertIn("agents order", refused.stderr)
self.assertFalse(planted.exists() or order.exists())
def test_a_symlinked_register_is_refused_and_never_copied_into_the_council(self):
outside = Path(self.tmp.name) / "outside.json"