Mirror review actions into gates

This commit is contained in:
yaojingang
2026-06-17 05:17:41 +08:00
parent 7050664b48
commit cd71fd61e4
37 changed files with 732 additions and 386 deletions
+67
View File
@@ -55,6 +55,71 @@ def git_worktree_status(skill_dir: Path) -> dict[str, Any]:
return {"available": True, "clean": not changes, "changed_file_count": len(changes)}
def build_review_studio_gate_action_mirror_check(review_studio: dict[str, Any]) -> dict[str, Any]:
gates = review_studio.get("gates", []) if isinstance(review_studio.get("gates", []), list) else []
actions = (
review_studio.get("review_actions", [])
if isinstance(review_studio.get("review_actions", []), list)
else []
)
non_pass_gates = [gate for gate in gates if isinstance(gate, dict) and gate.get("status") != "pass"]
pass_gates = [gate for gate in gates if isinstance(gate, dict) and gate.get("status") == "pass"]
actions_by_gate = {
str(action.get("gate_key", "")): action
for action in actions
if isinstance(action, dict) and str(action.get("gate_key", ""))
}
expected = {
"non_pass_gate_keys": sorted(str(gate.get("key", "")) for gate in non_pass_gates),
"action_gate_keys": sorted(str(gate.get("key", "")) for gate in non_pass_gates),
"pass_gate_action_ids_empty": True,
"gate_action_mirrors": {
str(gate.get("key", "")): {
"review_action_id": f"review-action-{gate.get('key', '')}",
"review_action_status": gate.get("status", ""),
"source_ref_present": True,
"verification_command_present": True,
}
for gate in non_pass_gates
},
}
actual = {
"non_pass_gate_keys": sorted(str(gate.get("key", "")) for gate in non_pass_gates),
"action_gate_keys": sorted(actions_by_gate),
"pass_gate_action_ids_empty": all(not gate.get("review_action_id") for gate in pass_gates),
"gate_action_mirrors": {},
}
for gate in non_pass_gates:
key = str(gate.get("key", ""))
action = actions_by_gate.get(key, {})
actual["gate_action_mirrors"][key] = {
"review_action_id": gate.get("review_action_id", ""),
"review_action_status": gate.get("review_action_status", ""),
"source_ref_present": bool(gate.get("review_action_source_ref_count")),
"verification_command_present": bool(gate.get("review_action_verification_command")),
"top_level_action_id": action.get("action_id", ""),
"top_level_action_status": action.get("status", ""),
"top_level_source_ref_present": bool(action.get("source_refs")),
"top_level_verification_command_present": bool(action.get("verification_command")),
}
expected["gate_action_mirrors"][key]["top_level_action_id"] = f"review-action-{key}"
expected["gate_action_mirrors"][key]["top_level_action_status"] = gate.get("status", "")
expected["gate_action_mirrors"][key]["top_level_source_ref_present"] = True
expected["gate_action_mirrors"][key]["top_level_verification_command_present"] = True
return {
"key": "review-studio-gate-action-mirror",
"label": "Review Studio gates mirror review actions",
"status": "pass" if expected == actual else "fail",
"expected": expected,
"actual": actual,
"paths": [REQUIRED_REPORTS["review_studio"]],
"detail": (
"Every non-pass Review Studio gate must have exactly one top-level review action and a gate-local "
"action summary with source refs and a verification command."
),
}
def build_report(skill_dir: Path, generated_at: str) -> dict[str, Any]:
reports: dict[str, dict[str, Any]] = {}
text_reports: dict[str, str] = {}
@@ -100,6 +165,8 @@ def build_report(skill_dir: Path, generated_at: str) -> dict[str, Any]:
context_budget = reports["context_budget"]
claim_guard = reports["world_class_claim_guard"]
checks.append(build_review_studio_gate_action_mirror_check(review_studio))
benchmark_summary = nested(benchmark, ["summary"], {})
adoption_summary = nested(adoption, ["summary"], {})
ledger_summary = nested(ledger, ["summary"], {})
+7
View File
@@ -514,6 +514,13 @@ def render_review_studio(skill_dir: Path, output_html: Path | None = None, outpu
contract = gate_contract(gates)
blockers, warnings = add_blockers_from_gate(gates)
review_actions = build_review_actions(gates, skill_dir, output_html, data)
action_by_gate = {str(item.get("gate_key", "")): item for item in review_actions}
for gate in gates:
action = action_by_gate.get(str(gate.get("key", "")))
gate["review_action_id"] = str(action.get("action_id", "")) if action else ""
gate["review_action_status"] = str(action.get("status", "")) if action else ""
gate["review_action_source_ref_count"] = len(action.get("source_refs", [])) if action else 0
gate["review_action_verification_command"] = str(action.get("verification_command", "")) if action else ""
score = weighted_score(gates)
annotation_summary = data["review_annotations"].get("summary", {})
open_annotation_blockers = int(annotation_summary.get("open_blocker_count", 0) or 0)
+1
View File
@@ -297,6 +297,7 @@ def build_review_actions(
refs = source_refs(skill_dir, output_html, guidance.get("source_paths", []))
actions.append(
{
"action_id": f"review-action-{gate_item['key']}",
"gate_key": gate_item["key"],
"label": gate_item["label"],
"status": gate_item["status"],