mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-11-08 22:38:36 +01:00
fix: apply beacon switches at runtime
This commit is contained in:
1 parent
4d96822c0c
commit
b8bb86977f
30 files changed
+903
-133
No files matched your search
@@ -215,6 +215,8 @@ CR/LF framing, XML framing, ports/transports, callsign normalization and frequen
|
||||
- Automated-message loops must be prevented.
|
||||
- Cooldown/minimum-interval rules must be preserved.
|
||||
- A reply rejected before a complete valid TX item is queued must not consume cooldown.
|
||||
- Both category beacons share one timer, while their enable flags and templates remain profile-scoped and independent. The enable flags are observable runtime preferences: Settings changes and the `MyBeacon` status-chip action update them immediately, and every timer run reads their current values without restarting the timer or causing an immediate transmission. Only the explicit full settings write persists those flags; layout autosave deliberately leaves the on-disk functional state untouched.
|
||||
- `MyBeacon` owns one aggregate thread-status entry for both categories (`off`, a partial `enabled/available` count, `on`, or `FAILED`). Its action disables all currently usable beacons if any is enabled, otherwise it enables all currently usable beacons. A disabled second chat is not usable and its dormant enable flag must not be changed by the aggregate action. Category-specific timer failures remain authoritative while the affected beacon stays active; independent switch changes cannot hide them. The status bar resolves the aggregate from current controller state when a queued UI update is applied, so a delayed timer snapshot cannot overwrite a newer manual switch. Open Settings views observe the same preference values, so changes from the status chip remain synchronized without a parallel UI state.
|
||||
- Current implementation/tests define the exact message markers and timer details.
|
||||
|
||||
## Build / Verification
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# Live Beacon Control Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make both beacon enable switches effective immediately at runtime and make the aggregate beacon status chip an accurate shared toggle.
|
||||
|
||||
**Architecture:** Keep `ChatPreferences` as the profile-scoped source of truth, but expose the two activation flags as thread-safe observable values. Route settings and chip actions through `ChatController`, publish one aggregate `MyBeacon` status, and give only that thread-status chip an optional click action.
|
||||
|
||||
**Tech Stack:** Java 21, Kotlin 2.2, Compose Multiplatform, JUnit 5, Mockito, Gradle wrapper
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-11-04-live-beacon-control-design.md`
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Work directly on `main`, as explicitly authorized.
|
||||
- Do not stage, commit, push, merge, tag, release or deploy.
|
||||
- Keep beacon templates, interval handling, TX framing and second-chat eligibility unchanged.
|
||||
- Write source-code and configuration comments in English.
|
||||
- Use focused tests first and finish with `./gradlew.bat build --console=plain`.
|
||||
|
||||
## Review Focus
|
||||
|
||||
- A disabled second chat must leave its dormant second-beacon flag unchanged when the chip is clicked.
|
||||
- An external chip toggle must update an already open Beacon settings tab without reopening it.
|
||||
- A runtime toggle must not restart the timer or enqueue an immediate message.
|
||||
- An invalid beacon template must still be reported as a critical status rather than hidden by the aggregate state.
|
||||
- Profile reload must replace the observable values without carrying the previous profile's runtime flags across.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Observable profile-scoped beacon activation
|
||||
|
||||
**Files:**
|
||||
- Modify: `core/src/main/java/kst4contest/model/ChatPreferences.java`
|
||||
- Test: `core/src/test/java/kst4contest/model/ChatPreferencesBeaconStateTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: existing boolean getters/setters plus observable main/second beacon value accessors
|
||||
- Consumes: existing `MutableValue` / `SimpleValue` infrastructure
|
||||
|
||||
- [x] Write tests that changes are observable, values remain independent, XML reload restores both values, and an unsaved in-memory change does not survive a fresh load.
|
||||
- [x] Run `./gradlew.bat :core:test --tests kst4contest.model.ChatPreferencesBeaconStateTest --console=plain` and verify the new observable-accessor tests fail because the API is absent.
|
||||
- [x] Back the two flags with `SimpleValue<Boolean>` while preserving the existing getters, setters and XML element names.
|
||||
- [x] Re-run the focused test and the existing ChatPreferences tests.
|
||||
|
||||
### Task 2: Immediate settings effect and aggregate controller semantics
|
||||
|
||||
**Files:**
|
||||
- Modify: `core/src/main/java/kst4contest/controller/ChatController.java`
|
||||
- Modify: `core/src/main/java/kst4contest/controller/BeaconTask.java`
|
||||
- Create: `core/src/main/java/kst4contest/controller/BeaconStatus.java`
|
||||
- Test: `core/src/test/java/kst4contest/controller/BeaconControlTest.java`
|
||||
- Test: `core/src/test/java/kst4contest/controller/BeaconTaskTest.java`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/tabs/BeaconTabState.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/tabs/BeaconTab.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/ObservedValue.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/SettingsTabs.kt`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/tabs/BeaconTabStateTest.kt`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/tabs/SettingsApplyScreenTest.kt`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/tabs/DraftedSettingsTableTest.kt`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: observable preference values from Task 1
|
||||
- Produces: controller setters, usable-beacon toggle, aggregate status publication, Compose observation bridge
|
||||
|
||||
- [x] Write failing controller tests for `off`, `1/2`, `on`, main-only toggling when second chat is disabled, and both-category toggling when it is enabled.
|
||||
- [x] Write failing BeaconTask tests proving a flag changed between two runs changes queued output without restarting a timer, and that the final status is aggregate.
|
||||
- [x] Change Beacon settings tests so activation is immediate while templates and interval still wait for Apply; verify RED against the current draft-backed flags.
|
||||
- [x] Implement the aggregate status helper and controller actions without changing the outbound-message path.
|
||||
- [x] Make only the enable flags bypass `SettingsDraft`, observe their preference values in Compose, and wire their setters through the controller.
|
||||
- [x] Run the core and app-desktop focused tests and verify GREEN.
|
||||
|
||||
### Task 3: Clickable beacon status chip
|
||||
|
||||
**Files:**
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/StatusIndicatorState.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/StatusBar.kt`
|
||||
- Modify: `app-desktop/src/main/java/kst4contest/view/Kst4ContestApplication.java`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/StatusIndicatorStateTest.kt`
|
||||
- Create or modify: focused Compose status-bar rendering test under `app-desktop/src/test/kotlin/kst4contest/view/compose/`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: controller usable-beacon toggle from Task 2
|
||||
- Produces: optional per-source chip action registered only for `MyBeacon`
|
||||
|
||||
- [x] Write failing state tests for actions registered before and after the first status report and for non-action thread chips.
|
||||
- [x] Write a failing Compose test proving the beacon chip invokes its action while an ordinary status chip remains non-clickable.
|
||||
- [x] Add optional actions to thread-status buttons and apply button semantics only when an action exists.
|
||||
- [x] Register the controller toggle for `MyBeacon` during main-window state construction.
|
||||
- [x] Run the focused status tests and the affected main-window tests.
|
||||
|
||||
### Task 4: Documentation and verification
|
||||
|
||||
**Files:**
|
||||
- Modify: relevant beacon sections in `github_docs/de-Konfiguration.md`
|
||||
- Modify: corresponding sections in `github_docs/en-Configuration.md`
|
||||
- Modify: `docs/PROJECT_CONTEXT.md`
|
||||
- Review: relevant screenshots and changelog impact only
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: completed runtime and UI behavior from Tasks 1-3
|
||||
- Produces: aligned user documentation and durable state/persistence invariant
|
||||
|
||||
- [x] Update both manuals with immediate runtime effect, explicit-save persistence, aggregate chip behavior and second-chat handling.
|
||||
- [x] Record the observable canonical state, timer-read rule and persistence boundary in `docs/PROJECT_CONTEXT.md`.
|
||||
- [x] Run all focused tests, then `./gradlew.bat build --console=plain` and read test-result XML summaries.
|
||||
- [x] Run `git diff --check`, inspect PMD/SpotBugs XML for findings in changed production files, and review the final diff for unrelated changes.
|
||||
- [x] Leave all changes unstaged and uncommitted and report remaining manual UI checks.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Live Beacon Control Design
|
||||
|
||||
Freigegeben von Marc am 2026-11-04.
|
||||
|
||||
## Ziel
|
||||
|
||||
Die beiden Beacon-Aktivierungsschalter wirken in der laufenden Sitzung sofort. Der gemeinsame
|
||||
Beacon-Timer bleibt bestehen und liest bei jedem Lauf die aktuellen Zustände. Der Beacon-Chip
|
||||
im Hauptfenster zeigt den zusammengefassten Zustand und kann die aktuell nutzbaren Beacons
|
||||
gemeinsam ein- oder ausschalten.
|
||||
|
||||
## Verbindliches Verhalten
|
||||
|
||||
- Die gespeicherten Beacon-Zustände werden beim Profilstart geladen.
|
||||
- Ein Klick auf eine Beacon-Checkbox wirkt sofort im Speicher und damit beim nächsten
|
||||
regulären Timerlauf.
|
||||
- Aktivieren sendet nicht sofort und startet den Timer nicht neu.
|
||||
- Erst **Einstellungen speichern** schreibt die Zustände in die Profil-XML. Ohne explizites
|
||||
Speichern gilt die Änderung nur für die laufende Sitzung.
|
||||
- Beacon-Text und Intervall bleiben normale Settings-Entwurfswerte. Das Intervall startet den
|
||||
Timer erst beim Anwenden neu.
|
||||
- Der Status-Chip zeigt `off`, `1/2` oder `on` für die aktuell nutzbaren Kategorien.
|
||||
- Sind alle nutzbaren Beacons aus, aktiviert ein Chip-Klick alle nutzbaren Beacons. Ist
|
||||
mindestens eine nutzbare Beacon an, deaktiviert der Klick alle nutzbaren Beacons.
|
||||
- Bei deaktiviertem zweiten Chat schaltet der Chip nur die Hauptkategorie und verändert das
|
||||
gespeicherte Flag der zweiten Kategorie nicht.
|
||||
- Chip und geöffnetes Settings-Fenster zeigen denselben beobachtbaren Zustand.
|
||||
- Nur der Beacon-Chip wird anklickbar. Andere Thread-Status-Chips bleiben reine Anzeigen.
|
||||
|
||||
## Unveränderte Grenzen
|
||||
|
||||
- Beide Kategorien behalten eigene Aktivierungsflags und Texte.
|
||||
- Der zweite Beacon-Versand setzt weiterhin einen aktivierten zweiten Chat voraus.
|
||||
- Nachrichtenvalidierung, TX-Warteschlange und ON4KST-Protokoll bleiben unverändert.
|
||||
- Mindestintervall, gemeinsamer Timer und Intervall-Persistenz bleiben unverändert.
|
||||
- Profilzustände werden nicht miteinander vermischt.
|
||||
|
||||
## Technischer Ansatz
|
||||
|
||||
Die vorhandenen `ChatPreferences`-Getter und -Setter bleiben die kompatible Schnittstelle,
|
||||
werden für die beiden Aktivierungsflags aber auf thread-sichere beobachtbare Werte gestellt.
|
||||
Der Settings-Tab liest diese Werte als Compose-State und schreibt Aktivierungen direkt durch
|
||||
den Controller. Der Controller veröffentlicht nach jeder manuellen Umschaltung einen
|
||||
zusammengefassten `MyBeacon`-Status. `BeaconTask` meldet nach einem Timerlauf ebenfalls genau
|
||||
diesen zusammengefassten Status. `ThreadStatusButtons` erhält eine optionale Aktion pro
|
||||
Quelle; die Anwendung registriert sie nur für `MyBeacon`.
|
||||
Reference in new issue
Block a user