From 7ef6ba323e6dad4884be53e983b41ace0e668518 Mon Sep 17 00:00:00 2001 From: codex Date: Sun, 11 Oct 2026 23:06:25 +0200 Subject: [PATCH] Sync work-record index Co-Authored-By: Claude Opus 5.5 --- .custodian-brief.md | 4 ++-- scripts/security_flow_report.py | 21 ++++++++++++----- tests/test_security_flow_report.py | 36 ++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/.custodian-brief.md b/.custodian-brief.md index 166eaae2..11210288 100644 --- a/.custodian-brief.md +++ b/.custodian-brief.md @@ -2,7 +2,7 @@ # Custodian Brief — the-custodian **Domain:** infotech -**Last synced:** 2026-10-11 19:30 UTC +**Last synced:** 2026-10-11 21:06 UTC **State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)* ## Active Workstreams @@ -16,7 +16,7 @@ Progress: 3/7 done | workplan_id: `ab288f92-d364-5c24-9362-aee451f266c3` - ! Encode the standing change rule as a policy-nexus guardrail `5dd52156` *(wait: policy-nexus owns guardrail publication; handoff written as PNEX-WP-0006.)* - ! Attended window #1 `e3da807f` - *(wait: Founder runs docs/attended-window/2026-10-11-checklist.md (about 2 h).)* + *(wait: Partly done 2026-10-11: list cut from 14 to 3; U05-U07 accepted, U08 waits on KEY-WP-0040-T01. Remaining founder acts: USER-WP-0026-T03 readback, RPF-WP-0044-T08 coulombcore check, the U08 re-run, and Sol's added RPF-WP-0044-T04 issuer login.)* - ► Stop agent-authored index and sync commits `8a3dc219` ### Separate agent credentials and establish supervised privileged execution diff --git a/scripts/security_flow_report.py b/scripts/security_flow_report.py index e648cdb0..288a0db9 100644 --- a/scripts/security_flow_report.py +++ b/scripts/security_flow_report.py @@ -2,12 +2,13 @@ """Deterministic flow report for the NetKingdom security estate. Replaces agent sessions that poll wait tasks. Reads workplan files only (no hub, -no network) and prints four lists: +no network) and prints five lists: - READY todo/progress tasks in non-residual workplans: what agents should work on + READY todo/progress tasks with no unresolved explicit dependency or owner/human gate UNBLOCKED wait tasks whose every depends_on target is done/cancel: requalify to todo ATTENDED needs_human wait tasks: the attended-window checklist for the operator/founder STALLED wait tasks qualified only by blocked_on message-from (owner reply), oldest first by file + DEPENDENT todo/progress tasks that still carry an unresolved dependency or owner gate Usage: security_flow_report.py [--repos a,b,c] [--json] """ @@ -54,13 +55,19 @@ def classify(tasks): own = [t for t in tasks.values() if t["id"].startswith(d + "-T")] return bool(own) and all(t["status"] in TERMINAL for t in own) - out = {"READY": [], "UNBLOCKED": [], "ATTENDED": [], "STALLED": []} + out = {"READY": [], "UNBLOCKED": [], "ATTENDED": [], "STALLED": [], "DEPENDENT": []} for t in tasks.values(): wp = t["wp"] if wp["status"] in ("finished", "archived") or wp["flavor"] == "residual": continue if t["status"] in ("todo", "progress"): - out["READY"].append(t) + missing = [d for d in t["deps"] if not dep_done(d)] + if t["human"]: + out["ATTENDED"].append(t) + elif missing or t["blocked_on"]: + out["DEPENDENT"].append(t | {"pending_dependencies": missing}) + else: + out["READY"].append(t) elif t["status"] == "wait": if t["human"]: out["ATTENDED"].append(t) @@ -83,12 +90,16 @@ def main(): res = classify(load(a.root, a.repos.split(","))) if a.json: print(json.dumps({k: [{x: t[x] for x in ("id", "status", "priority", "reason", "blocked_on")} - | {"repo": t["wp"]["repo"]} for t in v] for k, v in res.items()}, indent=1)) + | {"repo": t["wp"]["repo"]} + | ({"pending_dependencies": t["pending_dependencies"]} if k == "DEPENDENT" else {}) + for t in v] for k, v in res.items()}, indent=1)) return for k, v in res.items(): print(f"\n## {k} ({len(v)})") for t in v: extra = t["blocked_on"] if k == "STALLED" else t["reason"] + if k == "DEPENDENT": + extra = ", ".join(t["pending_dependencies"]) or t["blocked_on"] print(f"- {t['id']} [{t['status']}/{t['priority'] or '-'}] {t['wp']['repo']}" + (f" — {extra[:140]}" if extra else "")) diff --git a/tests/test_security_flow_report.py b/tests/test_security_flow_report.py index 1bf1db92..c89bc84e 100644 --- a/tests/test_security_flow_report.py +++ b/tests/test_security_flow_report.py @@ -46,3 +46,39 @@ def test_default_estate_includes_custodian_and_explains_human_gate(tmp_path): assert [t["id"] for t in result["READY"]] == ["CUST-WP-0079-T05"] assert result["ATTENDED"][0]["reason"] == "Public publication in daily batch" assert result["UNBLOCKED"] == [] + + +def test_pending_owner_task_is_not_ready_until_predecessor_finishes(tmp_path): + workplan(tmp_path, "railiance-platform", + "id: RPF-WP-0044-T06\nstatus: todo\npriority: medium\n" + "depends_on: [ACTIVITY-WP-0041-T03]") + workplan(tmp_path, "activity-core", + "id: ACTIVITY-WP-0041-T03\nstatus: progress\npriority: high") + waiting = report(tmp_path) + assert [t["id"] for t in waiting["READY"]] == ["ACTIVITY-WP-0041-T03"] + assert waiting["DEPENDENT"][0]["pending_dependencies"] == ["ACTIVITY-WP-0041-T03"] + workplan(tmp_path, "activity-core", + "id: ACTIVITY-WP-0041-T03\nstatus: done\npriority: high") + assert [t["id"] for t in report(tmp_path)["READY"]] == ["RPF-WP-0044-T06"] + + +def test_unknown_dependency_and_legacy_owner_gate_are_visible_but_not_ready(tmp_path): + workplan(tmp_path, "access-engine", + "id: FLEX-WP-0036-T06\nstatus: todo\npriority: medium\n" + "depends_on: [UNKNOWN-WP-0001-T01]") + workplan(tmp_path, "ops-mason", + "id: MASON-WP-0010-T03\nstatus: progress\npriority: high\n" + "blocked_on: message-from:railiance-platform") + result = report(tmp_path) + assert not result["READY"] + assert len(result["DEPENDENT"]) == 2 + assert result["DEPENDENT"][0]["blocked_on"] == "message-from:railiance-platform" + + +def test_human_flag_prevents_ready_even_if_status_has_not_been_requalified(tmp_path): + workplan(tmp_path, "user-engine", + "id: USER-WP-0027-T04\nstatus: progress\npriority: high\n" + "needs_human: true\nintervention_note: Real MFA journey") + result = report(tmp_path) + assert not result["READY"] + assert result["ATTENDED"][0]["id"] == "USER-WP-0027-T04"