156 lines
6 KiB
Markdown
156 lines
6 KiB
Markdown
---
|
|
type: Modul
|
|
_organized: true
|
|
---
|
|
|
|
# Modul-15 → Modul-09 Control-Anbindung — Implementierung & Live-E2E
|
|
|
|
**Status: FREIGEGEBEN / PRODUKTIV VERIFIZIERT** (20.08.2026, Nutzer-Bestätigung).
|
|
**Datum:** 20.08.2026 · **Autor:** Rain Ocampo (Hermes)
|
|
**Gilt für:** Modul-09-Execution-Service ↔ Modul-15-Monitoring-Control
|
|
|
|
> **Freigabe-Hinweis:** Diese Doku dokumentiert den Implementierungs- und E2E-Stand.
|
|
> Die **finale Freigabe** (M15/M09 als FREIGEGEBEN markieren) erfolgte am **20.08.2026**
|
|
> durch Nutzer-Bestätigung. M16 wird **nicht** begonnen.
|
|
|
|
---
|
|
|
|
## 1. Umgesetzte Architektur (Variante C)
|
|
|
|
**Event-Cache als nicht-kritischer Vorfilter + synchroner HTTP-Final-Check als Autorität.**
|
|
|
|
- **M15** = autoritative Safety-/Trading-Control-Instanz.
|
|
- **M09** sendet neue Orders (OPEN/INCREASE) **nur**, wenn M15 eindeutig `ENABLED` + frisch bestätigt.
|
|
- **REDUCE/CLOSE/CANCEL** (Risikoabbau) sind **immer** erlaubt — unabhängig vom M15-Status.
|
|
|
|
### Kernregel
|
|
| State | OPEN/INCREASE | REDUCE/CLOSE/CANCEL |
|
|
|-------|---------------|---------------------|
|
|
| `ENABLED` | **ERLAUBT** | erlaubt |
|
|
| `PAUSED` | **VERBOTEN** | erlaubt |
|
|
| `HALTED` | **VERBOTEN** | erlaubt |
|
|
| `UNKNOWN` / M15-down / stale | **VERBOTEN (FAIL-CLOSED)** | erlaubt |
|
|
|
|
---
|
|
|
|
## 2. API-Vertrag M15 → M09 (additiv, kein Breaking Change)
|
|
|
|
### `GET /control/trading-state`
|
|
```json
|
|
{
|
|
"trading_status": "ENABLED", // ENABLED|PAUSED|HALTED|UNKNOWN
|
|
"system_status": "HEALTHY",
|
|
"state_version": 3, // monoton, je Status-Änderung inkrementiert
|
|
"timestamp": "2026-08-20T15:30:00Z",
|
|
"expires_at": "2026-08-20T15:30:00.5Z", // TTL-Horizont (now + 500ms)
|
|
"ttl_seconds": 0.5,
|
|
"audit_id": "ctl-..." // M15-interne Audit-Kennung
|
|
}
|
|
```
|
|
Nur `trading_status=ENABLED` **und** `expires_at` in der Zukunft = eindeutige Erlaubnis.
|
|
Timeout/5xx/503 → **FAIL-CLOSED** (als UNKNOWN behandeln).
|
|
|
|
### Event-Kanal (Event-Cache)
|
|
- Exchange `market.control`, Routing-Key `trading.state` (nur bei Status-Änderung).
|
|
- M09-Consumer `ControlCacheConsumer` speist den Event-Cache-Vorfilter.
|
|
- Cache-TTL: 5 s. Stale-Cache → als UNKNOWN behandeln → OPEN/INCREASE blockiert.
|
|
|
|
---
|
|
|
|
## 3. M09-Implementierung
|
|
|
|
### Neue Dateien
|
|
- `app/control/client.py` — **ControlClient** (Event-Cache-Vorfilter + HTTP-Final-Check, FAIL-CLOSED)
|
|
- `app/control/__init__.py`
|
|
- `app/consumer/control_consumer.py` — **ControlCacheConsumer** (`market.control`/`trading.state`)
|
|
|
|
### Geänderte Dateien
|
|
- `app/core/service.py` — Control-Check zwischen Schritt 4 (Order anlegen) und Schritt 5 (`_submit_and_track`); `_apply_control_audit`; `action_type`-Ableitung; Consumer-Start/Stop
|
|
- `app/core/models.py` — `ExecutionOrder` + Audit-Felder
|
|
- `app/config.py` — M15-URL/Timeout/TTL/Cache-TTL + Control-Exchange/Routing-Key
|
|
- `app/storage/storage.py` — INSERT/UPDATE um control_*-Felder; `update_control_audit`
|
|
- `migrations/001_execution.sql` — Audit-Spalten (idempotent via `ADD COLUMN IF NOT EXISTS`)
|
|
|
|
### Audit-Felder je Order
|
|
`action_type`, `control_status`, `control_state_version`, `control_expires_at`,
|
|
`control_audit_id`, `control_check_source` (`http`|`cache`|`bypass`|`none`).
|
|
|
|
### Parameter
|
|
- Final-Check-HTTP-Timeout: **500 ms**, Retry: **max 1** sofort.
|
|
- `expires_at`-TTL (M15): **500 ms**.
|
|
- Cache-TTL (M09): **5 s**.
|
|
- Kein Auto-Resume; kein "Senden ohne Check".
|
|
|
|
---
|
|
|
|
## 4. Live-E2E-Ergebnisse (VPS, 20.08.2026)
|
|
|
|
Alle Szenarien auf dem VPS (187.124.31.123) live ausgeführt. **Alle grün.**
|
|
|
|
| # | Szenario | Ergebnis |
|
|
|---|----------|----------|
|
|
| S1 | **ENABLED-Pfad**: OPEN-Order durch, Auditfelder in DB | **9/9 PASS** |
|
|
| S2 | **HALTED-Pfad**: M03 gestoppt → OPEN blockiert, kein Broker-Send, reason `CONTROL_HALTED` | **9/9 PASS** |
|
|
| S3 | **PAUSED-Pfad**: nicht-krit. Service down → OPEN blockiert, reason `CONTROL_PAUSED` | **4/4 PASS** |
|
|
| S4 | **Risikoabbau bei HALTED**: REDUCE/CLOSE/CANCEL erlaubt (bypass) | **4/4 PASS** |
|
|
| S5 | **M15-down**: OPEN FAIL-CLOSED (`CONTROL_UNREACHABLE`), REDUCE/CLOSE/CANCEL erlaubt | **7/7 PASS** |
|
|
| S6 | **Cache-vs-Final-Check**: HTTP HALTED gewinnt über Cache | **2/2 PASS** |
|
|
| S7 | **Race/TTL**: Doppel-Publish → keine Doppelorder (Idempotenz) | **2/2 PASS** |
|
|
| S8 | **Event-Cache**: 1 Consumer, 0 Backlog, Reconnect nach RabbitMQ-Restart | **verifiziert** |
|
|
| S9 | **Recovery**: nach Behebung wieder ENABLED, OPEN erlaubt | **3/3 PASS** |
|
|
| S10 | **Health/Security**: health/ready 200, keine öffentl. Ports, keine Secrets, keine echten Tracebacks | **verifiziert** |
|
|
| S11 | **Regression**: bestehender M09-Paper-E2E (Kette 03→09) | **ALLE CHECKS BESTANDEN** |
|
|
|
|
### S1-Detail (ENABLED)
|
|
```
|
|
control_status=ENABLED
|
|
control_state_version=1
|
|
control_expires_at=1787241066.98
|
|
control_audit_id=ctl-2073194e651040db
|
|
control_check_source=http
|
|
action_type=OPEN
|
|
broker_order_id=PAPER-EXEC-... (Broker-Send erfolgt)
|
|
status=FILLED
|
|
```
|
|
|
|
### S2-Detail (HALTED)
|
|
```
|
|
control_status=HALTED
|
|
control_state_version=2
|
|
control_audit_id=ctl-b2cd6303f8754328
|
|
control_check_source=http
|
|
action_type=OPEN
|
|
broker_order_id=None (KEIN Broker-Send)
|
|
reason_codes=['CONTROL_HALTED']
|
|
status=FAILED
|
|
```
|
|
|
|
### S5-Detail (M15-down)
|
|
```
|
|
reason_codes=['CONTROL_UNREACHABLE']
|
|
broker_order_id=None (FAIL-CLOSED, kein Broker-Send)
|
|
REDUCE/CLOSE/CANCEL → control_check_source=bypass (erlaubt)
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Verifikation Health/Security
|
|
|
|
- M09 + M15 `health` und `health/ready` → **200**.
|
|
- Keine öffentlichen Ports (nur Docker-intern via `expose:`).
|
|
- Keine Secrets in Logs/API/DB.
|
|
- Tracebacks in Logs: ausschließlich pika `AMQPConnectionError` während des
|
|
kontrollierten RabbitMQ-Restarts (erwartete Reconnect-Logs, keine echten Fehler).
|
|
|
|
---
|
|
|
|
## 6. Freigabe-Status
|
|
|
|
- **FREIGEGEBEN / PRODUKTIV VERIFIZIERT** (20.08.2026, Nutzer-Bestätigung).
|
|
- M15/M09-Control-Anbindung ist **final freigegeben** — keine weiteren technischen Änderungen an M09/M15.
|
|
- M16: **nicht beginnen**.
|
|
- Credential-Cleanup: temporäre Forgejo-Tokens/Deploy-Keys → count=0 (siehe Git-Commit).
|
|
|
|
---
|
|
|
|
*Implementierung + Live-E2E abgeschlossen. Finale Freigabe erteilt (20.08.2026).*
|