Some checks failed
Test Suite / lint-backend (push) Waiting to run
Test Suite / compose-smoke (push) Waiting to run
Test Suite / k6 /api/health Baseline (push) Blocked by required conditions
Test Suite / playwright-smoke (push) Blocked by required conditions
Deploy Development / deploy (push) Successful in 45s
Test Suite / pytest-backend (push) Has been cancelled
Archetyp-Strategien priorisieren ausführungsbereite APs mit Begründung execution_ready/critical_path; continuous_product und program_delivery integriert. Co-authored-by: Cursor <cursoragent@cursor.com>
137 lines
4.4 KiB
Python
137 lines
4.4 KiB
Python
"""Unit tests for AP2.0d NextAction execution-ready strategies."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from steering.graph.execution_engine import compute_execution_graph_state
|
|
from steering.methods.registry import list_methods
|
|
from steering.strategies.next_action import register_builtin_strategies
|
|
from steering.strategies.next_action.execution_ready import (
|
|
build_execution_ready_candidates,
|
|
merge_candidates,
|
|
rank_ready_action_ids,
|
|
)
|
|
from steering.strategies.next_action.registry import get_next_action_strategy
|
|
|
|
|
|
def _action(action_id: str, status: str = "open", **kwargs):
|
|
return {
|
|
"id": action_id,
|
|
"initiative_id": kwargs.get("initiative_id", "init-1"),
|
|
"status": status,
|
|
"sort_order": kwargs.get("sort_order", 0),
|
|
"title": kwargs.get("title", action_id),
|
|
"action_kind": kwargs.get("action_kind", "delivery"),
|
|
"roadmap_item_id": kwargs.get("roadmap_item_id"),
|
|
}
|
|
|
|
|
|
def test_rank_ready_prefers_critical_path():
|
|
actions = [
|
|
_action("a", "done", sort_order=0),
|
|
_action("b", "open", sort_order=1),
|
|
_action("c", "open", sort_order=2),
|
|
]
|
|
deps = [
|
|
{
|
|
"predecessor_action_id": "a",
|
|
"successor_action_id": "b",
|
|
"dependency_kind": "requires",
|
|
},
|
|
{
|
|
"predecessor_action_id": "b",
|
|
"successor_action_id": "c",
|
|
"dependency_kind": "requires",
|
|
},
|
|
]
|
|
state = compute_execution_graph_state(actions=actions, dependencies=deps)
|
|
ranked = rank_ready_action_ids(state, prefer_critical_path=True)
|
|
assert ranked == ["b"]
|
|
|
|
|
|
def test_build_execution_ready_skips_blocked():
|
|
actions = [
|
|
_action("first", "open", sort_order=0),
|
|
_action("second", "open", sort_order=1),
|
|
]
|
|
state = compute_execution_graph_state(actions=actions, dependencies=[])
|
|
candidates = build_execution_ready_candidates(
|
|
actions=actions, graph_state=state, limit=5
|
|
)
|
|
assert len(candidates) == 1
|
|
assert candidates[0]["action_id"] == "first"
|
|
assert candidates[0]["reason_code"] in ("execution_ready", "execution_critical_path")
|
|
|
|
|
|
def test_critical_path_reason_code():
|
|
actions = [
|
|
_action("a", "done", sort_order=0),
|
|
_action("b", "open", sort_order=1),
|
|
_action("c", "open", sort_order=2),
|
|
]
|
|
deps = [
|
|
{
|
|
"predecessor_action_id": "a",
|
|
"successor_action_id": "b",
|
|
"dependency_kind": "requires",
|
|
},
|
|
{
|
|
"predecessor_action_id": "b",
|
|
"successor_action_id": "c",
|
|
"dependency_kind": "requires",
|
|
},
|
|
]
|
|
state = compute_execution_graph_state(actions=actions, dependencies=deps)
|
|
candidates = build_execution_ready_candidates(
|
|
actions=actions, graph_state=state, limit=5, prefer_critical_path=True
|
|
)
|
|
assert candidates[0]["reason_code"] == "execution_critical_path"
|
|
|
|
|
|
def test_merge_candidates_deduplicates_actions():
|
|
first = [
|
|
{
|
|
"kind": "action",
|
|
"action_id": "a1",
|
|
"title": "A",
|
|
}
|
|
]
|
|
second = [
|
|
{
|
|
"kind": "action",
|
|
"action_id": "a1",
|
|
"title": "A duplicate",
|
|
},
|
|
{
|
|
"kind": "review_milestone",
|
|
"title": "Gate",
|
|
},
|
|
]
|
|
merged = merge_candidates(first, second, limit=5)
|
|
assert len(merged) == 2
|
|
assert merged[0]["action_id"] == "a1"
|
|
assert merged[1]["kind"] == "review_milestone"
|
|
|
|
|
|
def test_ap20d_strategies_registered():
|
|
register_builtin_strategies()
|
|
for key in (
|
|
"sequential_dependency",
|
|
"maturity_progression",
|
|
"recurring_control",
|
|
"queue_pull",
|
|
"continuous_product",
|
|
"program_delivery",
|
|
):
|
|
assert get_next_action_strategy(key) is not None
|
|
|
|
|
|
def test_ap20d_methods_wire_strategies():
|
|
register_builtin_strategies()
|
|
methods = {m.key: m for m in list_methods()}
|
|
assert methods["sequential_dependency"].next_action_strategy_key == "sequential_dependency"
|
|
assert methods["maturity_progression"].next_action_strategy_key == "maturity_progression"
|
|
assert methods["recurring_control"].next_action_strategy_key == "recurring_control"
|
|
assert methods["queue_pull"].next_action_strategy_key == "queue_pull"
|
|
assert methods["continuous_product"].next_action_strategy_key == "continuous_product"
|
|
assert methods["program_delivery"].next_action_strategy_key == "program_delivery"
|