Count occupied restarts as failed missions; sync published Workshop version
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-11-07 01:05:43 +01:00
parent 161100cf08
commit e421dcfc15
14 changed files with 640 additions and 50 deletions
+22 -12
View File
@@ -44,23 +44,33 @@ headings inside code examples within an entry. Keep the formatted newest entry
within Discord's 2000-character limit; oversized entries fail without truncation.
The dated files in `publishing/` remain separate Workshop release notes.
After compiling/bundling and successfully publishing in Workbench, run:
Before preparing every push, synchronize the last published version automatically:
```sh
python3 tools/workshop_changelog.py --published
python3 tools/workshop_changelog.py --sync --native-compat .local/rhs-19-work/compat
```
The helper reads `asset.version` from Workbench's local publishing manifest and
updates `Latest published Workshop version: **0.0.109**` above the changelog
entries. It verifies the addon ID against `addons/core/addon.gproj`. Use
`--manifest /path/to/manifest.json` on another installation. Without `--published`
it only displays the bundle version. The flag confirms that you observed a
successful upload; the helper does not upload or query the Workshop.
This workstation uses the game's live public Workshop catalogue because the web
listing can lag behind publication. The helper uses the existing disposable
Proton prefix under `.local`, takes its test-run lock, opens a temporary muted
headless game profile, queries only this addon, and closes its own processes.
It neither downloads addons nor uploads or changes Workshop content. The query
is bounded to 60 seconds and refuses a busy prefix.
Commit that record together with the new player-facing entry and source changes,
then push. Drone reads the version from Git, without needing Workbench files.
Updating only the version does not resend the previous entry. The message labels
it as the last published version, since a Git push can contain newer changes.
On a machine without that native setup, `--sync` alone reads the official
Workshop page. It checks the addon ID and the current version's published and
approved flags. Neither route overwrites a newer recorded publication with an
older response. Lookup/validation failure leaves the changelog unchanged and
returns failure; obtain fresh publication evidence before pushing.
`--published` remains available immediately after an observed successful
Workbench upload. It records the matching local publishing manifest's version;
without either flag the helper only displays the bundled version. Bundling alone
is never publication confirmation.
Commit the synchronized preamble with the requested changes. Updating only that
version does not resend the previous entry. Drone labels it as the last published
version because a Git push can contain changes newer than the Workshop upload.
The notifier compares `DRONE_COMMIT_BEFORE` with `DRONE_COMMIT_SHA`, covering the
whole push, even when a documentation commit follows the changelog commit.
+27 -10
View File
@@ -124,15 +124,15 @@ existing queued payloads retain their original values and event IDs.
| `phase_changed` | An actual nonterminal mission transition. Use elapsed times for milestone durations. |
| `heartbeat` | A snapshot every five minutes while unfinished. |
| `telemetry_resumed` | Re-enabled during the same mission; the mission ID stays the same and `partial` is true. |
| `mission_finished` | Exactly one local result snapshot, before normal teardown. |
| `mission_finished` | One local result snapshot, at teardown or recovered on the next startup. |
| Outcome | Count as a gameplay result? |
| --- | --- |
| `victory` | Yes, successful mission. |
| `defeat` | Yes, failed mission, including administrator abandonment. |
| `defeat` | Yes, failed mission, including administrator abandonment and a restart with players connected. |
| `preparation_failed` | No, startup error; inspect `preparationError`. |
| `restarted_empty` | No, automatic last-disconnect or idle-empty restart. |
| `interrupted` | No, session ended without a gameplay result. |
| `interrupted` | No, an empty session ended without a gameplay result (also used by older clients for occupied interruptions). |
| `unfinished` in `previousOutcome` | No confirmed ending survived. May be a crash/forced stop. Do not infer a defeat. |
Player names and stable game account UUIDs support history across servers. No IP
@@ -161,8 +161,8 @@ summary containing matching map/server/mission/event/outcome identifiers plus
`server` and `allServers` records. Each record has completed rounds, wins,
failures, win rate and partial-round coverage. The mission validates these
identifiers and counts before displaying the current map's record on its result
screen. Retries never increase the totals twice. Startup failures, interrupted
sessions and empty restarts are excluded from win/failure totals. If a summary
screen. Retries never increase the totals twice. Startup failures, events marked `interrupted`, and empty restarts are excluded
from win/failure totals. Occupied restarts now produce explicit `defeat` events. If a summary
cannot be delivered before the next mission starts, the screen reports it as
unavailable and keeps local statistics visible.
Once a confirmed record is displayed, failures uploading older queued events
@@ -209,8 +209,10 @@ retry without edits; retries still use the original event IDs and count once.
Requests have a 15-second timeout, with a 30-second callback watchdog. Retries
back off from 10 seconds to five minutes. A five-second dispatch tick sends one
request at a time. Disk writes occur on events and acknowledgement, not every
player sample. Delivery never blocks mission startup or shutdown.
request at a time. Disk writes occur on events and acknowledgement. While occupied, a private
restart checkpoint is also saved every five seconds and on roster changes; it
is not sent as a result while the mission is running. An empty snapshot clears
that candidate, so earlier attendance alone does not turn a restart into a loss. Delivery never blocks mission startup or shutdown.
The profile queue holds at most 64 events of 64 KiB each. On overflow it discards
queued heartbeats first, then the oldest non-in-flight event; `droppedEvents`
@@ -220,9 +222,15 @@ recovery. An unreadable queue suspends telemetry and preserves evidence for
repair instead of silently replacing the server identity.
Unsent final results survive normal scenario reloads and are retried in the next
enabled instance. Abrupt termination can lose the latest event; the next start's
`previousOutcome` remains unfinished if no result was saved. A permanently
stopped host cannot send further data.
enabled instance. After abrupt termination, the next enabled instance promotes the last saved
occupied checkpoint to a `defeat` for the original mission, with its original
players and statistics. The checkpoint and queue transition are saved together;
retries retain the recovered event ID. Its timestamp and duration reflect the
last sample, not the next startup time. Connection changes in the final five
seconds may be missed if their roster callback or profile write did not complete.
Completed results are never replaced. Empty or legacy states without an occupied
checkpoint remain unknown rather than inventing a result. A permanently stopped
host cannot send further data.
Disabling immediately stops collection/new requests and discards queued events
and recovery copies. It cannot recall an HTTP request already submitted or erase
@@ -232,6 +240,15 @@ discards unsent data instead of forwarding old records to a different recipient.
Native API references: [RestContext](https://community.bistudio.com/wikidata/external-data/arma-reforger/EnfusionScriptAPIPublic/interfaceRestContext.html) and [RestCallback](https://community.bistudio.com/wikidata/external-data/arma-reforger/EnfusionScriptAPIPublic/interfaceRestCallback.html).
### Restart verification
The [native restart fixture](../tests/native/telemetry_restart/README.md) runs
two isolated Workbench processes with a real connected local player. It checks
native shutdown results, JSON/profile persistence, unfinished-state recovery,
completed-state deduplication and receiver validation of the generated events.
Telemetry network dispatch is replaced in the test copy only. This does not
certify a multiplayer AMP deployment or optional asset integrity.
### Round combat counters
Player records additionally include `kills`, `friendlyKills`, `deaths`, `downed`