94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
|
|
"""Unit tests — gate_next_actions proposal."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from steering.eval_context import SteeringEvalContext
|
||
|
|
from steering.kernel.models import HorizonMarker, LifecycleContext, SteeringBinding
|
||
|
|
from steering.proposals.gate_next_actions import propose_gate_next_actions
|
||
|
|
from tenant_context import TenantContext
|
||
|
|
|
||
|
|
|
||
|
|
def _ctx(*, backlog_items, read_models=None, gate_id="gate-1"):
|
||
|
|
binding = SteeringBinding(
|
||
|
|
primary_method_key="sequential_dependency",
|
||
|
|
composition_modifier=None,
|
||
|
|
next_work_strategy_key="sequential_dependency",
|
||
|
|
)
|
||
|
|
lifecycle = LifecycleContext(
|
||
|
|
current_state="execution",
|
||
|
|
current_state_label="Ausführung",
|
||
|
|
slot_map={},
|
||
|
|
active_slots=(),
|
||
|
|
operational_slots=(),
|
||
|
|
)
|
||
|
|
horizon = HorizonMarker(
|
||
|
|
kind="gate",
|
||
|
|
gate_roadmap_item_id=gate_id,
|
||
|
|
gate_title="Gate A",
|
||
|
|
)
|
||
|
|
eval_ctx = SteeringEvalContext(
|
||
|
|
tenant_ctx=TenantContext(
|
||
|
|
user_id="u1",
|
||
|
|
email="t@example.com",
|
||
|
|
display_name="Test",
|
||
|
|
portal_role="user",
|
||
|
|
tenant_id="t1",
|
||
|
|
tenant_slug="t",
|
||
|
|
tenant_name="T",
|
||
|
|
tenant_role="admin",
|
||
|
|
actor_id=None,
|
||
|
|
actor_type=None,
|
||
|
|
session_token="test",
|
||
|
|
capabilities=frozenset(),
|
||
|
|
),
|
||
|
|
initiative_id="init-1",
|
||
|
|
binding=binding,
|
||
|
|
horizon=horizon,
|
||
|
|
lifecycle=lifecycle,
|
||
|
|
operating_context={
|
||
|
|
"steering_elements": ["gate_fulfillment", "critical_path"],
|
||
|
|
"data_slices": ["backlog", "roadmap", "actions"],
|
||
|
|
"backlog_vocabulary": {"convertible_kinds": ["story", "bug", "issue"]},
|
||
|
|
},
|
||
|
|
)
|
||
|
|
eval_ctx._backlog_items = backlog_items
|
||
|
|
eval_ctx._actions = []
|
||
|
|
eval_ctx._work_cycles = []
|
||
|
|
return eval_ctx, read_models or {}
|
||
|
|
|
||
|
|
|
||
|
|
def test_gate_proposal_includes_planning_debt():
|
||
|
|
eval_ctx, read_models = _ctx(
|
||
|
|
backlog_items=[],
|
||
|
|
read_models={
|
||
|
|
"planning_debt": [
|
||
|
|
{
|
||
|
|
"roadmap_item_id": "gate-1",
|
||
|
|
"title": "Gate A",
|
||
|
|
"message": "Kein Plan",
|
||
|
|
}
|
||
|
|
]
|
||
|
|
},
|
||
|
|
)
|
||
|
|
result = propose_gate_next_actions(eval_ctx, read_models=read_models)
|
||
|
|
assert result[0]["scope_type"] == "roadmap_item"
|
||
|
|
assert result[0]["reason_code"] == "planning_debt"
|
||
|
|
|
||
|
|
|
||
|
|
def test_gate_proposal_backlog_at_gate():
|
||
|
|
eval_ctx, read_models = _ctx(
|
||
|
|
backlog_items=[
|
||
|
|
{
|
||
|
|
"id": "b1",
|
||
|
|
"title": "Story",
|
||
|
|
"item_kind": "story",
|
||
|
|
"status": "accepted",
|
||
|
|
"roadmap_item_id": "gate-1",
|
||
|
|
"priority": "normal",
|
||
|
|
"sort_order": 0,
|
||
|
|
}
|
||
|
|
],
|
||
|
|
)
|
||
|
|
result = propose_gate_next_actions(eval_ctx, read_models=read_models)
|
||
|
|
assert any(p["scope_type"] == "backlog_item" for p in result)
|