225 lines
6.6 KiB
Markdown
225 lines
6.6 KiB
Markdown
|
|
# 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*
|