Skip to content

Send a random per-installation ID as the tag install (0.5.0) - #9

Merged
dmccoystephenson merged 1 commit into
mainfrom
feat/install-id
Oct 3, 2026
Merged

dmccoystephenson merged 1 commit into
mainfrom
feat/install-id

Conversation

@dmccoystephenson

Copy link
Copy Markdown
Member

What

Every event now carries a random per-installation ID as the tag install, so the trace server can count distinct servers ("active servers in the last 30 days") instead of raw events. Version bumped to 0.5.0 (VERSION and pom.xml).

How

  • Spigot (server-wide config given): the ID is the server-id: key of plugins/trace/config.yml, following bStats' serverUuid precedent. When an enabled client finds no usable server-id: line, a UUID.randomUUID() is appended to the file under a short comment; nothing else in the file is touched (operator text is kept byte for byte, a missing trailing newline is handled). The file is read back after the append so two clients racing on one file agree on the first line.
  • Cannot write / cannot read: a fresh ID is used in memory for that process only, logged at FINE; build() never throws. A file that exists but cannot be read (e.g. not UTF-8) is deliberately not appended to, otherwise it would gain a line on every start.
  • Non-Spigot programs: new Builder.installId(String). Without it (and without serverWideConfig), no install tag is sent and no file is written anywhere. Blank/null means none; over 255 characters throws IllegalArgumentException from the setter (same as an overlong version). An explicit ID wins over server-id:, and the file then gains no server-id:.
  • Opt-outs first: the ID is resolved only after disabledReason() is computed. With TRACE_USAGE_REPORTING=off / DO_NOT_TRACK=1, enabled: false, enabled(false) or no key, no ID is generated or written.
  • Tag precedence: an event's own install tag wins (like version); the install tag is placed before server-wide tags: entries, so a tags: entry named install does not override server-id:. It is not added if the event is already at MAX_TAGS.
  • Parsing: server-id: is read at column 0, outside a tags: block, first valid one wins; the value must match [A-Za-z0-9][A-Za-z0-9_.-]* and be at most 255 characters, otherwise it is ignored (and a new one appended).
  • New public accessor installId() (null when disabled or none), so a program can print it.
  • The default-file template gains a comment explaining server-id: random, identifies no person or IP address, delete the line to reset.

Docs

README gains a section "Every event carries a random server ID" (what it is, where it lives, how to reset, how opt-outs stop it, non-plugin usage), the example startup log line now mentions the random server ID, the opting-out table no longer claims the file is never rewritten, and the wire-format example shows install.

Tests

mvn test: 54 tests, 0 failures (47 before). Existing exact-body tests were updated for the new tag (the writeServerWideConfig test helper now appends a fixed server-id: test-server). New tests:

  • ID generated + persisted once and reused across builds/plugins
  • existing operator file preserved byte for byte, block appended
  • server-id: parsing (quoted, first wins, invalid ignored, column 0 only, inside tags: is a tag)
  • unwritable plugins dir → in-memory ID, no exception, differs per build
  • disabled (environment, enabled: false, enabled(false), no key) → no ID, file untouched / not created
  • explicit installId(...), blank/null/overlong, explicit wins over file
  • plugin's own install tag wins

A mutation probe (resolving the ID regardless of disabledReason) fails 2 tests.

Downstream

The server side should count distinct values of the install tag. Vendored copies in plugins are unchanged until they are re-vendored to 0.5.0; no plugin repo is touched here.

🤖 Generated with Claude Code

https://claude.ai/code/session_014ztkfamsbEqQfcu76me5SL


drafted by Claude on behalf of Daniel Stephenson

Every event now carries `install`, so the trace server can count distinct
servers instead of raw events. On Spigot it is the `server-id:` line of
plugins/trace/config.yml: when an enabled client finds none, a
UUID.randomUUID() is appended under an explanatory comment, leaving the
rest of the file byte for byte. A file that cannot be read or written
gives an in-memory ID for that run; build() still never throws.

Programs without a server-wide config send no ID unless they pass one with
Builder.installId(String). Every opt-out is checked first: a disabled
client never generates, writes or sends an ID. An event's own `install`
tag wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ztkfamsbEqQfcu76me5SL
@dmccoystephenson
dmccoystephenson merged commit 628bde2 into main Oct 3, 2026
3 checks passed
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