Skip to content

feat: monthly active users per platform, answered by /mau - #71

Closed
Bilb wants to merge 1 commit into
mainfrom
feat/platform-stats
Closed

Bilb wants to merge 1 commit into
mainfrom
feat/platform-stats

Conversation

@Bilb

@Bilb Bilb commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

/mau for monthly active users per platform, and /mau-upload to hand it the store exports. Stacked on #81, which adds the relay, /run and /versions.

mau lands off (enabled = false in jobs.toml): /mau and /mau-upload are not registered and no mau unit is enabled until that line is removed. Deploying this changes nothing until then.

/mau: monthly active users

No timer: mau runs only when someone asks with /mau (optionally month:YYYY-MM). The silence checker leaves it alone.

Answers

  • Every answer is seen only by the person who ran /mau, nothing is posted in the channel.
  • Both stores have a final figure for the month's last day: the asker gets the figures.
  • Otherwise, only the asker sees which exports are missing and how to get them; before about the 9th it also says when Play will have the month's end. A month that has not ended is refused the same way.
  • A failure is told to the asker alone and alerted to alerts.env's channel, a systemd stop at the 5-minute timeout included.
  • Asked again, it answers again.

Sources

  • Android, Play and iOS: neither store has an API for active users. Someone exports Play's MAU report and App Store Connect's Active in Last 30 Days (both daily CSVs) and hands them to /mau-upload.
  • iOS counts only devices sharing analytics, so it is divided by the month's opt-in rate from the App Store Connect API's App Opt In report (a Sales and Reports key, loaded as a systemd credential). The answer names the report, the rate and its counts. The API's App Sessions report is not used: summing its rows counts a device once per app version, OS and territory, 5% to 20% too many.
  • Android outside Play: the highest stable release's GitHub APK downloads, plus an F-Droid estimate of 10% of every other figure, since F-Droid publishes no counts.
  • Desktop: the highest stable release's (as store-versions picks it, not GitHub's newest) downloads per platform, Flathub's installs included. Desktop has no active-user count.

Flow

  • The relay validates the month, then, under its start lock, writes inbox/request.json (the interaction's application id and token, and the month) and asks for the unit as /run does. It acknowledges Discord with an ephemeral deferral, and removes request.json if the unit did not start.
  • mau removes request.json, checks its shape (digits for the id, no / in the token), merges every export in inbox/ into a daily history.json and files them in done/, then answers by editing the acknowledgement. It retries a 404, since its first edit can reach Discord before the relay's acknowledgement. The token never reaches an alert or the journal.
  • A changed figure for the month before's end is listed in every answer that month, and forgotten once no default /mau compares against that day.

Relay changes

  • /mau-upload file:<csv> downloads the attachment from Discord's CDN, checks it with mau.parse_export, and only then renames it into mau's inbox. It replies to the uploader alone, saying whether the export has last month's final figure.
  • /run no longer offers mau: started any other way, it has nobody to answer.
  • /mau and /mau-upload are registered hidden from everyone but server administrators, like /run, and only while mau is on.
  • The relay can also write mau's inbox (sessionops:opsbot 0770).

Registry and install

  • jobs.toml: enabled (default true; a job set false gets no units, is refused by the runner, and is offered nowhere). session-ops list --off lists those jobs.
  • install.sh: mau's inbox, mau.env and an empty asc-key.p8.

Deploy

  • /etc/session-ops/mau.env: ASC_ISSUER_ID, ASC_KEY_ID; /etc/session-ops/asc-key.p8, mode 600 (install.sh creates it empty, and an empty one fails the run naming it).
  • session-ops discord-register again once mau is on.

Not yet done: /mau-upload refusals ran against a test app, before /mau answered through the interaction. Nothing has run on the host. Once mau is on: /mau with no exports tells only you what is missing; with both, it shows you the figures, and no one else sees them.

Tests

uv run --locked python -m unittest discover -s tests -t . (991 OK, 1 skipped), ruff check . clean.

@Bilb Bilb changed the title feat: per-platform usage stats: Desktop downloads and Android MAU feat: monthly active users per platform: Android, iOS and Desktop Oct 9, 2026
@Bilb Bilb changed the title feat: monthly active users per platform: Android, iOS and Desktop feat: monthly active users per platform, and Discord commands to feed and run jobs Oct 9, 2026
@Bilb
Bilb force-pushed the feat/platform-stats branch from f24e162 to 53eee94 Compare October 16, 2026 08:29
@Bilb
Bilb marked this pull request as ready for review November 3, 2026 02:52
mau merges the Play Console and App Store Connect exports handed to /mau-upload into
a daily history, scales iOS by Apple's opt-in rate, adds GitHub APK and Desktop
downloads and an F-Droid estimate, and answers the asker alone.

`enabled = false` in jobs.toml keeps a job off; mau ships off.
@Bilb
Bilb force-pushed the feat/platform-stats branch from ee9c6f7 to f71e8ee Compare November 3, 2026 03:28
@Bilb Bilb changed the title feat: monthly active users per platform, and Discord commands to feed and run jobs feat: monthly active users per platform, answered by /mau Nov 3, 2026
@Bilb
Bilb changed the base branch from main to feat/discord-commands November 3, 2026 03:28
Base automatically changed from feat/discord-commands to main November 3, 2026 06:21
@Bilb Bilb closed this Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant