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
@@ -41,14 +41,24 @@ def timer_rows(folder: Path) -> list[dict]:
|
||||
return rows
|
||||
|
||||
|
||||
def queue_rows(council: Path) -> list[dict]:
|
||||
def queue_entries(council: Path) -> list[tuple[dict, float]]:
|
||||
"""Returns:
|
||||
Each kvb-org-queue entry of queue.json with its enqueue time; an
|
||||
entry without one is no entry.
|
||||
"""
|
||||
data = read_json(council / "queue.json")
|
||||
entries = data.get("entries") if isinstance(data, dict) else None
|
||||
rows = []
|
||||
found = []
|
||||
for entry in entries if isinstance(entries, list) else []:
|
||||
created = epoch(entry.get("enqueued")) if isinstance(entry, dict) else None
|
||||
if created is None:
|
||||
continue
|
||||
if created is not None:
|
||||
found.append((entry, created))
|
||||
return found
|
||||
|
||||
|
||||
def queue_rows(council: Path) -> list[dict]:
|
||||
rows = []
|
||||
for entry, created in queue_entries(council):
|
||||
running = "läuft" if entry.get("status") == "active" else "wartet"
|
||||
rows.append({
|
||||
"key": f"queue:{shown(entry.get('id'))}", "type": "queue", "session": shown(entry.get("session")), "sub": "", "created": created,
|
||||
|
||||
Reference in new issue
Block a user