Orientation labels for support/evidence

This commit is contained in:
2026-04-29 17:59:47 +02:00
parent 466fd86d6d
commit 3de1d6da1d
3 changed files with 43 additions and 0 deletions

View File

@@ -2232,6 +2232,7 @@ def filter_element_rows(
str(row.get("target_id", "")), str(row.get("target_id", "")),
str(row.get("reference_kind", "")), str(row.get("reference_kind", "")),
str(row.get("reference_id", "")), str(row.get("reference_id", "")),
support_orientation_label(row),
source_refs_text(row["source_refs"]), source_refs_text(row["source_refs"]),
] ]
).lower() ).lower()
@@ -2291,11 +2292,45 @@ def render_element_source_detail(row: dict) -> str:
return ( return (
f'<p><span class="pill">supports {target}{f" #{target_id}" if target_id else ""}</span>' f'<p><span class="pill">supports {target}{f" #{target_id}" if target_id else ""}</span>'
f' <span class="pill">references {reference_kind}{f" #{reference_id}" if reference_id else ""}</span></p>' f' <span class="pill">references {reference_kind}{f" #{reference_id}" if reference_id else ""}</span></p>'
f'<p>{render_support_orientation(row)}</p>'
f'{render_sources(row["source_refs"])}' f'{render_sources(row["source_refs"])}'
) )
return render_sources(row["source_refs"]) return render_sources(row["source_refs"])
def support_orientation_label(row: dict) -> str:
if row.get("item_kind") != "evidence":
return ""
target_kind = str(row.get("target_kind") or "capability")
reference_kind = str(row.get("reference_kind") or "source")
levels = {
"scope": 0,
"ability": 1,
"capability": 2,
"feature": 3,
"fact": 4,
"source": 4,
"content": 4,
"chunk": 4,
}
target_level = levels.get(target_kind)
reference_level = levels.get(reference_kind)
if target_level is None or reference_level is None:
return "unclassified support"
if reference_level > target_level:
return "downward support"
if reference_level == target_level:
return "same-level support review"
return "upward support review"
def render_support_orientation(row: dict) -> str:
label = support_orientation_label(row)
if not label:
return ""
return f'<span class="pill">{escape(label)}</span>'
def render_element_actions( def render_element_actions(
row: dict, row: dict,
repository_id: int, repository_id: int,
@@ -3020,6 +3055,7 @@ def render_approved_evidence(evidence: dict, repository_id: int) -> str:
<span class="pill">{escape(evidence["strength"])}</span> <span class="pill">{escape(evidence["strength"])}</span>
<span class="pill">supports {target_kind}{f' #{target_id}' if target_id else ''}</span> <span class="pill">supports {target_kind}{f' #{target_id}' if target_id else ''}</span>
<span class="pill">references {reference_kind}{f' #{reference_id}' if reference_id else ''}</span> <span class="pill">references {reference_kind}{f' #{reference_id}' if reference_id else ''}</span>
{render_support_orientation(evidence | {"item_kind": "evidence"})}
<span class="source">{escape(evidence["reference"])}</span> <span class="source">{escape(evidence["reference"])}</span>
{render_sources(evidence.get("source_refs", []))} {render_sources(evidence.get("source_refs", []))}
<form class="stack" method="post" action="/ui/repos/{repository_id}/evidence/{evidence['id']}/edit"> <form class="stack" method="post" action="/ui/repos/{repository_id}/evidence/{evidence['id']}/edit">

View File

@@ -1722,6 +1722,7 @@ def test_ui_manual_registry_entry_loop(tmp_path):
assert "README.md" in detail_response.text assert "README.md" in detail_response.text
assert "supports capability" in detail_response.text assert "supports capability" in detail_response.text
assert "references source" in detail_response.text assert "references source" in detail_response.text
assert "downward support" in detail_response.text
assert "ID " in detail_response.text assert "ID " in detail_response.text
assert "Save Ability" in detail_response.text assert "Save Ability" in detail_response.text
@@ -1786,6 +1787,7 @@ def test_ui_manual_registry_entry_loop(tmp_path):
assert "Edited Manual API" in detail_response.text assert "Edited Manual API" in detail_response.text
assert "tests/test_manual.py" in detail_response.text assert "tests/test_manual.py" in detail_response.text
assert f"references feature #{feature_id}" in detail_response.text assert f"references feature #{feature_id}" in detail_response.text
assert "downward support" in detail_response.text
delete_feature_response = client.post( delete_feature_response = client.post(
f"{repository_path}/features/{feature_id}/delete", f"{repository_path}/features/{feature_id}/delete",

View File

@@ -247,3 +247,8 @@ from the UI and service layer. Accepting support promotes the parent ability and
capability context as needed, records a review decision, marks the candidate capability context as needed, records a review decision, marks the candidate
support approved, and maps capability support targets to the approved capability support approved, and maps capability support targets to the approved capability
ID. ID.
Implementation note 2026-04-29: support rows now show an orientation label based
on target/reference abstraction levels. Downward support is normal, same-level
support is marked for review, and upward support is marked for review because it
usually indicates an abstraction or organization problem.