Stabilize control surface and external bridge v1

This commit is contained in:
jan
2026-04-20 01:13:27 +02:00
parent a56cecb23d
commit 07c52db5fb
29 changed files with 8818 additions and 1510 deletions

92
docs/control_ownership.md Normal file
View File

@@ -0,0 +1,92 @@
# Control Ownership
## Ziel
Diese Regeln definieren die konfliktfreie Steuersemantik zwischen allen aktuellen und spaeteren Control-Quellen auf derselben Host-Core-v1-Aussenkante.
Betroffene Quellen:
- kreative Web-UI
- technische Desktop-GUI
- generischer externer Control-Adapter
- spaetere grandMA-Anbindung
## Gemeinsame Grundregel
Der Host-Core bleibt die einzige mutierende Autoritaet fuer Show-State.
Keine Quelle darf:
- intern an Simulation-, Persistenz- oder UI-Zustaende vorbeischreiben
- eigene Sonderpfade fuer Pattern-, Preset-, Group- oder Transition-Logik einziehen
- die LED-Taktung oder Timing-Autoritaet uebernehmen
## Rollen
### Web-UI
- kreative Oberflaeche
- darf direkte Primitive und lokale staged Sessions benutzen
- staged Zustand bleibt lokal, bis `trigger_transition` explizit committed wird
### technische Desktop-GUI
- Engineering- und Diagnoseoberflaeche
- bevorzugt direkte Operationen, Beobachtung und Admin-Aktionen
- bekommt keine priorisierte Besitzrolle gegenueber anderen Quellen
### externer Control-Adapter
- darf nur auf die eingefrorene v1-Primitive-Semantik abbilden
- staged Sessions muessen pro externer Session sauber getrennt gehalten werden
- Fehlercodes aus dem Host werden unveraendert durchgereicht
### spaetere grandMA-Anbindung
- ist spaeter nur eine weitere Quelle auf derselben Bridge-/Primitive-Aussenkante
- bekommt keine Sonderrechte gegenueber Web-UI, GUI oder anderen Adaptern
## Konfliktregeln
### Direkte Operationen
- direkte Primitive mutieren sofort den globalen Host-State
- letzte erfolgreich ausgefuehrte Mutation gewinnt
- dazu gehoeren insbesondere:
- `blackout`
- `recall_preset`
- `recall_creative_snapshot`
- `set_master_brightness`
- `upsert_group`
### Staged Operationen
- staged Primitive mutieren den globalen Host-State nicht sofort
- staged Zustand gehoert immer nur zur lokalen Session der jeweiligen Quelle
- staged Sessions duerfen parallel existieren
- staged Inhalt wird erst mit `trigger_transition` global wirksam
### Commit-Verhalten
- `trigger_transition` ist der einzige Commit-Punkt fuer staged Pattern-/Parameter-/Transition-Intents
- ein erfolgreicher Commit konsumiert nur die staged Session der commitenden Quelle
- andere offene Sessions bleiben unveraendert bestehen
### Beobachtung
- `request_snapshot` und State-Projektionen sind read-only
- Beobachtung erzeugt keinen Ownership-Anspruch auf den Show-State
## Praktische Auswirkungen
- es gibt aktuell kein verteiltes Locking zwischen Quellen
- konfliktfreie Zusammenarbeit entsteht ueber:
- identische Primitive-Semantik
- lokale Session-Isolation fuer staged Flows
- last-write-wins fuer direkte globale Mutationen
- explizite Commits statt impliziter Side Effects
## Persistenz
- nur global wirksame Host-Mutationen und Persistenz-Kommandos beeinflussen Runtime-State-Dateien
- uncommittete staged Sessions sind absichtlich nicht Teil des globalen Persistenzzustands

View File

@@ -0,0 +1,126 @@
# External Control Bridge
## Zweck
Der External-Control-Bridge-Prozess ist eine duenne generische Prozess-Aussenkante fuer die eingefrorene Show-Control-v1-Semantik.
Er:
- bildet externe Commands auf die bestehenden Show-Control-Primitives ab
- haelt staged Sessions pro `session_id`
- reicht Host-Fehlercodes unveraendert durch
- fuegt keine neue Geschaeftslogik hinzu
Implementierung:
- `crates/infinity_host/src/external_bridge.rs`
- CLI-Einstieg ueber `cargo run -p infinity_host -- external-control-bridge ...`
## Start
```bash
. "$HOME/.cargo/env"
cargo run -p infinity_host -- external-control-bridge --config config/project.example.toml --runtime-state data/runtime_state.json
```
Der Prozess nutzt `stdin`/`stdout` im JSONL-Format:
- eine JSON-Nachricht pro Zeile nach `stdin`
- eine JSON-Antwort pro Zeile auf `stdout`
## Request-Form
```json
{
"request_id": "ext-1",
"session_id": "desk-a",
"command": {
"type": "execute_primitive",
"payload": {
"primitive": {
"primitive": "set_pattern",
"payload": {
"pattern_id": "noise"
}
}
}
}
}
```
Weitere Bridge-Commands:
- `execute_primitive`
- `get_state`
- `clear_session`
Hinweis:
- `request_snapshot` bleibt ein Show-Control-Primitive und laeuft deshalb ueber `execute_primitive`
- `get_state` liefert die read-only State-Projektion ohne Preview
## Response-Form
```json
{
"semantic_version": "v1",
"request_id": "ext-1",
"session_id": "desk-a",
"result": {
"type": "primitive_buffered",
"payload": {
"summary": "pattern staged: noise"
}
},
"session": {
"session_id": "desk-a",
"pending": {
"pattern_id": "noise",
"has_group_target": false,
"group_id": null,
"parameters": {},
"transition_style": null,
"transition_duration_ms": null
}
}
}
```
Moegliche Result-Typen:
- `primitive_buffered`
- `command_accepted`
- `snapshot`
- `state`
- `session_cleared`
- `error`
## Fehlerverhalten
Primitive-Fehler bleiben unveraendert:
- `unknown_group`
- `unknown_preset`
- `unknown_creative_snapshot`
- `group_exists`
- `persist_failed`
- `show_control_session_required`
- `transition_pattern_required`
Bridge-spezifische Rahmenfehler:
- `invalid_bridge_request_json`
- `session_id_required`
## Session-Regeln
- staged Primitive mit `session_id` werden in einer isolierten Session gepuffert
- staged Primitive ohne `session_id` laufen absichtlich gegen den stateless Port und liefern `show_control_session_required`
- direkte Primitive koennen mit oder ohne Session aufgerufen werden
- `clear_session` verwirft nur die angegebene Session
## Ownership
Die Konflikt- und Ownership-Regeln fuer mehrere Control-Quellen stehen in:
- `docs/control_ownership.md`

61
docs/pattern_matrix_v1.md Normal file
View File

@@ -0,0 +1,61 @@
# Show-Control Pattern Matrix v1
Die Web-UI orientiert sich wieder an der alten Python-Bedienung, ohne die neue Host-/API-Architektur zu verlassen.
## Kanonische Modi
| Python-Referenz | Host-v1 `pattern_id` | Status | Bemerkung |
| --- | --- | --- | --- |
| Arrow | `arrow` | implementiert | diskrete Chevron-Belegung |
| Breathing | `breathing` | implementiert | globale Atemkurve |
| Center Pulse | `center_pulse` | implementiert | Center-/Outline-Modi ueber `center_pulse_mode` |
| Checkerd | `checker` | implementiert | `classic`, `diagonal`, `checkerd` ueber `checker_mode` |
| Column Gradient | `column_gradient` | implementiert | horizontale Verlaufslogik |
| Row Gradient | `row_gradient` | implementiert | vertikale Verlaufslogik |
| Saw | `saw` | implementiert | quantisierte Sweep-Logik |
| Scan | `scan` | implementiert | Winkel-/Line-/Bands-Scan |
| Scan Dual | `scan_dual` | implementiert | gespiegelt laufende Scanner |
| Snake | `snake` | implementiert | deterministische software-only Snake-Approximation |
| Solid | `solid` | implementiert | statischer Vollfarben-Look |
| Sparkle | `sparkle` | implementiert | randomisierte LED-Aktivierung |
| Stopwatch | `stopwatch` | implementiert | LED-Fuell-/Leerlauf ueber Tile-Perimeter |
| Strobe | `strobe` | implementiert | `global`, `random_pixels`, `random_leds` |
| Sweep | `sweep` | implementiert | gerichteter Color-Wipe |
| Two Dots | `two_dots` | implementiert | zwei gespiegelt laufende Highlights |
| Wave Line | `wave_line` | implementiert | diskrete Wellenlinie ueber das 3x6-Raster |
## Gemeinsame Parameterbasis
Die v1-Host-Semantik lehnt sich fuer die Pattern jetzt wieder an die alte Python-Parameterbasis an:
- gemeinsam: `speed` (Default `0.45`), `brightness` (`1.0`), `fade` (`0.35`), `tempo_multiplier` (`1.0`)
- Farben: `color_mode`, `primary_color`, `secondary_color`, `palette`
- modusspezifisch nach alter Logik: z. B. `direction`, `symmetry`, `checker_mode`, `center_pulse_mode`, `scan_style`, `angle`, `on_width`, `off_width`, `band_thickness`, `flip_horizontal`, `flip_vertical`, `strobe_mode`, `pixel_group_size`, `strobe_duty_cycle`, `randomness`
## Kompatibilitaets-IDs
Diese IDs bleiben fuer bestehende Presets, Tests und API-v1-Replays erhalten:
| Bestehende ID | Laufzeit-Ziel |
| --- | --- |
| `solid_color` | `solid` |
| `gradient` | `column_gradient` |
| `chase` | `sweep` |
| `pulse` | `breathing` |
| `noise` | `sparkle` |
| `walking_pixel` | `scan` |
Die Kompatibilitaets-IDs behalten ihre bisherigen Parametervertraege, damit bestehende Replays und Presets nicht brechen.
## Arbeitsmodi in der Web-UI
- `Test/Edit`: Pattern- und Parameter-Aenderungen wirken sofort direkt gegen den Host.
- `Show/Event`: Pattern- und Parameter-Aenderungen werden lokal gestaged und erst ueber `Go` oder `Fade Go` committed.
- Preview-Modus in der Creative Surface bleibt bewusst nur `LEDs Only`.
- Pattern-Wechsel uebernimmt die bestehende Parameterbasis wie im alten Python-Tool; es werden keine versteckten UI-Defaults pro Modus injiziert.
## Offline-/Preview-only-Semantik
- Ohne echte Clients/Nodetelemetrie zeigt der Simulation-Host die Topologie als `preview-only`.
- Node-/Panel-Verbindungen bleiben ehrlich `offline`.
- Es werden keine simulierten Online-/Offline-Events fuer Operatoren erzeugt.

View File

@@ -8,6 +8,8 @@ Diese Primitive-Menge ist die kleine, dauerhafte interne Steuersemantik fuer sof
- keine grandMA-spezifische Kopplung
- keine zweite Architektur neben Host-Core und API
Der aktuelle Stand gilt faktisch als eingefrorene Show-Control-v1-Semantik. Erweiterungen muessen kuenftig kompatibel zur bestehenden direct-/staged-Trennung, Fehlercode-Menge und Event-Sicht bleiben.
Der Implementierungspfad liegt in `crates/infinity_host/src/external_control.rs`.
## Primitive
@@ -111,3 +113,8 @@ Der sehr duenne generische Referenzpfad liegt in `crates/infinity_host/src/exter
- `ReferenceShowControlClient::stateful(...)` fuer direkte plus staged Flows
- `ReferenceShowControlClient::stateless(...)` zum bewussten Nachweis, dass staged Primitive am nackten Port mit `show_control_session_required` abgewiesen werden
- `BufferedShowControlAdapter` und `ShowControlSession` als kleine Buffer-/Commit-Implementierung ohne neue Grundarchitektur
Ergaenzende Randbedingungen:
- `docs/external_control_bridge.md` beschreibt die generische Prozess-Aussenkante auf Basis derselben Primitive
- `docs/control_ownership.md` beschreibt die konfliktfreie Koexistenz mehrerer Control-Quellen