trading-system-docs/notes/trading/system-docs/modul-16-paperclip.md

8.6 KiB
Raw Blame History

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 /backtestSUCCEEDED, agent_run + run_id/result_refs korrekt (kind:"backtest").
  • Optimization-Flow: M16 → M13 POST /optimizationSUCCEEDED, 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.