shinkan-jinkendo/backend/tests/test_planning_progression_roadmap.py
Lars f074a8bef0
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Test Suite / pytest-backend (push) Successful in 47s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 14s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m13s
Implement Roadmap Review Features and Enhance Progression Path Management
- Added support for editable major steps in the roadmap, allowing users to modify phase, learning goals, and order before exercise matching.
- Introduced a new `roadmap_override` feature to facilitate customized retrieval without re-invoking the roadmap AI.
- Updated the `ExerciseProgressionPathBuilder` component to incorporate these new features, enhancing user interaction and flexibility.
- Incremented application version to 0.8.207 to reflect these changes.
2026-06-08 14:59:24 +02:00

137 lines
5.1 KiB
Python

"""Tests Planungs-KI Phase F — Progressions-Roadmap Pipeline."""
from planning_progression_roadmap import (
PROMPT_SLUG_GOAL_ANALYSIS,
PROMPT_SLUG_ROADMAP,
PROMPT_SLUG_STAGE_SPEC,
MajorStep,
StageSpecArtifact,
build_goal_analysis,
build_roadmap_unfilled_gap_specs,
consolidate_micro_to_major,
develop_micro_objectives,
progression_roadmap_to_api_dict,
resolve_step_exercise_kind_filter,
run_progression_roadmap_pipeline,
stage_spec_exercise_kind_filter,
stage_spec_retrieval_query,
normalize_major_steps_for_override,
roadmap_context_from_override,
RoadmapOverridePayload,
)
from planning_exercise_semantics import build_semantic_brief
def test_run_progression_roadmap_pipeline_major_step_count():
ctx = run_progression_roadmap_pipeline(
"Von Erlernen bis zur Perfektion des Fußtritts Mae Geri",
max_steps=5,
)
assert ctx.roadmap is not None
assert len(ctx.roadmap.major_steps) == 5
assert len(ctx.roadmap.micro_objectives) >= 6
assert len(ctx.stage_specs) == 5
assert ctx.goal_analysis is not None
assert "Mae" in ctx.goal_analysis.primary_topic or "mae" in ctx.goal_analysis.primary_topic.lower()
def test_consolidate_micro_to_major_reduces_count():
brief = build_semantic_brief("Mae Geri")
ga = build_goal_analysis("Mae Geri Perfektion", brief)
micro = develop_micro_objectives(brief, goal_analysis=ga, min_count=8)
majors, notes = consolidate_micro_to_major(micro, max_steps=5)
assert len(majors) == 5
if len(micro) > 5:
assert notes
assert all(m.learning_goal for m in majors)
def test_major_steps_have_learning_goals():
ctx = run_progression_roadmap_pipeline("Mae Geri Grundlagen", max_steps=3)
for step in ctx.roadmap.major_steps:
assert step.learning_goal.strip()
assert step.consolidates
def test_stage_spec_retrieval_query_includes_learning_goal():
brief = build_semantic_brief("Mae Geri Perfektion")
spec = StageSpecArtifact(
major_step_index=1,
learning_goal="Koordination und Präzision vertiefen",
load_profile=["präzision"],
exercise_type="kihon_einzel",
)
major = MajorStep(index=1, phase="vertiefung", learning_goal=spec.learning_goal, consolidates=["m3"])
q = stage_spec_retrieval_query(
semantic_brief=brief,
goal_query="Mae Geri Perfektion",
stage_spec=spec,
major_step=major,
)
assert "vertiefung" in q.lower()
assert "Koordination" in q or "Präzision" in q
def test_stage_spec_exercise_kind_filter_maps_combination():
spec = StageSpecArtifact(major_step_index=0, exercise_type="kombination")
assert stage_spec_exercise_kind_filter(spec) == ["combination"]
assert resolve_step_exercise_kind_filter(spec, ["simple"]) == ["simple"]
def test_build_roadmap_unfilled_gap_specs():
brief = build_semantic_brief("Mae Geri")
spec = StageSpecArtifact(major_step_index=2, learning_goal="Anwendung im Partnerdrill")
major = MajorStep(index=2, phase="anwendung", learning_goal=spec.learning_goal, consolidates=["m5"])
specs = build_roadmap_unfilled_gap_specs(
unfilled_specs=[(2, spec)],
major_steps_by_index={2: major},
steps=[{"exercise_id": 1, "title": "A"}, {"exercise_id": 2, "title": "B"}],
brief=brief,
goal_query="Mae Geri",
)
assert len(specs) == 1
assert specs[0]["source"] == "roadmap_unfilled"
assert specs[0]["phase"] == "anwendung"
def test_normalize_major_steps_reindexes():
majors = normalize_major_steps_for_override(
[
MajorStep(index=9, phase="einstieg", learning_goal="Einstieg", consolidates=[]),
MajorStep(index=8, phase="perfektion", learning_goal="Ziel", consolidates=[]),
],
max_steps=5,
)
assert len(majors) == 2
assert majors[0].index == 0
assert majors[1].index == 1
def test_roadmap_context_from_override():
brief = build_semantic_brief("Mae Geri Perfektion")
override = RoadmapOverridePayload(
major_steps=[
MajorStep(index=0, phase="einstieg", learning_goal="Mae Geri Einstieg", consolidates=[]),
MajorStep(index=1, phase="grundlage", learning_goal="Stand und Hüfte", consolidates=[]),
MajorStep(index=2, phase="perfektion", learning_goal="Präzision unter Belastung", consolidates=[]),
]
)
ctx = roadmap_context_from_override(
"Mae Geri Perfektion",
max_steps=5,
semantic_brief=brief,
override=override,
)
assert ctx.pipeline_phase == "roadmap_v1_edited"
assert len(ctx.roadmap.major_steps) == 3
assert len(ctx.stage_specs) == 3
assert ctx.stage_specs[1].learning_goal == "Stand und Hüfte"
def test_api_dict_exposes_prompt_slug_catalog():
ctx = run_progression_roadmap_pipeline("Mae Geri", max_steps=3, include_llm_roadmap=False)
api = progression_roadmap_to_api_dict(ctx)
assert api["prompt_slug_catalog"]["goal_analysis"] == PROMPT_SLUG_GOAL_ANALYSIS
assert api["prompt_slug_catalog"]["roadmap"] == PROMPT_SLUG_ROADMAP
assert api["prompt_slug_catalog"]["stage_spec"] == PROMPT_SLUG_STAGE_SPEC
assert api["prompt_slugs"] == []