"""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_includes_queue_pull(): methods = list_compatible_methods("initiative.linear_project") keys = {m.key for m in methods} assert "sequential_dependency" in keys assert "queue_pull" in keys 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_on_linear_changes_steering_elements(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 Queue", archetype_key="initiative.linear_project", ) initiative_id = created.json()["id"] client.patch( f"/api/steering/initiatives/{initiative_id}/context", json={"method_key": "queue_pull"}, headers=_auth(token), ) ctx = client.get( f"/api/initiatives/{initiative_id}/operating-context", headers=_auth(token), ) body = ctx.json() assert "queue_inbox" in body["steering_elements"] assert "critical_path" not in body["steering_elements"] assert body["ui_features"].get("criticalPathControl") is not True