Skip to content

Report a startup event to trace, off the main thread and with an opt-out - #26

Merged
dmccoystephenson merged 1 commit into
mainfrom
usage-reporting-via-trace
Sep 12, 2026
Merged

Report a startup event to trace, off the main thread and with an opt-out#26
dmccoystephenson merged 1 commit into
mainfrom
usage-reporting-via-trace

Conversation

@dmccoystephenson

Copy link
Copy Markdown
Member

Summary

Usage reporting to trace is wired into Patchwork, the Preponderous-Software rollout counterpart of the Dans-Plugins one documented in docs/CONSUMERS.md there.

  • trace_client.py is vendored from trace-client-python as a single standard-library-only module, unmodified apart from a vendoring note in its docstring; its test is vendored as tests/test_trace_client.py with one import adjusted.
  • usage_reporting.py is added. It reads the usage_reporting block from settings.json in the working directory (the same place environments.json is kept; *.json is already git-ignored), builds the client and reports one startup event tagged with the version read from version.txt. The client is closed at interpreter exit via atexit.
  • main() calls startUsageReporting(log=log) as its first line — a two-line change to main.py, kept deliberately small so that it composes with the open restructure in Make main.py importable and cap its render loop #23.
  • The README gains a "Usage reporting" section describing what is sent and how to turn it off.

The guarantees of the client are kept: report() returns immediately (the HTTP call happens on one daemon thread), never raises, and queues at most 256 reports before dropping. A settings file that is missing, unwritable or corrupt cannot raise either — an unreadable settings.json yields a disabled client and one logged line, and is not overwritten.

What is sent, and what is not

One startup event per launch: {"application":"patchwork","name":"startup","tags":{"version":"0.2.0-SNAPSHOT-8-8-2026"}}. No username, hostname, IP, path, grid size, environment id or anything else about the machine or the person is included.

Opt-out

Reporting is on by default. The first launch after this change prints exactly one line through the program's existing log() channel —

Usage reporting is on: patchwork sends a startup event (program name and version only) to trace.danielstephenson.dev. Turn it off with "usage_reporting": {"enabled": false} in settings.json.

— and writes the block {"usage_reporting": {"enabled": true, "endpoint": "https://trace.danielstephenson.dev", "key": "..."}} to settings.json, so the notice is not shown again. Setting enabled to false disables reporting entirely; keys already present in an existing settings.json are preserved.

Test plan

  • python3 -m unittest discover -s tests (Python 3.8.10, pygame 2.1.2 — the project's documented test command; the repository has no CI workflow): 9 tests OK before → 30 tests OK after (9 RenderWindow, 11 vendored client, 10 new usage_reporting tests covering first-run write + notice, no notice on the second run, preservation of other settings, opt-out, corrupt-file handling, default fallbacks, the version source, and the startup body arriving at a loopback stub).
  • python3 -c "import trace_client, usage_reporting" from the repository root succeeds; there is no packaging manifest to update (the project is run from a checkout).
  • The bundled key was substituted by script from the issued key file and verified byte-for-byte (grep -c → 1), never retyped.
  • Local stub proof, production untouched. The real main.py was run headless (SDL_VIDEODRIVER=dummy, Viron services stubbed, python main.py 5 --exit-after-create) with the endpoint pointed at a 10-line loopback http.server handler. Run 1 (no settings.json): the notice was printed once, the block was written, and the stub received POST /api/metrics with Authorization: Bearer <key> and body {"application":"patchwork","name":"startup","tags":{"version":"0.2.0-SNAPSHOT-8-8-2026"}}. Run 2 (block present): no notice, the same body arrived. Run 3 ("enabled": false): nothing arrived.
  • A launch against a live Viron server was not performed here (no Docker on this box); the startup path does not depend on Viron.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WYoD9SsaRz8PjakTSHhmn6


drafted by Claude on behalf of Daniel Stephenson

trace-client-python's single module is vendored as trace_client.py
(unmodified apart from the vendoring note) together with its test. A new
usage_reporting.py reads a usage_reporting block from settings.json in the
working directory - enabled (default true), endpoint and key - writing the
defaults and printing a one-line notice the first time the block is
absent, then builds the client and reports one startup event tagged with
the version from version.txt. main() calls it as its first line; the
client is closed at interpreter exit.

Nothing about the machine, the user, the grid size or the environments is
sent. A missing or corrupt settings.json can never raise: an unreadable
file yields a disabled client and a logged line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYoD9SsaRz8PjakTSHhmn6
@dmccoystephenson
dmccoystephenson merged commit 4d5dcf9 into main Sep 12, 2026
@dmccoystephenson
dmccoystephenson deleted the usage-reporting-via-trace branch September 12, 2026 04:06
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