Kairo-Jinkendo/docs/sprints/Sprint1_AP1_0_Steering_Foundation_Assignment_v0.1.md
Lars 95feba6204
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Test Suite / pytest-backend (push) Successful in 1m19s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 18s
Test Suite / playwright-smoke (push) Successful in 11s
AP1.0: Steering Foundation — Lifecycle, Context, Signal Engine
Persistierter Standard Lifecycle pro Initiative, backend/steering/ Skeleton, Attention-Refactor und Hook-Dispatch als Basis für Method Registry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 17:09:20 +02:00

6.6 KiB

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

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

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:

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:

{
  "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_initiativesteering_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