generated from coulomb/repo-seed
Finalized dependency aware scope prop
This commit is contained in:
@@ -47,6 +47,14 @@ The current implementation exposes this through `RegistryService`:
|
|||||||
The impact result includes changed fact keys, impacted items, reason chains,
|
The impact result includes changed fact keys, impacted items, reason chains,
|
||||||
maximum propagation depth, breadth, and whether the root scope was affected.
|
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
|
## Interactive Visualization
|
||||||
|
|
||||||
The accepted implementation framework for the interactive graph view is
|
The accepted implementation framework for the interactive graph view is
|
||||||
|
|||||||
@@ -1619,6 +1619,11 @@ def analysis_run_diff_detail(
|
|||||||
base_analysis_run_id,
|
base_analysis_run_id,
|
||||||
target_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:
|
except NotFoundError as exc:
|
||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
display_name = repository_display_name(diff.repository)
|
display_name = repository_display_name(diff.repository)
|
||||||
@@ -1639,6 +1644,13 @@ def analysis_run_diff_detail(
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section class="panel" style="margin-top:18px">
|
||||||
|
<div class="actions">
|
||||||
|
<h2 style="margin-right:auto">Dependency Impact</h2>
|
||||||
|
<a class="button secondary" href="/ui/repos/{repository_id}/dependency-graph?base_analysis_run_id={base_analysis_run_id}&target_analysis_run_id={target_analysis_run_id}">Open Graph</a>
|
||||||
|
</div>
|
||||||
|
{render_dependency_impact_summary(asdict(impact))}
|
||||||
|
</section>
|
||||||
<div class="grid" style="margin-top:18px">
|
<div class="grid" style="margin-top:18px">
|
||||||
<section class="panel">
|
<section class="panel">
|
||||||
<h2>Approved Registry Impact</h2>
|
<h2>Approved Registry Impact</h2>
|
||||||
@@ -2403,6 +2415,65 @@ def render_diff_section(section: dict) -> str:
|
|||||||
return rendered or '<p class="muted">No differences.</p>'
|
return rendered or '<p class="muted">No differences.</p>'
|
||||||
|
|
||||||
|
|
||||||
|
def render_dependency_impact_summary(impact: dict) -> str:
|
||||||
|
impacts = impact.get("impacts", [])
|
||||||
|
metric_row = (
|
||||||
|
f'<span class="pill">{escape(str(impact.get("propagation_breadth", 0)))} impacted</span>'
|
||||||
|
f'<span class="pill">depth {escape(str(impact.get("max_depth", 0)))}</span>'
|
||||||
|
+ (
|
||||||
|
'<span class="pill">scope impacted</span>'
|
||||||
|
if impact.get("scope_impacted")
|
||||||
|
else '<span class="pill">scope current</span>'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
changed_facts = impact.get("changed_fact_keys", [])
|
||||||
|
changed_fact_rows = "".join(
|
||||||
|
f'<li class="source">{escape(str(fact_key))}</li>'
|
||||||
|
for fact_key in changed_facts[:8]
|
||||||
|
)
|
||||||
|
changed_fact_note = (
|
||||||
|
f"<ul>{changed_fact_rows}</ul>"
|
||||||
|
if changed_fact_rows
|
||||||
|
else '<p class="muted">No changed facts reached approved characteristics.</p>'
|
||||||
|
)
|
||||||
|
rows = "\n".join(
|
||||||
|
f"""
|
||||||
|
<tr>
|
||||||
|
<td><span class="pill">{escape(str(item.get('item_kind', '')))}</span></td>
|
||||||
|
<td>{escape(str(item.get('name', '')))}</td>
|
||||||
|
<td><span class="pill">{escape(str(item.get('freshness_state', '')))}</span></td>
|
||||||
|
<td>{escape(str(item.get('recommended_action', '')))}</td>
|
||||||
|
<td>{escape(str(item.get('impact_depth', '')))}</td>
|
||||||
|
<td>{render_impact_reasons(item.get('reasons', []))}</td>
|
||||||
|
</tr>
|
||||||
|
"""
|
||||||
|
for item in impacts
|
||||||
|
)
|
||||||
|
table = (
|
||||||
|
f"""
|
||||||
|
<table>
|
||||||
|
<thead><tr><th>Kind</th><th>Name</th><th>Freshness</th><th>Action</th><th>Depth</th><th>Why</th></tr></thead>
|
||||||
|
<tbody>{rows}</tbody>
|
||||||
|
</table>
|
||||||
|
"""
|
||||||
|
if rows
|
||||||
|
else '<p class="muted">No approved downstream items were marked stale.</p>'
|
||||||
|
)
|
||||||
|
return f"""
|
||||||
|
<div class="actions">{metric_row}</div>
|
||||||
|
<h3>Changed Facts</h3>
|
||||||
|
{changed_fact_note}
|
||||||
|
<h3>Impacted Items</h3>
|
||||||
|
{table}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_impact_reasons(reasons: list[str]) -> str:
|
||||||
|
if not reasons:
|
||||||
|
return '<span class="muted">No reason recorded.</span>'
|
||||||
|
return "<br>".join(escape(str(reason)) for reason in reasons[:3])
|
||||||
|
|
||||||
|
|
||||||
def render_diff_group(items: list[dict], title: str) -> str:
|
def render_diff_group(items: list[dict], title: str) -> str:
|
||||||
if not items:
|
if not items:
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -1691,6 +1691,8 @@ def test_ui_register_analyze_and_approve_loop(tmp_path):
|
|||||||
)
|
)
|
||||||
assert diff_response.status_code == 200
|
assert diff_response.status_code == 200
|
||||||
assert "Change Review" in diff_response.text
|
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 "Approved Registry Impact" in diff_response.text
|
||||||
assert "Candidate Claims" in diff_response.text
|
assert "Candidate Claims" in diff_response.text
|
||||||
assert "GET /ready" in diff_response.text
|
assert "GET /ready" in diff_response.text
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ type: workplan
|
|||||||
title: "Dependency-Aware Scope Propagation"
|
title: "Dependency-Aware Scope Propagation"
|
||||||
domain: capabilities
|
domain: capabilities
|
||||||
repo: repo-scoping
|
repo: repo-scoping
|
||||||
status: active
|
status: done
|
||||||
owner: codex
|
owner: codex
|
||||||
topic_slug: foerster-capabilities
|
topic_slug: foerster-capabilities
|
||||||
created: "2026-05-01"
|
created: "2026-05-01"
|
||||||
@@ -80,7 +80,7 @@ Acceptance criteria:
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: RREG-WP-0008-T03
|
id: RREG-WP-0008-T03
|
||||||
status: in_progress
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "29a85e0a-7203-484c-aa5d-94096ab695a9"
|
state_hub_task_id: "29a85e0a-7203-484c-aa5d-94096ab695a9"
|
||||||
```
|
```
|
||||||
@@ -115,7 +115,7 @@ Acceptance criteria:
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: RREG-WP-0008-T05
|
id: RREG-WP-0008-T05
|
||||||
status: in_progress
|
status: done
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "02147d64-d339-40e2-b88d-406567bfa366"
|
state_hub_task_id: "02147d64-d339-40e2-b88d-406567bfa366"
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user