From cb165cd821a49e4f1caab336ff08c48477bccf31 Mon Sep 17 00:00:00 2001 From: Lars Date: Wed, 29 Jul 2026 08:41:28 +0200 Subject: [PATCH] =?UTF-8?q?fix(A1):=20pytest=20Progression=20=E2=80=94=20l?= =?UTF-8?q?egacy=20Stufen=20aus=20Join-Graph=20ausschlie=C3=9Fen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retire Starter-Kit-Stufen ohne Strang beim Progression-Demo; active_work_gates zählt nur stranggebundene Gates wenn Join existiert. E2E-Test an maturity_transition-Struktur angepasst. Co-authored-by: Cursor --- backend/services/archetype_starter_kit.py | 45 +++++++++++++++++++++++ backend/services/progression_graph.py | 2 + backend/tests/test_ap22c_maturity_e2e.py | 8 +++- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/backend/services/archetype_starter_kit.py b/backend/services/archetype_starter_kit.py index c61f18d..d98ef5a 100644 --- a/backend/services/archetype_starter_kit.py +++ b/backend/services/archetype_starter_kit.py @@ -312,6 +312,45 @@ def _apply_a2( } +def _retire_legacy_linear_stages_for_progression( + *, + tenant_id: str, + initiative_id: str, + user_id: Optional[str] = None, +) -> None: + """Starter-Kit-Stufen ohne Strang zurückstellen, wenn Join-Graph angelegt wird.""" + from services.maturity_practice import list_practices_for_stage, update_recurring_element + from services.roadmap import list_roadmap_items_for_initiative, update_roadmap_item + + for item in list_roadmap_items_for_initiative( + tenant_id=tenant_id, initiative_id=initiative_id + ): + if item.get("item_type") != "maturity_stage": + continue + if item.get("strand_project_id"): + continue + if item.get("status") not in ("active", "at_risk"): + continue + update_roadmap_item( + tenant_id=tenant_id, + item_id=item["id"], + status="planned", + user_id=user_id, + ) + for practice in list_practices_for_stage( + tenant_id=tenant_id, + initiative_id=initiative_id, + stage_id=item["id"], + ): + if practice.get("status") == "active": + update_recurring_element( + tenant_id=tenant_id, + recurring_id=practice["id"], + status="paused", + user_id=user_id, + ) + + def apply_a1_progression_demo( *, tenant_id: str, @@ -428,6 +467,12 @@ def apply_a1_progression_demo( tenant_id=tenant_id, initiative_id=initiative_id, stage=h1, user_id=user_id ) + _retire_legacy_linear_stages_for_progression( + tenant_id=tenant_id, + initiative_id=initiative_id, + user_id=user_id, + ) + return { "applied": True, "projects": ["Dehnung", "Hüftrotation"], diff --git a/backend/services/progression_graph.py b/backend/services/progression_graph.py index 9b3cad8..e2ce356 100644 --- a/backend/services/progression_graph.py +++ b/backend/services/progression_graph.py @@ -71,10 +71,12 @@ def list_active_work_gates( items = list_roadmap_items_for_initiative( tenant_id=tenant_id, initiative_id=initiative_id ) + has_join_graph = any(is_join_gate(item) for item in items) active = [ item for item in items if is_work_gate(item) and item.get("status") in ACTIVE_WORK_STATUSES + and (not has_join_graph or item.get("strand_project_id") is not None) ] active.sort(key=lambda item: (item.get("sort_order", 0), item.get("title", ""))) return active diff --git a/backend/tests/test_ap22c_maturity_e2e.py b/backend/tests/test_ap22c_maturity_e2e.py index f0c8f59..518414d 100644 --- a/backend/tests/test_ap22c_maturity_e2e.py +++ b/backend/tests/test_ap22c_maturity_e2e.py @@ -116,7 +116,13 @@ def test_a1_stage_verify_rotates_recurring_and_next_action(client): body = verify.json() assert body["status"] == "reached" transition = body.get("maturity_transition") or {} - assert transition.get("new_recurring_id") + legacy = transition.get("legacy_linear") or {} + practice_ids = (legacy.get("practice_transition") or {}).get("practice_ids") or [] + assert ( + practice_ids + or transition.get("successors_activated") + or transition.get("joins_switched") + ) recurring = client.get( f"/api/initiatives/{initiative_id}/recurring",