From 0fb2ebdeea5e7b36280b93a719df10bb8f08d54b Mon Sep 17 00:00:00 2001 From: yaojingang Date: Sun, 14 Jun 2026 14:15:28 +0800 Subject: [PATCH] feat: expose next source actions in world-class runbook --- .../render_world_class_operator_runbook.py | 36 ++++++++++++++----- tests/verify_world_class_operator_runbook.py | 15 +++++++- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/scripts/render_world_class_operator_runbook.py b/scripts/render_world_class_operator_runbook.py index b263a9ae..de5e111a 100644 --- a/scripts/render_world_class_operator_runbook.py +++ b/scripts/render_world_class_operator_runbook.py @@ -45,6 +45,15 @@ def build_runbook_item( ) -> dict[str, Any]: commands = checklist.get("commands", {}) if isinstance(checklist.get("commands", {}), dict) else {} must_collect = checklist.get("must_collect", {}) if isinstance(checklist.get("must_collect", {}), dict) else {} + source_checklist = review_item.get("source_checklist", []) + blocked_source_checks = [ + row for row in source_checklist if isinstance(row, dict) and row.get("status") != "pass" + ] + next_source_actions = [] + for row in blocked_source_checks: + action = str(row.get("next_action", "")).strip() + if action and action not in next_source_actions: + next_source_actions.append(action) return { "evidence_key": entry.get("key", ""), "label": entry.get("label", entry.get("key", "")), @@ -73,7 +82,9 @@ def build_runbook_item( }, "evidence_artifacts": entry.get("evidence_artifacts", []), "observed_state": entry.get("observed_state", {}), - "source_checklist": review_item.get("source_checklist", []), + "source_checklist": source_checklist, + "blocked_source_check_count": len(blocked_source_checks), + "next_source_actions": next_source_actions, "submission_state": entry.get("submission_state", {}), "anti_overclaim": entry.get("anti_overclaim", {}), } @@ -165,13 +176,14 @@ def render_markdown(report: dict[str, Any]) -> str: "", "## Evidence Items", "", - "| Evidence | Ledger | Intake | Review | Owner |", - "| --- | --- | --- | --- | --- |", + "| Evidence | Ledger | Intake | Review | Blocked checks | Next source action | Owner |", + "| --- | --- | --- | --- | ---: | --- | --- |", ] for item in report["items"]: + next_action = item.get("next_source_actions", ["none"])[0] if item.get("next_source_actions") else "none" lines.append( f"| `{item['evidence_key']}` | `{item['ledger_status']}` | `{item['intake_readiness']}` | " - f"`{item['review_state']}` | {item['owner']} |" + f"`{item['review_state']}` | `{item.get('blocked_source_check_count', 0)}` | {next_action} | {item['owner']} |" ) for item in report["items"]: lines.extend( @@ -181,6 +193,7 @@ def render_markdown(report: dict[str, Any]) -> str: "", f"- objective: {item['objective']}", f"- blocking reason: {item['blocking_reason']}", + f"- blocked source checks: `{item.get('blocked_source_check_count', 0)}`", f"- submission: `{item['submission_path'] or 'missing'}`", f"- template: `{item['template_path'] or 'missing'}`", "", @@ -198,23 +211,25 @@ def render_markdown(report: dict[str, Any]) -> str: lines.extend(list_lines(item["must_collect"].get("privacy_contract", []), "No privacy contract listed.")) lines.extend(["", "### Evidence Artifacts", ""]) lines.extend(list_lines(item.get("evidence_artifacts", []), "No evidence artifacts listed.")) + lines.extend(["", "### Next Source Actions", ""]) + lines.extend(list_lines(item.get("next_source_actions", []), "No blocked source checks.")) lines.extend( [ "", "### Source Evidence Snapshot", "", - "| Check | Current | Expected | Status |", - "| --- | --- | --- | --- |", + "| Check | Current | Expected | Status | Next action |", + "| --- | --- | --- | --- | --- |", ] ) source_rows = item.get("source_checklist", []) if source_rows: for row in source_rows: lines.append( - f"| {row['label']} | `{row['actual']}` | `{row['expected']}` | `{row['status']}` |" + f"| {row['label']} | `{row['actual']}` | `{row['expected']}` | `{row['status']}` | {row.get('next_action', '')} |" ) else: - lines.append("| No source checks listed. | `n/a` | `n/a` | `n/a` |") + lines.append("| No source checks listed. | `n/a` | `n/a` | `n/a` | n/a |") lines.extend( [ "", @@ -264,6 +279,7 @@ def render_html_item(item: dict[str, Any]) -> str:
Owner
{html_text(item['owner'])}
Ledger
{html_text(item['ledger_status'])}
+
Blocked
{html_text(item.get('blocked_source_check_count', 0))}
Submission
{html_text(item['submission_path'])}

Commands

@@ -272,6 +288,7 @@ def render_html_item(item: dict[str, Any]) -> str:

Success Checks

Privacy

+

Next Source Actions

Source Evidence Snapshot

{html_source_checks(item.get('source_checklist', []))}
""".strip() @@ -284,6 +301,7 @@ def render_html(report: dict[str, Any]) -> str: ("Awaiting", summary["awaiting_submission_count"]), ("Ready", summary["ready_for_ledger_review_count"]), ("Source", f"{summary.get('source_pass_count', 0)}/{summary.get('source_check_count', 0)}"), + ("Blocked", summary.get("source_blocked_count", 0)), ("Invalid", summary["invalid_submission_count"]), ] stat_html = "".join(f"
{html_text(label)}{html_text(value)}
" for label, value in stats) @@ -312,7 +330,7 @@ def render_html(report: dict[str, Any]) -> str: h3 {{ margin:4px 0 10px; font-size:22px; }} h4 {{ margin:0 0 8px; font-size:16px; }} .lede {{ max-width:800px; color:var(--muted); font-size:20px; }} - .stats {{ display:grid; grid-template-columns:repeat(5, minmax(0,1fr)); gap:12px; margin-top:26px; }} + .stats {{ display:grid; grid-template-columns:repeat(6, minmax(0,1fr)); gap:12px; margin-top:26px; }} .stats article, .panel, .item-card {{ border:1px solid var(--line); border-radius:8px; background:#fff; }} .stats article {{ padding:16px; }} .stats span, .item-card span, .muted {{ color:var(--muted); }} diff --git a/tests/verify_world_class_operator_runbook.py b/tests/verify_world_class_operator_runbook.py index abc277bb..2127ab2b 100644 --- a/tests/verify_world_class_operator_runbook.py +++ b/tests/verify_world_class_operator_runbook.py @@ -120,6 +120,9 @@ def main() -> None: provider = items["provider-holdout"] assert provider["review_state"] == "awaiting-submission", provider assert provider["source_accepted"] is False, provider + assert provider["blocked_source_check_count"] == 2, provider + assert "Run provider-backed output-exec with real credentials." in provider["next_source_actions"], provider + assert "Provider execution should return non-estimated token usage." in provider["next_source_actions"], provider assert provider["commands"]["prepare_submission"].startswith("python3 scripts/yao.py world-class-submission-kit"), provider assert "world-class-intake" in provider["commands"]["validate_intake"], provider assert "world-class-submission-review" in provider["commands"]["review_queue"], provider @@ -135,12 +138,20 @@ def main() -> None: assert "World-Class Operator Runbook" in markdown, markdown assert "runbook counts as completion: `false`" in markdown, markdown assert "Valid intake means ready for submission review; ledger review still requires passing source evidence." in markdown, markdown + assert "| Evidence | Ledger | Intake | Review | Blocked checks | Next source action | Owner |" in markdown, markdown + assert "| `provider-holdout` | `pending` | `awaiting-submission` | `awaiting-submission` | `2` | Run provider-backed output-exec with real credentials." in markdown, markdown + assert "### Next Source Actions" in markdown, markdown + assert "- Provider execution should return non-estimated token usage." in markdown, markdown assert "Source Evidence Snapshot" in markdown, markdown - assert "| Provider model run | `0` | `>0` | `blocked` |" in markdown, markdown + assert "| Check | Current | Expected | Status | Next action |" in markdown, markdown + assert "| Provider model run | `0` | `>0` | `blocked` | Run provider-backed output-exec with real credentials. |" in markdown, markdown html = output_html.read_text(encoding="utf-8") assert "World-Class Operator Runbook" in html, html[:400] assert "ledger and claim guard" in html, html assert "position:sticky" in html, html + assert "Blocked7" in html, html + assert "
Blocked
2
" in html, html + assert "Next Source Actions" in html, html assert "Source Evidence Snapshot" in html, html assert "model_executed_count" in html, html assert " None: assert submitted_provider["intake_readiness"] == "source-evidence-incomplete", submitted_provider assert submitted_provider["review_state"] == "source-evidence-incomplete", submitted_provider assert submitted_provider["source_accepted"] is False, submitted_provider + assert submitted_provider["blocked_source_check_count"] == 2, submitted_provider + assert submitted_provider["next_source_actions"] == provider["next_source_actions"], submitted_provider assert "tests/tmp_world_class_operator_runbook/valid_submissions" in submitted_provider["commands"]["validate_intake"], submitted_provider assert "tests/tmp_world_class_operator_runbook/valid_submissions" in submitted_provider["commands"]["review_queue"], submitted_provider assert "tests/tmp_world_class_operator_runbook/valid_submissions" in submitted_provider["commands"]["refresh_ledger"], submitted_provider