mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-10-19 05:42:58 +02:00
* docs: add the test-coverage design spec (#62) Records the state found for issue #62 (JUnit classes under src/main that never run, test libraries in the shipped app image, dead 2023/2024 scratch tests, no coverage figure), the decisions taken (delete, move to src/test, JaCoCo report-only without a threshold, tests before packaging), what is deliberately left to separate issues, and the definition of done. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test: move the JUnit classes out of src/main and drop the dead 2023 tests (#62) Gradle's test task scans src/test only, so the six JUnit classes under src/main compiled on every build and were never executed. They move to src/test of the module that owns the class under test, keeping their package names: On4KstProtocolTest, On4KstSocketThreadTest and ChatMemberDirectionOpportunityTest within core; Utils4KSTFrequencyTest, FrequencyTextParserTest and ChatPreferencesStationMapVisibilityTest from app-desktop into core, next to the sibling tests that already live there, because they test core classes only. All 26 of them run and pass. The fully commented-out MessageBusManagementThreadFrequencyContextTest is deleted. Eight files under core/src/test/java/kst4contest/test from 2023/2024 go as well: they carry no assertion, five of them annotate a static main() with @Test, which Jupiter never runs, and some write the real preferences file, send real UDP broadcasts or open the real user database when started by hand. The five main() scratch programs under src/main (ReadUDPByWintestThreadTest, PatternMatcherTest, mapTest, RegexTester, locatorUtils/TestLocatorUtils) and MockKstServer, which only an unused import in ChatController still referenced, are removed too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * build: make JUnit and Mockito test-only dependencies (#62) With no test class left under src/main, the implementation declarations of junit-jupiter-api and mockito-core in core and app-desktop lose their only justification. They put junit-jupiter-api, junit-platform-commons, opentest4j, mockito-core, byte-buddy, byte-buddy-agent and objenesis on the runtime classpath and into lib/app of every app image, Flatpak and installer. The duplicate catalog entries junit-jupiter-api, mockito-core-compile and the mockitoCompile version go with them. Verified: `:app-desktop:dependencies --configuration runtimeClasspath` no longer lists any of the seven artifacts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: state that test failures fail the build and tests live under src/test (#62) AGENTS.md and docs/PROJECT_CONTEXT.md still said the build configuration had allowed test failures to pass. That was true of the Maven build; under Gradle a test failure fails the build, and only PMD and SpotBugs run with ignoreFailures. Both documents now say so, note that test classes live under src/test only and that JUnit and Mockito are test-only dependencies, and keep the rule to read the test-result XML rather than the exit code. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * build: add a JaCoCo coverage report (#62) The jacoco plugin is applied to every module from the root build with the tool version held in the catalog. jacocoTestReport now depends on test and writes XML and HTML per module; a root task jacocoAggregatedReport merges core and app-desktop into build/reports/jacoco/aggregated/ (XML plus HTML). i18n-generator is excluded: it is a build tool and its coverage says nothing about the shipped application. Kotlin classes are counted, because the Kotlin plugin adds its output to the main source set the report reads. Report only, on purpose. There is no jacocoTestCoverageVerification and no threshold: a minimum set at today's number would trip on the next unrelated change, and one set at a target would fail every build until tests exist for the number's sake. The figure is published so it can be read when deciding what to test next; the reasoning is in docs/superpowers/specs/2026-10-11-test-coverage-design.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * ci: run the tests before packaging and publish coverage (#62) The nightly and tagged-release workflows built seven package formats from commits nobody had tested on the way: pr-compile-check.yml runs the suite for pull requests only, and main can be pushed to directly. Both workflows now carry a copy of that test job, including the libgl1 step and the XML-based summary, and every packaging job declares `needs: test`. Copied rather than factored into a reusable workflow on purpose: the comments in the job explain decisions the packaging workflows should carry with them, and three copies read better than one indirection. build-docs-pdf runs pandoc only and is left alone; publish-flatpak-repo and release-tag are gated through the jobs they already need. The PR test job additionally runs jacocoTestReport and jacocoAggregatedReport once the tests have run (not `if: always()`: a report from an incomplete run would mislead), prints a line/branch coverage table per module and aggregated into the job summary from the JaCoCo XML, and uploads the aggregated HTML report as the coverage-report artifact for 14 days whenever it exists. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: describe the coverage report in the project context (#62) A short paragraph on JaCoCo in docs/PROJECT_CONTEXT.md: report only and why, where the per-module and aggregated reports land, which Gradle tasks write them, that i18n-generator is excluded, how the PR job summary and the coverage-report artifact show the figure, and that the nightly and tagged-release workflows run the tests before any packaging job. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test: round-trip every ChatPreferences field through the XML file (#62) Drive all public single-argument setters by reflection to non-default values, write preferences.xml, read it back and compare every getter. Fields that are not persisted on purpose are listed with their evidence; two real reader/writer gaps (second-category locator, sniffer words) are documented with a BUG marker instead of being fixed here. Two further tests load the bundled template and a legacy file without configVersion. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test: cover the DBController schema migration from older user_version values (#62) Open the seeded template database and hand-built release 1.1 and 1.3 schema fixtures with a DBController and verify that PRAGMA user_version reaches the current level, every column of the current CREATE TABLE statements exists, legacy callsign keys are merged to base callsigns and existing rows and flags survive. A further test proves that reopening an up-to-date database changes neither schema nor rows. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore: drop the committed JVM crash report and ignore future ones (#62) hs_err_pid26344.log in the repository root was a HotSpot crash dump that had been committed by accident. It carries no information about the project and must not travel with the sources. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: drop the dead QSO sniffer word list that corrupted the callsign list on load (#103) ChatPreferences carried a second sniffer list, lstNotify_QSOSniffer_sniffedWordsList, that no UI, no manual and no consumer outside ChatPreferences ever touched. It was still written to preferences.xml as <snifferWords><w>, and the matching reader block was a copy of the <snifferCallSigns> block: it cleared the word list and then added every word, normalised as a callsign, to lstNotify_QSOSniffer_sniffedCallSignList. Any entry that ever reached the word list therefore leaked into QSO monitoring on every load. Remove the field, its accessors, the write block and the read block. A <snifferWords> element in an older preferences file is now ignored like any unknown element; the callsign list and its persistence are unchanged. ChatPreferencesSnifferListTest loads a file that carries both lists and asserts that only the <snifferCallSigns> entry is monitored. The round-trip test loses its exclusion entry for the removed setter. Fixes #103 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: remove the second-category locator that could never be set (#104) ChatPreferences declared stn_loginLocatorSecondCat with the compiled-in default "jn49fk". Nothing wrote it to or read it from preferences.xml, no settings tab exposed it and no caller ever invoked the setter, so the field always held its default. On4KstConnectionManager.configureMainChat nevertheless compared that default with the station's locator and, with the second chat enabled, raised the warning "ON4KST uses one locator per TCP session. The second-chat locator ... is ignored" whenever the station's locator was not jn49fk, which is practically every installation. ON4KST uses one locator per TCP session by design, so a second-category locator can never become meaningful. Remove the field, its accessors, the comparison and the warning; the rest of configureMainChat is unchanged. The round-trip test loses its exclusion entry for the removed setter. No automated test covers configureMainChat: it is private, works on the manager's private Session and needs a mocked ChatController plus a live socket handshake, so a harness would far exceed the scope of this fix. The compile of core and app-desktop and the shorter exclusion list are the evidence that nothing references the member. Fixes #104 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
182 lines
9.4 KiB
Markdown
182 lines
9.4 KiB
Markdown
# KST4Contest agent instructions
|
|
|
|
These project instructions extend Marc's global Codex working agreements.
|
|
|
|
## Project identity
|
|
|
|
KST4Contest is a Java/Kotlin desktop client for ON4KST chat, with a Compose Multiplatform user interface with contest-oriented workflows and integrations including logging software, AirScout, rotor control, DXCluster and local persistence.
|
|
|
|
Primary repository areas:
|
|
|
|
- `core/src/main/java/kst4contest/` and `core/src/test/`
|
|
- `app-desktop/src/main/java/kst4contest/` and `app-desktop/src/test/`
|
|
- `github_docs/`
|
|
- `website/`
|
|
- `docs/`
|
|
- `packaging/`
|
|
- `.github/`
|
|
- `build.gradle.kts`, `settings.gradle.kts`, `gradle.properties`, `gradle/`
|
|
|
|
Inspect the current tree before assuming an exact class/path still exists.
|
|
|
|
## Mandatory interaction rule
|
|
|
|
For every planned code or documentation implementation:
|
|
|
|
1. inspect first;
|
|
2. explain the task understanding in German;
|
|
3. identify and ask all relevant implementation questions;
|
|
4. wait for answers when needed;
|
|
5. present the final concept in German;
|
|
6. state what must remain unchanged;
|
|
7. request explicit concept approval;
|
|
8. wait;
|
|
9. implement only after approval.
|
|
|
|
If an answer is uncertain, do not interpolate it. Check current code/tests/docs/project context first and ask Marc when the uncertainty can affect behaviour.
|
|
|
|
## Language
|
|
|
|
- Communicate with Marc in German.
|
|
- Write source-code comments and Javadoc exclusively in English.
|
|
- Keep log/protocol/API literals in their canonical form.
|
|
- Commit messages are concise English when a commit is explicitly requested.
|
|
- User-facing DE/EN documentation follows `$praktimarc-writing-style`.
|
|
|
|
## Java and user-interface architecture
|
|
|
|
- Preserve or improve separation between network/parsing/service/controller/UI responsibilities.
|
|
- Do not solve architecture problems by letting worker/model code directly manipulate user-interface collections.
|
|
- Active chat-member domain state is conceptually thread-safe state and lives in an `ObservableRoster` in `core`; the `ObservableList` a `TableView` is bound to is a mirror of it, not the store.
|
|
- `MessageBusManagementThread` must not directly read or mutate the row lists the user interface draws from; it works on snapshots.
|
|
- Route UI-visible mutations through the controller and the `UiDispatcher` (`AwtUiDispatcher` hands them to the AWT event dispatch thread, where Compose draws). Do not reach for a toolkit thread call such as `Platform.runLater` or `EventQueue.invokeLater` in `core`; it has no toolkit dependency.
|
|
- Prefer explicit DTOs over records when introducing transport/parser DTOs in this codebase unless the approved concept says otherwise.
|
|
- Handle incomplete external/historical data defensively.
|
|
- `qrb`, QTF and related external values can be absent. `null` means unavailable, not zero.
|
|
- Unexpected input must not terminate message-processing or UI threads.
|
|
|
|
## Callsign and category identity
|
|
|
|
- Preserve full callsign variants as distinct chat-member identities where the server exposes them separately.
|
|
- Category is part of chat identity. Do not merge messages across categories.
|
|
- Base-call normalization may be used only for explicitly base-call-wide features such as worked status or monitoring rules.
|
|
- Worked status is shared across suffix variants of the same base call.
|
|
- Monitoring a callsign variant such as `DN9APW-2` or `DN9APW-70` is intended to monitor the base call `DN9APW`, so users do not need to enter every SSID.
|
|
- Do not generalize suffix semantics beyond behaviour explicitly established by the current code/specification.
|
|
|
|
## Bands and availability
|
|
|
|
- ON4KST categories 2 and 3 are central to the normal VHF/UHF workflow, but other category values can occur and must fail safely.
|
|
- Do not let unsupported categories produce exceptions.
|
|
- Known-active-band logic and `B+` interpretation must remain consistent across the application.
|
|
- Band information parsed from names/text must respect explicit `NOT-QRV` information; NOT-QRV overrides positive availability hints.
|
|
- Do not silently fall back to a fixed band/frequency when a required decision is ambiguous unless an approved fallback exists.
|
|
- Manual band settings and actual current QRG must remain consistent with features that depend on frequency.
|
|
|
|
## External protocols and integrations
|
|
|
|
Before changing ON4KST, AirScout, UCXLog/DXLog, Win-Test, PSTRotator or DXCluster handling:
|
|
|
|
- inspect the current implementation;
|
|
- preserve exact framing and compatibility;
|
|
- inspect current tests;
|
|
- check authoritative upstream documentation when the protocol detail is uncertain;
|
|
- ask Marc if more than one behaviour is plausible.
|
|
|
|
Specific invariants and historical context are in `$kst4contest-change` references.
|
|
|
|
Never change CR/LF, XML framing, callsign normalization, frequency formatting or port/transport assumptions casually.
|
|
|
|
## UI behaviour
|
|
|
|
- Preserve contest workflow speed and discoverability.
|
|
- Do not change zoom, selection, focus, sorting, tab choice or prefilled text as an incidental side effect.
|
|
- Map reset behaviour should clear the selected target without changing the zoom unless a new task explicitly changes this.
|
|
- New station selection should preserve the established `/cq callsign` prefill behaviour.
|
|
- If no send category is selected, preserve the established Main-category fallback unless explicitly changed.
|
|
- Null/unknown data must render as unavailable/empty according to current UI conventions, not as fake zero values.
|
|
|
|
## Map
|
|
|
|
- The station map is a Compose canvas. It fetches its tiles directly; the former JavaFX WebView, the bundled Leaflet resources, the CSS-3D-transform workaround and the `TileProxyServer` that worked around the WebView's TLS behaviour in AppImage and Flatpak packaging are all gone.
|
|
- Map reset clears the selected target without changing the zoom. Offline DEM, terrain packages and the profile cache must keep working unchanged.
|
|
|
|
## Autoanswer / beacon safety
|
|
|
|
- Prevent automated-message loops.
|
|
- Respect the established minimum interval/cooldown logic.
|
|
- Do not consume a cooldown for a reply that is rejected before a complete valid TX item is queued.
|
|
- Preserve priority of frequency/QRG requests where established.
|
|
- Cooldown identity must not accidentally collapse unrelated callsign/category identities.
|
|
- Treat the current implementation/tests as the source of truth for exact message markers and timer details.
|
|
|
|
## Build and verification
|
|
|
|
Use the Gradle wrapper.
|
|
|
|
Windows:
|
|
|
|
```text
|
|
.\gradlew.bat ...
|
|
```
|
|
|
|
Read the current `gradle.properties` and `gradle/libs.versions.toml` before relying on version numbers.
|
|
|
|
At this context snapshot the project uses Java 21, Kotlin 2.2 and Compose Multiplatform 1.8.x, with JUnit 5/Mockito, PMD and SpotBugs integrated. JavaFX is gone; there is no `org.openjfx` dependency left.
|
|
|
|
Important: a test failure fails the build, but PMD and SpotBugs run with `ignoreFailures`, so static-analysis findings do not. Test classes live under `src/test` only (since #62; before that a few sat under `src/main` and were never run), and JUnit/Mockito are test-only dependencies. Therefore:
|
|
|
|
- inspect the Gradle test summary;
|
|
- inspect the test-results XML under `*/build/test-results/` when needed;
|
|
- do not infer "all tests passed" from exit code 0 -- read the XML;
|
|
- report PMD/SpotBugs findings that are visible in the relevant build.
|
|
|
|
Run focused tests first, then normally the relevant broader test/build command for the scope.
|
|
|
|
## Documentation and durable project context
|
|
|
|
Use `$software-project-context`, `$kst4contest-documentation`, and `$praktimarc-writing-style` as relevant.
|
|
|
|
Do not perform a full manual or website audit after every implementation.
|
|
|
|
After a completed change:
|
|
|
|
1. perform a short documentation-impact classification;
|
|
2. if user-visible behaviour is plausibly affected, search only the relevant German and English manual sections under `github_docs/`;
|
|
3. keep both language versions semantically aligned when an update is required;
|
|
4. check README and website feature text only when the changed feature/configuration is represented there or is likely to need representation;
|
|
5. identify screenshots that are likely stale instead of fabricating replacements;
|
|
6. update `docs/PROJECT_CONTEXT.md` for significant architectural, protocol, state/persistence, operational, integration, deployment, workaround, or long-lived behavioural decisions;
|
|
7. keep `Related Projects / Integration Points` current when KST4Contest, its website, hamradioonline infrastructure or planned propagation services affect one another.
|
|
|
|
A full documentation audit is reserved for explicit audit requests, major release preparation, broad UI/workflow changes, or evidence that documentation is broadly stale.
|
|
|
|
## Website
|
|
|
|
The repository contains an Eleventy-based website under `website/` with its own tests/build logic.
|
|
|
|
Do not assume website deployment/update-feed details; inspect current scripts/workflows before changing them.
|
|
|
|
## Change scope and Git
|
|
|
|
- No unrelated refactoring.
|
|
- No production dependency without prior approval.
|
|
- No automatic version bump.
|
|
- No commit/push/merge/tag/release/deploy without separate explicit authorization.
|
|
- Preserve deliberate test data and easter eggs unless explicitly changed.
|
|
- Never overwrite unrelated working-tree changes.
|
|
|
|
## Completion
|
|
|
|
After implementation, report in German:
|
|
|
|
- understanding fulfilled;
|
|
- changed files;
|
|
- important design decisions;
|
|
- tests/builds and exact results;
|
|
- documentation-impact classification;
|
|
- manual/website/README/context updates made or why none were necessary;
|
|
- related-project impact when relevant;
|
|
- remaining uncertainty;
|
|
- suggested next action, without performing it automatically.
|