Files
kst4contest/docs/superpowers/specs/2026-10-16-message-bus-second-slice-design.md
Rsclub2_2andClaude Opus 5.5 e0c1c6b6d4 One chat-frame flow for live and history messages (#105) (#139)
Second slice of making MessageBusManagementThread testable. The CH (live)
and CR (history) chat-frame branches of processRXMessage23001 were near
copies; they are now one processChatFrame(fields, live), with behaviour
unchanged.

- InboundChatFrame, ChatRoute and classifyRoute: where a message belongs
  (public, to me, from me, between others), pure.
- ChatMessageEffects and decideChatFrameEffects: what a message triggers
  (sounds, //BELL, //VER reply, auto-answer, directional tick, in-angle
  flag, DX cluster spot), pure. History frames trigger nothing but the flag.
- The four live/history differences are kept on purpose: frequency
  detection before routing (live) or after publishing (history), effects
  for messages to me, tick and spot between others, AirScout info on the
  SERVER sender.
- MessageBusManagementThreadChatFrameTest pins both branches through the
  real thread, including the frequency order on directed frames and the
  spot entry; ChatFrameDecisionTest covers the pure functions.
- Spec: docs/superpowers/specs/2026-10-16-message-bus-second-slice-design.md

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:45:21 +02:00

3.8 KiB

Entwurf — MessageBusManagementThread, zweite Scheibe (#105)

Freigegeben vom Maintainer am 2026-10-16 (Gespräch). Baut auf der ersten Scheibe auf (PR #123: Frequenz- und Auto-Antwort-Charakterisierung, reine Entscheidungsfunktionen für Auto-Antwort, Frequenzerkennung, Richtungs-Chance und DX-Cluster-Spot).

Warum

processRXMessage23001 behandelt Chatnachrichten zweimal: im CH-Zweig (Live-Chat, rund 350 Zeilen) und im CR-Zweig (Verlauf beim Anmelden, rund 130 Zeilen). Der CR-Zweig ist eine nachgeführte Kopie des CH-Zweigs. Jede Korrektur muss zweimal gemacht werden, und was im CH-Zweig passiert — Töne, Befehle, Auto-Antwort, Tick, DX-Cluster-Spot — ist nur über einen laufenden Thread mit gemockten Mitspielern erreichbar.

Ziel

Ein gemeinsamer Ablauf für CH und CR, dessen Entscheidungen als reine Funktionen ohne Thread testbar sind. Verhalten bleibt unverändert, auch dort, wo es eigenartig ist.

Die vier Unterschiede, die erhalten bleiben

CH (live) CR (Verlauf)
Frequenzerkennung vor dem Zuordnen und Veröffentlichen nach dem Veröffentlichen und dem Diagnose-Log
an mich veröffentlichen, Töne (P, CW, Stimme), //BELL, //VER-Antwort, Auto-Antwort nur veröffentlichen
zwischen anderen Winkel-Flag, Tick, DX-Cluster-Spot, Diagnose-Logs nur Winkel-Flag
SERVER-Absender mit leerer AirPlaneReflectionInfo ohne

Gleich in beiden: öffentliche Nachricht (Empfängerfeld 0) wird mit dem „alle“-Empfänger veröffentlicht; eigene Nachricht an andere bekommt (>CALL) vorangestellt; ein NullPointerException beim Zuordnen wird geloggt und verschluckt.

Bausteine

  1. Charakterisierungstests für CR durch den echten Thread, wie die erste Scheibe es für CH getan hat. Sie halten die vier Unterschiede fest, bevor irgendetwas verschoben wird.
  2. InboundChatFrame — reines Record aus den Feldern eines CH/CR-Frames: Kategorie-Nummer, Zeit, Absender-Call, Absender-Name, Text, Empfängerfeld. Fabrikmethode aus String[].
  3. ChatRoute classifyRoute(String receiverField, String senderCall, String receiverCall, String ownCall) → PUBLIC | TO_ME | FROM_ME | BETWEEN_OTHERS. Rein. Erhält die bekannte Eigenart: „an mich“ vergleicht mit Groß-/Kleinschreibung, „von mir“ ohne.
  4. ChatMessageEffects — Entscheidungsobjekt. Eine reine Funktion decide(frame, route, live, context) liefert, was zu tun ist: Töne, //BELL, //VER-Antwort, Auto-Antwort-Text, Tick, Winkel-Flag, Spot-Entscheidung. Der Kontext trägt die Präferenzwerte und den bisherigen Winkel-Zustand des Absenders, keine Objekte mit Seiteneffekten. Die vorhandenen reinen Funktionen der ersten Scheibe werden genutzt, nicht dupliziert.
  5. Ein Ausführer wendet die Effekte an (Töne abspielen, in die TX-Queue legen, Cooldown setzen, Spot senden, veröffentlichen) — in der heutigen Reihenfolge.
  6. processChatFrame(String[] fields, boolean live) ersetzt CH- und CR-Zweig. live steuert die vier Unterschiede oben, sonst nichts.

Bewusst nicht

  • Die Eigenarten werden nicht korrigiert; sie werden als Kandidaten für eigene Issues gelistet (Groß-/Kleinschreibung bei „an mich“, Reihenfolge der Frequenzerkennung in CR, SERVER ohne AirScout-Info in CR).
  • Sniffer, Erinnerungen und Skeds im ChatController sind ein eigenes Thema.
  • Andere Frame-Typen (Benutzerliste, LOC, DX-Cluster, UE …) bleiben, wie sie sind.

Tests

  • CR-Charakterisierung durch den Thread (Schritt 1); die vorhandenen CH-Tests der ersten Scheibe bleiben unverändert grün — sie sichern das Zusammenlegen ab.
  • InboundChatFrame, classifyRoute (alle vier Routen, beide Schreibweisen-Eigenarten), decide (je Route live und Verlauf, mit und ohne Töne/Befehle/Auto-Antwort/Spot).
  • Voller Build grün; Testzahlen aus den XML-Berichten.