Mirror review actions into gates
This commit is contained in:
@@ -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"], {})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"],
|
||||
|
||||
Reference in New Issue
Block a user