"""AP2.4 — Steering elements and method contract.""" from __future__ import annotations from steering.elements.registry import validate_steering_element_keys from steering.methods.registry import get_method, list_compatible_methods, ui_features_as_dict from steering.graph.profiles import get_graph_profile def test_all_methods_have_valid_steering_elements(): from steering.methods.registry import list_methods for method in list_methods(): validate_steering_element_keys(method.steering_elements) def test_sequential_dependency_contract(): method = get_method("sequential_dependency") assert method is not None assert "critical_path" in method.steering_elements assert "criticalPathControl" in method.ui_features assert get_graph_profile("sequential_dependency").enforce_gate_blocking is True def test_continuous_product_ui_features_from_method(): method = get_method("continuous_product") assert method is not None features = ui_features_as_dict(method.ui_features) assert features["continuousProductWorkMode"] is True assert features["steeringSnapshotOnWorkSprint"] is True def test_list_compatible_methods_linear_excludes_queue_pull(): methods = list_compatible_methods("initiative.linear_project") keys = {m.key for m in methods} assert "sequential_dependency" in keys assert "queue_pull" not in keys assert "agile_iteration" not in keys # modifier, not primary switch target def test_agile_iteration_composes_with_matrix(): method = get_method("agile_iteration") assert method is not None assert method.composes_with == frozenset( { "continuous_product", "sequential_dependency", "recurring_control", } ) assert "program_delivery" not in method.composes_with def test_list_composable_modifiers_for_linear(): from steering.methods.registry import list_composable_modifiers modifiers = list_composable_modifiers("sequential_dependency") assert len(modifiers) == 1 assert modifiers[0].key == "agile_iteration" def test_list_compatible_methods_product_excludes_maturity(): methods = list_compatible_methods("initiative.product") keys = {m.key for m in methods} assert "continuous_product" in keys assert "maturity_progression" not in keys def test_product_milestone_driven_compatible_with_generic(): from steering.methods.registry import list_compatible_methods methods = list_compatible_methods("initiative.generic") keys = {m.key for m in methods} assert "product_milestone_driven" in keys def test_operating_context_includes_method_contract(client): from tests.factories import provision_user_in_tenant from tests.test_initiatives_actions import _auth, _create_initiative, _login user = provision_user_in_tenant(tenant_role="member") token = _login(client, user) created = _create_initiative( client, token, title="Linear Contract", archetype_key="initiative.linear_project", ) initiative_id = created.json()["id"] res = client.get( f"/api/initiatives/{initiative_id}/operating-context", headers=_auth(token), ) assert res.status_code == 200 body = res.json() assert "critical_path" in body["steering_elements"] assert body["ui_features"].get("criticalPathControl") is True assert "graph_profile" in body assert body["compatible_methods"] assert any(m["key"] == "sequential_dependency" for m in body["compatible_methods"]) def test_steering_methods_filtered_by_archetype(client): from tests.factories import provision_user_in_tenant from tests.test_initiatives_actions import _auth, _login user = provision_user_in_tenant(tenant_role="member") token = _login(client, user) res = client.get( "/api/steering/methods", params={"archetype_key": "initiative.product"}, headers=_auth(token), ) assert res.status_code == 200 keys = {m["key"] for m in res.json()} assert "continuous_product" in keys assert "maturity_progression" not in keys product = next(m for m in res.json() if m["key"] == "continuous_product") assert "steering_elements" in product assert product["is_default"] is True def test_queue_pull_rejected_on_linear(client): user = provision_user_in_tenant(tenant_role="member") token = _login(client, user) created = _create_initiative( client, token, title="Linear Block Queue", archetype_key="initiative.linear_project", ) initiative_id = created.json()["id"] res = client.patch( f"/api/steering/initiatives/{initiative_id}/context", json={"method_key": "queue_pull"}, headers=_auth(token), ) assert res.status_code == 400 assert "kompatibel" in res.json()["detail"].lower() def test_operating_context_composable_modifiers_linear(client): user = provision_user_in_tenant(tenant_role="member") token = _login(client, user) created = _create_initiative( client, token, title="Linear Modifiers", archetype_key="initiative.linear_project", ) initiative_id = created.json()["id"] ctx = client.get( f"/api/initiatives/{initiative_id}/operating-context", headers=_auth(token), ) assert ctx.status_code == 200 modifiers = ctx.json().get("composable_modifiers") or [] assert any(m["key"] == "agile_iteration" for m in modifiers)