diff --git a/docs/dependency-aware-scope-propagation.md b/docs/dependency-aware-scope-propagation.md index e17ee58..13f84ec 100644 --- a/docs/dependency-aware-scope-propagation.md +++ b/docs/dependency-aware-scope-propagation.md @@ -47,6 +47,14 @@ The current implementation exposes this through `RegistryService`: The impact result includes changed fact keys, impacted items, reason chains, maximum propagation depth, breadth, and whether the root scope was affected. +## Review Workflow + +The change-review UI shows dependency impact alongside ordinary run diffs. Each +impacted item carries a freshness state, reason chain, propagation depth, and a +recommended action. Curators can accept recalculated candidate text by approving +the target run, keep prior approved claims by leaving the change unapproved, or +edit approved characteristics through the existing manual registry forms. + ## Interactive Visualization The accepted implementation framework for the interactive graph view is diff --git a/src/repo_registry/web_ui/views.py b/src/repo_registry/web_ui/views.py index 1d48dc1..ef0d22a 100644 --- a/src/repo_registry/web_ui/views.py +++ b/src/repo_registry/web_ui/views.py @@ -1619,6 +1619,11 @@ def analysis_run_diff_detail( base_analysis_run_id, target_analysis_run_id, ) + impact = service.analyze_dependency_impact( + repository_id, + base_analysis_run_id, + target_analysis_run_id, + ) except NotFoundError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc display_name = repository_display_name(diff.repository) @@ -1639,6 +1644,13 @@ def analysis_run_diff_detail( +
+
+

Dependency Impact

+ Open Graph +
+ {render_dependency_impact_summary(asdict(impact))} +

Approved Registry Impact

@@ -2403,6 +2415,65 @@ def render_diff_section(section: dict) -> str: return rendered or '

No differences.

' +def render_dependency_impact_summary(impact: dict) -> str: + impacts = impact.get("impacts", []) + metric_row = ( + f'{escape(str(impact.get("propagation_breadth", 0)))} impacted' + f'depth {escape(str(impact.get("max_depth", 0)))}' + + ( + 'scope impacted' + if impact.get("scope_impacted") + else 'scope current' + ) + ) + changed_facts = impact.get("changed_fact_keys", []) + changed_fact_rows = "".join( + f'
  • {escape(str(fact_key))}
  • ' + for fact_key in changed_facts[:8] + ) + changed_fact_note = ( + f"" + if changed_fact_rows + else '

    No changed facts reached approved characteristics.

    ' + ) + rows = "\n".join( + f""" + + {escape(str(item.get('item_kind', '')))} + {escape(str(item.get('name', '')))} + {escape(str(item.get('freshness_state', '')))} + {escape(str(item.get('recommended_action', '')))} + {escape(str(item.get('impact_depth', '')))} + {render_impact_reasons(item.get('reasons', []))} + + """ + for item in impacts + ) + table = ( + f""" + + + {rows} +
    KindNameFreshnessActionDepthWhy
    + """ + if rows + else '

    No approved downstream items were marked stale.

    ' + ) + return f""" +
    {metric_row}
    +

    Changed Facts

    + {changed_fact_note} +

    Impacted Items

    + {table} + """ + + +def render_impact_reasons(reasons: list[str]) -> str: + if not reasons: + return 'No reason recorded.' + return "
    ".join(escape(str(reason)) for reason in reasons[:3]) + + def render_diff_group(items: list[dict], title: str) -> str: if not items: return "" diff --git a/tests/test_web_api.py b/tests/test_web_api.py index e781c82..23e1239 100644 --- a/tests/test_web_api.py +++ b/tests/test_web_api.py @@ -1691,6 +1691,8 @@ def test_ui_register_analyze_and_approve_loop(tmp_path): ) assert diff_response.status_code == 200 assert "Change Review" in diff_response.text + assert "Dependency Impact" in diff_response.text + assert "Open Graph" in diff_response.text assert "Approved Registry Impact" in diff_response.text assert "Candidate Claims" in diff_response.text assert "GET /ready" in diff_response.text diff --git a/workplans/RREG-WP-0008-dependency-aware-scope-propagation.md b/workplans/RREG-WP-0008-dependency-aware-scope-propagation.md index 6deb8c4..7baa21a 100644 --- a/workplans/RREG-WP-0008-dependency-aware-scope-propagation.md +++ b/workplans/RREG-WP-0008-dependency-aware-scope-propagation.md @@ -4,7 +4,7 @@ type: workplan title: "Dependency-Aware Scope Propagation" domain: capabilities repo: repo-scoping -status: active +status: done owner: codex topic_slug: foerster-capabilities created: "2026-05-01" @@ -80,7 +80,7 @@ Acceptance criteria: ```task id: RREG-WP-0008-T03 -status: in_progress +status: done priority: high state_hub_task_id: "29a85e0a-7203-484c-aa5d-94096ab695a9" ``` @@ -115,7 +115,7 @@ Acceptance criteria: ```task id: RREG-WP-0008-T05 -status: in_progress +status: done priority: medium state_hub_task_id: "02147d64-d339-40e2-b88d-406567bfa366" ```