From 62d14af53c5466e92f47258cad24d0dfba083b5a Mon Sep 17 00:00:00 2001 From: Rain Ocampo Date: Fri, 21 Aug 2026 01:04:36 +0000 Subject: [PATCH] Modul-16-Paperclip: Orchestrierungsebene implementiert + E2E dokumentiert (noch NICHT FREIGEGEBEN, 21.08.2026) --- modul-16-paperclip.md | 136 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 modul-16-paperclip.md diff --git a/modul-16-paperclip.md b/modul-16-paperclip.md new file mode 100644 index 0000000..66ebaee --- /dev/null +++ b/modul-16-paperclip.md @@ -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-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. + +## 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. +```