# AP1.0 — Steering Foundation (Skeleton) ## Implementierungsauftrag v0.1 **Status:** umgesetzt **Stand:** 2026-07-05 **Vorgänger:** AP0.10b ✓ **ADP:** `docs/architecture/ADP_AP1_0_Steering_Foundation_Scope_Lock_v0.1.md` **Zielversion:** `0.11.0-ap1.0` · Schema `009` --- ## Ziel **Eine persistierte Steuerungswahrheit pro Initiative** — Standard Lifecycle als Foundation, in die Methoden später einhängen. Leitfrage bleibt: *Welcher nächste Schritt bringt ein Vorhaben am wirkungsvollsten voran?* — technisch beantwortet über `SteeringContext.lifecycle_state` + Signal Engine, nicht über verstreute Heuristiken. --- ## Scope Lock (verbindlich) Siehe ADP § Scope Lock. **Kein AP0.10c.** Keine neuen Attention-Regeln. Keine neuen OM-Tabellen außer `steering_contexts`. --- ## Teil A — Schema 009 ### Tabelle `steering_contexts` ```sql CREATE TABLE steering_contexts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, initiative_id UUID NOT NULL REFERENCES initiatives(id) ON DELETE CASCADE, method_key VARCHAR(64) NOT NULL DEFAULT 'generic_operating', method_version VARCHAR(32) NOT NULL DEFAULT '0.1.0', lifecycle_state VARCHAR(64) NOT NULL DEFAULT 'intake', lifecycle_metadata JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (tenant_id, initiative_id) ); CREATE INDEX idx_steering_contexts_tenant ON steering_contexts(tenant_id); ``` ### Backfill (Seed oder Migration-Block) Bestehende Initiativen erhalten Context: | Bedingung | `lifecycle_state` | |-----------|-------------------| | `status IN (completed, archived)` | `closure` | | offene Actions existieren | `action_selection` | | nur Backlog (new/triaged/accepted), keine offenen Actions | `structure_setup` | | sonst active/paused | `planning` | --- ## Teil B — `backend/steering/` ### B1 — Lifecycle **Datei:** `steering/lifecycle/states.py` ```python STANDARD_LIFECYCLE_STEPS = ( "intake", "method_selection", "structure_setup", "planning", "action_selection", "assignment", "waiting", "result_intake", "validation", "review", "adaptation", "closure", ) ``` **Datei:** `steering/lifecycle/orchestrator.py` - `get_lifecycle_state(ctx, initiative_id) -> str` - `transition(ctx, initiative_id, to_state, *, reason: str) -> dict` — Guard minimal: nur erlaubte Übergänge aus `generic_operating` oder freier Übergang für AP1.0 stub - Audit-Log bei Transition ### B2 — Hook Registry **Datei:** `steering/hooks/registry.py` - `HookDefinition` dataclass (slug, lifecycle_step, description, since_version) - `register_hook()`, `get_hook()`, `list_hooks()` - Registrierung der Slugs aus Target Architecture §7.3 (Definition only, Implementierung stub) **Datei:** `steering/hooks/dispatch.py` - `dispatch_hook(slug, ctx, payload) -> list[dict]` — ruft registrierte Handler; AP1.0: leere Handler + Audit-Eintrag ### B3 — Method Registry **Datei:** `steering/methods/registry.py` + `registrations/generic_operating.py` - Eine Built-in-Methode: `generic_operating` - Liefert: `default_lifecycle_steps`, erlaubte Hooks (alle globalen), keine Structure Builder ### B4 — Signal Engine **Datei:** `steering/signals/default_rules.py` - Bestehende Regeln aus `data_layer/attention.py` **verschieben** (nicht duplizieren) - `evaluate_attention(ctx) -> list[dict]` - `evaluate_next_actions(ctx, *, limit, initiative_id=None) -> list[dict]` **Datei:** `steering/signals/engine.py` - `evaluate(ctx, kind='attention'|'next_action', **kwargs)` — delegiert an default_rules **Datei:** `data_layer/attention.py` - Wird dünner Wrapper um `steering.signals.engine` (API-Kompatibilität) ### B5 — Steering Context Service **Datei:** `steering/context.py` + `services/steering_context.py` (Write) - `get_or_create_for_initiative(ctx, initiative_id)` - `get_steering_context(ctx, initiative_id) -> Optional[dict]` - Tenant-scoped; Cross-Tenant → None / 404 --- ## Teil C — Integration bestehender Flows ### C1 — `operating_transitions.py` Vor/nach bestehender Logik: ```python from steering.hooks.dispatch import dispatch_hook dispatch_hook("on_blocker_resolved", ctx, {...}) # optional: lifecycle transition assignment → action_selection ``` Verhalten Blocker→entblocken **unverändert** (Regression-Tests). ### C2 — `initiative_snapshot.py` Snapshot ergänzt: ```json { "lifecycle_state": "action_selection", "lifecycle_label": "Maßnahmen auswählen", "operating_phase": "execute", "operating_phase_deprecated": true } ``` `_derive_operating_phase` bleibt für Rückwärtskompatibilität; markiert deprecated in Docstring. ### C3 — Initiative Create Bei `create_initiative` → `steering_contexts` Zeile anlegen (`lifecycle_state=intake` oder Backfill-Regel). --- ## Teil D — API | Endpoint | Capability | Beschreibung | |----------|------------|--------------| | `GET /api/initiatives/{id}/steering-context` | `kairo.initiative.read` | Context DTO | | `GET .../steering-snapshot` | (bestehend) | + lifecycle Felder | --- ## Teil E — Frontend (minimal) **Datei:** `frontend/src/constants/operating.js` - `LIFECYCLE_LABELS` für 12 Standard-Schritte (DE) - Steuerungszustand-Panel: primär `lifecycle_label`; `operating_phase` nur Fallback Kein Maßnahmen-Hub. Keine neuen Widgets. --- ## Teil F — Tests | Test | Erwartung | |------|-----------| | `test_ap1_steering_context.py` | CRUD Context, tenant isolation | | `test_ap1_lifecycle.py` | Transition + Audit | | `test_ap1_signals_regression.py` | Attention/NextAction gleich wie vor Refactor | | `test_ap10_integration.py` | weiter grün; Snapshot hat lifecycle_state | --- ## Nicht-Scope - Workflow Runtime, Waiting/Reminder Scheduler - Zweite Built-in-Methode (`product_milestone_driven`) → AP1.1 - `roadmap_items`, `projects`, `milestones`-Migration - AP0.10c UI - Prompt/KI/MCP - Entfernen von `operating_phase` → AP1.2 --- ## Abnahme 1. Migration 009 deployed; bestehende Initiativen haben Context 2. `backend/steering/` existiert mit Lifecycle, Hooks, Methods, Signals 3. Attention/NextAction APIs unverändert im Verhalten (Regression) 4. Snapshot + neuer steering-context Endpoint liefern `lifecycle_state` 5. Scope Lock aus ADP eingehalten (kein AP0.10c) 6. pytest grün remote --- ## Reihenfolge Implementierung 1. Migration 009 + Backfill 2. `steering/lifecycle`, `steering/context` 3. Initiative-Create Hook 4. `steering/signals` Refactor aus attention.py 5. Hook dispatch in operating_transitions 6. API + Snapshot + Frontend Labels 7. Tests + Version bump --- *Nächster Schritt nach Abnahme: AP0.10d Validation Report, dann AP1.1 Method Registry erweitern*