Modul-16-Paperclip: Orchestrierungsebene implementiert + E2E dokumentiert (noch NICHT FREIGEGEBEN, 21.08.2026)

This commit is contained in:
Rain Ocampo 2026-08-21 01:04:36 +00:00
parent 59e771759c
commit 62d14af53c

136
modul-16-paperclip.md Normal file
View file

@ -0,0 +1,136 @@
# Modul-16: Paperclip (Agent-Orchestrierungsebene)
**Status: NICHT FREIGEGEBEN (in Verifikation)** · Container `Modul-16-Paperclip` · Image `trading-modules-modul16-paperclip:latest`
> ⚠️ **Achtung Namenskollision:** Es existiert ein **Fremdsystem** `paperclip-dn8l-paperclip-1`
> (Coolify, Hostinger hvps-paperclip) im `coolify`-Netz. Dies ist **NICHT** unser Modul-16.
> Unser Modul-16 läuft im `trading-modules`-Netz als `Modul-16-Paperclip`. Fremdsystem nie anfassen.
## Zweck
Paperclip ist die **übergeordnete Agent-/Orchestrierungsebene** des Trading-Systems. Er nimmt
Research-, Analytics-, Strategieüberprüfungs-, Backtest-, Optimization- und Monitoring-Aufträge
entgegen, wählt eine **Agent-Rolle** (Strategy/Research/Analytics/Validation/System) und führt sie
deterministisch aus. Später (V2) können daraus Hermes-Agent-Aufgaben entstehen.
**Kritische Grenze:** Paperclip ist **NICHT Teil des kritischen Trading-Pfads.**
- ✅ Er liest READ-ONLY aus Modul-0315 und startet klar begrenzte, nicht-kritische Writes (Backtest, Optimization).
- ❌ Er DARF KEINE Broker-Orders senden, Modul-09 nicht zur Orderausführung anweisen, Risk-/Portfolio-Regeln nicht
überschreiben, M15-Safety nicht überschreiben, Strategien nicht automatisch produktiv aktivieren,
Optimierungsparameter nicht automatisch deployen.
- **Trading-Core (M0315) läuft bei komplettem Ausfall von Modul-16 unverändert weiter.**
## Architektur / Datenfluss
```
Client/Auftrag
│ POST /tasks (task_type + payload)
Modul-16-Paperclip (Port 55016, NUR intern/expose)
├── app/core/orchestrator.py Rollen-Wahl + deterministische Ausführung
├── app/core/proposal_gate.py Proposal-Gate (NIE Auto-APPROVED/aktiviert)
├── app/storage/storage.py Persistenz agent_task/agent_run/agent_proposal/agent_audit
├── app/clients/clients.py Read-Clients + 2 begrenzte Write-Clients
└── app/api/main.py REST-API (/health, /tasks, /proposals)
├── Read-Only (tolerant): Modul-03/04/06 (research), M05+M11 (strategy_review),
│ M11 (analytics), M15 (monitoring, NUR GET)
└── Write (begrenzt): Modul-12 POST /backtest, Modul-13 POST /optimization
```
**API (Docker-intern, Port 55016):**
- `GET /health` — Liveness (`{"status":"ok","service":"paperclip","version":"0.1.0"}`)
- `GET /health/ready` — Readiness (DB + Schema vorhanden) → 200 `{"status":"ready"}`
- `POST /tasks` — Auftrag einreichen (validiert; unbekannte/`execute_order` → 422)
- `GET /tasks` / `GET /tasks/{id}` — Aufträge + Status/result_refs
- `POST /tasks/{id}/run` — Aufgabe synchron ausführen (erzeugt `agent_run`)
- `POST /proposals` — Proposal als DRAFT erzeugen (APPROVED via Paperclip → 422)
- `GET /proposals` / `GET /proposals/{id}`
Kein RabbitMQ: synchroner request/response. Port 55016 ist **nur intern** (`expose:`), kein öffentliches Mapping.
## Agent-Rollen (V1, vorbereitet)
| Rolle | task_type | liest | schreibt |
|-------|-----------|-------|----------|
| `analytics` | `analytics` | Modul-11 (portfolio/strategy/regime) | — |
| `research` | `research` | Modul-03/04/06 | — |
| `strategy` | `strategy_review` | Modul-05 (Strategien) + Modul-11 | — |
| `validation` | `backtest`, `optimization`, `validation` | Modul-12/13 | M12 POST /backtest, M13 POST /optimization |
| `system` | `monitoring` | Modul-15 (NUR GET) | — |
Alle Rollen sind per `ENABLED_ROLES` registriert; es werden **nicht unnötig viele aktiviert**.
`TASK_TO_ROLE` mappt `task_type → Rolle`.
## Proposal-Prinzip (ProposalGate)
Wenn Paperclip eine Änderung empfiehlt, wird sie **als Proposal** gespeichert, niemals direkt angewendet:
```
STRATEGY_CHANGE_PROPOSAL mit:
proposal_id, source/agent, strategy, aktuelle Version, vorgeschlagene Änderung (JSON),
Begründung (rationale), Analytics-/Backtest-Referenzen, Confidence, created_at, status
Status: DRAFT / PROPOSED / REVIEWED / APPROVED / REJECTED
```
- `create_proposal` läuft ausschließlich über `ProposalGate` (nur `status in {DRAFT, PROPOSED}` erlaubt).
- Paperclip kann `APPROVED` **NIE selbst setzen** (validiert in `proposal_gate.py`; API gibt 422).
- Proposal wird mit `auto_activated=false` persistiert — **keine automatische Aktivierung**.
- **Keine automatische Übernahme optimierter Parameter** in Produktion.
## Sicherheit
- **Keine öffentlichen Ports**: 55016 nur `expose` (Docker-intern), kein Host-Mapping.
- **Internes Docker-Netzwerk** `trading-modules`.
- **Secrets nur ENV/Secret** (`PG_PASSWORD` aus Compose `environment`); keine Secrets in Logs/API/DB.
- **Keine Broker-Credentials.**
- **Kein Docker-Socket-/Root-Recht, kein Shell-Zugriff auf andere Container.**
- **M15-Ausfall kann Paperclip nicht dazu bringen, Safety zu umgehen** (Paperclip hat KEINE M15-Control-Write-Methode).
- **Paperclip-Ausfall stoppt Trading nicht** (eigene DB-Tabellen, kein Einfluss auf Trading-Core).
## Persistenz / Audit (Migration `migrations/001_paperclip.sql`)
- `agent_task` — Aufträge (id, agent_role, task_type, status, payload, result_refs, error_*).
- `agent_run` — Ausführungen (run_id, task_id, agent_role, status, result, idempotent).
- `agent_proposal` — Vorschläge (proposal_id, source, strategy, proposed_change, rationale, references, confidence, status, auto_activated).
- `agent_audit` — lückenloses Audit-Log (actor, action, detail, task_id, run_id, proposal_id).
Jede Agent-Aktion (task_created, run_started, run_succeeded, run_failed, run_rejected, proposal_*) wird in `agent_audit` protokolliert.
## Read-Clients (tolerant)
Einzelne Quellen-Fehler (404/5xx/Timeout) werden über `_safe_get` als `{"_error": code, "_message": …}`
Teil-Ergebnis gekapselt → der Gesamt-Task bleibt SUCCEEDED. Nur wenn ein Service **komplett unreachable**
(`UNREACHABLE`/`TIMEOUT`) ist, liefert er `None`. Write-Aktionen (Backtest/Optimization) bleiben strikt FAILED bei Fehlern.
## Tests & E2E-Verifikation (VPS, 21.08.2026)
- **Unit-Tests** `tests/test_paperclip.py`: 10/10 grün (ProposalGate-Safety, Task-Validierung, Worker, Idempotenz, Auto-Aktivierungs-Verbot).
- **Backtest-Flow**: M16 → M12 `POST /backtest`**SUCCEEDED**, `agent_run` + `run_id`/`result_refs` korrekt (`kind:"backtest"`).
- **Optimization-Flow**: M16 → M13 `POST /optimization`**SUCCEEDED**, `run_id`/`result_refs` korrekt (`kind:"optimization"`).
- **Monitoring-Flow**: M16 → M15 `/monitoring/status` (READ-ONLY) → **SUCCEEDED**, Ergebnis gespeichert.
- **Research-Flow**: M16 → M03/M04/M06 → **SUCCEEDED** (M04 404 „Kein Regime" als Teil-Ergebnis gekapselt, kein Crash).
- **Strategy-Review-Flow**: M16 → M05+M11 → **SUCCEEDED**.
- **Proposal**: erstellt als `DRAFT`/`auto_activated=false`; `APPROVED` → 422. **NICHT auto-aktiviert.**
- **Kein M09-Zugriff**: `task_type=execute_order` → 422; kein `ExecutionClient`, keine `/order`-Endpunkte, kein `execution_base_url`.
- **Kein M15-Override**: Paperclip hat nur GET-Methoden auf M15, keine Control-Write.
- **Ausfall-Toleranz**: fehlende Daten/Fehler → Task FAILED, Container bleibt **healthy**; Container-Restart → healthy.
- **Idempotenz**: erneuter `run` erzeugt neuen `agent_run`, überschreibt frühere Runs nicht.
- **Ungültige Aufgabe**: `task_type=delete_database` → 422.
- **Keine Secrets in Logs/API**: `docker logs` frei von password/secret/token/api_key.
- **Health/Ready**: beide 200.
## Bugs / Fixes (modul-16, dokumentiert)
1. **`references`-SQL-Keyword** → Spalte in Migration + Queries als `"references"` gequoted.
2. **Migration-Commit**: psycopg2 braucht `conn.autocommit = True` (Muster wie M15), sonst bleiben Tabellen
uncommittet → `relation agent_task does not exist` bei `/health/ready`. Behoben in `_connect`.
3. **create_task RETURNING-Mismatch**: RETURNING listete 7 Spalten, `_task_row` erwartete 10 →
`IndexError`. Behoben: vollständige Spaltenliste.
4. **Research-Einzelfehler-Crash**: Einzelne fehlende Quelle (M04 404) failte den ganzen Research-Task.
Behoben: `_safe_get` kapselt Einzelquellen-Fehler, Task bleibt SUCCEEDED mit Teil-Ergebnissen.
## Compose / Betrieb
- Netzwerk `trading-modules`, DB-Host `Modul-01-PostgreSQL` (Modul-01), Port 55016 nur intern (`expose`),
`restart: unless-stopped`. Kein öffentliches Port-Mapping.
- **Kein Teil des kritischen Trading-Pfads:** kein M09-, kein M15-Control-Zugriff.
---
## Geändert
```
Geändert von: Rain Ocampo
Datum: 21.08.2026
Grund: Modul-16-Paperclip implementiert + E2E verifiziert (Backtest/Optimization/Monitoring/Research/Strategy-Success, Safety 422, ProposalGate, Ausfall-toleranz, Idempotenz). Noch NICHT FREIGEGEBEN — bis E2E final grün. Modul-17 NICHT begonnen.
```