Skip to content

feat(telemetry): send the scale activity, game mix, permission shape, region and export signals - #1609

Merged
rumblefrog merged 1 commit into
mainfrom
claude/loving-gauss-7yjbek
Oct 25, 2026
Merged

rumblefrog merged 1 commit into
mainfrom
claude/loving-gauss-7yjbek

Conversation

@rumblefrog

Copy link
Copy Markdown
Member

Description

Paired panel change for sbpp/cf-analytics#6. sbpp/cf-analytics#7 added 16 new optional fields to the schema-1 Analytics Engine layout. This PR adds the same fields to the vendored JSON Schema (web/includes/Telemetry/schema-1.lock.json) and the collectors that fill them. TelemetrySchemaParityTest needs both: every schema field must have a collector, and every collector field must be in the schema.

Field Source
scale.bans_30d :prefix_bans.created in the last 30 days
scale.admins_active_30d :prefix_admins.lastvisit in the last 30 days
scale.ban_history_months whole calendar months since MIN(:prefix_bans.created), ignoring created = 0 legacy rows. null with no bans, so it is left out of the request
scale.web_bans_majority_30d more than half of the last 30 days' bans have sid = 0
scale.games.{tf,cstrike,csgo,garrysmod,left4dead2,other} modfolder of enabled servers (join on :prefix_mods). Folder names outside the five tracked games are never sent
scale.perms.{web_groups,server_groups,overrides,immunity} any :prefix_groups row with type = 1, any :prefix_srvgroups row, any :prefix_overrides row, any admin with immunity > 0
panel.exported_30d a successful Data Export row (LogType::Message) in :prefix_log in the last 30 days. web/export.php logs both ZIP and S3 successes this way; failures and denials log as e / w
panel.region continent code from the new Sbpp\Telemetry\Region (see below)

Docs: the operator-facing payload list in updating/1-8-to-2-0.mdx, the help text under Settings → Features (it now mentions the continent and the game mix), ARCHITECTURE.md and AGENTS.md.

Note on panel.region

The issue says "from config.timezone", but on 2.0 that setting is mostly empty. Fresh installs never write it, and installs upgraded from 1.x can hold a bare UTC offset like -8 (left by updater 150.php), which can't be turned into a continent. Region::resolve() therefore uses config.timezone when it holds an IANA zone name, and otherwise falls back to PHP's default timezone (date.timezone), which is the zone the panel actually shows dates in. Either way the value comes only from configuration, never from the request or the IP. UTC, Etc/*, Antarctica and unknown names give null, so the field is left out.

The mapping is a hardcoded table, not DateTimeZone::getLocation(), because distro PHP builds that use the system tzdata don't always include the location data. On a host whose timezone is unset (UTC), the field will simply be absent. That will likely be common on shared hosts, where the timezone may also reflect the hosting provider rather than the community.

Motivation and Context

Without this PR the new slots stay empty: every ping leaves the new doubles null and the new bits 0, the same gap #1606 fixed for the env fingerprint.

How Has This Been Tested?

  • PHPStan: phpstan analyse --configuration=phpstan.neon, with phpstan-dba connected (DBA_REQUIRE=1) to MariaDB 10.11 loaded from struc.sql. No errors.
  • PHPUnit itself did not run locally. The composer lock pins PHPUnit for PHP ≥ 8.4.1 and this sandbox only has PHP 8.3. Instead I ran the real test methods in TelemetryCollectTest, TelemetrySchemaParityTest and the new TelemetryRegionTest through a minimal stand-in for PHPUnit's assertions, with the real tests/bootstrap.php and Fixture against a local MariaDB 10.11: 40/40 passed. With the original Telemetry.php restored, the same run fails 12, so the tests do check the new collectors. CI's test.yml (PHP 8.5) is the authoritative run.
  • New and extended tests:
    • TelemetryCollectTest: the existing seeded universe now asserts every new field. A second dataset covers mixed games, mostly web bans, a 400-day-old ban (always exactly 13 calendar months), groups, overrides and a recent export. Further tests check that ban_history_months is null and dropped from the request with no bans, and that failed or 31-day-old exports don't count.
    • TelemetryRegionTest: the zone → continent table, the legacy-offset fallback, the games mapping and monthsBetween.
    • TelemetrySchemaParityTest: the expected field list is extended.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.

Generated by Claude Code

… region and export signals

sbpp/cf-analytics#7 appended these slots to schema-1 for
sbpp/cf-analytics#6. Mirror them in the vendored JSON Schema and add
the matching extractors so the parity test stays green:

- scale.bans_30d / admins_active_30d: 30-day counts from
  :prefix_bans.created and :prefix_admins.lastvisit.
- scale.ban_history_months: whole calendar months since the oldest
  ban (created = 0 legacy rows ignored); null without bans, so it is
  dropped from the wire body.
- scale.web_bans_majority_30d: more than half of last-30d bans have
  sid = 0.
- scale.games.*: tf / cstrike / csgo / garrysmod / left4dead2 / other
  over enabled servers' modfolders. Other folder names never leave
  the panel.
- scale.perms.*: any web group (type 1), server group, override, or
  admin with immunity > 0.
- panel.exported_30d: a Data Export success row in :prefix_log in the
  last 30 days.
- panel.region: continent code via the new Sbpp\Telemetry\Region,
  from config.timezone when it holds a zone name, else PHP's default
  timezone. Fresh 2.0 installs have no config.timezone and pre-2.0
  upgrades can hold a bare UTC offset there, so the fallback is what
  most installs will use. Never derived from the request.

Operator docs and the Features help text list the new fields.

Refs sbpp/cf-analytics#6

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsiwAF3BzPy1aMBEuQcGZe
@rumblefrog
rumblefrog requested a review from a team October 25, 2026 17:22
@github-actions

Copy link
Copy Markdown

Thanks for the PR! This change touches web/** (the SourceBans++ web panel),
which is covered by the project's Contributor License Agreement.

To sign, comment exactly the following line on this PR:

I have read the CLA Document and I hereby sign the CLA

You only need to sign once — your signature applies to every future
web-panel PR you open against this repo. Plugin-only PRs
(game/addons/sourcemod/**) don't need a signature.

See CONTRIBUTING.md
for the rationale.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@rumblefrog
rumblefrog merged commit 1917e0a into main Oct 25, 2026
5 of 6 checks passed
@rumblefrog
rumblefrog deleted the claude/loving-gauss-7yjbek branch October 25, 2026 17:33
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants