AP2.0: Archetyp-Katalog, Method-Stubs und sichtbare Steuerung in Kontrolle.
Some checks failed
Deploy Development / deploy (push) Successful in 46s
Test Suite / pytest-backend (push) Failing after 2m2s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 3s
Test Suite / compose-smoke (push) Has been skipped
Some checks failed
Deploy Development / deploy (push) Successful in 46s
Test Suite / pytest-backend (push) Failing after 2m2s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 3s
Test Suite / compose-smoke (push) Has been skipped
PO-Dokumente (ADP v0.2, MVP v0.3) und Minimal Complete Slice: Registry-Methoden, Initiative/Project-Spiegel, Default-Methode bei Anlage, Lagebild mit Archetyp und Guidance. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
21d948634e
commit
3bd983297b
|
|
@ -11,6 +11,7 @@ from psycopg2.extras import RealDictCursor
|
||||||
|
|
||||||
from db import get_connection
|
from db import get_connection
|
||||||
from data_layer.attention import get_next_action_candidates_for_initiative
|
from data_layer.attention import get_next_action_candidates_for_initiative
|
||||||
|
from entity_archetypes.registry import archetype_label
|
||||||
from steering.context import get_steering_context_dto
|
from steering.context import get_steering_context_dto
|
||||||
from steering.signals.snapshot_signals import derive_initiative_signals
|
from steering.signals.snapshot_signals import derive_initiative_signals
|
||||||
from services.initiatives import get_initiative
|
from services.initiatives import get_initiative
|
||||||
|
|
@ -20,6 +21,41 @@ OPEN_BLOCKER = ("open", "in_progress")
|
||||||
OPEN_ACTION = ("open", "ready", "in_progress", "blocked", "review_required")
|
OPEN_ACTION = ("open", "ready", "in_progress", "blocked", "review_required")
|
||||||
ACTIVE_INITIATIVE = ("active", "paused")
|
ACTIVE_INITIATIVE = ("active", "paused")
|
||||||
|
|
||||||
|
_REASON_LABELS = {
|
||||||
|
"open_action_priority": "Offenes Arbeitspaket",
|
||||||
|
"milestone_at_risk_or_active": "Plan-Element aktiv oder gefährdet",
|
||||||
|
"blocked_action": "Blockiertes Arbeitspaket",
|
||||||
|
"backlog_triage": "Eingang triagieren",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _steering_guidance(
|
||||||
|
*,
|
||||||
|
next_actions: list[dict[str, Any]],
|
||||||
|
signals: list[str],
|
||||||
|
method_key: str,
|
||||||
|
) -> str:
|
||||||
|
if next_actions:
|
||||||
|
item = next_actions[0]
|
||||||
|
title = item.get("title") or "Nächster Schritt"
|
||||||
|
hint = (
|
||||||
|
item.get("recommended_action")
|
||||||
|
or item.get("summary")
|
||||||
|
or _REASON_LABELS.get(item.get("reason_code", ""), "")
|
||||||
|
)
|
||||||
|
if hint:
|
||||||
|
return f"Als Nächstes: {title} — {hint}"
|
||||||
|
return f"Als Nächstes: {title}"
|
||||||
|
if signals:
|
||||||
|
return "Attention: Struktur oder Ist-Arbeit ergänzen, um Next Actions zu erzeugen."
|
||||||
|
return (
|
||||||
|
f"Methode {method_key}: Plan oder Eingang befüllen, dann committete Arbeit starten."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _attention_items(signals: list[str]) -> list[dict[str, str]]:
|
||||||
|
return [{"code": code, "label": code.replace("_", " ")} for code in signals]
|
||||||
|
|
||||||
|
|
||||||
def _sid(value: Any) -> Optional[str]:
|
def _sid(value: Any) -> Optional[str]:
|
||||||
return str(value) if value else None
|
return str(value) if value else None
|
||||||
|
|
@ -261,16 +297,32 @@ def get_initiative_steering_snapshot(
|
||||||
)
|
)
|
||||||
|
|
||||||
steering = get_steering_context_dto(ctx, initiative_id=initiative_id)
|
steering = get_steering_context_dto(ctx, initiative_id=initiative_id)
|
||||||
|
metadata = steering.get("lifecycle_metadata") or {}
|
||||||
|
if isinstance(metadata, str):
|
||||||
|
metadata = {}
|
||||||
|
method_profile_key = metadata.get("method_profile_key")
|
||||||
|
initiative_archetype = initiative.get("archetype_key") or "initiative.generic"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"initiative_id": initiative_id,
|
"initiative_id": initiative_id,
|
||||||
"initiative_title": initiative["title"],
|
"initiative_title": initiative["title"],
|
||||||
"initiative_status": initiative["status"],
|
"initiative_status": initiative["status"],
|
||||||
|
"archetype_key": initiative_archetype,
|
||||||
|
"archetype_label": archetype_label(
|
||||||
|
entity_type="initiative", archetype_key=initiative_archetype
|
||||||
|
),
|
||||||
|
"method_profile_key": method_profile_key,
|
||||||
"lifecycle_state": steering["lifecycle_state"],
|
"lifecycle_state": steering["lifecycle_state"],
|
||||||
"lifecycle_label": steering["lifecycle_label"],
|
"lifecycle_label": steering["lifecycle_label"],
|
||||||
"method_key": steering["method_key"],
|
"method_key": steering["method_key"],
|
||||||
"method_label": steering.get("method_label"),
|
"method_label": steering.get("method_label"),
|
||||||
"method_version": steering["method_version"],
|
"method_version": steering["method_version"],
|
||||||
|
"steering_guidance": _steering_guidance(
|
||||||
|
next_actions=next_actions,
|
||||||
|
signals=signals,
|
||||||
|
method_key=steering["method_key"],
|
||||||
|
),
|
||||||
|
"attention_items": _attention_items(signals),
|
||||||
"signals": signals,
|
"signals": signals,
|
||||||
"upcoming_milestones": upcoming_milestones,
|
"upcoming_milestones": upcoming_milestones,
|
||||||
"upcoming_roadmap_items": upcoming_milestones,
|
"upcoming_roadmap_items": upcoming_milestones,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,21 @@
|
||||||
from entity_archetypes.registry import (
|
from entity_archetypes.registry import (
|
||||||
|
ENTITY_ARCHETYPES,
|
||||||
INITIATIVE_ARCHETYPES,
|
INITIATIVE_ARCHETYPES,
|
||||||
|
PROJECT_ARCHETYPES,
|
||||||
archetype_label,
|
archetype_label,
|
||||||
list_archetypes,
|
list_archetypes,
|
||||||
|
mirror_project_archetype_key,
|
||||||
|
resolve_default_method_key,
|
||||||
validate_archetype_key,
|
validate_archetype_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
"ENTITY_ARCHETYPES",
|
||||||
"INITIATIVE_ARCHETYPES",
|
"INITIATIVE_ARCHETYPES",
|
||||||
|
"PROJECT_ARCHETYPES",
|
||||||
"archetype_label",
|
"archetype_label",
|
||||||
"list_archetypes",
|
"list_archetypes",
|
||||||
|
"mirror_project_archetype_key",
|
||||||
|
"resolve_default_method_key",
|
||||||
"validate_archetype_key",
|
"validate_archetype_key",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""System-Archetypen (AP1.10a/10b) — In-Memory-Seed + DB-Registry."""
|
"""System-Archetypen (AP1.10 + AP2.0) — Seeds, Bindings, Spiegel Project."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
@ -8,39 +8,136 @@ from psycopg2.extras import RealDictCursor
|
||||||
|
|
||||||
from db import get_connection
|
from db import get_connection
|
||||||
|
|
||||||
INITIATIVE_ARCHETYPES: tuple[dict[str, Any], ...] = (
|
# initiative suffix → default method (shared by initiative + project mirror)
|
||||||
{
|
_METHOD_BY_SUFFIX: dict[str, str] = {
|
||||||
"key": "initiative.generic",
|
"generic": "generic_operating",
|
||||||
"entity_type": "initiative",
|
"maturity_journey": "maturity_progression",
|
||||||
"label": "Allgemeines Vorhaben",
|
"linear_project": "sequential_dependency",
|
||||||
"description": "Standard-Vorhaben ohne spezielle Vorlage.",
|
"recurring_program": "recurring_control",
|
||||||
"is_system": True,
|
"support_queue": "queue_pull",
|
||||||
},
|
"program": "program_delivery",
|
||||||
{
|
"product": "continuous_product",
|
||||||
"key": "initiative.program",
|
"dispute_case": "dispute_procedure",
|
||||||
"entity_type": "initiative",
|
"content_project": "chapter_based_progression",
|
||||||
"label": "Programm / Mega-Vorhaben",
|
}
|
||||||
"description": "Mehrere Stränge, Zielzustand und Vision zentral.",
|
|
||||||
"is_system": True,
|
_INITIATIVE_SPEC_META: tuple[tuple[str, str, str], ...] = (
|
||||||
},
|
("generic", "Allgemeines Vorhaben", "Fallback ohne spezielle Steuerungsvorlage."),
|
||||||
{
|
(
|
||||||
"key": "initiative.product",
|
"maturity_journey",
|
||||||
"entity_type": "initiative",
|
"Reifegrad-Entwicklung",
|
||||||
"label": "Produkt / Release",
|
"Mehrstufige Entwicklung, Routinen, Graph-Voraussetzungen.",
|
||||||
"description": "Produkt- oder Release-orientiertes Vorhaben.",
|
),
|
||||||
"is_system": True,
|
(
|
||||||
},
|
"linear_project",
|
||||||
|
"Lineares Vorhaben",
|
||||||
|
"Einmalprojekte mit Pfaden, Gates und Graph.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"recurring_program",
|
||||||
|
"Dauerprogramm / Rhythmus",
|
||||||
|
"Haushalt, Rhythmen, Abweichungs-Steuerung.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"support_queue",
|
||||||
|
"Inbox / Queue",
|
||||||
|
"Ad-hoc-Eingang, triage, thematische Zuordnung.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"program",
|
||||||
|
"Programm (begrenzt)",
|
||||||
|
"Phasen, Release-Programm mit Abschluss.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"product",
|
||||||
|
"Produkt (kontinuierlich)",
|
||||||
|
"Dauerbetrieb, Wartung, Issues, Weiterentwicklung.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"dispute_case",
|
||||||
|
"Verfahren / Konflikt",
|
||||||
|
"Reaktive Steuerung, Fristen, Entscheidungen.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"content_project",
|
||||||
|
"Inhalt / Kapitel",
|
||||||
|
"Bücher, Konzepte, Kapitelstruktur.",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
_ARCHETYPE_INDEX = {
|
|
||||||
(item["entity_type"], item["key"]): item for item in INITIATIVE_ARCHETYPES
|
def _build_specs() -> tuple[dict[str, Any], ...]:
|
||||||
|
specs: list[dict[str, Any]] = []
|
||||||
|
for suffix, label, description in _INITIATIVE_SPEC_META:
|
||||||
|
method = _METHOD_BY_SUFFIX[suffix]
|
||||||
|
specs.append(
|
||||||
|
{
|
||||||
|
"key": f"initiative.{suffix}",
|
||||||
|
"entity_type": "initiative",
|
||||||
|
"label": label,
|
||||||
|
"description": description,
|
||||||
|
"is_system": True,
|
||||||
|
"default_method_key": method,
|
||||||
|
"default_method_profile_key": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
specs.append(
|
||||||
|
{
|
||||||
|
"key": f"project.{suffix}",
|
||||||
|
"entity_type": "project",
|
||||||
|
"label": label,
|
||||||
|
"description": f"Project-Spiegel: {description}",
|
||||||
|
"is_system": True,
|
||||||
|
"default_method_key": method,
|
||||||
|
"default_method_profile_key": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return tuple(specs)
|
||||||
|
|
||||||
|
|
||||||
|
ENTITY_ARCHETYPES: tuple[dict[str, Any], ...] = _build_specs()
|
||||||
|
|
||||||
|
INITIATIVE_ARCHETYPES: tuple[dict[str, Any], ...] = tuple(
|
||||||
|
item for item in ENTITY_ARCHETYPES if item["entity_type"] == "initiative"
|
||||||
|
)
|
||||||
|
|
||||||
|
PROJECT_ARCHETYPES: tuple[dict[str, Any], ...] = tuple(
|
||||||
|
item for item in ENTITY_ARCHETYPES if item["entity_type"] == "project"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ARCHETYPE_INDEX: dict[tuple[str, str], dict[str, Any]] = {
|
||||||
|
(item["entity_type"], item["key"]): item for item in ENTITY_ARCHETYPES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_KEY_INDEX: dict[str, dict[str, Any]] = {item["key"]: item for item in ENTITY_ARCHETYPES}
|
||||||
|
|
||||||
|
|
||||||
def _list_archetypes_from_memory(*, entity_type: Optional[str] = None) -> list[dict[str, Any]]:
|
def _list_archetypes_from_memory(*, entity_type: Optional[str] = None) -> list[dict[str, Any]]:
|
||||||
if entity_type is None:
|
items = ENTITY_ARCHETYPES
|
||||||
return [dict(item) for item in INITIATIVE_ARCHETYPES]
|
if entity_type is not None:
|
||||||
return [dict(item) for item in INITIATIVE_ARCHETYPES if item["entity_type"] == entity_type]
|
items = tuple(i for i in items if i["entity_type"] == entity_type)
|
||||||
|
return [_public_archetype(item) for item in items]
|
||||||
|
|
||||||
|
|
||||||
|
def _public_archetype(item: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"key": item["key"],
|
||||||
|
"entity_type": item["entity_type"],
|
||||||
|
"label": item["label"],
|
||||||
|
"description": item["description"],
|
||||||
|
"is_system": item["is_system"],
|
||||||
|
"default_method_key": item["default_method_key"],
|
||||||
|
"default_method_profile_key": item.get("default_method_profile_key"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _enrich_row(row: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
base = dict(row)
|
||||||
|
spec = _KEY_INDEX.get(base.get("key", ""))
|
||||||
|
if spec:
|
||||||
|
base.setdefault("default_method_key", spec["default_method_key"])
|
||||||
|
base.setdefault("default_method_profile_key", spec.get("default_method_profile_key"))
|
||||||
|
return base
|
||||||
|
|
||||||
|
|
||||||
def list_archetypes(*, entity_type: Optional[str] = None) -> list[dict[str, Any]]:
|
def list_archetypes(*, entity_type: Optional[str] = None) -> list[dict[str, Any]]:
|
||||||
|
|
@ -67,7 +164,7 @@ def list_archetypes(*, entity_type: Optional[str] = None) -> list[dict[str, Any]
|
||||||
)
|
)
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
if rows:
|
if rows:
|
||||||
return [dict(row) for row in rows]
|
return [_enrich_row(dict(row)) for row in rows]
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
|
|
@ -83,3 +180,19 @@ def validate_archetype_key(*, entity_type: str, archetype_key: str) -> None:
|
||||||
def archetype_label(*, entity_type: str, archetype_key: str) -> Optional[str]:
|
def archetype_label(*, entity_type: str, archetype_key: str) -> Optional[str]:
|
||||||
item = _ARCHETYPE_INDEX.get((entity_type, archetype_key))
|
item = _ARCHETYPE_INDEX.get((entity_type, archetype_key))
|
||||||
return item["label"] if item else None
|
return item["label"] if item else None
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_default_method_key(archetype_key: str) -> str:
|
||||||
|
spec = _KEY_INDEX.get(archetype_key)
|
||||||
|
if not spec:
|
||||||
|
return "generic_operating"
|
||||||
|
return spec.get("default_method_key", "generic_operating")
|
||||||
|
|
||||||
|
|
||||||
|
def mirror_project_archetype_key(initiative_archetype_key: str) -> str:
|
||||||
|
if initiative_archetype_key.startswith("initiative."):
|
||||||
|
suffix = initiative_archetype_key[len("initiative.") :]
|
||||||
|
candidate = f"project.{suffix}"
|
||||||
|
if ( "project", candidate) in _ARCHETYPE_INDEX:
|
||||||
|
return candidate
|
||||||
|
return "project.generic"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""System-Felddefinitionen (Seed) — AP1.10b."""
|
"""System-Felddefinitionen (Seed) — AP1.10b / AP2.0b."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
@ -45,4 +45,44 @@ FIELD_DEFINITIONS: tuple[dict[str, Any], ...] = (
|
||||||
"sort_order": 20,
|
"sort_order": 20,
|
||||||
"validation_json": {},
|
"validation_json": {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"archetype_key": "initiative.maturity_journey",
|
||||||
|
"field_key": "current_focus",
|
||||||
|
"field_type": "text",
|
||||||
|
"label": "Aktueller Fokus",
|
||||||
|
"required": False,
|
||||||
|
"searchable": True,
|
||||||
|
"sort_order": 10,
|
||||||
|
"validation_json": {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"archetype_key": "initiative.maturity_journey",
|
||||||
|
"field_key": "training_frequency",
|
||||||
|
"field_type": "enum",
|
||||||
|
"label": "Trainingsfrequenz",
|
||||||
|
"required": False,
|
||||||
|
"searchable": False,
|
||||||
|
"sort_order": 20,
|
||||||
|
"validation_json": {"options": ["daily", "3x_week", "weekly", "flexible"]},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"archetype_key": "initiative.content_project",
|
||||||
|
"field_key": "manuscript_status",
|
||||||
|
"field_type": "text",
|
||||||
|
"label": "Manuskript-Status",
|
||||||
|
"required": False,
|
||||||
|
"searchable": True,
|
||||||
|
"sort_order": 10,
|
||||||
|
"validation_json": {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"archetype_key": "initiative.content_project",
|
||||||
|
"field_key": "word_count_goal",
|
||||||
|
"field_type": "number",
|
||||||
|
"label": "Wortziel",
|
||||||
|
"required": False,
|
||||||
|
"searchable": False,
|
||||||
|
"sort_order": 20,
|
||||||
|
"validation_json": {},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
"""Sync Entity-Archetypen und Felddefinitionen in PostgreSQL — AP1.10b."""
|
"""Sync Entity-Archetypen und Felddefinitionen in PostgreSQL — AP1.10b / AP2.0b."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from db import get_connection
|
from db import get_connection
|
||||||
from entity_archetypes.registry import INITIATIVE_ARCHETYPES
|
from entity_archetypes.registry import ENTITY_ARCHETYPES
|
||||||
from entity_fields.definitions import FIELD_DEFINITIONS
|
from entity_fields.definitions import FIELD_DEFINITIONS
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ def sync_entity_field_registry_to_db() -> int:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
try:
|
try:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
for archetype in INITIATIVE_ARCHETYPES:
|
for archetype in ENTITY_ARCHETYPES:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO entity_archetypes (
|
INSERT INTO entity_archetypes (
|
||||||
|
|
@ -68,7 +68,7 @@ def sync_entity_field_registry_to_db() -> int:
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print(
|
print(
|
||||||
"[entity_fields] Sync OK — "
|
"[entity_fields] Sync OK — "
|
||||||
f"{len(INITIATIVE_ARCHETYPES)} Archetyp(en), "
|
f"{len(ENTITY_ARCHETYPES)} Archetyp(en), "
|
||||||
f"{len(FIELD_DEFINITIONS)} Felddefinition(en)"
|
f"{len(FIELD_DEFINITIONS)} Felddefinition(en)"
|
||||||
)
|
)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
1
backend/method_profiles/__init__.py
Normal file
1
backend/method_profiles/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
"""Package marker for method profile seeds."""
|
||||||
63
backend/method_profiles/registry.py
Normal file
63
backend/method_profiles/registry.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
"""Referenz-Ausprägungen (Method Profiles) — Code-Seeds AP2.0b."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
METHOD_PROFILES: tuple[dict[str, Any], ...] = (
|
||||||
|
{
|
||||||
|
"key": "maturity.karate_kumite",
|
||||||
|
"label": "Karate Kumite",
|
||||||
|
"description": "Mehrere Fähigkeiten mit Stufen, Routinen und Voraussetzungs-Graph.",
|
||||||
|
"initiative_archetype_key": "initiative.maturity_journey",
|
||||||
|
"method_key": "maturity_progression",
|
||||||
|
"seed_hints": {
|
||||||
|
"skill_count": 8,
|
||||||
|
"stages_per_skill": "5-7",
|
||||||
|
"graph_prerequisites": True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "content.book_writing",
|
||||||
|
"label": "Buch schreiben",
|
||||||
|
"description": "Kapitelstruktur, Schreib-APs, Review-Gates.",
|
||||||
|
"initiative_archetype_key": "initiative.content_project",
|
||||||
|
"method_key": "chapter_based_progression",
|
||||||
|
"seed_hints": {
|
||||||
|
"roadmap_item_type": "chapter",
|
||||||
|
"review_gates": True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "product.kairo_dev",
|
||||||
|
"label": "Kairo Entwicklung",
|
||||||
|
"description": "Kontinuierliches Produkt mit Gate-Orientierung und optionaler Sprint-Zeitbox.",
|
||||||
|
"initiative_archetype_key": "initiative.product",
|
||||||
|
"method_key": "continuous_product",
|
||||||
|
"seed_hints": {
|
||||||
|
"agile_iteration_profile": True,
|
||||||
|
"default_actor_setup": "po_plus_vibe_coder",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
_PROFILE_INDEX = {item["key"]: item for item in METHOD_PROFILES}
|
||||||
|
|
||||||
|
|
||||||
|
def get_method_profile(key: str) -> Optional[dict[str, Any]]:
|
||||||
|
item = _PROFILE_INDEX.get(key)
|
||||||
|
return dict(item) if item else None
|
||||||
|
|
||||||
|
|
||||||
|
def list_method_profiles(*, initiative_archetype_key: Optional[str] = None) -> list[dict[str, Any]]:
|
||||||
|
items = METHOD_PROFILES
|
||||||
|
if initiative_archetype_key:
|
||||||
|
items = tuple(
|
||||||
|
i for i in items if i["initiative_archetype_key"] == initiative_archetype_key
|
||||||
|
)
|
||||||
|
return [dict(item) for item in items]
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_method_for_profile(profile_key: str) -> Optional[str]:
|
||||||
|
profile = get_method_profile(profile_key)
|
||||||
|
return profile["method_key"] if profile else None
|
||||||
27
backend/migrations/019_project_archetype_key.sql
Normal file
27
backend/migrations/019_project_archetype_key.sql
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
-- AP2.0b: Project archetype_key (Spiegel der Initiative)
|
||||||
|
|
||||||
|
ALTER TABLE projects
|
||||||
|
ADD COLUMN IF NOT EXISTS archetype_key VARCHAR(64) NULL;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_projects_archetype
|
||||||
|
ON projects (tenant_id, archetype_key)
|
||||||
|
WHERE archetype_key IS NOT NULL;
|
||||||
|
|
||||||
|
-- Bestehende Projects: Mirror aus Initiative (einmalig)
|
||||||
|
UPDATE projects p
|
||||||
|
SET archetype_key = CASE i.archetype_key
|
||||||
|
WHEN 'initiative.generic' THEN 'project.generic'
|
||||||
|
WHEN 'initiative.maturity_journey' THEN 'project.maturity_journey'
|
||||||
|
WHEN 'initiative.linear_project' THEN 'project.linear_project'
|
||||||
|
WHEN 'initiative.recurring_program' THEN 'project.recurring_program'
|
||||||
|
WHEN 'initiative.support_queue' THEN 'project.support_queue'
|
||||||
|
WHEN 'initiative.program' THEN 'project.program'
|
||||||
|
WHEN 'initiative.product' THEN 'project.product'
|
||||||
|
WHEN 'initiative.dispute_case' THEN 'project.dispute_case'
|
||||||
|
WHEN 'initiative.content_project' THEN 'project.content_project'
|
||||||
|
ELSE 'project.generic'
|
||||||
|
END
|
||||||
|
FROM initiatives i
|
||||||
|
WHERE p.initiative_id = i.id
|
||||||
|
AND p.tenant_id = i.tenant_id
|
||||||
|
AND p.archetype_key IS NULL;
|
||||||
|
|
@ -124,6 +124,7 @@ def create_initiative(
|
||||||
tenant_id=tenant_id,
|
tenant_id=tenant_id,
|
||||||
initiative_id=row["id"],
|
initiative_id=row["id"],
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
|
archetype_key=archetype_key,
|
||||||
)
|
)
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from psycopg2.extras import RealDictCursor
|
||||||
|
|
||||||
from db import get_connection
|
from db import get_connection
|
||||||
from services.audit import log_audit
|
from services.audit import log_audit
|
||||||
|
from entity_archetypes import mirror_project_archetype_key, validate_archetype_key
|
||||||
from services.initiatives import get_initiative
|
from services.initiatives import get_initiative
|
||||||
|
|
||||||
ProjectStatus = Literal["active", "paused", "completed", "archived"]
|
ProjectStatus = Literal["active", "paused", "completed", "archived"]
|
||||||
|
|
@ -21,7 +22,7 @@ MAX_PROJECT_DEPTH = 5
|
||||||
|
|
||||||
_PROJECT_COLUMNS = """
|
_PROJECT_COLUMNS = """
|
||||||
id, tenant_id, initiative_id, parent_project_id, container_kind,
|
id, tenant_id, initiative_id, parent_project_id, container_kind,
|
||||||
title, description, status,
|
archetype_key, title, description, status,
|
||||||
roadmap_item_id, sort_order, target_date, created_at, updated_at
|
roadmap_item_id, sort_order, target_date, created_at, updated_at
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -227,6 +228,7 @@ def create_project(
|
||||||
roadmap_item_id: Optional[str] = None,
|
roadmap_item_id: Optional[str] = None,
|
||||||
sort_order: int = 0,
|
sort_order: int = 0,
|
||||||
target_date: Optional[date] = None,
|
target_date: Optional[date] = None,
|
||||||
|
archetype_key: Optional[str] = None,
|
||||||
user_id: Optional[str] = None,
|
user_id: Optional[str] = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
title = title.strip()
|
title = title.strip()
|
||||||
|
|
@ -234,9 +236,15 @@ def create_project(
|
||||||
raise ValueError("Titel ist erforderlich")
|
raise ValueError("Titel ist erforderlich")
|
||||||
_validate_status(status)
|
_validate_status(status)
|
||||||
_validate_container_kind(container_kind)
|
_validate_container_kind(container_kind)
|
||||||
if not get_initiative(tenant_id=tenant_id, initiative_id=initiative_id):
|
initiative = get_initiative(tenant_id=tenant_id, initiative_id=initiative_id)
|
||||||
|
if not initiative:
|
||||||
raise ValueError("Initiative nicht gefunden")
|
raise ValueError("Initiative nicht gefunden")
|
||||||
|
|
||||||
|
resolved_archetype = archetype_key or mirror_project_archetype_key(
|
||||||
|
initiative["archetype_key"]
|
||||||
|
)
|
||||||
|
validate_archetype_key(entity_type="project", archetype_key=resolved_archetype)
|
||||||
|
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
try:
|
try:
|
||||||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||||||
|
|
@ -257,10 +265,10 @@ def create_project(
|
||||||
f"""
|
f"""
|
||||||
INSERT INTO projects (
|
INSERT INTO projects (
|
||||||
tenant_id, initiative_id, parent_project_id, container_kind,
|
tenant_id, initiative_id, parent_project_id, container_kind,
|
||||||
title, description, status,
|
archetype_key, title, description, status,
|
||||||
roadmap_item_id, sort_order, target_date
|
roadmap_item_id, sort_order, target_date
|
||||||
)
|
)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
RETURNING {_PROJECT_COLUMNS}
|
RETURNING {_PROJECT_COLUMNS}
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
|
|
@ -268,6 +276,7 @@ def create_project(
|
||||||
initiative_id,
|
initiative_id,
|
||||||
parent_project_id,
|
parent_project_id,
|
||||||
container_kind,
|
container_kind,
|
||||||
|
resolved_archetype,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
status,
|
status,
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ def ensure_steering_context(
|
||||||
initiative_id: str,
|
initiative_id: str,
|
||||||
initial_state: Optional[str] = None,
|
initial_state: Optional[str] = None,
|
||||||
user_id: Optional[str] = None,
|
user_id: Optional[str] = None,
|
||||||
|
method_key: Optional[str] = None,
|
||||||
|
lifecycle_metadata: Optional[dict[str, Any]] = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
existing = get_steering_context(tenant_id=tenant_id, initiative_id=initiative_id)
|
existing = get_steering_context(tenant_id=tenant_id, initiative_id=initiative_id)
|
||||||
if existing:
|
if existing:
|
||||||
|
|
@ -113,6 +115,16 @@ def ensure_steering_context(
|
||||||
)
|
)
|
||||||
validate_lifecycle_state(state)
|
validate_lifecycle_state(state)
|
||||||
|
|
||||||
|
resolved_method = method_key or DEFAULT_METHOD_KEY
|
||||||
|
from steering.methods.registry import get_method
|
||||||
|
|
||||||
|
method = get_method(resolved_method)
|
||||||
|
if not method:
|
||||||
|
resolved_method = DEFAULT_METHOD_KEY
|
||||||
|
method = get_method(resolved_method)
|
||||||
|
method_version = method.version if method else DEFAULT_METHOD_VERSION
|
||||||
|
metadata = lifecycle_metadata or {}
|
||||||
|
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
try:
|
try:
|
||||||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||||||
|
|
@ -129,10 +141,10 @@ def ensure_steering_context(
|
||||||
(
|
(
|
||||||
tenant_id,
|
tenant_id,
|
||||||
initiative_id,
|
initiative_id,
|
||||||
DEFAULT_METHOD_KEY,
|
resolved_method,
|
||||||
DEFAULT_METHOD_VERSION,
|
method_version,
|
||||||
state,
|
state,
|
||||||
Json({}),
|
Json(metadata),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
row = _serialize_row(dict(cur.fetchone()))
|
row = _serialize_row(dict(cur.fetchone()))
|
||||||
|
|
@ -144,7 +156,11 @@ def ensure_steering_context(
|
||||||
"steering_context.created",
|
"steering_context.created",
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
tenant_id=tenant_id,
|
tenant_id=tenant_id,
|
||||||
details={"initiative_id": initiative_id, "lifecycle_state": state},
|
details={
|
||||||
|
"initiative_id": initiative_id,
|
||||||
|
"lifecycle_state": state,
|
||||||
|
"method_key": resolved_method,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
|
@ -250,10 +266,25 @@ def create_context_for_new_initiative(
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
initiative_id: str,
|
initiative_id: str,
|
||||||
user_id: Optional[str] = None,
|
user_id: Optional[str] = None,
|
||||||
|
archetype_key: str = "initiative.generic",
|
||||||
|
method_profile_key: Optional[str] = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
|
from entity_archetypes.registry import resolve_default_method_key
|
||||||
|
from method_profiles.registry import resolve_method_for_profile
|
||||||
|
|
||||||
|
method_key = resolve_default_method_key(archetype_key)
|
||||||
|
lifecycle_metadata: dict[str, Any] = {}
|
||||||
|
if method_profile_key:
|
||||||
|
profile_method = resolve_method_for_profile(method_profile_key)
|
||||||
|
if profile_method:
|
||||||
|
method_key = profile_method
|
||||||
|
lifecycle_metadata["method_profile_key"] = method_profile_key
|
||||||
|
|
||||||
return ensure_steering_context(
|
return ensure_steering_context(
|
||||||
tenant_id=tenant_id,
|
tenant_id=tenant_id,
|
||||||
initiative_id=initiative_id,
|
initiative_id=initiative_id,
|
||||||
initial_state="intake",
|
initial_state="intake",
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
|
method_key=method_key,
|
||||||
|
lifecycle_metadata=lifecycle_metadata or None,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
"""Adaptive Steering Core — AP1.0 Foundation."""
|
"""Adaptive Steering Core — AP1.0 Foundation + AP2.0 methods."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from steering.hooks.registry import register_builtin_hooks
|
from steering.hooks.registry import register_builtin_hooks
|
||||||
from steering.methods.registrations import generic_operating, product_milestone_driven
|
from steering.methods.registrations import (
|
||||||
|
ap20_method_stubs,
|
||||||
|
continuous_product,
|
||||||
|
generic_operating,
|
||||||
|
product_milestone_driven,
|
||||||
|
program_delivery,
|
||||||
|
)
|
||||||
from steering.strategies.next_action import register_builtin_strategies
|
from steering.strategies.next_action import register_builtin_strategies
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,6 +19,9 @@ def bootstrap_steering() -> None:
|
||||||
register_builtin_strategies()
|
register_builtin_strategies()
|
||||||
generic_operating.register()
|
generic_operating.register()
|
||||||
product_milestone_driven.register()
|
product_milestone_driven.register()
|
||||||
|
program_delivery.register()
|
||||||
|
continuous_product.register()
|
||||||
|
ap20_method_stubs.register()
|
||||||
|
|
||||||
|
|
||||||
bootstrap_steering()
|
bootstrap_steering()
|
||||||
|
|
|
||||||
70
backend/steering/methods/registrations/_helpers.py
Normal file
70
backend/steering/methods/registrations/_helpers.py
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
"""Shared registration helper for AP2.0 method stubs."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from steering.lifecycle.states import STANDARD_LIFECYCLE_STEPS
|
||||||
|
from steering.methods.registry import MethodDefinition, get_method, register_method
|
||||||
|
|
||||||
|
_PRODUCT_LIKE_STEPS = (
|
||||||
|
"intake",
|
||||||
|
"method_selection",
|
||||||
|
"structure_setup",
|
||||||
|
"planning",
|
||||||
|
"action_selection",
|
||||||
|
"assignment",
|
||||||
|
"waiting",
|
||||||
|
"result_intake",
|
||||||
|
"validation",
|
||||||
|
"review",
|
||||||
|
"adaptation",
|
||||||
|
"closure",
|
||||||
|
)
|
||||||
|
|
||||||
|
_LIGHT_STEPS = (
|
||||||
|
"intake",
|
||||||
|
"structure_setup",
|
||||||
|
"action_selection",
|
||||||
|
"assignment",
|
||||||
|
"waiting",
|
||||||
|
"review",
|
||||||
|
"adaptation",
|
||||||
|
"closure",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def register_stub_method(
|
||||||
|
*,
|
||||||
|
key: str,
|
||||||
|
label: str,
|
||||||
|
description: str,
|
||||||
|
next_action_strategy_key: str = "default",
|
||||||
|
lifecycle_steps: tuple[str, ...] | None = None,
|
||||||
|
) -> None:
|
||||||
|
if get_method(key):
|
||||||
|
return
|
||||||
|
register_method(
|
||||||
|
MethodDefinition(
|
||||||
|
key=key,
|
||||||
|
version="0.1.0",
|
||||||
|
label=label,
|
||||||
|
description=description,
|
||||||
|
default_lifecycle_steps=lifecycle_steps or STANDARD_LIFECYCLE_STEPS,
|
||||||
|
next_action_strategy_key=next_action_strategy_key,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def register_product_like_method(
|
||||||
|
*,
|
||||||
|
key: str,
|
||||||
|
label: str,
|
||||||
|
description: str,
|
||||||
|
next_action_strategy_key: str,
|
||||||
|
) -> None:
|
||||||
|
register_stub_method(
|
||||||
|
key=key,
|
||||||
|
label=label,
|
||||||
|
description=description,
|
||||||
|
next_action_strategy_key=next_action_strategy_key,
|
||||||
|
lifecycle_steps=_PRODUCT_LIKE_STEPS,
|
||||||
|
)
|
||||||
50
backend/steering/methods/registrations/ap20_method_stubs.py
Normal file
50
backend/steering/methods/registrations/ap20_method_stubs.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
"""AP2.0a — remaining method stubs."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from steering.methods.registrations._helpers import register_stub_method
|
||||||
|
|
||||||
|
|
||||||
|
def register() -> None:
|
||||||
|
register_stub_method(
|
||||||
|
key="maturity_progression",
|
||||||
|
label="Reifegrad-Entwicklung",
|
||||||
|
description="Stufen, Routinen, historische Entwicklung",
|
||||||
|
next_action_strategy_key="default",
|
||||||
|
)
|
||||||
|
register_stub_method(
|
||||||
|
key="sequential_dependency",
|
||||||
|
label="Sequenzielle Abhängigkeit",
|
||||||
|
description="Graph-Pfade, kritischer Pfad (read model)",
|
||||||
|
next_action_strategy_key="default",
|
||||||
|
)
|
||||||
|
register_stub_method(
|
||||||
|
key="recurring_control",
|
||||||
|
label="Rhythmus-Steuerung",
|
||||||
|
description="Dauerprogramm, fällig/überfällig, Abweichungen",
|
||||||
|
next_action_strategy_key="default",
|
||||||
|
)
|
||||||
|
register_stub_method(
|
||||||
|
key="queue_pull",
|
||||||
|
label="Inbox / Queue",
|
||||||
|
description="Pull oder Empfehlung aus Queue",
|
||||||
|
next_action_strategy_key="default",
|
||||||
|
)
|
||||||
|
register_stub_method(
|
||||||
|
key="agile_iteration",
|
||||||
|
label="Iterations-Zeitbox",
|
||||||
|
description="Sprint/work_cycle Profil auf Product/Programm",
|
||||||
|
next_action_strategy_key="default",
|
||||||
|
)
|
||||||
|
register_stub_method(
|
||||||
|
key="dispute_procedure",
|
||||||
|
label="Verfahren / Konflikt",
|
||||||
|
description="Reaktive Steuerung, Fristen, Entscheidungen",
|
||||||
|
next_action_strategy_key="default",
|
||||||
|
)
|
||||||
|
register_stub_method(
|
||||||
|
key="chapter_based_progression",
|
||||||
|
label="Kapitel-Entwicklung",
|
||||||
|
description="Inhaltliche Progression, Reviews",
|
||||||
|
next_action_strategy_key="default",
|
||||||
|
)
|
||||||
14
backend/steering/methods/registrations/continuous_product.py
Normal file
14
backend/steering/methods/registrations/continuous_product.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
"""Built-in method: continuous_product — AP2.0a."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from steering.methods.registrations._helpers import register_product_like_method
|
||||||
|
|
||||||
|
|
||||||
|
def register() -> None:
|
||||||
|
register_product_like_method(
|
||||||
|
key="continuous_product",
|
||||||
|
label="Produkt (kontinuierlich)",
|
||||||
|
description="Kontinuierlicher Betrieb — Ist zuerst, Plan als Orientierung",
|
||||||
|
next_action_strategy_key="continuous_product",
|
||||||
|
)
|
||||||
14
backend/steering/methods/registrations/program_delivery.py
Normal file
14
backend/steering/methods/registrations/program_delivery.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
"""Built-in method: program_delivery — AP2.0a."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from steering.methods.registrations._helpers import register_product_like_method
|
||||||
|
|
||||||
|
|
||||||
|
def register() -> None:
|
||||||
|
register_product_like_method(
|
||||||
|
key="program_delivery",
|
||||||
|
label="Programm (begrenzt)",
|
||||||
|
description="Meilenstein- und gate-orientierte Steuerung mit Abschluss",
|
||||||
|
next_action_strategy_key="program_delivery",
|
||||||
|
)
|
||||||
|
|
@ -2,10 +2,18 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from steering.strategies.next_action.continuous_product import (
|
||||||
|
continuous_product_strategy,
|
||||||
|
register_continuous_product_strategy,
|
||||||
|
)
|
||||||
from steering.strategies.next_action.default_strategy import default_strategy
|
from steering.strategies.next_action.default_strategy import default_strategy
|
||||||
from steering.strategies.next_action.product_milestone_driven import (
|
from steering.strategies.next_action.product_milestone_driven import (
|
||||||
product_milestone_strategy,
|
product_milestone_strategy,
|
||||||
)
|
)
|
||||||
|
from steering.strategies.next_action.program_delivery import (
|
||||||
|
program_delivery_strategy,
|
||||||
|
register_program_delivery_strategy,
|
||||||
|
)
|
||||||
from steering.strategies.next_action.registry import (
|
from steering.strategies.next_action.registry import (
|
||||||
get_next_action_strategy,
|
get_next_action_strategy,
|
||||||
register_next_action_strategy,
|
register_next_action_strategy,
|
||||||
|
|
@ -16,3 +24,5 @@ def register_builtin_strategies() -> None:
|
||||||
for strategy in (default_strategy, product_milestone_strategy):
|
for strategy in (default_strategy, product_milestone_strategy):
|
||||||
if not get_next_action_strategy(strategy.key):
|
if not get_next_action_strategy(strategy.key):
|
||||||
register_next_action_strategy(strategy)
|
register_next_action_strategy(strategy)
|
||||||
|
register_program_delivery_strategy()
|
||||||
|
register_continuous_product_strategy()
|
||||||
|
|
|
||||||
114
backend/steering/strategies/next_action/continuous_product.py
Normal file
114
backend/steering/strategies/next_action/continuous_product.py
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
"""Continuous product NextAction strategy — AP2.0a (Ist zuerst)."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from db import get_connection
|
||||||
|
from psycopg2.extras import RealDictCursor
|
||||||
|
from steering.signals import default_rules
|
||||||
|
from steering.strategies.next_action.default_strategy import DefaultNextActionStrategy
|
||||||
|
from steering.strategies.next_action.registry import (
|
||||||
|
get_next_action_strategy,
|
||||||
|
register_next_action_strategy,
|
||||||
|
)
|
||||||
|
from tenant_context import TenantContext
|
||||||
|
|
||||||
|
_default = DefaultNextActionStrategy()
|
||||||
|
|
||||||
|
_OPEN_ACTION = ("open", "ready", "in_progress", "blocked", "review_required")
|
||||||
|
|
||||||
|
|
||||||
|
class ContinuousProductStrategy:
|
||||||
|
key = "continuous_product"
|
||||||
|
|
||||||
|
def evaluate(
|
||||||
|
self,
|
||||||
|
ctx: TenantContext,
|
||||||
|
*,
|
||||||
|
initiative_id: str | None = None,
|
||||||
|
limit: int = 10,
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
if limit < 1:
|
||||||
|
limit = 1
|
||||||
|
if not initiative_id:
|
||||||
|
return _default.evaluate(ctx, limit=limit)
|
||||||
|
|
||||||
|
candidates: list[dict[str, Any]] = []
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
'action' AS kind,
|
||||||
|
a.title AS title,
|
||||||
|
'Offenes Arbeitspaket priorisieren' AS summary,
|
||||||
|
a.initiative_id,
|
||||||
|
a.id AS action_id,
|
||||||
|
NULL::uuid AS backlog_item_id,
|
||||||
|
'open_action_priority' AS reason_code,
|
||||||
|
'Als Nächstes ausführen' AS recommended_action
|
||||||
|
FROM actions a
|
||||||
|
WHERE a.tenant_id = %s AND a.initiative_id = %s
|
||||||
|
AND a.status = ANY(%s)
|
||||||
|
ORDER BY
|
||||||
|
CASE a.status
|
||||||
|
WHEN 'blocked' THEN 0
|
||||||
|
WHEN 'review_required' THEN 1
|
||||||
|
WHEN 'in_progress' THEN 2
|
||||||
|
WHEN 'ready' THEN 3
|
||||||
|
ELSE 4
|
||||||
|
END,
|
||||||
|
CASE a.priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1 ELSE 2 END,
|
||||||
|
a.due_at ASC NULLS LAST,
|
||||||
|
a.updated_at DESC
|
||||||
|
LIMIT %s
|
||||||
|
""",
|
||||||
|
(ctx.tenant_id, initiative_id, list(_OPEN_ACTION), limit),
|
||||||
|
)
|
||||||
|
for row in cur.fetchall():
|
||||||
|
item = dict(row)
|
||||||
|
item["initiative_id"] = str(item["initiative_id"])
|
||||||
|
item["action_id"] = str(item["action_id"])
|
||||||
|
candidates.append(item)
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
remaining = limit - len(candidates)
|
||||||
|
if remaining > 0:
|
||||||
|
from steering.strategies.next_action.product_milestone_driven import (
|
||||||
|
ProductMilestoneDrivenStrategy,
|
||||||
|
)
|
||||||
|
|
||||||
|
gate_items = ProductMilestoneDrivenStrategy().evaluate(
|
||||||
|
ctx, initiative_id=initiative_id, limit=remaining
|
||||||
|
)
|
||||||
|
for item in gate_items:
|
||||||
|
if item.get("kind") == "review_milestone":
|
||||||
|
candidates.append(item)
|
||||||
|
remaining -= 1
|
||||||
|
if remaining <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(candidates) < limit:
|
||||||
|
rest = default_rules.get_next_action_candidates_for_initiative(
|
||||||
|
ctx, initiative_id=initiative_id, limit=limit - len(candidates)
|
||||||
|
)
|
||||||
|
seen = {c.get("action_id") for c in candidates if c.get("action_id")}
|
||||||
|
for item in rest:
|
||||||
|
if item.get("action_id") and item["action_id"] in seen:
|
||||||
|
continue
|
||||||
|
candidates.append(item)
|
||||||
|
if len(candidates) >= limit:
|
||||||
|
break
|
||||||
|
|
||||||
|
return candidates[:limit]
|
||||||
|
|
||||||
|
|
||||||
|
continuous_product_strategy = ContinuousProductStrategy()
|
||||||
|
|
||||||
|
|
||||||
|
def register_continuous_product_strategy() -> None:
|
||||||
|
if not get_next_action_strategy(continuous_product_strategy.key):
|
||||||
|
register_next_action_strategy(continuous_product_strategy)
|
||||||
28
backend/steering/strategies/next_action/program_delivery.py
Normal file
28
backend/steering/strategies/next_action/program_delivery.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""Program delivery NextAction strategy — AP2.0a (Gate-Horizont)."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from steering.strategies.next_action.product_milestone_driven import (
|
||||||
|
ProductMilestoneDrivenStrategy,
|
||||||
|
)
|
||||||
|
from steering.strategies.next_action.registry import (
|
||||||
|
get_next_action_strategy,
|
||||||
|
register_next_action_strategy,
|
||||||
|
)
|
||||||
|
|
||||||
|
_strategy = ProductMilestoneDrivenStrategy()
|
||||||
|
|
||||||
|
|
||||||
|
class ProgramDeliveryStrategy:
|
||||||
|
key = "program_delivery"
|
||||||
|
|
||||||
|
def evaluate(self, ctx, *, initiative_id=None, limit=10):
|
||||||
|
return _strategy.evaluate(ctx, initiative_id=initiative_id, limit=limit)
|
||||||
|
|
||||||
|
|
||||||
|
program_delivery_strategy = ProgramDeliveryStrategy()
|
||||||
|
|
||||||
|
|
||||||
|
def register_program_delivery_strategy() -> None:
|
||||||
|
if not get_next_action_strategy(program_delivery_strategy.key):
|
||||||
|
register_next_action_strategy(program_delivery_strategy)
|
||||||
|
|
@ -49,7 +49,11 @@ def test_list_entity_archetypes(client):
|
||||||
)
|
)
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
keys = {item["key"] for item in res.json()}
|
keys = {item["key"] for item in res.json()}
|
||||||
assert keys == {"initiative.generic", "initiative.program", "initiative.product"}
|
assert "initiative.generic" in keys
|
||||||
|
assert "initiative.program" in keys
|
||||||
|
assert "initiative.product" in keys
|
||||||
|
assert "initiative.maturity_journey" in keys
|
||||||
|
assert "initiative.content_project" in keys
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_archetype_rejected(client):
|
def test_invalid_archetype_rejected(client):
|
||||||
|
|
|
||||||
104
backend/tests/test_ap20_steering_archetypes.py
Normal file
104
backend/tests/test_ap20_steering_archetypes.py
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
"""AP2.0 — Method registry, Archetyp defaults, Project mirror."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from auth import AUTH_HEADER
|
||||||
|
from steering.methods.registry import list_methods
|
||||||
|
from tests.factories import provision_user_in_tenant
|
||||||
|
from tests.test_initiatives_actions import _auth, _create_initiative, _login
|
||||||
|
|
||||||
|
|
||||||
|
def test_ap20_all_methods_registered():
|
||||||
|
keys = {m.key for m in list_methods()}
|
||||||
|
assert "generic_operating" in keys
|
||||||
|
assert "product_milestone_driven" in keys
|
||||||
|
assert "program_delivery" in keys
|
||||||
|
assert "continuous_product" in keys
|
||||||
|
assert "maturity_progression" in keys
|
||||||
|
assert "chapter_based_progression" in keys
|
||||||
|
assert "agile_iteration" in keys
|
||||||
|
|
||||||
|
|
||||||
|
def test_product_initiative_gets_continuous_product_method(client):
|
||||||
|
user = provision_user_in_tenant(tenant_role="member")
|
||||||
|
token = _login(client, user)
|
||||||
|
|
||||||
|
created = _create_initiative(
|
||||||
|
client,
|
||||||
|
token,
|
||||||
|
title="Kairo Product",
|
||||||
|
archetype_key="initiative.product",
|
||||||
|
)
|
||||||
|
assert created.status_code == 201
|
||||||
|
initiative_id = created.json()["id"]
|
||||||
|
|
||||||
|
snap = client.get(
|
||||||
|
f"/api/initiatives/{initiative_id}/steering-snapshot",
|
||||||
|
headers=_auth(token),
|
||||||
|
)
|
||||||
|
assert snap.status_code == 200
|
||||||
|
body = snap.json()
|
||||||
|
assert body["method_key"] == "continuous_product"
|
||||||
|
assert body["archetype_key"] == "initiative.product"
|
||||||
|
assert body.get("archetype_label")
|
||||||
|
assert body.get("steering_guidance")
|
||||||
|
|
||||||
|
|
||||||
|
def test_program_initiative_gets_program_delivery_method(client):
|
||||||
|
user = provision_user_in_tenant(tenant_role="member")
|
||||||
|
token = _login(client, user)
|
||||||
|
|
||||||
|
created = _create_initiative(
|
||||||
|
client,
|
||||||
|
token,
|
||||||
|
title="Release Program",
|
||||||
|
archetype_key="initiative.program",
|
||||||
|
)
|
||||||
|
assert created.status_code == 201
|
||||||
|
initiative_id = created.json()["id"]
|
||||||
|
|
||||||
|
ctx = client.get(
|
||||||
|
f"/api/steering/initiatives/{initiative_id}/context",
|
||||||
|
headers=_auth(token),
|
||||||
|
)
|
||||||
|
assert ctx.status_code == 200
|
||||||
|
assert ctx.json()["method_key"] == "program_delivery"
|
||||||
|
|
||||||
|
|
||||||
|
def test_project_inherits_mirror_archetype(client):
|
||||||
|
user = provision_user_in_tenant(tenant_role="member")
|
||||||
|
token = _login(client, user)
|
||||||
|
|
||||||
|
created = _create_initiative(
|
||||||
|
client,
|
||||||
|
token,
|
||||||
|
title="Mirror Test",
|
||||||
|
archetype_key="initiative.product",
|
||||||
|
)
|
||||||
|
initiative_id = created.json()["id"]
|
||||||
|
|
||||||
|
project = client.post(
|
||||||
|
f"/api/initiatives/{initiative_id}/projects",
|
||||||
|
json={"title": "Product Stream"},
|
||||||
|
headers=_auth(token),
|
||||||
|
)
|
||||||
|
assert project.status_code == 201
|
||||||
|
assert project.json()["archetype_key"] == "project.product"
|
||||||
|
|
||||||
|
|
||||||
|
def test_entity_archetypes_include_ap20_portfolio(client):
|
||||||
|
user = provision_user_in_tenant(tenant_role="member")
|
||||||
|
token = _login(client, user)
|
||||||
|
|
||||||
|
res = client.get(
|
||||||
|
"/api/entity-archetypes?entity_type=initiative",
|
||||||
|
headers=_auth(token),
|
||||||
|
)
|
||||||
|
assert res.status_code == 200
|
||||||
|
keys = {item["key"] for item in res.json()}
|
||||||
|
assert "initiative.maturity_journey" in keys
|
||||||
|
assert "initiative.content_project" in keys
|
||||||
|
assert "initiative.product" in keys
|
||||||
|
|
||||||
|
sample = next(i for i in res.json() if i["key"] == "initiative.product")
|
||||||
|
assert sample.get("default_method_key") == "continuous_product"
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
APP_VERSION = "0.17.0-ap1.5d"
|
APP_VERSION = "0.18.0-ap2.0"
|
||||||
DB_SCHEMA_VERSION = "018"
|
DB_SCHEMA_VERSION = "019"
|
||||||
APP_NAME = "jinkendo-kairo"
|
APP_NAME = "jinkendo-kairo"
|
||||||
|
|
|
||||||
303
docs/architecture/ADP_Archetype_and_Method_Catalog_v0.1.md
Normal file
303
docs/architecture/ADP_Archetype_and_Method_Catalog_v0.1.md
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
# ADP — Archetyp- & Methoden-Katalog v0.1
|
||||||
|
|
||||||
|
> **⚠ Superseded (2026-07-10):** Verwende [`ADP_Archetype_and_Method_Catalog_v0.2.md`](ADP_Archetype_and_Method_Catalog_v0.2.md) — enthält B3 Agile Iteration, Steuerungs-Matrix, Sprint-Semantik.
|
||||||
|
|
||||||
|
**Status:** superseded — siehe v0.2
|
||||||
|
**Stand:** 2026-07-10
|
||||||
|
**Bezug:** `Kairo_MVP_Definition_v0.3.md`, `ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`, `Kairo_Method_Design_Principles_v0.1.md`
|
||||||
|
**Auslöser:** Vorhaben jenseits von Software (Gewohnheit, Haushalt, Queue, Verfahren); Archetypen auf Initiative- **und** Project-Ebene; Steuerung methodengebunden
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Problem
|
||||||
|
|
||||||
|
Heute:
|
||||||
|
|
||||||
|
- `archetype_key` nur auf **Initiative**, drei Seeds (`generic`, `program`, `product`) — Dev-Sprache
|
||||||
|
- Archetyp ändert **Felder**, nicht **Steuerungsmethode**, Plan-Sicht oder Next-Action-Logik
|
||||||
|
- `project.archetype_key` **deferred** (ADP AP1.10)
|
||||||
|
- Nutzer mit heterogenem Portfolio (privat + beruflich) sieht **eine flache Vorhabenliste** und keine methodengerechte Führung
|
||||||
|
|
||||||
|
**Ziel:** Archetyp = Eintritt in ein **Steuerungspaket** (Methode + Struktur-Empfehlung + UI-Profil + EFS), nicht nur Label.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Entscheidung
|
||||||
|
|
||||||
|
### 2.1 Zwei Registry-Ebenen
|
||||||
|
|
||||||
|
| Ebene | Tabelle / Registry | Zweck |
|
||||||
|
|-------|-------------------|--------|
|
||||||
|
| **Initiative-Archetyp** | `entity_archetypes` + EFS | Welches **Programm/Vorhaben** ist das? Default-`method_key`, Profilfelder |
|
||||||
|
| **Project-Archetyp** | `entity_archetypes` (`entity_type=project`) + EFS | Welche **Rolle** hat dieser Strang im Vorhaben? |
|
||||||
|
|
||||||
|
Bestehende Initiativen: Default `initiative.generic` + `generic_operating` — unverändert.
|
||||||
|
|
||||||
|
### 2.2 Archetyp bindet Default-Methode
|
||||||
|
|
||||||
|
Jeder Initiative-Archetyp referenziert genau eine **Default-Steuerungsmethode** (`steering_context.method_key`). Nutzer kann später wechseln (mit Audit), MVP: Default reicht.
|
||||||
|
|
||||||
|
Methoden sind **registrierte Pakete** in `backend/steering/methods/` — keine Hardcodierung in React.
|
||||||
|
|
||||||
|
### 2.3 UI-Profil (kein neues OM-Objekt)
|
||||||
|
|
||||||
|
Pro Archetyp: **dominante Modus-Ansichten** und **versteckte** Patterns (z. B. Queue zeigt Pull-Queue, nicht Gate-Graph).
|
||||||
|
|
||||||
|
Speicherung MVP: Seed-JSON in Registry-Sync (`ui_profile_json`), nicht ad-hoc im Frontend.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Katalog — Initiative-Archetypen
|
||||||
|
|
||||||
|
| `archetype_key` | Label (DE) | Beispiel | Default-Methode | MVP-Stufe |
|
||||||
|
|-----------------|------------|----------|-------------------|-----------|
|
||||||
|
| `initiative.generic` | Allgemeines Vorhaben | Fallback | `generic_operating` | ✓ (bestehend) |
|
||||||
|
| `initiative.maturity_journey` | Reifegrad-Entwicklung | Spagat können | `maturity_progression` | **A** |
|
||||||
|
| `initiative.linear_project` | Lineares Vorhaben | Neue Küche | `sequential_dependency` | **A** |
|
||||||
|
| `initiative.recurring_program` | Dauerprogramm / Rhythmus | Haus in Ordnung | `recurring_control` | **B** |
|
||||||
|
| `initiative.support_queue` | Queue / Supportdesk | Tickets, Pool | `queue_pull` | **B** |
|
||||||
|
| `initiative.program` | Programm / Mega-Vorhaben | Kairo Gesamt | `product_milestone_driven` | **A** (bestehend, umbenannt semantisch) |
|
||||||
|
| `initiative.product` | Produkt / Release | Release-Track | `product_milestone_driven` | **B** |
|
||||||
|
| `initiative.dispute_case` | Verfahren / Konflikt | Miterstreit | `dispute_procedure` | **C** (Katalog) |
|
||||||
|
|
||||||
|
**Hinweis:** `initiative.program` / `initiative.product` bleiben technisch; semantisch = agile/technische Entwicklung (B2).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Katalog — Project-Archetypen
|
||||||
|
|
||||||
|
| `archetype_key` | Label (DE) | Typische Initiative | Rolle |
|
||||||
|
|-----------------|------------|---------------------|--------|
|
||||||
|
| `project.generic` | Allgemeines Projekt | alle | Standard-Container |
|
||||||
|
| `project.maturity_lane` | Reifegrad-Spur | maturity_journey | Übungs-/Entwicklungsspur pro Körperregion o.ä. |
|
||||||
|
| `project.primary_chain` | Primärstrang | linear_project | Kritischer Pfad (Wasserfall-Hauptlinie) |
|
||||||
|
| `project.companion_track` | Begleitstrang | linear_project | Parallele Nebenaktivitäten |
|
||||||
|
| `project.recurring_domain` | Bereich mit Rhythmus | recurring_program | Küche, Garten, Kind — Recurring-Owner |
|
||||||
|
| `project.queue_stream` | Ticket-Strom | support_queue | Kategorie/Team-Queue |
|
||||||
|
| `project.release_stream` | Release/Phase | program, product | Technischer Strang |
|
||||||
|
| `project.dispute_track` | Verfahrensstrang | dispute_case | z. B. „Gericht“, „Mediation“ |
|
||||||
|
|
||||||
|
Migration: `projects.archetype_key VARCHAR(64) DEFAULT 'project.generic'` (AP2.0b).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Steuerungsmethoden (Registry-Ziel)
|
||||||
|
|
||||||
|
| `method_key` | Status heute | Kurzbeschreibung | Next-Action-Fokus |
|
||||||
|
|--------------|--------------|------------------|-------------------|
|
||||||
|
| `generic_operating` | ✓ registriert | Leichte Struktur, Gates optional | offene Actions, Backlog-Triage |
|
||||||
|
| `product_milestone_driven` | ✓ registriert | Gate-horizont, Meilenstein | Gate + offene AP am Gate |
|
||||||
|
| `maturity_progression` | ○ Ziel | Reifegrad-Stufen, Übungswechsel | **heutige Übung** + Stufen-Kriterium |
|
||||||
|
| `sequential_dependency` | ○ Ziel | Linearer Graph, Begleitstränge | **nächster freier Schritt** am kritischen Pfad |
|
||||||
|
| `recurring_control` | ○ Ziel | Dauerprogramm, Assignments | **fällig / überfällig** pro Actor, nicht Gesamtliste |
|
||||||
|
| `queue_pull` | ○ Ziel | Pool, Selbstwahl oder Empfehlung | **1 Empfehlung** oder gewähltes Item |
|
||||||
|
| `dispute_procedure` | ○ Katalog | Phasen, Fristen, Iterationen | **nächste Frist / Entscheidung** |
|
||||||
|
|
||||||
|
Neue Methoden: nur via `steering/methods/registrations/*.py` + Tests — siehe `Kairo_Method_Design_Principles_v0.1.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Archetyp-Detail (PO-Spezifikation)
|
||||||
|
|
||||||
|
### A1 — `initiative.maturity_journey` (Spagat)
|
||||||
|
|
||||||
|
**Plan:**
|
||||||
|
|
||||||
|
- `RoadmapItem` mit `item_type=maturity_stage` (Reifegrad-Stufen)
|
||||||
|
- Kriterien pro Stufe (Checkliste AP1.4b)
|
||||||
|
|
||||||
|
**Ist:**
|
||||||
|
|
||||||
|
- `RecurringElement` für Übungsroutine **pro Stufe**
|
||||||
|
- Bei Verify `reached` → Recurring-Set wechseln (Hook/Service, AP2.0d)
|
||||||
|
|
||||||
|
**Steuerung:**
|
||||||
|
|
||||||
|
- Next Action: heutige Recurring-Instanz + Hinweis „Stufe X, Kriterium Y offen“
|
||||||
|
- Attention: Stagnation (keine Recurring-Erfüllung), Stufe ohne Fortschritt
|
||||||
|
|
||||||
|
**EFS (Seed):**
|
||||||
|
|
||||||
|
- `current_body_focus` (text), `training_frequency` (enum), `progress_notes` (longtext)
|
||||||
|
|
||||||
|
**UI-Profil:** Kontrolle dominant; Plan = Stufen; Ausführen = heute; Gates-Graph **aus**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### A2 — `initiative.linear_project` (Küche)
|
||||||
|
|
||||||
|
**Plan:**
|
||||||
|
|
||||||
|
- `project.primary_chain` + `project.companion_track`
|
||||||
|
- Gates entlang Primärstrang; `roadmap_item_dependencies` (AP1.4d/13)
|
||||||
|
|
||||||
|
**Ist:**
|
||||||
|
|
||||||
|
- Actions an Blatt-Projects / Initiative
|
||||||
|
- Begleit-APs parallel
|
||||||
|
|
||||||
|
**Steuerung:**
|
||||||
|
|
||||||
|
- Next Action: nächster **ready** Schritt am kritischen Pfad (Graph Engine read model)
|
||||||
|
- Attention: Blocker auf Pfad, Gate at risk, überfälliges `target_date`
|
||||||
|
|
||||||
|
**EFS:**
|
||||||
|
|
||||||
|
- `budget_summary`, `primary_contractor`, `target_completion` (date)
|
||||||
|
|
||||||
|
**UI-Profil:** Plan (Graph/Liste) + Kontrolle; Recurring **aus**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### A3 — `initiative.recurring_program` (Haus)
|
||||||
|
|
||||||
|
**Plan:**
|
||||||
|
|
||||||
|
- optional `project.recurring_domain` pro Bereich/Person
|
||||||
|
- wenig / keine Gates (`generic_operating`-light)
|
||||||
|
|
||||||
|
**Ist:**
|
||||||
|
|
||||||
|
- `RecurringElement` + `ActionAssignment` pro Familien-Actor
|
||||||
|
- Roll-up: überfällige Recurring → Attention
|
||||||
|
|
||||||
|
**Steuerung:**
|
||||||
|
|
||||||
|
- Next Action: **eigene** fällige Recurring (+ optional eine aus Pool „Haus“)
|
||||||
|
- Cockpit: wer ist überfällig — **nicht** alle Tasks aller Personen
|
||||||
|
|
||||||
|
**EFS:**
|
||||||
|
|
||||||
|
- `household_members` (longtext / später actor_ref_list), `cadence_default` (enum)
|
||||||
|
|
||||||
|
**UI-Profil:** Ausführen + Team; Plan minimal
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### B1 — `initiative.support_queue` (Supportdesk)
|
||||||
|
|
||||||
|
**Plan:**
|
||||||
|
|
||||||
|
- flacher Eingang → triage → Queue
|
||||||
|
- optional `project.queue_stream` pro Kategorie
|
||||||
|
|
||||||
|
**Ist:**
|
||||||
|
|
||||||
|
- Actions als Tickets; Status open/ready/in_progress
|
||||||
|
- Actor-Gruppe: Pull-Berechtigung
|
||||||
|
|
||||||
|
**Steuerung:**
|
||||||
|
|
||||||
|
- Next Action: **Empfehlung** aus Queue-Strategie oder selbst gewählt (Pull)
|
||||||
|
- Attention: SLA, unassigned high-priority
|
||||||
|
|
||||||
|
**EFS:**
|
||||||
|
|
||||||
|
- `queue_policy` (enum: pull, assign, hybrid), `sla_hours` (number)
|
||||||
|
|
||||||
|
**UI-Profil:** Ausführen (Queue) dominant; Plan = Eingang
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### B2 — `initiative.program` / `initiative.product` (Agile / Kairo)
|
||||||
|
|
||||||
|
Bestehendes Modell — im Katalog **explizit** als technische Entwicklung verankert, nicht als einziger Typ.
|
||||||
|
|
||||||
|
**UI-Profil:** Plan (Gates) + Kontrolle (Snapshot) + Ausführen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### C1 — `initiative.dispute_case` (Miterstreit)
|
||||||
|
|
||||||
|
**Plan:**
|
||||||
|
|
||||||
|
- Phasen-Gates: Auslöser → Reaktion → … → Einigung → Abschluss
|
||||||
|
- Iterationen (Reopen / neue Runde) mit Decision-Pflicht
|
||||||
|
|
||||||
|
**Ist:**
|
||||||
|
|
||||||
|
- Decisions (Argumentationsketten), Evidence (Dokumente), Fristen auf Gates/Actions
|
||||||
|
- optional `project.dispute_track` (Anwalt, Gericht, Mediation)
|
||||||
|
|
||||||
|
**Steuerung:**
|
||||||
|
|
||||||
|
- Next Action: **nächste Frist** oder **offene Entscheidung**
|
||||||
|
- Attention: Frist läuft ab, fehlende Evidence
|
||||||
|
|
||||||
|
**EFS:**
|
||||||
|
|
||||||
|
- `counterparty`, `legal_counsel_actor_ref`, `next_deadline` (date), `case_reference` (text)
|
||||||
|
|
||||||
|
**MVP-Stufe C:** Katalog + Profilfelder + generische Gates; spezialisierte UI post-MVP
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Plan-/Ist-Muster (übergreifend)
|
||||||
|
|
||||||
|
```text
|
||||||
|
Eingang Plan (optional) Ist Steuerung
|
||||||
|
maturity_journey selten maturity_stages Recurring heutige Übung
|
||||||
|
linear_project selten Gate-Graph Actions kritischer Pfad
|
||||||
|
recurring_program selten Domains Recurring fällig/heute
|
||||||
|
support_queue triage Queue-Streams Actions Pull/Empfehlung
|
||||||
|
program/product Backlog Gates Actions+Tasks Gate+Next AP
|
||||||
|
dispute_case Eingang Phasen-Gates Decisions+Ev. Frist/Entscheidung
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Scope Lock
|
||||||
|
|
||||||
|
| Verboten | Erlaubt |
|
||||||
|
|----------|---------|
|
||||||
|
| React-Formulare pro Archetyp hardcoden | FieldRenderer + Registry |
|
||||||
|
| OM-Tabelle `disputes`, `habits`, … | EFS + bestehende OM-Entitäten |
|
||||||
|
| Steering-Heuristiken in Routern | `backend/steering/` |
|
||||||
|
| Alle Methoden voll implementieren vor A-Abnahme | Stubs + A1/A2/B2 zuerst |
|
||||||
|
| Archetyp ohne `method_key`-Bindung | Seed + Sync |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Implementierungspakete
|
||||||
|
|
||||||
|
```text
|
||||||
|
AP2.0a Method-Stubs registrieren (4 neue + dispute stub)
|
||||||
|
AP2.0b entity_archetypes Seeds (Initiative + Project); projects.archetype_key; EFS field_definitions
|
||||||
|
AP2.0c Kontrolle-Lagebild: method_key, lifecycle, next action, attention (UI)
|
||||||
|
AP2.0d Next-Action-Strategien: maturity, sequential, recurring, queue (minimal)
|
||||||
|
AP2.0e Recurring-Stufenwechsel bei maturity_stage reached (A1)
|
||||||
|
AP2.1 Validation Report v0.3 — Referenz A1, A2, B2 mit echten Daten
|
||||||
|
```
|
||||||
|
|
||||||
|
Erweitert AP1.10 — **ersetzt nicht** EFS-Architektur, nutzt sie.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Risiko
|
||||||
|
|
||||||
|
| Risiko | Mitigation |
|
||||||
|
|--------|------------|
|
||||||
|
| Methoden-Overengineering | Stubs + eine Strategie pro A-Archetyp |
|
||||||
|
| dispute_case zu groß | Stufe C, nur Katalog im MVP |
|
||||||
|
| Recurring-Stufenwechsel komplex | AP2.0e nach A1-Grundlage |
|
||||||
|
| Todo-Wand trotz Archetyp | MVP v0.3 UI-Regeln + Review-Pflicht |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. PO-Freigabe
|
||||||
|
|
||||||
|
- [ ] Acht Initiative-Archetypen (+ generic) akzeptiert oder korrigiert
|
||||||
|
- [ ] Project-Archetypen akzeptiert
|
||||||
|
- [ ] Methoden-Keys akzeptiert
|
||||||
|
- [ ] MVP-Stufen A/B/C akzeptiert
|
||||||
|
- [ ] AP2.0-Reihenfolge freigegeben
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Referenzen
|
||||||
|
|
||||||
|
- `docs/product/Kairo_MVP_Definition_v0.3.md`
|
||||||
|
- `docs/architecture/ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`
|
||||||
|
- `docs/architecture/Kairo_Target_Architecture_Method_Driven_Adaptive_Steering_Core_v0.1.md`
|
||||||
|
- `backend/steering/methods/registrations/generic_operating.py`
|
||||||
|
- `backend/steering/methods/registrations/product_milestone_driven.py`
|
||||||
601
docs/architecture/ADP_Archetype_and_Method_Catalog_v0.2.md
Normal file
601
docs/architecture/ADP_Archetype_and_Method_Catalog_v0.2.md
Normal file
|
|
@ -0,0 +1,601 @@
|
||||||
|
# ADP — Archetyp- & Methoden-Katalog v0.2
|
||||||
|
|
||||||
|
**Status:** PO-freigegeben
|
||||||
|
**Stand:** 2026-07-10 (Archetypen-, Project- und Methoden-Schichten; Vier-Schichten-Modell)
|
||||||
|
**Bezug:** `Kairo_MVP_Definition_v0.3.md`, `ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`, `Kairo_Method_Design_Principles_v0.1.md`, `Kairo_Canonical_Operating_Model_v0.2.md`
|
||||||
|
**Ersetzt:** `ADP_Archetype_and_Method_Catalog_v0.1.md` (Inhalt konsolidiert + B3 Agile Iteration)
|
||||||
|
**Auslöser:** Vorhaben jenseits von Software; heterogenes Portfolio; **Agile (Backlog, Sprint, Release)** vollständig im Katalog verankern
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Problem
|
||||||
|
|
||||||
|
Heute:
|
||||||
|
|
||||||
|
- `archetype_key` nur auf **Initiative**, drei Seeds (`generic`, `program`, `product`) — Dev-Sprache
|
||||||
|
- Archetyp ändert **Felder**, nicht **Steuerungsmethode**, Plan-Sicht oder Next-Action-Logik
|
||||||
|
- `project.archetype_key` **deferred** (ADP AP1.10)
|
||||||
|
- **Agile** ist implizit in B2 (`product_milestone_driven`) — **Release-/Gate-Agile**, nicht **Iterations-Agile** (Sprint, Sprint-Backlog)
|
||||||
|
- Nutzer mit heterogenem Portfolio sieht **eine flache Vorhabenliste** und keine methodengerechte Führung
|
||||||
|
|
||||||
|
**Ziel:** Generische **Archetypen** liefern den **Methodenbaukasten** (Default-Methode, Felder, UI); **Ausprägungen** konkretisieren (Buch schreiben, Kumite, …). Die **Magie** (automatische Steuerung, Monitoring, KI, Gitea, Vibe-Coder) sitzt in der **Methoden-Modulregistrierung** auf dem Standard-Framework — nicht im Archetyp hardcodiert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Entscheidung
|
||||||
|
|
||||||
|
### 2.0 Vier Schichten — wo die Magie sitzt — **PO 2026-07-10**
|
||||||
|
|
||||||
|
```text
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Schicht 4 (später) Integrationen & Agenten │
|
||||||
|
│ MCP/Vibe-Coder, Gitea, Webhooks — an Hook Slugs gebunden │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Schicht 3 Ausprägung (Method Profile / Domain Template) │
|
||||||
|
│ „Buch schreiben“, „Karate Kumite“ — Felder, Vorbefüllung, │
|
||||||
|
│ Kategorien, Mitwirkende, Struktur-Seeds │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Schicht 2 Generischer Archetyp (entity_archetypes + EFS) │
|
||||||
|
│ maturity_journey, product, linear_project, … │
|
||||||
|
│ → Default method_key, Feldprofil, UI-Profil (Methodenbaukasten)│
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Schicht 1 Methode (Method Registry — Steuerungsmodul) │
|
||||||
|
│ register_method: Lifecycle, Hooks, Builder, Strategies, Signals│
|
||||||
|
│ → automatische Steuerung, Planung, Monitoring, Next Action │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Schicht 0 Standard-Framework (Adaptive Steering Core) │
|
||||||
|
│ backend/steering/, OM, TenantContext, Audit, Operational API │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
| Schicht | Was | MVP | Später |
|
||||||
|
|---------|-----|-----|--------|
|
||||||
|
| **0 Framework** | Steering Core, OM, Capabilities | ✓ Foundation | Waiting, Runtime |
|
||||||
|
| **1 Methode** | Modul in `steering/methods/registrations/` | Stubs + 1–2 Strategien | Volle Profiles, Workflow-Fragmente |
|
||||||
|
| **2 Archetyp** | `entity_archetypes` + EFS + `ui_profile_json` | Seeds AP2.0b | Tenant-Templates |
|
||||||
|
| **3 Ausprägung** | `method_profile_key` + `configuration_json` + EFS-Seeds | Katalog + 1–2 Referenz-Seeds | Designer, Tenant-Kopien |
|
||||||
|
| **4 Integration** | Hooks → MCP, Gitea, Vibe-Coder (`/api/operational/`) | **eingefroren** | KI-gestützte Steuerung |
|
||||||
|
|
||||||
|
**PO-Regel:** Archetyp **beschreibt den Baukasten**, Ausprägung **beschreibt die konkrete Variante**. Keine Sonder-OM-Tabellen pro Ausprägung.
|
||||||
|
|
||||||
|
**Beispiele Ausprägungen (Schicht 3) — referenzieren generischen Archetyp:**
|
||||||
|
|
||||||
|
| `profile_key` (Ziel) | Archetyp (Schicht 2) | Methode (Schicht 1) | Liefert u. a. |
|
||||||
|
|----------------------|----------------------|----------------------|---------------|
|
||||||
|
| `maturity.karate_kumite` | `initiative.maturity_journey` | `maturity_progression` | 8 Fähigkeiten-Seed, Stufen-Raster, Coach-Rolle |
|
||||||
|
| `content.book_writing` | `initiative.content_project` | `chapter_based_progression` | Kapitel-Gliederung, Wortziel, Lector |
|
||||||
|
| `product.kairo_dev` | `initiative.product` | `continuous_product` + `agile_iteration` | Gate-Set, Sprint-Cadence, Agent-Actor |
|
||||||
|
| `recurring.household` | `initiative.recurring_program` | `recurring_control` | Domains, Score-Policy (AP2.0g) |
|
||||||
|
|
||||||
|
Speicherung Zielbild: `method_profiles` (tenant-scoped, siehe Target Architecture §15) + EFS `field_definitions` pro Archetyp/Profile; MVP: **Code-Seeds** in Registry-Sync.
|
||||||
|
|
||||||
|
**Integrationen (Schicht 4):** Methoden exponieren **Hook Slugs** (`on_next_action_requested`, `on_result_received`, …). Bindings:
|
||||||
|
|
||||||
|
- **Vibe-Coder / MCP** → Operational API + Hook-Handler (kein Prompt hardcoden)
|
||||||
|
- **Gitea** → Events → `result_intake` / Journey / Gate-Verify
|
||||||
|
- **KI** → Signal Engine / Next-Action-Vorschläge — **ersetzt nicht** Methoden-Strategie ohne Audit
|
||||||
|
|
||||||
|
Siehe `Kairo_Method_Design_Principles_v0.1.md`, `ADP_Operational_Actor_Interface_Vibe_Coder_v0.1.md`.
|
||||||
|
|
||||||
|
### 2.1 Zwei Registry-Ebenen (Archetyp Initiative + Project)
|
||||||
|
|
||||||
|
| Ebene | Tabelle / Registry | Zweck |
|
||||||
|
|-------|-------------------|--------|
|
||||||
|
| **Initiative-Archetyp** | `entity_archetypes` + EFS | Welches **Programm/Vorhaben** ist das? Default-`method_key`, Profilfelder |
|
||||||
|
| **Project-Archetyp** | `entity_archetypes` (`entity_type=project`) + EFS | Welche **Rolle** hat dieser Strang im Vorhaben? |
|
||||||
|
|
||||||
|
Bestehende Initiativen: Default `initiative.generic` + `generic_operating` — unverändert.
|
||||||
|
|
||||||
|
### 2.2 Archetyp → Default-Methode + optional Ausprägung
|
||||||
|
|
||||||
|
Jeder Archetyp referenziert:
|
||||||
|
|
||||||
|
```text
|
||||||
|
default_method_key # Schicht 1 — Steuerungsmodul
|
||||||
|
default_method_profile_key # Schicht 3 — optional, z. B. content.book_writing
|
||||||
|
efs_field_profile # Schicht 2/3 — Felder
|
||||||
|
ui_profile_json # dominante Modus-Ansichten
|
||||||
|
```
|
||||||
|
|
||||||
|
Nutzer/PO wählt bei Anlage: **Archetyp** (generisch) und optional **Ausprägung** (konkret). Project erbt + darf `method_key` / Profile **override** (§4.3).
|
||||||
|
|
||||||
|
Methoden = **registrierte Module** in `backend/steering/methods/` — keine Hardcodierung in React, keine Steuerung in Routern.
|
||||||
|
|
||||||
|
### 2.3 Methoden-Komposition (Product + Sprint)
|
||||||
|
|
||||||
|
**Release/Programm** und **Iterations-Zeitbox** sind **keine Gegensätze**:
|
||||||
|
|
||||||
|
| Methode | Horizont | Steuerungsfrage |
|
||||||
|
|---------|----------|-----------------|
|
||||||
|
| `program_delivery` (B2a) | Begrenztes Programm, Abschluss | „Was blockiert den nächsten Meilenstein?“ |
|
||||||
|
| `continuous_product` (B2b) | Dauerbetrieb, Wartung, Issues | „Was ist jetzt am wirksamsten — ohne fixes Ende?“ |
|
||||||
|
| `agile_iteration` (B3 Profil) | Sprint / `work_cycle` auf B2 | „Was ist der Schritt **in dieser Zeitbox**?“ |
|
||||||
|
|
||||||
|
**Komposition:** Kairo als **`initiative.product`** nutzt `continuous_product` **und** optional `work_cycle` — **kein** eigener Archetyp `agile_team`. Sprint kann in Release/Product-Betrieb übergehen. PO + Vibe Coder; Kairo übernimmt Scrum-Master-Logik (Next Action, Attention).
|
||||||
|
|
||||||
|
Kein zweiter SteeringContext, kein paralleles OM.
|
||||||
|
|
||||||
|
### 2.4 Project-Archetyp: Spiegel der Initiative, Struktur separat — **PO 2026-07-10**
|
||||||
|
|
||||||
|
**Grundsatz:** Project-Archetypen **entsprechen** den Initiative-Archetypen (gleiche Familie, `project.*`-Prefix) — **kein** paralleles Typensystem (`primary_chain`, `maturity_lane`, …).
|
||||||
|
|
||||||
|
| Aspekt | Regel |
|
||||||
|
|--------|--------|
|
||||||
|
| **Default bei Anlage** | `project.archetype_key` = **abgeleitet** von `initiative.archetype_key` (Mapping 1:1) |
|
||||||
|
| **Abweichung erlaubt** | Project darf **andere Methode** (`method_key`) und **andere EFS-Felder** als die Initiative haben |
|
||||||
|
| **Struktur** | Abhängigkeiten, Pfade, Lanes, Domains → **Graph + Roadmap + Konfiguration**, nicht eigener Archetyp pro Pfadtyp |
|
||||||
|
| **`project.generic`** | Nur wenn **nichts** ableitbar — UI-Hinweis: *keine Steuerungsstruktur*; **Prefer inherit** |
|
||||||
|
|
||||||
|
**Beispiel Kumite (A1):** Initiative `maturity_journey` → Projects pro Fähigkeit (ebenfalls `maturity_journey`); Stufen = `maturity_stage`; Routinen = Recurring; **Voraussetzungen** = Graph-Kanten zwischen Stufen/Projects — kein Sondermodell „lane“.
|
||||||
|
|
||||||
|
**Beispiel Küche (A2):** Mehrere Haupt- und Nebenpfade; **kritischer Pfad** = **berechnetes** Read Model aus Graph + Status — nicht fest ein `primary_chain`-Objekt.
|
||||||
|
|
||||||
|
### 2.5 UI-Profil (kein neues OM-Objekt)
|
||||||
|
|
||||||
|
Pro Archetyp: **dominante Modus-Ansichten** und **versteckte** Patterns (z. B. Queue zeigt Pull-Queue, nicht Gate-Graph).
|
||||||
|
|
||||||
|
Speicherung MVP: Seed-JSON in Registry-Sync (`ui_profile_json`), nicht ad-hoc im Frontend.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Steuerungs-Landschaft — Vollständigkeits-Matrix
|
||||||
|
|
||||||
|
Diese Matrix ist die **Checkliste**, dass keine wesentliche Steuerungsform übersehen wird.
|
||||||
|
|
||||||
|
### 3.1 Initiative-Archetypen (Referenz-Portfolio)
|
||||||
|
|
||||||
|
| ID | `archetype_key` | Label (DE) | Beispiel | Default-Methode | MVP-Stufe |
|
||||||
|
|----|-----------------|------------|----------|-------------------|-----------|
|
||||||
|
| — | `initiative.generic` | Allgemeines Vorhaben | Fallback | `generic_operating` | ✓ (bestehend) |
|
||||||
|
| **A1** | `initiative.maturity_journey` | Reifegrad-Entwicklung | Spagat können | `maturity_progression` | **A** |
|
||||||
|
| **A2** | `initiative.linear_project` | Lineares Vorhaben | Neue Küche | `sequential_dependency` | **A** |
|
||||||
|
| **A3** | `initiative.recurring_program` | Dauerprogramm / Rhythmus | Haus in Ordnung | `recurring_control` | **B** |
|
||||||
|
| **B1** | `initiative.support_queue` | Queue / Supportdesk | Tickets, Pool | `queue_pull` | **B** |
|
||||||
|
| **B2a** | `initiative.program` | Programm (begrenzt) | Kairo-Release-Programm, Großprojekt mit Abschluss | `program_delivery` | **A** |
|
||||||
|
| **B2b** | `initiative.product` | Produkt (kontinuierlich) | Kairo-Betrieb, Wartung, Issues | `continuous_product` | **A** |
|
||||||
|
| **B3** | *(kein eigener Initiative-Archetyp)* | Sprint / Iteration | PO + Vibe-Coder-Zeitbox | `agile_iteration` als **Profil** auf B2 | **A** (Minimal) |
|
||||||
|
| **C1** | `initiative.dispute_case` | Verfahren / Konflikt | Miterstreit | `dispute_procedure` | **C** (Katalog) |
|
||||||
|
| **D1** | `initiative.content_project` | Inhalt / Kapitel | Buch, Konzept schreiben | `chapter_based_progression` | **B** |
|
||||||
|
|
||||||
|
**PO 2026-07-10 — Archetypen:** A1 ✓ · A2 ✓ · A3 ✓ (Score-Logik, siehe §5) · B1 ✓ · B2a/B2b getrennt · B3 kein eigener Typ · C1 Katalog · D1 in MVP Stufe B
|
||||||
|
|
||||||
|
**Hinweis B2/B3:** `program` vs. `product` = **unterschiedlicher Lifecycle** (begrenzt vs. kontinuierlich). Sprint/`work_cycle` hängt an **Product/Programm**, nicht an `initiative.agile_team`. Kairo-Setup: PO + Vibe Coder; „Scrum Master“ = Kairo-Steuerungslogik.
|
||||||
|
|
||||||
|
### 3.2 Steuerungsmethoden (Registry)
|
||||||
|
|
||||||
|
| `method_key` | Status heute | Archetyp(e) | Kurzbeschreibung | Next-Action-Fokus |
|
||||||
|
|--------------|--------------|-------------|------------------|-------------------|
|
||||||
|
| `generic_operating` | ✓ registriert | generic | Leichte Struktur, Gates optional | offene Actions, Backlog-Triage |
|
||||||
|
| `program_delivery` | ○ Ziel (Stub; heute: `product_milestone_driven`) | program | Begrenztes Programm, Phasen, Abschluss | Gate + AP am Horizont; **Closure** vorgesehen |
|
||||||
|
| `continuous_product` | ○ Ziel (Stub AP2.0a) | product | Kontinuierlicher Betrieb, Wartung, Issues | Nächster wirkungsvoller Schritt; **kein** fixes End-Gate |
|
||||||
|
| `agile_iteration` | ○ Ziel (Profil/Hook) | product, program | Zeitbox / Sprint auf Ist-Ebene | 1–3 Items im aktiven `work_cycle` |
|
||||||
|
| `product_milestone_driven` | ✓ registriert | *(Legacy-Seed → migrieren zu program/product)* | Meilenstein-orientiert | Gate + offene AP am Gate |
|
||||||
|
| `maturity_progression` | ○ Ziel | maturity_journey | Reifegrad-Stufen, Übungswechsel | **heutige Übung** + Stufen-Kriterium |
|
||||||
|
| `sequential_dependency` | ○ Ziel | linear_project | Linearer Graph, Begleitstränge | **nächster ready Schritt** am kritischen Pfad |
|
||||||
|
| `recurring_control` | ○ Ziel | recurring_program | Dauerprogramm, Assignments | **fällig / überfällig** pro Actor |
|
||||||
|
| `queue_pull` | ○ Ziel | support_queue | Pool, Selbstwahl oder Empfehlung | **1 Empfehlung** oder gewähltes Item |
|
||||||
|
| `dispute_procedure` | ○ Katalog | dispute_case | Phasen, Fristen, Iterationen | **nächste Frist / Entscheidung** |
|
||||||
|
| `chapter_based_progression` | ○ Katalog | content_project | Kapitel-Reihenfolge, Review-Gates | **nächstes Kapitel / Review** |
|
||||||
|
|
||||||
|
Neue Methoden: nur via `steering/methods/registrations/*.py` + Tests — siehe `Kairo_Method_Design_Principles_v0.1.md`.
|
||||||
|
|
||||||
|
### 3.3 RoadmapItem-Typen (Plan-Schicht)
|
||||||
|
|
||||||
|
Kanoniche Typen aus OM v0.2 — **keine eigenen Tabellen** pro Typ.
|
||||||
|
|
||||||
|
| `item_type` | Bedeutung | Primär-Archetyp | MVP |
|
||||||
|
|-------------|-----------|-----------------|-----|
|
||||||
|
| `milestone` | Meilenstein / Release-Punkt | program, product, linear_project | ✓ AP1.4 |
|
||||||
|
| `maturity_stage` | Reifegrad-Stufe | maturity_journey | A |
|
||||||
|
| `feature` | Feature-Landschaft (optional) | program, product | post-A |
|
||||||
|
| `review_gate` | Review / Quality Gate | program, product, content_project | ◐ |
|
||||||
|
| `chapter` | Kapitel / Abschnitt | content_project | **B** |
|
||||||
|
| `work_cycle` | **Sprint / Iteration / Zeitbox** | product, program | **A (B3)** |
|
||||||
|
| `phase` | Verfahrensphase | dispute_case | C |
|
||||||
|
|
||||||
|
**Sprint in Kairo** = `RoadmapItem(type=work_cycle)`, nicht eigene `sprints`-Tabelle.
|
||||||
|
|
||||||
|
### 3.4 Ist-Schicht — Was committet wird
|
||||||
|
|
||||||
|
| OM-Entität | Rolle | Nicht verwechseln mit |
|
||||||
|
|------------|-------|------------------------|
|
||||||
|
| `BacklogItem` | Eingang, noch nicht committet | Sprint-Backlog (Ist!) |
|
||||||
|
| `Action` | Committetes Arbeitspaket | Task |
|
||||||
|
| `Task` | Feingranularität unter Action | BacklogItem |
|
||||||
|
| `RecurringElement` | Rhythmus / Routine | Backlog, Sprint |
|
||||||
|
| `Decision` | Steuerungsentscheidung | Action |
|
||||||
|
| `Evidence` | Nachweis für Gate/DoD | Attachment-Dummy |
|
||||||
|
|
||||||
|
**Sprint-Backlog-Semantik (B3):**
|
||||||
|
|
||||||
|
- **Product Backlog** = `BacklogItem` (+ optional Gate-Link) — Plan-Eingang
|
||||||
|
- **Sprint Backlog** = `Action` (Status open/ready/in_progress) mit **`work_cycle_id`** (FK auf `roadmap_items.id` wo `item_type=work_cycle`)
|
||||||
|
- Commit aus Eingang → Action **mit** aktivem Zyklus = Sprint-Commit
|
||||||
|
- Abgeschlossener Sprint: Actions done/cancelled; Zyklus `reached` oder `closed`; Review optional via `Review`-Objekt
|
||||||
|
|
||||||
|
Migration: `actions.work_cycle_id UUID NULL REFERENCES roadmap_items(id)` (AP2.0f).
|
||||||
|
|
||||||
|
### 3.5 Agile-Begriffe — Abbildung in Kairo
|
||||||
|
|
||||||
|
| Scrum/Agile-Begriff | In Kairo | Status |
|
||||||
|
|---------------------|----------|--------|
|
||||||
|
| Product Backlog | `BacklogItem`, Plan → Eingang | ✓ implementiert |
|
||||||
|
| Sprint | `RoadmapItem(type=work_cycle)` | ○ Katalog + AP2.0f |
|
||||||
|
| Sprint Goal | `work_cycle.title` + optional EFS `sprint_goal` | ○ |
|
||||||
|
| Sprint Backlog | `Action.work_cycle_id` | ○ AP2.0f |
|
||||||
|
| Sprint Planning | Commit/Triage Eingang → Sprint-Actions | ○ |
|
||||||
|
| Daily / Standup | **kein Objekt** — Ausführen-Modus zeigt Next Action | bewusst |
|
||||||
|
| Sprint Review | `Review` + Gate optional | ◐ |
|
||||||
|
| Retrospective | `Review` / `Decision` | ◐ |
|
||||||
|
| Velocity / Burndown | — | **explizit post-MVP** |
|
||||||
|
| Kanban-Board | — | **explizit nicht Kern** |
|
||||||
|
| Story Points | EFS optional | post-MVP |
|
||||||
|
|
||||||
|
### 3.6 Explizit nicht im MVP-Kern (Anti-Scope)
|
||||||
|
|
||||||
|
Damit nichts „vergessen“ wirkt, aber klar **ausgeschlossen** ist:
|
||||||
|
|
||||||
|
| Thema | Warum nicht Kern |
|
||||||
|
|-------|------------------|
|
||||||
|
| Kanban-Board als Haupt-UI | Todo-Wand-Risiko; Queue (B1) deckt Pull ab |
|
||||||
|
| Velocity, Burndown, CFD | Reporting-Edge, nicht Steuerungskern |
|
||||||
|
| Scrum-Rituale als Workflow-Engine | Lifecycle + Review reicht |
|
||||||
|
| Jira/Linear-Import | post-MVP |
|
||||||
|
| `sprints`-Tabelle parallel zu RoadmapItem | Scope Lock — nur `work_cycle` |
|
||||||
|
| Mitai/Shinkan-Trainingslogik | Produktfamilien-Trennung |
|
||||||
|
| Billing, SSO, MCP/KI | eingefroren |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Katalog — Project-Archetypen — **PO-Neuausrichtung 2026-07-10**
|
||||||
|
|
||||||
|
### 4.1 Spiegel-Tabelle (1:1 zur Initiative)
|
||||||
|
|
||||||
|
Project-Registry **spiegelt** Initiative-Registry (`entity_archetypes`, `entity_type=project`):
|
||||||
|
|
||||||
|
| Initiative-Archetyp | Project-Archetyp (Default bei Anlage) | Anmerkung |
|
||||||
|
|---------------------|----------------------------------------|-----------|
|
||||||
|
| `initiative.generic` | `project.generic` | **Vermeiden** — lieber von Initiative erben |
|
||||||
|
| `initiative.maturity_journey` | `project.maturity_journey` | z. B. eine **Fähigkeit** (Kumite-Angriff) |
|
||||||
|
| `initiative.linear_project` | `project.linear_project` | Strang in einem Gesamtvorhaben |
|
||||||
|
| `initiative.recurring_program` | `project.recurring_program` | Domain **konfigurierbar** (Raum, Person, Thema) |
|
||||||
|
| `initiative.support_queue` | `project.support_queue` | Queue **unter** Product/Programm |
|
||||||
|
| `initiative.program` | `project.program` | Phase/Release-Strang |
|
||||||
|
| `initiative.product` | `project.product` | Stream unter Produkt (Feature, Ops, …) |
|
||||||
|
| `initiative.dispute_case` | `project.dispute_case` | Verfahrensstrang |
|
||||||
|
| `initiative.content_project` | `project.content_project` | Teil, Band, großer Block |
|
||||||
|
|
||||||
|
**Migration AP2.0b:** `projects.archetype_key VARCHAR(64) NULL` — bei INSERT Default = **Mirror** der Initiative, nicht blind `generic`.
|
||||||
|
|
||||||
|
### 4.2 Was **kein** Project-Archetyp ist (Struktur statt Label)
|
||||||
|
|
||||||
|
Diese Konzepte aus v0.2-Entwurf sind **keine** eigenen Archetypen — sie werden **generisch** modelliert:
|
||||||
|
|
||||||
|
| Konzept | Modellierung | Werkzeug |
|
||||||
|
|---------|--------------|----------|
|
||||||
|
| Reifegrad-Spur / Lane | Project oder Roadmap-Lane mit gleichem Archetyp | Roadmap + Graph |
|
||||||
|
| Primär- / Nebenpfad | Knoten + Kanten; Rolle an Kante/Knoten | **Gate-Graph (AP1.13)** |
|
||||||
|
| Kritischer Pfad | **Berechnet** aus Graph + Ist-Status | Steering Read Model |
|
||||||
|
| Voraussetzung Stufe 3 Angriff braucht Stufe 2 Bein | `roadmap_item_dependencies` / Graph | A1 Kumite-Beispiel |
|
||||||
|
| Recurring-Domain (Küche / Person) | `project.recurring_program` + **EFS-Konfiguration** | Felder, nicht Typ |
|
||||||
|
| Sprint-Zeitbox | `RoadmapItem(work_cycle)` + `Action.work_cycle_id` | B3 Profil — **kein** Project-Typ |
|
||||||
|
| Thema ohne Project | **eigene Initiative** (`support_queue`) oder BacklogItem-Triage | B1 PO |
|
||||||
|
|
||||||
|
**PO:** Kein exaktes Datenmodell + exakte Steuerung **pro Bezeichner** — Archetyp liefert **Default-Methode + Feldprofil + UI-Empfehlung**; Feinsteuerung über Graph, EFS, optional `method_key`-Override am Project.
|
||||||
|
|
||||||
|
### 4.3 Abweichende Methode / Struktur am Project
|
||||||
|
|
||||||
|
```text
|
||||||
|
Initiative (method_key, archetype_key)
|
||||||
|
└── Project (archetype_key default=Mirror, method_key optional OVERRIDE)
|
||||||
|
├── structure: parent_project_id, roadmap_item_id, graph edges
|
||||||
|
└── Actions / Recurring / Tasks
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Override `method_key`:** z. B. Initiative `product` (continuous), ein Project `linear_project` (method `sequential_dependency`) für einen begrenzten Release-Strang
|
||||||
|
- **Audit** bei Override; MVP: manuelle Wahl, kein Designer
|
||||||
|
- **`container_kind`** (bestehend: `project|stream|phase|release`) bleibt **Strukturhint** — orthogonal zu `archetype_key` (Variante 1)
|
||||||
|
|
||||||
|
### 4.4 `project.generic` — bewusst schwach
|
||||||
|
|
||||||
|
**PO:** Default `generic` ohne Ableitung ist ** strukturlos** und **steuerungslos** — nur Notfall.
|
||||||
|
|
||||||
|
| Bevorzugt | Statt generic |
|
||||||
|
|-----------|----------------|
|
||||||
|
| Anlage unter Initiative | Archetyp **erben** |
|
||||||
|
| Thema/Inbox ohne Parent-Project | **Neue Initiative** (`support_queue`) |
|
||||||
|
| Explizit unstrukturiert | generic + Attention „Struktur fehlt“ |
|
||||||
|
|
||||||
|
### 4.5 Referenz — Kumite (Komplexität A1)
|
||||||
|
|
||||||
|
```text
|
||||||
|
Initiative: Karate Kumite (maturity_journey)
|
||||||
|
├── Project: Angriff (maturity_journey) — 5–7 Stufen
|
||||||
|
├── Project: Beinarbeit (maturity_journey)
|
||||||
|
├── … (8 Fähigkeiten)
|
||||||
|
│ └── RoadmapItem maturity_stage je Stufe
|
||||||
|
│ └── RecurringElement: Trainingsroutinen (Varianten)
|
||||||
|
└── Graph: Stufe 3 Angriff REQUIRES Stufe 2 Beinarbeit, Stufe 2 Reaktion, …
|
||||||
|
```
|
||||||
|
|
||||||
|
Kein Sonder-Archetyp „lane“ — nur **Spiegel-Archetyp** + **Graph** + **Roadmap** + **Recurring**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Archetyp-Detail (PO-Spezifikation)
|
||||||
|
|
||||||
|
### A1 — `initiative.maturity_journey` (Reifegrad) — **PO ✓**
|
||||||
|
|
||||||
|
**Nutzerbild:** Karate, Fitness, Fähigkeiten mit **mehrstufigen Reifegradmodellen**, Abhängigkeiten zwischen Fähigkeiten, **Variation** der Übungen. Ziel **entwicklungsbasiert**, nicht fest definierter Endzustand — Fortschritt aus **Historie** und erreichtem (weichen) Status. **Ausprägung** z. B. `maturity.karate_kumite` (8 Fähigkeiten, Stufen-Raster, Routinen-Seed, Voraussetzungs-Graph).
|
||||||
|
|
||||||
|
**Plan:** Projects (Spiegel-Archetyp) + `maturity_stage` RoadmapItems; **Graph** für Voraussetzungen zwischen Stufen/Projects
|
||||||
|
|
||||||
|
**Ist:** `RecurringElement` pro Stufe (Übungsvarianten rotierend); bei Verify `reached` → Recurring-Set wechseln (AP2.0e); Journey dokumentiert Entwicklung
|
||||||
|
|
||||||
|
**Steuerung (`maturity_progression`):**
|
||||||
|
|
||||||
|
- Next Action: heutige Recurring-Instanz + Hinweis auf offenes Stufen-Kriterium
|
||||||
|
- Attention: Stagnation (keine Erfüllung), Stufe ohne Fortschritt über Zeit
|
||||||
|
- **Nicht:** starres „Ziel erreicht = Ende“ — Reifegrad bleibt adaptierbar
|
||||||
|
|
||||||
|
**EFS:** `current_body_focus`, `training_frequency`, `progress_notes`, optional `discipline` (enum: karate, fitness, …)
|
||||||
|
|
||||||
|
**UI-Profil:** Kontrolle dominant; Plan = Stufen; Gates-Graph **aus**; Journey **ein**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### A2 — `initiative.linear_project` (Linear / Einmalprojekt) — **PO ✓**
|
||||||
|
|
||||||
|
**Nutzerbild:** Einmalige Vorhaben (Küche, Umzug, Event). **Ein oder mehrere lineare Pfade** plus **unabhängige/parallele** Aktivitäten — daher **Gate-Graph** als Zielmodell, nicht nur eine Liste.
|
||||||
|
|
||||||
|
**Plan:** Projects + Gates; **mehrere Pfade**, Graph-Designer (AP1.13); kritischer Pfad **dynamisch**
|
||||||
|
|
||||||
|
**Ist:** Actions an Strängen; parallele APs ohne Pfad-Blockade wo erlaubt
|
||||||
|
|
||||||
|
**Steuerung (`sequential_dependency`):**
|
||||||
|
|
||||||
|
- Next Action: nächster **ready** Schritt am gewählten Pfad / kritischen Pfad
|
||||||
|
- Attention: Blocker auf Pfad, Gate at risk, überfälliges `target_date`
|
||||||
|
|
||||||
|
**EFS:** `budget_summary`, `primary_contractor`, `target_completion`
|
||||||
|
|
||||||
|
**UI-Profil:** Plan (Graph/Liste) + Kontrolle; Recurring **aus**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### A3 — `initiative.recurring_program` (Dauerprogramm / Haushalt) — **PO ✓**
|
||||||
|
|
||||||
|
**Nutzerbild:** Rhythmus-Vorhaben (Haus in Ordnung). Steuerung über **Abweichungen und Gesundheit des Systems** — **nicht** über x-fach auflaufende Einzel-Tasks („10× Staubsaugen mit unterschiedlichem Datum“).
|
||||||
|
|
||||||
|
**Plan:** optional Projects (`recurring_program`); Domains **konfigurierbar** (EFS: Raum, Person, Thema)
|
||||||
|
|
||||||
|
**Ist:** `RecurringElement` + `ActionAssignment` pro Actor; **eine** offene Instanz pro Rhythmus — bei Nicht-Erledigung **Eskalation/Score**, kein neuer Duplikat-Task
|
||||||
|
|
||||||
|
**Steuerung (`recurring_control`) — MVP minimal, Zielbild:**
|
||||||
|
|
||||||
|
| Signal | Logik (Ziel) |
|
||||||
|
|--------|----------------|
|
||||||
|
| Dringlichkeit | Datum **+** Anzahl verpasster Zyklen (nicht nur Fälligkeit) |
|
||||||
|
| Regelmäßigkeit | Bonus / grüner Score bei stabil erfüllter Cadence |
|
||||||
|
| Freiwilligkeit | Bonus bei freiwilliger Übernahme fremder offener Rhythmen |
|
||||||
|
| Haushalts-Pool | Offene Rhythmen einer Person für **alle** sichtbar; andere können **freiwillig übernehmen** (Assignment-Wechsel mit Audit) |
|
||||||
|
| Attention | Abweichung vom Soll-Rhythmus, nicht Gesamtliste aller Haus-Tasks |
|
||||||
|
|
||||||
|
**Anti-Pattern:** Jede verpasste Ausführung erzeugt neuen Task → **verboten**. Stattdessen: Recurring-Instanz + Score/Attention.
|
||||||
|
|
||||||
|
**EFS:** `household_members`, `cadence_default`, optional `domain_label` (Küche, Garten, …)
|
||||||
|
|
||||||
|
**UI-Profil:** Ausführen + Team-Health; Plan minimal; **kein** Task-Wall aller Familienmitglieder
|
||||||
|
|
||||||
|
**MVP-Stufe:** **B** (Minimal: fällig/heute ohne Score); **B+** / AP2.0g: Score + freiwillige Übernahme
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### B1 — `initiative.support_queue` (Inbox / Queue) — **PO ✓**
|
||||||
|
|
||||||
|
**Nutzerbild:** **Inbox** für Ad-hoc-Aufgaben („nicht vergessen“), plus **Queue** für bearbeitbare Items. Items müssen **themenbezogen** zuordenbar sein (Initiative, Project, Tag/Thema) — nicht alles in einer globalen Mülltonne.
|
||||||
|
|
||||||
|
**Plan:** Eingang → triage; Queue **unter** Product/Programm **oder** als **eigene Initiative** (Thema = Vorhaben)
|
||||||
|
|
||||||
|
**Ist:** Actions als Tickets; Zuordnung zu Vorhaben/Thema bei Triage oder Commit
|
||||||
|
|
||||||
|
**Steuerung (`queue_pull`):**
|
||||||
|
|
||||||
|
- Next Action: Empfehlung aus Queue **im gewählten Themen-Scope** oder Pull
|
||||||
|
- Attention: SLA, unassigned high-priority
|
||||||
|
|
||||||
|
**EFS:** `queue_policy`, `sla_hours`, `default_topic_ref` (optional)
|
||||||
|
|
||||||
|
**UI-Profil:** Eingang + Ausführen (Queue) dominant; thematische Filter Pflicht
|
||||||
|
|
||||||
|
**MVP-Stufe:** **B** (Inbox + Queue + Themen-Zuordnung minimal)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### B2a — `initiative.program` (Programm, begrenzt) — **PO ✓**
|
||||||
|
|
||||||
|
**Abgrenzung zu Product:** Programm hat **Ziel und Abschluss** (Phasen, Release-Programme, Großvorhaben mit Ende). Lifecycle führt zu **Closure**.
|
||||||
|
|
||||||
|
**Plan:** `RoadmapItem`: `milestone`, `feature`, `review_gate`; Product Backlog im Eingang
|
||||||
|
|
||||||
|
**Ist:** Actions + Tasks; optional Gate- und `work_cycle`-Bindung
|
||||||
|
|
||||||
|
**Steuerung (`program_delivery`):**
|
||||||
|
|
||||||
|
- Next Action: nächstes Gate / AP am Programm-Horizont
|
||||||
|
- Attention: Gate at risk, Blocker, offenes Backlog am aktiven Gate
|
||||||
|
- Lifecycle: Standard inkl. **closure**
|
||||||
|
|
||||||
|
**Komposition B3:** `work_cycle` (Sprint) optional; Sprint kann in Release münden → Übergang in Product-Betrieb
|
||||||
|
|
||||||
|
**UI-Profil:** Plan (Gates) + Kontrolle + Ausführen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### B2b — `initiative.product` (Produkt, kontinuierlich) — **PO ✓**
|
||||||
|
|
||||||
|
**Abgrenzung zu Program:** Produkt = **kontinuierliche Weiterentwicklung** ohne definiertes Ende — **Wartung, Issues, Betrieb** sind Dauer-Themen. Lifecycle **ohne** fixes Closure-Ziel (Adaptation statt Abschluss).
|
||||||
|
|
||||||
|
**Plan:** Gates/Meilensteine als **Orientierung**, nicht als finales End-Gate; Backlog dauerhaft
|
||||||
|
|
||||||
|
**Ist:** Actions (Features, Fixes, Ops); Sprint/`work_cycle` als **Zeitbox** auf Ist-Ebene
|
||||||
|
|
||||||
|
**Steuerung (`continuous_product`):**
|
||||||
|
|
||||||
|
- Next Action: wirkungsvollster Schritt im aktiven Horizont (Gate **oder** aktiver Sprint)
|
||||||
|
- Attention: kritische Issues, technische Schuld, leerer Sprint bei aktivem Zyklus
|
||||||
|
- Lifecycle: **kein** erzwungenes `closure` — `adaptation` / Dauerbetrieb
|
||||||
|
|
||||||
|
**Kairo-Referenz:** Kairo selbst eher **Product** als begrenztes Programm; Vibe-Coding-Sprints hängen hier als `work_cycle`.
|
||||||
|
|
||||||
|
**UI-Profil:** Plan + Kontrolle; Betrieb/Issues sichtbar; Sprint-Banner wenn Zyklus aktiv
|
||||||
|
|
||||||
|
**Technik:** Bestehendes `product_milestone_driven` bleibt Übergangs-Seed bis AP2.0a Split in `program_delivery` + `continuous_product`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### B3 — Sprint / Iteration ( **kein** Initiative-Archetyp) — **PO ✓**
|
||||||
|
|
||||||
|
**PO-Entscheidung:** Sprint ist **kein eigener Vorhaben-Typ**, sondern **Plan-/Ist-Konstrukt** auf Product/Programm — fühlt sich nahe an **Arbeitspaket-Zeitbox** an, kann in Release/Product-Betrieb übergehen.
|
||||||
|
|
||||||
|
**Erstes Setup:** **Product Owner + Vibe Coder** — kein klassisches Dev-Team; **Scrum-Master-Rolle** = Kairo-Steuerungslogik (Next Action, Attention, Sprint-Grenzen).
|
||||||
|
|
||||||
|
**Plan:** `RoadmapItem(type=work_cycle)` — optional, nicht jedes Product braucht Sprints
|
||||||
|
|
||||||
|
**Ist:** Actions mit optional `work_cycle_id`; Sprint kann **klein** sein (1–3 APs)
|
||||||
|
|
||||||
|
**Steuerung (`agile_iteration` Profil):** Hook auf `continuous_product` / `program_delivery` wenn aktiver Zyklus
|
||||||
|
|
||||||
|
**Offen (bewusst):** Ob Sprint langfristig eher `Action`-Granularität oder `work_cycle`-Granularität — MVP: `work_cycle` minimal, ohne Team-Archetyp
|
||||||
|
|
||||||
|
**MVP-Stufe A:** ein aktiver Zyklus auf Kairo-Product, Next Action im Zyklus — **ohne** Team-Board
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### C1 — `initiative.dispute_case` (Miterstreit) — **PO ✓ Katalog, nicht MVP**
|
||||||
|
|
||||||
|
**Nutzerbild:** **Reaktiv**, nicht planerisch — aus **Status** entstehen fortlaufend neue Handlungsstränge und Aufgaben (Fristen, Entscheidungen, Reaktionen).
|
||||||
|
|
||||||
|
**Plan:** Phasen-Gates als Orientierung; Iterationen (Reopen) mit Decision-Pflicht
|
||||||
|
|
||||||
|
**Ist:** Decisions, Evidence, Fristen auf Gates/Actions
|
||||||
|
|
||||||
|
**Steuerung (`dispute_procedure`):** Next Action: nächste Frist / offene Entscheidung / neuer Strang aus Statuswechsel
|
||||||
|
|
||||||
|
**MVP-Stufe C:** Katalog + Profilfelder; UI spezialisiert post-MVP
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### D1 — `initiative.content_project` (Inhalt / Kapitel) — **PO ✓ MVP Stufe B**
|
||||||
|
|
||||||
|
**Nutzerbild:** Buch- und Konzeptprojekte — generischer Archetyp; **Ausprägung** z. B. `content.book_writing` mit Kapitel-Seed, Mitwirkenden, Vorbefüllung.
|
||||||
|
|
||||||
|
**Plan:** `RoadmapItem(type=chapter)` + `review_gate`
|
||||||
|
|
||||||
|
**Ist:** Actions (Schreib-APs, Recherche)
|
||||||
|
|
||||||
|
**Steuerung (`chapter_based_progression`):** Next Action: nächstes Kapitel / Review / Schreib-AP
|
||||||
|
|
||||||
|
**Ausprägung `content.book_writing` (Schicht 3):** Gliederungs-Template, `word_count_goal`, Rollen (Autor, Lector), Kategorien
|
||||||
|
|
||||||
|
**MVP-Stufe B:** Archetyp + eine Ausprägung als Seed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Plan-/Ist-Muster (übergreifend)
|
||||||
|
|
||||||
|
```text
|
||||||
|
Eingang Plan (optional) Ist Steuerung
|
||||||
|
maturity_journey selten maturity_stages Recurring heutige Übung
|
||||||
|
linear_project selten Gate-Graph Actions kritischer Pfad
|
||||||
|
recurring_program selten Domains Recurring fällig/heute
|
||||||
|
support_queue triage Queue-Streams Actions (Tickets) Pull/Empfehlung
|
||||||
|
program Product Backlog milestones, gates Actions+Tasks Gate-Horizont + Closure
|
||||||
|
product Product Backlog milestones (orientierend) Actions+Tasks+Ops Next Step + Dauerbetrieb
|
||||||
|
(work_cycle) — work_cycles on B2 Actions (Zeitbox) Sprint Next Action (Profil)
|
||||||
|
dispute_case Eingang phase gates Decisions+Evidence reaktiv: Frist/Strang
|
||||||
|
content_project Ideen chapters Actions (Schreib-AP) nächstes Kapitel
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Scope Lock
|
||||||
|
|
||||||
|
| Verboten | Erlaubt |
|
||||||
|
|----------|---------|
|
||||||
|
| React-Formulare pro Archetyp hardcoden | FieldRenderer + Registry |
|
||||||
|
| OM-Tabelle `disputes`, `habits`, `sprints` | EFS + RoadmapItem + bestehendes OM |
|
||||||
|
| Steering-Heuristiken in Routern | `backend/steering/` |
|
||||||
|
| Alle Methoden voll implementieren vor A-Abnahme | Stubs + A1/A2/B2/B3-minimal zuerst |
|
||||||
|
| Archetyp ohne `method_key`-Bindung | Seed + Sync |
|
||||||
|
| Sprint-Backlog als BacklogItem-Liste | Actions mit `work_cycle_id` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Implementierungspakete
|
||||||
|
|
||||||
|
```text
|
||||||
|
AP2.0a Method-Stubs: maturity_progression, sequential_dependency, recurring_control,
|
||||||
|
queue_pull, program_delivery, continuous_product, agile_iteration (Profil),
|
||||||
|
dispute_procedure (stub), chapter_based_progression (stub)
|
||||||
|
AP2.0b entity_archetypes Seeds (Initiative + Project Spiegel); projects.archetype_key;
|
||||||
|
EFS profiles; 2–3 Referenz-Ausprägungen (Seeds): kumite, book_writing, kairo_dev
|
||||||
|
AP2.0c Kontrolle-Lagebild: method_key, lifecycle, next action, attention (UI)
|
||||||
|
AP2.0d Next-Action-Strategien: maturity, sequential, recurring, queue (minimal)
|
||||||
|
AP2.0e Recurring-Stufenwechsel bei maturity_stage reached (A1)
|
||||||
|
AP2.0f work_cycle + actions.work_cycle_id; Sprint auf Product/Programm; agile_iteration Profil
|
||||||
|
AP2.0g A3 Score + freiwillige Übernahme (recurring_control erweitert) — Stufe B+
|
||||||
|
AP2.1 Validation Report v0.3 — A1, A2, B2b (Kairo Product), D1 mit echten Daten
|
||||||
|
```
|
||||||
|
|
||||||
|
Erweitert AP1.10 — **ersetzt nicht** EFS-Architektur, nutzt sie.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Risiko
|
||||||
|
|
||||||
|
| Risiko | Mitigation |
|
||||||
|
|--------|------------|
|
||||||
|
| Methoden-Overengineering | Stubs + eine Strategie pro A-Archetyp |
|
||||||
|
| B2/B3 Verwechslung | Kompositions-Regel §2.3; UI zeigt aktiven Horizont |
|
||||||
|
| Sprint = Todo-Wand | Default-Ansicht Sprint-Next-Action, nicht alle Actions |
|
||||||
|
| dispute_case zu groß | Stufe C |
|
||||||
|
| work_cycle ohne Migration | AP2.0f explizit, FK auf roadmap_items |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. PO-Freigabe
|
||||||
|
|
||||||
|
- [x] Initiative-Archetypen A1–D1 — **2026-07-10** (Details §5)
|
||||||
|
- [x] Project-Archetypen — **Spiegel-Modell §4** (2026-07-10)
|
||||||
|
- [x] Vier-Schichten-Modell §2.0 (Framework → Methode → Archetyp → Ausprägung)
|
||||||
|
- [x] Methoden-Keys §3.2 inkl. `program_delivery`, `continuous_product`, `agile_iteration`-Profil
|
||||||
|
- [x] B3 ohne eigenen Archetyp; Sprint/`work_cycle` auf Product/Programm
|
||||||
|
- [x] A3 Score-Logik Zielbild §5; MVP minimal, AP2.0g für Score/Übernahme
|
||||||
|
- [x] MVP-Stufen A/B/C (§3.1)
|
||||||
|
- [x] AP2.0-Reihenfolge §8 inkl. AP2.0f/2.0g
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. PO-Beschluss — Kurzfassung
|
||||||
|
|
||||||
|
**Gültig ab 2026-07-10.** Verbindlich für MVP v0.3 und AP2.0-Reihenfolge.
|
||||||
|
|
||||||
|
1. **Vier Schichten:** Framework → **Methode (Modul/Registry)** → **generischer Archetyp** → **Ausprägung (Profile)** → Integrationen später (MCP, Gitea, KI).
|
||||||
|
2. **Initiative-Archetypen:** A1–A3, B1, B2a/B2b, B3 als Profil, C1 Katalog, D1 Stufe B — Portfolio vollständig im Katalog.
|
||||||
|
3. **Project-Archetypen:** 1:1-Spiegel der Initiative; Struktur via Graph/Roadmap/EFS; Override `method_key` erlaubt; `generic` nur Notfall.
|
||||||
|
4. **Agile:** Product Backlog = Eingang; Sprint = `work_cycle`; Sprint-Backlog = Actions mit `work_cycle_id`; kein Kanban/Burndown-Kern.
|
||||||
|
5. **Program vs Product:** unterschiedlicher Lifecycle (Abschluss vs. Dauerbetrieb); gleiche Steuerungsbausteine.
|
||||||
|
6. **Nächster Code-Auftrag nach Push-Freigabe:** AP2.0a → 2.0b → 2.0c (kein Plan-Politur ohne Steuerung).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Referenzen
|
||||||
|
|
||||||
|
- `docs/product/Kairo_MVP_Definition_v0.3.md`
|
||||||
|
- `docs/architecture/ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`
|
||||||
|
- `docs/architecture/Kairo_Target_Architecture_Method_Driven_Adaptive_Steering_Core_v0.1.md`
|
||||||
|
- `docs/architecture/Kairo_Method_Design_Principles_v0.1.md`
|
||||||
|
- `docs/product/Kairo_Canonical_Operating_Model_v0.2.md`
|
||||||
|
- `backend/steering/methods/registrations/generic_operating.py`
|
||||||
|
- `backend/steering/methods/registrations/product_milestone_driven.py`
|
||||||
|
|
@ -65,7 +65,8 @@ Verhindert, dass Zielbild-Dokumente als Ist-Stand gelesen werden.
|
||||||
| steering_contexts (009) | ✓ | Lifecycle, method_key |
|
| steering_contexts (009) | ✓ | Lifecycle, method_key |
|
||||||
| backend/steering/ lifecycle | ✓ | |
|
| backend/steering/ lifecycle | ✓ | |
|
||||||
| Signal Engine | ◐ | Regeln begrenzt |
|
| Signal Engine | ◐ | Regeln begrenzt |
|
||||||
| Method Registry | ◐ | generic_operating, product_milestone_driven |
|
| Method Registry | ◐ | generic_operating, product_milestone_driven; **Ziel AP2.0a:** program_delivery, continuous_product, … — siehe `ADP_Archetype_and_Method_Catalog_v0.2.md` |
|
||||||
|
| Archetyp-/Methoden-Katalog PO | ✓ | ADP v0.2 + MVP v0.3 freigegeben 2026-07-10 |
|
||||||
| NextActionCandidate | ◐ | API + Widget; nicht konfigurierbar auf beiden Ebenen |
|
| NextActionCandidate | ◐ | API + Widget; nicht konfigurierbar auf beiden Ebenen |
|
||||||
| Portfolio-Priorität (Initiativen) | ✗ | |
|
| Portfolio-Priorität (Initiativen) | ✗ | |
|
||||||
| Situativer Steuerungskontext (Next Action) | ✗ | 📄 Vision §7.6 |
|
| Situativer Steuerungskontext (Next Action) | ✗ | 📄 Vision §7.6 |
|
||||||
|
|
|
||||||
223
docs/product/Kairo_MVP_Definition_v0.3.md
Normal file
223
docs/product/Kairo_MVP_Definition_v0.3.md
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
# Jinkendo Kairo
|
||||||
|
## MVP Definition v0.3
|
||||||
|
|
||||||
|
**Status:** PO-freigegeben (bezogen auf `ADP_Archetype_and_Method_Catalog_v0.2.md`)
|
||||||
|
**Stand:** 2026-07-10
|
||||||
|
**Auslöser:** Programm-Director-Ziel vs. flache Vorhabenliste; private und professionelle Vorhaben gleichwertig; Steuerung vor Status-Monitoring; **Agile vollständig** (Backlog ✓, Sprint/Iteration ○)
|
||||||
|
**Bezug:** `Kairo_Vision_and_Product_Direction_v0.2.md`, `Kairo_Canonical_Operating_Model_v0.2.md`, `ADP_Archetype_and_Method_Catalog_v0.2.md`
|
||||||
|
**Ersetzt als MVP-Nordstern:** implizite Annahme „MVP = Software-Programm mit Gates + Tasks“ in Sprint-Delivery; **nicht** die technische Roadmap v0.2 (bleibt Referenz für AP-Reihenfolge)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Nordstern
|
||||||
|
|
||||||
|
Kairo ist der **operative Program Director** — nicht ein To-do-Tool.
|
||||||
|
|
||||||
|
**Leitfrage (unverändert):**
|
||||||
|
|
||||||
|
> Welcher nächste Schritt bringt dieses Vorhaben **jetzt** am wirksamsten voran — und **warum**?
|
||||||
|
|
||||||
|
Der MVP ist erreicht, wenn ein Nutzer **mehrere typische Vorhabenarten** (privat und professionell) in Kairo **erfassen, steuern und nachvollziehen** kann — **ohne** dass die Oberfläche in unendliche To-do-Listen kollabiert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Was der MVP **ist** und **nicht ist**
|
||||||
|
|
||||||
|
### MVP ist
|
||||||
|
|
||||||
|
- **Steuerung sichtbar:** Methode, Lifecycle, Attention, Next Action (begründet) — nicht nur Status-Ampeln
|
||||||
|
- **Schichtenmodell:** Framework → Methode (Registry) → Archetyp (Baukasten) → Ausprägung (z. B. Buch, Kumite) — siehe ADP §2.0
|
||||||
|
- **Archetyp-gesteuert:** Vorhaben- und Projekt-Typ bestimmt Default-Methode, Felder, dominante Modus-Ansichten
|
||||||
|
- **Plan vs. Ist getrennt:** Eingang ≠ committete Arbeit; Recurring ≠ Backlog; **Product Backlog ≠ Sprint-Backlog**
|
||||||
|
- **Agile zweigleisig:** Release-Horizont (Gates, B2) **und** Iterations-Horizont (Sprint/`work_cycle`, B3) — komponierbar
|
||||||
|
- **Referenz-Portfolio:** mehrere Vorhaben **unterschiedlicher Typen** parallel im Tenant, davon **2–3 voll** durchspielbar
|
||||||
|
- **Historie:** Journey als steuerungsrelevante Narrative (inkl. rückwirkender Erfassung wichtiger Ereignisse)
|
||||||
|
|
||||||
|
### MVP ist nicht
|
||||||
|
|
||||||
|
- Vollständiger Import aus externen Tools
|
||||||
|
- Tenant-Admin-UI für Archetyp-Designer
|
||||||
|
- KI/Prompt/Workflow/MCP (bleibt eingefroren)
|
||||||
|
- Alle Archetypen **gleichzeitig voll implementiert** — Katalog ja, Vollimplementierung gestaffelt
|
||||||
|
- **Kanban-Board, Velocity, Burndown** als Kern
|
||||||
|
- Gantt-/Capacity-Planung
|
||||||
|
- Ersatz für Mitai/Shinkan oder Rechts-/Gesundheits-Spezialsoftware
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Anti-Patterns (explizit verboten im MVP-Slice)
|
||||||
|
|
||||||
|
| Verboten | Warum |
|
||||||
|
|----------|--------|
|
||||||
|
| Hauptbild = flache Liste aller offenen Actions/Tasks | Todo-Explosion; widerspricht Program Director |
|
||||||
|
| Archetyp nur als Formular-Label ohne Methode/Steuerung | Täuscht Vielfalt vor |
|
||||||
|
| Annahme „Vorhaben = Software-Release“ | schließt private Vorhaben aus |
|
||||||
|
| **Sprint-Backlog als BacklogItem-Liste** | Sprint = committete Actions am `work_cycle` |
|
||||||
|
| Plan-Modus ausbauen ohne Kontrolle/Steuerung | Monitoring ohne Begleitung |
|
||||||
|
| Neue OM-Tabellen pro Archetyp (`sprints`, `habits`, …) | Scope Lock — Method Registry + EFS + OM |
|
||||||
|
| Steering-Logik in Routern oder Frontend hardcoden | nur `backend/steering/` + Registry |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Referenz-Portfolio (Archetyp-Katalog)
|
||||||
|
|
||||||
|
Vollständige Matrix: **`ADP_Archetype_and_Method_Catalog_v0.2.md`** §3.
|
||||||
|
|
||||||
|
| ID | Typ | Beispiel | Default-Methode | Agile-Bezug |
|
||||||
|
|----|-----|----------|-------------------|-------------|
|
||||||
|
| **A1** | Reifegrad | Spagat können | `maturity_progression` | — |
|
||||||
|
| **A2** | Linear / Wasserfall | Neue Küche | `sequential_dependency` | — |
|
||||||
|
| **A3** | Dauerprogramm / Rhythmus | Haus in Ordnung | `recurring_control` | — |
|
||||||
|
| **B1** | Queue / Supportdesk | Tickets | `queue_pull` | Pull statt Board |
|
||||||
|
| **B2a** | Programm (begrenzt) | Release-Programm | `program_delivery` | Release + Abschluss |
|
||||||
|
| **B2b** | Produkt (kontinuierlich) | Kairo, Betrieb | `continuous_product` | Dauerbetrieb + Issues |
|
||||||
|
| **B3** | Sprint-Zeitbox *(Profil, kein Archetyp)* | PO + Vibe-Coder | `agile_iteration` | Zeitbox auf B2b |
|
||||||
|
| **C1** | Verfahren / Konflikt | Miterstreit | `dispute_procedure` | reaktiv, Katalog |
|
||||||
|
| **D1** | Inhalt / Kapitel | Buch, Konzept | `chapter_based_progression` | **Stufe B** |
|
||||||
|
|
||||||
|
### B2a vs B2b vs B3 (PO 2026-07-10)
|
||||||
|
|
||||||
|
- **Programm:** Ziel, Phasen, **Abschluss** — z. B. Release-Programm
|
||||||
|
- **Product:** **Kein** fixes Ende — Wartung, Issues, Weiterentwicklung; Kairo selbst = Product
|
||||||
|
- **Sprint:** Kein eigener Vorhaben-Typ — `work_cycle` auf Product/Programm; nahe an Arbeitspaket-Zeitbox
|
||||||
|
|
||||||
|
### MVP-Abnahfe-Priorität
|
||||||
|
|
||||||
|
| Stufe | Archetypen | Bedeutung |
|
||||||
|
|-------|------------|-----------|
|
||||||
|
| **Abnahfe A** | A1, A2, B2b (+ B3 minimal auf Kairo-Product) | Reifegrad, Linear, Kairo Product + optional Sprint |
|
||||||
|
| **Abnahfe B** | A3, B1, **D1**, B3 ausgebaut | Haushalt-Score (AP2.0g), Inbox/Queue, Buch |
|
||||||
|
| **Katalog C** | C1 | Miterstreit — Spezifikation, nicht MVP |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. MVP-Nutzbarkeits-Bar (v0.3)
|
||||||
|
|
||||||
|
Kairo ist **MVP-nah**, wenn ein Nutzer **pro Archetyp der Stufe A**:
|
||||||
|
|
||||||
|
1. Ein Vorhaben **anlegt** (Initiative-Archetyp, Default-Methode, Profil/EFS)
|
||||||
|
2. Die **passende Struktur** modelliert (Reifegrad-Stufen / Gate-Kette / Sprint-Zyklen — methodenabhängig)
|
||||||
|
3. **Ist** committet (Actions, Tasks, Recurring — nicht alles gleichzeitig sichtbar)
|
||||||
|
4. In **Kontrolle** den **Lagebild-Steuerungskern** sieht: Lifecycle, Methode, 1–3 Next Actions, Attention — **mit Begründung**
|
||||||
|
5. In **Journey** Entwicklung und Abweichungen **nachvollzieht** (min. 5 steuerungsrelevante Events, auch rückwirkend)
|
||||||
|
6. **Ohne CRUD-Wand** in ≤2 Minuten die Leitfrage für dieses Vorhaben beantworten kann
|
||||||
|
|
||||||
|
**Portfolio-Ebene (zusätzlich):**
|
||||||
|
|
||||||
|
7. Auf **Cockpit** sieht, **welches** Vorhaben welche Art von Attention braucht — nicht Details aller offenen Tasks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Steuerung vs. Monitoring
|
||||||
|
|
||||||
|
| Monitoring (reicht nicht) | Steuerung (MVP-Pflicht) |
|
||||||
|
|---------------------------|-------------------------|
|
||||||
|
| „12 offen“ | „Nächster Schritt: X, weil Gate Y blockiert / Stufe Z / **Sprint endet Freitag**“ |
|
||||||
|
| Status-Dropdown | Lifecycle-Übergang + Methode |
|
||||||
|
| Alle Tasks listen | Recurring: **heute fällig**; Queue: **nächster Pull**; Reifegrad: **aktuelle Übung**; Sprint: **1–3 Items im aktiven Zyklus** |
|
||||||
|
| Journey als Archiv | Journey + Decision als **Plan-Abweichung** |
|
||||||
|
| Product Backlog als Hauptliste | Sprint-Modus: **nur Sprint-Backlog** als Default |
|
||||||
|
|
||||||
|
Technische Anker: `steering_context.method_key`, `backend/steering/`, NextActionCandidate, AttentionItem, Method Registry, `actions.work_cycle_id` (AP2.0f).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Todo-Explosion verhindern (verbindliche UI-Regeln)
|
||||||
|
|
||||||
|
1. **Default-Ansicht** pro Methode zeigt **Next Action** (1–3), nicht Gesamtbestand
|
||||||
|
2. **Recurring** erscheint in Rhythmus-Ansicht, nicht im Action-Backlog
|
||||||
|
3. **Backlog/Eingang** (Product Backlog) getrennt von committeter Arbeit und von **Sprint-Backlog**
|
||||||
|
4. **Plan** (Gates, Graph, Stufen, **Sprints**) = Orientierung; **Ist** = Ausführung
|
||||||
|
5. **Drill-down** zu vollen Listen nur auf explizite Nutzeraktion („Alle anzeigen“)
|
||||||
|
6. **Scope:** Portfolio → Vorhaben → Projekt filtert sichtbare Operative
|
||||||
|
7. **Aktiver Sprint:** Ausführen-Modus default = Sprint-Backlog, nicht Product Backlog
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Abnahme-Szenarien (konkret)
|
||||||
|
|
||||||
|
### A1 — Spagat (Reifegrad)
|
||||||
|
|
||||||
|
- Stufen als `maturity_stage` RoadmapItems
|
||||||
|
- Recurring-Übungen; bei Stufenübergang **andere** Routine
|
||||||
|
- Kontrolle: aktuelle Stufe + heutige Übung + Kriterium bis nächste Stufe
|
||||||
|
- **Nicht:** 200 Übungs-Tasks in der Hauptliste
|
||||||
|
|
||||||
|
### A2 — Küche (Wasserfall)
|
||||||
|
|
||||||
|
- Primärstrang mit Abhängigkeiten (Graph oder sequenzielle Liste)
|
||||||
|
- Begleitprojekte parallel
|
||||||
|
- Kontrolle: kritischer Pfad / nächster blockierender Schritt
|
||||||
|
- **Nicht:** alle Handwerker-Schritte als flache Todo-Liste
|
||||||
|
|
||||||
|
### B2b — Kairo (Product, kontinuierlich)
|
||||||
|
|
||||||
|
- Gates/Meilensteine als Orientierung; Backlog im Eingang; Issues/Betrieb als Dauer-Thema
|
||||||
|
- Optional: `work_cycle` (Sprint-Zeitbox) für PO + Vibe Coder
|
||||||
|
- Kontrolle: Next Action im aktiven Horizont (Gate **oder** Sprint) — begründet
|
||||||
|
- **Nicht:** alle APs aller Gates gleichzeitig in der Hauptliste
|
||||||
|
|
||||||
|
### B3 — Sprint-Zeitbox (Profil auf Product, kein eigener Archetyp)
|
||||||
|
|
||||||
|
- Optional ein aktiver `work_cycle`; 1–3 Actions in der Zeitbox
|
||||||
|
- Kairo-Steuerung statt Scrum-Master-Rolle
|
||||||
|
- **Nicht:** Team-Board, Velocity
|
||||||
|
|
||||||
|
### D1 — Buch / Konzept (Stufe B)
|
||||||
|
|
||||||
|
- Kapitel als `chapter` RoadmapItems; mindestens ein Schreib-AP committet
|
||||||
|
- Kontrolle: nächstes Kapitel / aktuelles Schreib-AP
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Implementierungsfolge (nach PO-Freigabe dieses Dokuments)
|
||||||
|
|
||||||
|
**Kein weiterer „Plan-Modus-Politur“-Slice ohne Steuerungs-Bezug.**
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. ADP Archetype & Method Catalog v0.2 — ✓ PO-freigegeben 2026-07-10
|
||||||
|
2. AP2.0a Method Registry: Stubs inkl. program_delivery, continuous_product, agile_iteration
|
||||||
|
3. AP2.0b Archetyp-Seeds (Initiative + Project Spiegel); EFS; Referenz-Ausprägungen (Kumite, Buch, Kairo)
|
||||||
|
4. AP2.0c Kontrolle/Lagebild: Methode + Next Action + Attention (Hauptfläche)
|
||||||
|
5. AP2.0d Next-Action-Strategien: maturity, sequential, recurring, queue (minimal)
|
||||||
|
6. AP2.0f work_cycle + actions.work_cycle_id; Sprint auf Product; agile_iteration Profil
|
||||||
|
7. AP2.0g A3 Score + freiwillige Übernahme (Stufe B+)
|
||||||
|
8. AP2.1 Referenz-Abnahme A1, A2, B2b (+ B3 minimal), D1 (Validation v0.3)
|
||||||
|
9. Parallel wenn tragfähig: AP1.13 Gate-Graph für A2/B2 — nicht Default für alle
|
||||||
|
```
|
||||||
|
|
||||||
|
Bestehende APs (1.12, 1.10, 1.5d) bleiben **Infrastruktur** — werden im MVP v0.3 erst **wertvoll**, wenn 2.0c/2.0d/2.0f sie archetyp- und methodengebunden nutzen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Dokumentenpriorität bei Konflikten
|
||||||
|
|
||||||
|
Bei MVP-Fragen gilt:
|
||||||
|
|
||||||
|
1. Dieses Dokument (v0.3) + `ADP_Archetype_and_Method_Catalog_v0.2.md`
|
||||||
|
2. `Kairo_Vision_and_Product_Direction_v0.2.md`
|
||||||
|
3. `Kairo_Canonical_Operating_Model_v0.2.md`
|
||||||
|
4. `Kairo_Corrected_MVP_Roadmap_v0.2.md` (AP-Reihenfolge, technisch)
|
||||||
|
5. Sprint Completion Reports (historisch)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. PO-Freigabe
|
||||||
|
|
||||||
|
- [x] Nordstern und Anti-Patterns akzeptiert
|
||||||
|
- [x] Referenz-Portfolio A1–D1 als Katalog akzeptiert
|
||||||
|
- [x] Vier-Schichten-Modell (ADP §2.0) akzeptiert
|
||||||
|
- [x] B2a/B2b + B3-Profil; Project-Spiegel-Modell akzeptiert
|
||||||
|
- [x] Abnahfe Stufe A = A1 + A2 + B2b + B3-minimal; Stufe B = A3, B1, D1
|
||||||
|
- [x] Sprint-Semantik (Product Backlog vs. Sprint-Backlog) akzeptiert
|
||||||
|
- [x] Implementierungsfolge §9 akzeptiert
|
||||||
|
- [x] Kein MVP-Fortschritt mehr ohne sichtbare Steuerung pro Archetyp
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Referenzen
|
||||||
|
|
||||||
|
- `docs/architecture/ADP_Archetype_and_Method_Catalog_v0.2.md`
|
||||||
|
- `docs/architecture/Kairo_Method_Design_Principles_v0.1.md`
|
||||||
|
- `docs/architecture/Kairo_Target_Architecture_Method_Driven_Adaptive_Steering_Core_v0.1.md`
|
||||||
|
- `docs/product/Kairo_Implementation_Truth_Table_v0.1.md`
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
# AP2.0 — Steering, Archetypen & Ausprägungen (Minimal Complete Slice)
|
||||||
|
## Implementierungsauftrag v0.1
|
||||||
|
|
||||||
|
**Status:** umgesetzt (2026-07-10)
|
||||||
|
**Stand:** 2026-07-10
|
||||||
|
**PO-Basis:** `ADP_Archetype_and_Method_Catalog_v0.2.md` §11, `Kairo_MVP_Definition_v0.3.md`
|
||||||
|
**Vorgänger:** AP1.10 (EFS), AP1.1 (Method Registry), AP1.9 (Kontrolle-Shell)
|
||||||
|
**Zielversion:** `0.18.0-ap2.0` · Schema `019`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Ziel
|
||||||
|
|
||||||
|
Erster **Minimal Complete Steering Slice**: Archetyp-Katalog und Methoden-Module sind registriert; neues Vorhaben startet mit **passender Default-Methode**; **Kontrolle** zeigt Methode, Archetyp, Lifecycle, Next Actions **mit Begründung** — nicht nur Zähler.
|
||||||
|
|
||||||
|
**Leitfrage-Test (MVP §5):** Nutzer kann für ein Kairo-Product-Vorhaben in ≤2 Minuten beantworten: *Was ist als Nächstes dran — und warum?*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Vier Schichten — was dieser Slice liefert
|
||||||
|
|
||||||
|
| Schicht | AP2.0 | Nicht in AP2.0 |
|
||||||
|
|---------|-------|----------------|
|
||||||
|
| **0 Framework** | unverändert nutzen | Waiting Runtime, Workflow |
|
||||||
|
| **1 Methode** | **2.0a** — alle Keys registriert; 2 Strategien (program/continuous) | Volle Builder, KI |
|
||||||
|
| **2 Archetyp** | **2.0b** — Initiative + Project Spiegel, Default-Methode | Tenant-Designer |
|
||||||
|
| **3 Ausprägung** | **2.0b** — 3 Code-Seeds (Kumite, Buch, Kairo) | `method_profiles`-DB, UI |
|
||||||
|
| **4 Integration** | — | MCP, Gitea, KI |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Arbeitspakete
|
||||||
|
|
||||||
|
### AP2.0a — Method Registry erweitern
|
||||||
|
|
||||||
|
**DoD:**
|
||||||
|
|
||||||
|
- [ ] Registriert: `program_delivery`, `continuous_product`, `maturity_progression`, `sequential_dependency`, `recurring_control`, `queue_pull`, `agile_iteration`, `dispute_procedure`, `chapter_based_progression`
|
||||||
|
- [ ] Legacy `product_milestone_driven` bleibt (Alias-Kompatibilität)
|
||||||
|
- [ ] Next-Action-Strategien: `program_delivery` (Gate-Horizont), `continuous_product` (Ist zuerst, dann Plan)
|
||||||
|
- [ ] Stubs nutzen `default`-Strategy bis AP2.0d
|
||||||
|
- [ ] `GET /api/steering/methods` listet alle Methoden
|
||||||
|
- [ ] pytest: Methoden registriert, unbekannte Keys abgewiesen
|
||||||
|
|
||||||
|
**Nicht-Scope:** Structure Builder, Hook-Handler mit MCP, Method Profiles DB.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### AP2.0b — Archetyp- & Project-Spiegel
|
||||||
|
|
||||||
|
**DoD:**
|
||||||
|
|
||||||
|
- [ ] `entity_archetypes` Seeds: alle Initiative-Archetypen aus ADP §3.1 + Project-Spiegel §4.1
|
||||||
|
- [ ] Jeder Initiative-Archetyp: `default_method_key` (Code-Registry, API-Response)
|
||||||
|
- [ ] Migration **019**: `projects.archetype_key` NULL → Default = Mirror der Initiative bei INSERT
|
||||||
|
- [ ] `create_initiative` → SteeringContext mit **Archetyp-Default-Methode** (nicht blind `generic_operating`)
|
||||||
|
- [ ] `create_project` → `archetype_key` = Mirror der Initiative
|
||||||
|
- [ ] 3 Referenz-**Ausprägungen** (Code-Seeds): `maturity.karate_kumite`, `content.book_writing`, `product.kairo_dev`
|
||||||
|
- [ ] EFS: mindestens Felder für `initiative.product`, `initiative.content_project`, `initiative.maturity_journey`
|
||||||
|
- [ ] pytest: Product → `continuous_product`; Project erbt Archetyp
|
||||||
|
|
||||||
|
**Nicht-Scope:** Graph-Designer, Score-Logik (→ AP2.0g), `method_profiles`-Tabelle.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### AP2.0c — Kontrolle / Lagebild
|
||||||
|
|
||||||
|
**DoD:**
|
||||||
|
|
||||||
|
- [ ] `steering-snapshot` enthält: `archetype_key`, `archetype_label`, optional `method_profile_key`, `steering_guidance` (1 Satz)
|
||||||
|
- [ ] Next Actions enthalten `reason_code` / `recommended_action` sichtbar in UI
|
||||||
|
- [ ] `SteeringSnapshotPanel`: Archetyp-Zeile, Guidance, Attention aus Signals
|
||||||
|
- [ ] Kein neues Omnibus-CRUD; nutzt bestehende Kontrolle-Route (`ControlStatusPage`)
|
||||||
|
- [ ] pytest: Snapshot-Felder für Product-Initiative
|
||||||
|
|
||||||
|
**Nicht-Scope:** Burndown, Kanban, Sprint-UI (→ AP2.0f), Gate-Graph (→ AP1.13).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Referenz-Abnahme (manuell nach Deploy)
|
||||||
|
|
||||||
|
1. Vorhaben **Kairo** anlegen: Archetyp `initiative.product` → Methode `continuous_product`
|
||||||
|
2. Kontrolle: Lifecycle, Methode, Archetyp, ≥1 Next Action mit Begründung
|
||||||
|
3. Project anlegen → `archetype_key` = `project.product`
|
||||||
|
4. Optional: Archetyp `initiative.content_project` + Feldprofil sichtbar
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Explizit nicht in AP2.0
|
||||||
|
|
||||||
|
- Kanban-Board, Velocity, Burndown
|
||||||
|
- `work_cycle` / Sprint (`actions.work_cycle_id`) — AP2.0f
|
||||||
|
- A3 Score / freiwillige Übernahme — AP2.0g
|
||||||
|
- Gate-Graph-Designer — AP1.13
|
||||||
|
- MCP / Gitea / KI-Anbindung — eingefroren
|
||||||
|
- `method_profiles` PostgreSQL-Tabelle
|
||||||
|
- Archetyp-Designer Admin-UI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Reihenfolge & Abhängigkeiten
|
||||||
|
|
||||||
|
```text
|
||||||
|
AP2.0a → AP2.0b → AP2.0c (ein Release-Strang 0.18.0-ap2.0)
|
||||||
|
Danach: AP2.0d (Strategien pro Archetyp), AP2.0f (Sprint), AP2.0g (Score)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Guardrail:** Kein AP1.12/Plan-Politur-Commit ohne Bezug zu §3 AP2.0c DoD.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Referenzen
|
||||||
|
|
||||||
|
- `docs/architecture/ADP_Archetype_and_Method_Catalog_v0.2.md`
|
||||||
|
- `docs/product/Kairo_MVP_Definition_v0.3.md`
|
||||||
|
- `docs/architecture/Kairo_Method_Design_Principles_v0.1.md`
|
||||||
|
- `docs/sprints/Sprint1_AP1_1_Method_Registry_Assignment_v0.1.md`
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "kairo-jinkendo-frontend",
|
"name": "kairo-jinkendo-frontend",
|
||||||
"version": "0.17.0-ap1.5d",
|
"version": "0.18.0-ap2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,11 @@ export function SteeringSnapshotPanel({
|
||||||
lifecycle_label,
|
lifecycle_label,
|
||||||
method_key,
|
method_key,
|
||||||
method_label,
|
method_label,
|
||||||
|
archetype_key,
|
||||||
|
archetype_label,
|
||||||
|
method_profile_key,
|
||||||
|
steering_guidance,
|
||||||
|
attention_items = [],
|
||||||
signals = [],
|
signals = [],
|
||||||
counts,
|
counts,
|
||||||
upcoming_milestones = [],
|
upcoming_milestones = [],
|
||||||
|
|
@ -74,6 +79,9 @@ export function SteeringSnapshotPanel({
|
||||||
<h2 className="steering-hero-title">
|
<h2 className="steering-hero-title">
|
||||||
Wo stehe ich — und was ist als Nächstes dran?
|
Wo stehe ich — und was ist als Nächstes dran?
|
||||||
</h2>
|
</h2>
|
||||||
|
{steering_guidance && (
|
||||||
|
<p className="steering-guidance">{steering_guidance}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<span className="badge status-badge status-active steering-lifecycle-badge">
|
<span className="badge status-badge status-active steering-lifecycle-badge">
|
||||||
{displayLabel}
|
{displayLabel}
|
||||||
|
|
@ -81,6 +89,12 @@ export function SteeringSnapshotPanel({
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="steering-hero-toolbar">
|
<div className="steering-hero-toolbar">
|
||||||
|
{(archetype_label || archetype_key) && (
|
||||||
|
<p className="steering-archetype-row muted">
|
||||||
|
Archetyp: <strong>{archetype_label || archetype_key}</strong>
|
||||||
|
{method_profile_key ? ` · Ausprägung: ${method_profile_key}` : ''}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
{(method_label || canManageMethod) && (
|
{(method_label || canManageMethod) && (
|
||||||
<p className="steering-method-row">
|
<p className="steering-method-row">
|
||||||
<span className="muted">Methode: </span>
|
<span className="muted">Methode: </span>
|
||||||
|
|
@ -117,9 +131,13 @@ export function SteeringSnapshotPanel({
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{signals?.length > 0 && (
|
{(attention_items?.length > 0 || signals?.length > 0) && (
|
||||||
<p className="muted snapshot-signals">
|
<p className="muted snapshot-signals snapshot-attention">
|
||||||
{signals.map((s) => SIGNAL_LABELS[s] || s).join(' · ')}
|
Attention:{' '}
|
||||||
|
{(attention_items.length > 0
|
||||||
|
? attention_items.map((a) => a.label)
|
||||||
|
: signals.map((s) => SIGNAL_LABELS[s] || s)
|
||||||
|
).join(' · ')}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -135,6 +153,7 @@ export function SteeringSnapshotPanel({
|
||||||
<strong>{item.title}</strong>
|
<strong>{item.title}</strong>
|
||||||
<span className="muted list-item-sub">
|
<span className="muted list-item-sub">
|
||||||
{NEXT_ACTION_KIND_LABELS[item.kind] || item.kind}
|
{NEXT_ACTION_KIND_LABELS[item.kind] || item.kind}
|
||||||
|
{item.reason_code ? ` · ${item.reason_code}` : ''}
|
||||||
{item.recommended_action ? ` — ${item.recommended_action}` : ''}
|
{item.recommended_action ? ` — ${item.recommended_action}` : ''}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -716,6 +716,21 @@
|
||||||
margin: 0.75rem 0 0;
|
margin: 0.75rem 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.steering-guidance {
|
||||||
|
margin: 0.35rem 0 0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text-secondary, #555);
|
||||||
|
}
|
||||||
|
|
||||||
|
.steering-archetype-row {
|
||||||
|
margin: 0 0 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snapshot-attention {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.steering-method-row {
|
.steering-method-row {
|
||||||
margin: 0.5rem 0 0;
|
margin: 0.5rem 0 0;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user