Add all BMAD skill artifacts: epics, stories, sprint-status, QA tests, project-context, readiness report

Co-authored-by: Kenearos <86194771+Kenearos@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-12 14:26:40 +00:00
parent e37cb6f4c0
commit 3be3cb73b6
14 changed files with 1577 additions and 4 deletions

View file

@ -0,0 +1,159 @@
---
inputDocuments:
- _bmad-output/planning-artifacts/epics.md
- _bmad-output/planning-artifacts/architecture.md
- backend/tests/
bmadSkill: 'QA Agent (Quinn) — /bmad-agent-bmm-qa → [QE] Generate E2E Tests'
bmadWorkflow: '_bmad/bmm/workflows/qa-generate-e2e-tests/workflow.yaml'
---
<!-- 🧪 Generated by BMAD QA Skill — Agent: Quinn (QA Engineer) -->
<!-- Skill Command: /bmad-agent-bmm-qa → Generate E2E Tests -->
<!-- Workflow: _bmad/bmm/workflows/qa-generate-e2e-tests/workflow.yaml -->
# QA E2E Test-Manifest — CouncilOS
**Autor:** Quinn (🧪 BMAD QA Agent)
**Datum:** 2026-03-12
---
## 1. Bestehende Unit-Tests (Backend)
| Datei | Beschreibung | Status |
|-------|-------------|--------|
| `backend/tests/test_state.py` | CouncilState-Reducer, operator.add | ✅ |
| `backend/tests/test_routing.py` | Routing-Logik (score < 8, 8, safety valve) | |
| `backend/tests/test_api.py` | Health-Check, Run-Endpunkte (httpx AsyncClient) | ✅ |
| `backend/tests/test_blueprint_api.py` | Blueprint CRUD REST-API | ✅ |
| `backend/tests/test_blueprint_service.py` | Blueprint-Service-Layer | ✅ |
| `backend/tests/test_dynamic_graph_builder.py` | Dynamischer Graph-Builder | ✅ |
| `backend/tests/test_god_mode.py` | Human-in-the-Loop (approve/reject/modify) | ✅ |
| `backend/tests/test_run_service.py` | Run-History-Service | ✅ |
| `backend/tests/test_run_store.py` | In-Memory-Run-Store | ✅ |
| `backend/tests/test_tools.py` | Web-Search und PDF-Reader (gemockt) | ✅ |
## 2. Frontend-Unit-Tests
| Datei | Beschreibung | Status |
|-------|-------------|--------|
| `frontend/app/__tests__/` | Vitest-Tests für React-Komponenten | ✅ |
---
## 3. E2E-Test-Szenarien (für Playwright / Cypress — Post-MVP)
### TC-E2E-001: Council erstellen und ausführen (Happy Path)
**Voraussetzung:** Backend läuft auf Port 8000, Frontend auf 3000
**Schritte:**
1. Öffne `http://localhost:3000`
2. Wechsel zum Tab „Rat-Architekt"
3. Ziehe einen Agent-Node auf den Canvas
4. Setze Name: „Test Master", System-Prompt: „Du bist ein Test-Agent"
5. Ziehe einen zweiten Node (Critic)
6. Verbinde die Nodes mit einer linearen Edge
7. Klicke „Speichern" → Bestätigungsmeldung erscheint
8. Wechsel zum Tab „Konferenzzimmer"
9. Gib Prompt: „Schreibe einen kurzen Test-Text" ein
10. Wähle „Auto-Pilot"
11. Klicke „Starten"
12. Beobachte: Erster Node pulsiert gelb
13. Nach Abschluss: Finaler Text erscheint im Output-Bereich
**Erwartetes Ergebnis:** Run erreicht `status=completed`, `final_draft` nicht leer
---
### TC-E2E-002: God Mode — Approve
**Schritte:**
1. Wähle „God Mode" im Toggle
2. Starte Run mit beliebigem Prompt
3. Nach erstem Node: Overlay erscheint
4. Klicke „Genehmigen"
5. Nächster Node startet (pulsiert)
6. Bis Abschluss: alle Nodes genehmigen
**Erwartetes Ergebnis:** Run erreicht `status=completed`
---
### TC-E2E-003: God Mode — Reject
**Schritte:**
1. Starte Run in God Mode
2. Overlay erscheint
3. Klicke „Ablehnen"
**Erwartetes Ergebnis:** Run `status=failed`, Fehlermeldung „Rejected by user" sichtbar
---
### TC-E2E-004: PDF-Upload und Verwendung
**Schritte:**
1. Öffne `POST /api/councils/upload-pdf` mit Test-PDF
2. Response enthält `chunks_ingested > 0`
3. Erstelle Council mit Agent, der `pdf_reader=true` hat
4. Starte Run mit Thema aus dem PDF
5. Agent-Output referenziert PDF-Inhalte
**Erwartetes Ergebnis:** Chunks werden korrekt eingelesen und sind abrufbar
---
### TC-E2E-005: WebSocket-Events in korrekter Reihenfolge
**Schritte:**
1. Verbinde mit `WS /ws/council/{run_id}`
2. Starte Run
3. Zeichne alle empfangenen Events auf
**Erwartetes Ergebnis:**
```
{"node": "master_agent", "status": "running"}
{"node": "master_agent", "status": "completed"}
{"node": "critic_agent", "status": "running"}
{"node": "critic_agent", "status": "completed"}
... (ggf. Schleife)
{"node": "writer_agent", "status": "running"}
{"node": "writer_agent", "status": "completed"}
{"status": "done"}
```
---
## 4. Test-Mocking-Konventionen
```python
# Standard-Mock-Pattern für alle Agent-Tests (CLAUDE.md-Anforderung)
from unittest.mock import patch, MagicMock
@patch("agents.master_agent.ChatAnthropic")
def test_master_agent_node_appends_to_messages(mock_llm):
mock_llm.return_value.invoke.return_value = MagicMock(content="Draft v2")
state = {...}
result = master_agent_node(state)
assert result["current_draft"] == "Draft v2"
```
**Regeln (aus CLAUDE.md):**
- ❌ Niemals echte LLM-API-Aufrufe in Tests
- ❌ Kein shared Test-Datenbankzustand (Transactions rollback)
- ❌ Kein Snapshot-Test für React Flow Canvas
- ✅ Immer beide Seiten der Threshold-Grenze testen (7.9 und 8.0)
---
## 5. Coverage-Ziele
| Modul | Ziel-Coverage |
|-------|--------------|
| `backend/state.py` | ≥ 90 % |
| `backend/services/graph_builder.py` | ≥ 90 % |
| `backend/services/dynamic_graph_builder.py` | ≥ 85 % |
| `backend/agents/` | ≥ 80 % |
| `backend/api/` | ≥ 75 % |
| `backend/tools/` | ≥ 75 % |

View file

@ -0,0 +1,91 @@
# Sprint Status — CouncilOS
# Generated by BMAD SM Skill — Agent: Bob (Scrum Master)
# Skill Command: /bmad-agent-bmm-sm → [SP] Sprint Planning
# Workflow: _bmad/bmm/workflows/4-implementation/sprint-planning/workflow.yaml
# generated: 2026-03-12
# project: CouncilOS (KI-Rat Baukasten)
# project_key: COUNCILSOOS
# tracking_system: file-system
# story_location: "_bmad-output/implementation-artifacts/stories"
# STATUS DEFINITIONS:
# ==================
# Epic Status:
# - backlog: Epic not yet started
# - in-progress: Epic actively being worked on
# - done: All stories in epic completed
#
# Story Status:
# - backlog: Story only exists in epic file
# - ready-for-dev: Story file created, ready for development
# - in-progress: Developer actively working on implementation
# - review: Implementation complete, ready for review
# - done: Story completed
#
# Retrospective Status:
# - optional: Can be completed but not required
# - done: Retrospective has been completed
#
# WORKFLOW NOTES:
# ===============
# - Mark epic as 'in-progress' when starting work on its first story
# - SM typically creates next story ONLY after previous one is 'done' to incorporate learnings
# - Dev moves story to 'review', then Dev runs code-review (fresh context, ideally different LLM)
generated: 2026-03-12
project: CouncilOS
project_key: COUNCILSOOS
tracking_system: file-system
story_location: "_bmad-output/implementation-artifacts/stories"
development_status:
# ─────────────────────────────────────────────────────────────────
# Epic 1: Projekt-Setup & Infrastruktur
# ─────────────────────────────────────────────────────────────────
epic-1: done
1-1-docker-compose-umgebung-aufsetzen: done
1-2-backend-python-umgebung-requirements: done
1-3-datenbank-migrationen-mit-alembic: done
epic-1-retrospective: done
# ─────────────────────────────────────────────────────────────────
# Epic 2: LangGraph Engine Backend (Phase 1)
# ─────────────────────────────────────────────────────────────────
epic-2: done
2-1-councilstate-typeddict-implementieren: done
2-2-master-agent-node-implementieren: done
2-3-critic-agent-node-implementieren: done
2-4-writer-agent-node-implementieren: done
2-5-langgraph-graph-bauen-und-ausfuehren: done
2-6-fastapi-run-endpunkte-implementieren: done
epic-2-retrospective: done
# ─────────────────────────────────────────────────────────────────
# Epic 3: Visueller Baukasten Frontend (Phase 2)
# ─────────────────────────────────────────────────────────────────
epic-3: done
3-1-react-flow-canvas-mit-custom-agent-node: done
3-2-lineare-und-bedingte-edges: done
3-3-blueprint-parser-react-flow-json: done
3-4-blueprint-crud-frontend-backend: done
epic-3-retrospective: optional
# ─────────────────────────────────────────────────────────────────
# Epic 4: Frontend-Backend-Integration (Phase 3)
# ─────────────────────────────────────────────────────────────────
epic-4: done
4-1-dynamischer-graph-builder-aus-blueprint-json: done
4-2-websocket-agent-events-integrieren: done
4-3-konferenzzimmer-live-execution-ui: done
epic-4-retrospective: optional
# ─────────────────────────────────────────────────────────────────
# Epic 5: Tools & God Mode (Phase 4)
# ─────────────────────────────────────────────────────────────────
epic-5: done
5-1-tavily-web-suche-als-agent-tool: done
5-2-pdf-upload-chromadb-ingestion: done
5-3-god-mode-human-in-the-loop: done
5-4-run-verlauf-history: done
epic-5-retrospective: optional

View file

@ -0,0 +1,74 @@
# Story 2.3: Critic-Agent-Node implementieren
<!-- 🏃 Prepared by BMAD SM Skill — Agent: Bob (Scrum Master) -->
<!-- Skill Command: /bmad-agent-bmm-sm → [CS] Context Story -->
<!-- Workflow: _bmad/bmm/workflows/4-implementation/create-story/workflow.yaml -->
Status: done
## Story
Als **Backend-Entwickler**,
möchte ich **den `critic_agent_node` mit Score-Parsing, Routing-Logik und Safety-Valve**,
so dass er **Drafts bewertet, `route_decision` korrekt setzt und Endlosschleifen verhindert**.
## Acceptance Criteria
1. Score < 8 `route_decision = "rework"`, Feedback wird an `feedback_history` angehängt
2. Score ≥ 8 → `route_decision = "approve"`, `feedback_history` bleibt unverändert
3. `iteration_count >= MAX_ITERATIONS` → automatische Genehmigung ohne LLM-Aufruf (Safety Valve)
4. Nicht-parsbare LLM-Antwort → Fallback `route_decision = "rework"`, kein Crash
5. Score wird auf 010 geclampt (kein Overflow)
## Tasks / Subtasks
- [x] Task 1: `_parse_critic_response()` implementieren (AC: 1, 4, 5)
- [x] Subtask 1.1: Regex für SCORE, VERDICT, FEEDBACK-Blöcke
- [x] Subtask 1.2: Score-Clamping (max 0.0, min 10.0)
- [x] Subtask 1.3: Fallback auf (0.0, "rework", full_content) bei Parse-Fehler
- [x] Task 2: `critic_agent_node()` implementieren (AC: 1, 2, 3)
- [x] Subtask 2.1: Safety-Valve prüfen vor LLM-Aufruf
- [x] Subtask 2.2: LLM-Aufruf mit temperature=0.2
- [x] Subtask 2.3: Route-Decision aus Score und APPROVAL_THRESHOLD ableiten
- [x] Subtask 2.4: `feedback_history` nur bei rework anhängen
- [x] Task 3: Unit-Tests schreiben (AC: 15)
- [x] Subtask 3.1: Test score < 8 rework
- [x] Subtask 3.2: Test score ≥ 8 → approve
- [x] Subtask 3.3: Test safety valve bei MAX_ITERATIONS
- [x] Subtask 3.4: Test Parse-Fehler-Fallback
## Dev Notes
- **LLM-Mocking:** `@patch("agents.critic_agent.ChatAnthropic")` in allen Unit-Tests
- **Kein echter API-Aufruf in CI** — strikte Anforderung aus CLAUDE.md
- **Threshold-Tests:** Immer beide Seiten testen (score=7.9 → rework, score=8.0 → approve)
- Bezug: `backend/state.py#APPROVAL_THRESHOLD`, `backend/state.py#MAX_ITERATIONS`
### Project Structure Notes
- Implementiert in: `backend/agents/critic_agent.py`
- Tests in: `backend/tests/test_routing.py`
### References
- [Source: CLAUDE.md#Python Code Style] — Type hints mandatory
- [Source: _bmad-output/planning-artifacts/architecture.md#CouncilState] — State contract
- [Source: _bmad-output/planning-artifacts/epics.md#Story-2.3] — ACs
## Dev Agent Record
### Agent Model Used
Amelia (💻 BMAD Dev Agent) — `dev-story` workflow
### Completion Notes List
- Score-Clamping verhindert Werte außerhalb 010 auch bei fehlerhafter LLM-Formatierung.
- Safety-Valve gibt `APPROVAL_THRESHOLD` als Score zurück (nicht 10.0), damit Tests einheitlich bleiben.
- Feedback wird nur bei `rework` angehängt, da `operator.add`-Reducer andernfalls Genehmigungen in die History schreibt.
### File List
- `backend/agents/critic_agent.py`
- `backend/tests/test_routing.py`
- `backend/state.py` (nur gelesen, nicht verändert)

View file

@ -0,0 +1,82 @@
# Story 4.1: Dynamischer Graph-Builder aus Blueprint-JSON
<!-- 🏃 Prepared by BMAD SM Skill — Agent: Bob (Scrum Master) -->
<!-- Skill Command: /bmad-agent-bmm-sm → [CS] Context Story -->
<!-- Workflow: _bmad/bmm/workflows/4-implementation/create-story/workflow.yaml -->
Status: done
## Story
Als **Backend-Entwickler**,
möchte ich **`dynamic_graph_builder.py`**,
so dass er **aus einem Blueprint-JSON zur Laufzeit einen kompilierten LangGraph-Graphen baut, der Zyklen korrekt erhält**.
## Acceptance Criteria
1. Valides Blueprint-JSON mit N Nodes → kompilierter `StateGraph`
2. Blueprint mit Zyklus (A→B→A, bedingt) → Graph kompiliert, Zyklus erhalten
3. Blueprint mit nicht-existenter Node-ID in Edge → `ValueError` mit sprechender Fehlermeldung
4. Blueprint mit 0 Nodes → `ValueError`
5. Blueprint mit 2 Nodes, 0 Edges → `ValueError`
6. Bedingte Edge mit `condition`-Label wird korrekt als conditional edge verdrahtet
7. Nodes mit `tools.web_search = true` bekommen Tavily-Tool gebunden
8. Nodes mit `tools.pdf_reader = true` bekommen PDF-Search-Tool gebunden
## Tasks / Subtasks
- [x] Task 1: Blueprint-JSON-Schema validieren (AC: 3, 4, 5)
- [x] Subtask 1.1: Prüfen ob `nodes` nicht leer
- [x] Subtask 1.2: Alle Edge `source`/`target` IDs auf Existenz in `nodes` prüfen
- [x] Subtask 1.3: Sicherstellen ≥1 Edge vorhanden
- [x] Task 2: Node-Funktionen dynamisch erzeugen (AC: 1, 7, 8)
- [x] Subtask 2.1: Agent-Node-Fabrik mit konfigurierbarem System-Prompt und Modell
- [x] Subtask 2.2: Tool-Binding für web_search/pdf_reader
- [x] Task 3: Graph-Topologie aufbauen (AC: 1, 2, 6)
- [x] Subtask 3.1: Entry-Point = erster Node ohne eingehende Edges
- [x] Subtask 3.2: Lineare Edges als `add_edge`
- [x] Subtask 3.3: Bedingte Edges als `add_conditional_edges` mit Routing-Funktion
- [x] Task 4: God-Mode-Unterstützung via `interrupt_before` (AC für Story 5.3)
- [x] Subtask 4.1: `interrupt_before=node_ids` beim Kompilieren setzen
- [x] Task 5: Unit-Tests (AC: 16)
- [x] Subtask 5.1: Test valides Blueprint
- [x] Subtask 5.2: Test Blueprint mit Zyklus
- [x] Subtask 5.3: Test Blueprint mit ungültiger Edge (ValueError)
- [x] Subtask 5.4: Test Blueprint mit 0 Nodes (ValueError)
## Dev Notes
- **Zyklen sind First-Class**: Niemals den Graphen zu einem DAG vereinfachen.
- **Entry-Point-Erkennung**: Node ohne eingehende Edges = Startpunkt. Bei Zyklen: erster Node in `nodes`-Array.
- **Routing-Funktion**: Dynamisch erzeugte Closure über `route_decision`-State-Feld.
- Bezug: `backend/state.py`, `backend/services/graph_builder.py` (Phase-1-Referenz)
### Project Structure Notes
- Implementiert in: `backend/services/dynamic_graph_builder.py`
- Tests in: `backend/tests/test_dynamic_graph_builder.py`
- Nutzt: `backend/tools/web_search.py`, `backend/tools/pdf_reader.py`
### References
- [Source: _bmad-output/planning-artifacts/architecture.md#ADR-004] — Dynamischer Graph-Builder
- [Source: _bmad-output/planning-artifacts/architecture.md#Blueprint-JSON-Schema] — Datenformat
- [Source: _bmad-output/planning-artifacts/epics.md#Story-4.1] — ACs
- [Source: CLAUDE.md#Key Design Constraints] — Zyklen sind First-Class
## Dev Agent Record
### Agent Model Used
Amelia (💻 BMAD Dev Agent) — `dev-story` workflow
### Completion Notes List
- Entry-Point-Erkennung via Set-Differenz: `{alle Node-IDs} - {IDs die als Edge-Target vorkommen}`
- Routing-Closure für bedingte Edges: `lambda state: state.get("route_decision", "rework")`
- `interrupt_before` wird als Liste aller Node-IDs gesetzt wenn `god_mode=True`
### File List
- `backend/services/dynamic_graph_builder.py`
- `backend/tests/test_dynamic_graph_builder.py`

View file

@ -0,0 +1,89 @@
# Story 5.3: God Mode — Human-in-the-Loop
<!-- 🏃 Prepared by BMAD SM Skill — Agent: Bob (Scrum Master) -->
<!-- Skill Command: /bmad-agent-bmm-sm → [CS] Context Story -->
<!-- Workflow: _bmad/bmm/workflows/4-implementation/create-story/workflow.yaml -->
Status: done
## Story
Als **Nutzer**,
möchte ich **im God Mode jeden Schritt des Councils genehmigen, ablehnen oder modifizieren**,
so dass ich **volle Kontrolle über den KI-Prozess habe und kritische Entscheidungen absegnen kann**.
## Acceptance Criteria
1. `god_mode=true` → Graph pausiert via `interrupt_before` nach dem ersten Node-Abschluss
2. `POST /approve` mit `action=approve` → Run setzt am nächsten Node fort
3. `POST /approve` mit `action=reject` → Run bricht mit `status=failed` ab
4. `POST /approve` mit `action=modify` und `modified_state` → Run setzt mit modifiziertem Draft fort
5. `GET /councils/run/{run_id}/state` gibt den pausierten State zurück (inkl. `current_draft`, `next_nodes`)
6. Frontend-Overlay erscheint bei `status=paused` und zeigt Agent-Name, aktuellen Draft und drei Buttons
7. Zwei parallele god-mode Runs kontaminieren sich nicht gegenseitig (Session-Isolation)
8. Zweimaliges Approve ohne laufenden Run gibt `400 Bad Request` zurück
## Tasks / Subtasks
- [x] Task 1: `interrupt_before` in dynamischem Graph-Builder implementieren (AC: 1)
- [x] Subtask 1.1: `compile(interrupt_before=[...alle node IDs...])` bei `god_mode=True`
- [x] Subtask 1.2: Nach `graph.invoke()` auf `__interrupt__`-Signal prüfen
- [x] Task 2: God-Mode-State-Verwaltung implementieren (AC: 1, 5, 7)
- [x] Subtask 2.1: `_god_mode_sessions: dict[run_id, GodModeSession]` in-memory
- [x] Subtask 2.2: `GodModeSession` mit `graph`, `config`, `current_state`, `next_nodes`
- [x] Subtask 2.3: Session-Isolation sicherstellen (kein shared-state)
- [x] Task 3: Resume-Logik implementieren (AC: 2, 3, 4)
- [x] Subtask 3.1: `resume_god_mode(run_id, action, modified_state)` Funktion
- [x] Subtask 3.2: Bei `modify`: State-Override vor `graph.invoke(None, config)`
- [x] Subtask 3.3: Bei `reject`: Session löschen, Status auf `failed`
- [x] Task 4: API-Endpunkte (AC: 25, 8)
- [x] Subtask 4.1: `POST /councils/run/{run_id}/approve` Route
- [x] Subtask 4.2: `GET /councils/run/{run_id}/state` Route
- [x] Subtask 4.3: `400`-Guard wenn Session nicht pausiert
- [x] Task 5: Frontend God-Mode-UI (AC: 6)
- [x] Subtask 5.1: Polling `GET /councils/run/{run_id}` auf `status=paused`
- [x] Subtask 5.2: Overlay-Komponente mit Draft-Text, Agent-Name, drei Buttons
- [x] Subtask 5.3: Modify-Modus mit Textarea für Draft-Bearbeitung
- [x] Task 6: Tests (AC: 15, 7, 8)
- [x] Subtask 6.1: `test_god_mode.py` — alle AC als Tests
## Dev Notes
- **LangGraph `interrupt_before`**: Dies ist der einzige Pause-Mechanismus — kein eigener einbauen.
- **`graph.invoke(None, config)`**: Der `None`-Input setzt die Ausführung nach einem Interrupt fort.
- **God-Mode-State-Isolation**: Jede `run_id` hat eine eigene Session-Instanz im Dict.
- **Thread Safety**: Da LangGraph-Invokes in `run_in_executor` laufen, muss der Session-Store thread-safe sein.
- Bezug: `backend/services/dynamic_graph_builder.py`, LangGraph-Dokumentation zu `interrupt_before`
### Project Structure Notes
- Implementiert in: `backend/services/dynamic_graph_builder.py` (GodMode-Logik)
- Implementiert in: `backend/api/routes.py` (Endpunkte)
- Frontend: `frontend/app/konferenzzimmer/page.tsx` (Overlay)
- Tests in: `backend/tests/test_god_mode.py`
### References
- [Source: _bmad-output/planning-artifacts/architecture.md#ADR-001] — LangGraph interrupt_before
- [Source: _bmad-output/planning-artifacts/architecture.md#God-Mode-Sequenzdiagramm]
- [Source: _bmad-output/planning-artifacts/epics.md#Story-5.3] — ACs
- [Source: CLAUDE.md#Key Design Constraints] — Human-in-the-Loop via interrupt_before
## Dev Agent Record
### Agent Model Used
Amelia (💻 BMAD Dev Agent) — `dev-story` workflow
### Completion Notes List
- LangGraph `interrupt_before` gibt nach Pause eine `Command`-Instanz zurück; der Typ wird via `isinstance` geprüft.
- Der `config`-Parameter (`{"configurable": {"thread_id": run_id}}`) wird für LangGraph-Checkpointer benötigt.
- In-Memory-Sessions gehen bei Server-Neustart verloren — für MVP akzeptabel.
### File List
- `backend/services/dynamic_graph_builder.py`
- `backend/api/routes.py`
- `backend/tests/test_god_mode.py`
- `frontend/app/konferenzzimmer/page.tsx`