# Modul-16: Paperclip (Agent-Orchestrierungsebene) **Status: FREIGEGEBEN (21.08.2026)** · 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-03–15 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 (M03–15) 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. **Ausnahme — Monitoring (FAIL-CLOSED):** Der `monitoring`-Task ruft M15 **nicht** über `_safe_get`, sondern direkt auf. M15 ist die autoritative Trading-Status-Quelle — ist sie nicht erreichbar, wird der Monitoring-Task **FAILED** (kein „ok"-Status bei ausgefallenem M15). Bei M12/M13-Ausfall → betroffener Task (Backtest/Optimization) FAILED, M16 bleibt healthy, Trading-Core unbeeinflusst. ## 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**: M12 down → backtest FAILED, M13 down → optimization FAILED, M15 down → monitoring **FAILED (FAIL-CLOSED)**, M15 up → SUCCEEDED. M16 bleibt in allen Fällen **healthy**, Trading-Core unbeeinflusst, Erholung → SUCCEEDED. - **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. 5. **Monitoring-FAIL-CLOSED (21.08.2026)**: `monitoring`-Task nutzte `_safe_get`, was M15-`UNREACHABLE` zu `None` kapselte → Task blieb SUCCEEDED trotz ausgefallenem M15. Fix: `_monitoring` ruft M15 **direkt** auf, damit ein M15-Ausfall als `ClientError` weiterfaellt und der Task **FAILED** wird. Verifiziert: M15 down → monitoring FAILED, M15 up → SUCCEEDED. ## 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). Monitoring-FAIL-CLOSED-Fix: M15-Ausfall -> monitoring-Task FAILED statt SUCCEEDED. Ausfall-Toleranz-E2E (M12/M13/M15 down -> FAILED, healthy) gruen. Image neu gebaut (Fix persistent). FREIGEGEBEN. Modul-17 NICHT begonnen. ```