feat(orchestrator): tasks tab with register, inbox and queue
Add a Tasks tab that lists the kvb-org-rasci register next to the inbox and the heavy-job queue, in list, board and RASCI matrix views, each task with its roles, WSJF, open work and the merge flow of its worktree. - Task priority pins and WSJF estimates are signed with the operator's passkey and applied by the runner through rasci.py; the hub verifies the signature itself before it queues a job or logs the change, the runner verifies it again and runs only the checked argv, from /, with a pinned PATH and a 30 s process-group limit. - The runner refuses task changes into a council that is a symlink, not owned by its uid or given by a relative path, and while the installed council.py, nofollow.py or rasci.py differ from the tree. - Only tasks the hub can sign whole are editable (task slug and length). - Page lookups keyed by register text use Object.hasOwn, so a status or party named like an Object.prototype member cannot break the views. - The inbox screen renders through the tasks screen, so its task filter shows with "Wartet auf Operator" pressed. Tests: 604 unit tests OK, e2e 15/15 OK (Chromium and Firefox). 🎯 Fix: 93 % 💥 Break: 5 % 💸 Cost: 100 % ⏱️ Time: – 🛡️ Security: 100 % 🏆 Score: 88 🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 % Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
01f791a1f4
commit
c1310c3322
37 files changed
+1436
-80
No files matched your search
@@ -5,6 +5,7 @@ import itertools
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
@@ -20,6 +21,8 @@ from hub_support import (
|
||||
HUB,
|
||||
OPTIONS,
|
||||
PAGE,
|
||||
RASCI,
|
||||
RUNNER,
|
||||
SCORE,
|
||||
TREE,
|
||||
FakeScripts,
|
||||
@@ -156,6 +159,18 @@ class HubCase(unittest.TestCase):
|
||||
def client(self) -> dict[str, str]:
|
||||
return {"Host": self.host, "X-Kvb-Orchestrator": "1"}
|
||||
|
||||
def runner_jobs(self) -> list[dict]:
|
||||
status, _, body = self.call("GET", "/api/runner/jobs", None, self.client())
|
||||
self.assertEqual(status, 200, body)
|
||||
return json.loads(body)["jobs"]
|
||||
|
||||
def run_runner(self, register: bool = True, council: Path | None = None) -> None:
|
||||
trust = ["--approvers", str(self.approvers), "--replay", str(self.replay / "runner.json")]
|
||||
flags = ["--rasci", str(RASCI), "--council", str(council or self.council)] if register else []
|
||||
command = [sys.executable, str(RUNNER), "--port", str(self.port), "--interval", "0.1", *trust, *flags, "--once"]
|
||||
done = subprocess.run(command, capture_output=True, text=True, timeout=60, check=False)
|
||||
self.assertEqual(done.returncode, 0, done.stderr)
|
||||
|
||||
def settle(self, check: Callable[[], bool]) -> None:
|
||||
deadline = time.monotonic() + 10
|
||||
while time.monotonic() < deadline:
|
||||
|
||||
Reference in new issue
Block a user