Modul-16-Paperclip: Orchestrierungsebene implementiert + E2E dokumentiert (noch NICHT FREIGEGEBEN, 21.08.2026)
This commit is contained in:
parent
59e771759c
commit
62d14af53c
1 changed files with 136 additions and 0 deletions
136
modul-16-paperclip.md
Normal file
136
modul-16-paperclip.md
Normal 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-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.
|
||||
```
|
||||
Loading…
Reference in a new issue