Skip to content

feat(telemetry): default destination, extended reports and receiver dashboard - #617

Merged
ValgulNecron merged 49 commits into
masterfrom
feat/default-telemetry-dashboard
Oct 8, 2026
Merged

ValgulNecron merged 49 commits into
masterfrom
feat/default-telemetry-dashboard

Conversation

@ValgulNecron

@ValgulNecron ValgulNecron commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Spec 022 (specs/022-default-telemetry-dashboard/): a default telemetry destination with a first-login notice, extended telemetry, signed reports with install-ID claims, and a private dashboard plus public summary on the receiver.

  • telemetryschema (new shared module): report contract, strict decode, official module catalog, report signing, proof-of-work format and solver.
  • telemetry-receiver: extended ingest with signature and claim checks, replay protection, daily aggregates only (no raw reports or addresses), public summary, a private dashboard on :8081 behind DASHBOARD_TOKEN (32-character minimum), optional proof-of-work on /ingest with adaptive difficulty (INGEST_POW*, off by default).
  • api: opt-out default for new installs (gated on the notice), extended reports, signing, install-ID reset and claim rotation, GET /admin/telemetry status and preview, the challenge solver in the reporter.
  • chart: consent flags, bundled receiver dashboard port, token secret, proof-of-work values with render-time validation, install notes.
  • e2e: telemetry lifecycle subtests (destination, preview, dashboard, dedupe, summary, forgery, proof-of-work).
  • docs: install, security (threat model), provider runbook, receiver and API specs, CHANGELOG.

Merge gate

OD-1 was ruled on 2026-10-07: reports go to https://telemetry.gameplane.net/ingest, and the data-handling statement lives at https://gameplane.net/telemetry/. telemetry default gate passes (T099).

Merge together with GameplanePanel/website#13 (T096: statement page, provider guide, docs): this PR's notice links to https://gameplane.net/telemetry/, which goes live with #13, and #13 links to docs/telemetry-provider.md on master, which lands here.

T097 (security review, 2026-10-08) found no issues: one candidate was raised and rejected at confidence 4/10.

Browser smoke test (2026-10-08, kubelab dev cluster, Helm revision 11 with this branch's api/web/operator/telemetry-receiver images, bundled receiver):

  • Admin Settings › Telemetry: the bundled destination copy and badge, the basic and extended switches, the install ID row, the report preview and saving all work. Extended was turned on and off and saved, then restored.
  • Notice banner: not shown, as expected. kubelab predates this feature (consent_source=legacy, so FR-003 keeps basic off and FR-004 shows no notice). The new-install banner is covered by the live e2e on a fresh Kind install and by the unit and mock e2e tests.

Test sign-offs (system override 1)

Signed off 2026-10-06 ("Approve all", then "Approve" for the /metrics changes) and 2026-10-07:

  • api/internal/telemetry/telemetry_test.go: TestReportOnce_EnabledPostsAnonymousCounts, TestReportOnce_SendsAuthHeader, TestReportOnce_DisabledSkipsPost.
  • api/internal/telemetry/telemetry_branches_test.go: TestNew_DefaultsInterval, TestEnabled_Branches, TestCount_UnknownKind, TestReportOnce_EndpointErrorPropagates.
  • web/src/routes/AdminSettings.test.tsx "shows telemetry toggle and saves setting"; web/src/routes/AdminSettings_sections.test.tsx "toggles telemetry and saves" (web part pending).
  • telemetry-receiver/main_test.go: metrics() helper and TestMetricsMethodNotAllowed move to the dashboard handler; new case asserts public GET /metrics is 404.
  • .github/workflows/ci.yaml observability scrape TLS/reachability step: receiver ServiceMonitor/NetworkPolicy renders with the dashboard token.
  • api/internal/handlers/config_test.go TestConfig_GetEmpty → TestConfig_GetFreshInstallDefaults ("Assert the seeded default", 2026-10-07).
  • api/internal/handlers/config_validators_test.go TestValidateTelemetry ("Assert the new shape", 2026-10-07).
  • 2026-10-07 ("Approve all four"): web/src/components/ui/TelemetryNotice.test.tsx (provider on rerender; "destination absent" omits the key), the "send basic usage metrics" locator in web/e2e/specs/adminSettings.spec.ts and web/e2e/screenshots/slice4.spec.ts, and the exact "CPU" match in web/e2e/specs/live/liveAgentScreens.spec.ts.
  • 2026-10-07 ("you can also fix this bug"): test/e2e/telemetry_e2e_test.go waits on reports + duplicates where any accepted report will do, preview_matches_received resets the ID and waits on a counted report, and the old receiver is cleaned up by the parent test (telemetry_e2e_helpers_test.go). No assertion was relaxed.
  • Phase 9b (2026-10-07, "go ahead edit test"): newSink in api/internal/telemetry/telemetry_test.go and the server in TestTelemetryPreview_EqualsTheBodyTheReporterPosts (api/internal/handlers/telemetry_envtest_test.go) answer the reporter's challenge GET with 404; no assertion changed.

Test plan

  • CI green (run 37689050926 at cbaf6a3; e2e operator / amd64 flaked once on TestHelmInstall_MetricsNotOnPublicPort and passed on rerun)
  • CI green on 92313bf (merge of master after the GameplanePanel org move; the branch's Go module paths and edge image renamed to match)
  • E2E telemetry bucket passes (lifecycle incl. proof-of-work subtests)
  • Browser smoke test of the notice banner and Admin Settings Telemetry section (kubelab, see Merge gate)

🤖 Generated with Claude Code

https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT

ValgulNecron and others added 30 commits October 6, 2026 23:34
Spec, plan, research, data model, contracts, quickstart and tasks for a
default telemetry destination, extended opt-out telemetry with a
first-login notice, signed reports with install-ID claims, and a
private receiver dashboard with a small public summary.

OD-1 (the default domain) is open and blocks merge; OD-2 to OD-4 are
ruled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Create the stdlib-only telemetryschema module that api and
telemetry-receiver will share, and wire it into go.work, GO_MODULES,
the CI lint and unit matrices, path filters, Dependabot, the coverage
gate (90), the docs maps and both Dockerfiles (spec 022 T003-T009).

The go.mod require/replace lines land with the first import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…gning

Add the report types with deterministic Encode, the enumerations and
bands, a strict Decode that keeps the receiver's basic-path behaviour
and validates the optional ext object, the embedded official-module
catalog with a drift check against values.yaml, and Ed25519 report
signing with HKDF-derived per-ID keys (spec 022 T010-T016).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Add the new module to the dependency doc, README component table,
devcontainer module warm-up, CodeRabbit shared-package instructions
and the auto-label area map (area: shared).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Migration 015 adds telemetry_state and telemetry_notice_acks. Migrate
tells fresh installs from upgrades and seeds consent (default vs
legacy). Add destination resolution with an empty DefaultEndpoint
gated by a separate CI job until OD-1 is ruled, the telemetry flags,
and the basic plus extended collector with official-module and
distribution detection (spec 022 T009, T018-T029).

Three existing tests still assume no telemetry config row on a fresh
store; the next commit updates them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Add the SQLite aggregate store (private in-memory store when DATA_DIR
is unset), the new configuration with retention and expiry minimums,
the dashboard listener scaffold, chart persistence, and delegate
payload decoding to telemetryschema (spec 022 T009, T017, T030-T033).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…r_id

Migrate now seeds the fresh-install telemetry default, so the reporter
test helpers upsert or remove that row (T002) and TestConfig_GetEmpty
becomes TestConfig_GetFreshInstallDefaults, asserting the seeded
default (approved 2026-10-07). telemetry_notice_acks.user_id is now
BIGINT to match users.id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…eck in CI

Reject keys and signatures whose base64url form is not canonical (Go's
decoder skips embedded newlines), list "other" among tunnel values, and
run make check-telemetry-catalog in the lint job with path filters for
the catalog, its script and values.yaml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…etention minimums

An absent persistence block (upgrade with --reuse-values from beta.8)
now counts as disabled, so the upgrade adds no PVC. retentionDays < 365
or activityExpiryDays < 31 fails rendering instead of crash-looping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…tener and views

Move ingest to ingest.go with per-source daily limits and one-transaction
aggregate writes, add the hourly lifecycle job, BuildViews for the basic
block, and the token-protected dashboard listener (login, session cookie,
strict CSP, refusal invariant, /api/v1/views). /metrics moves behind the
dashboard token and answers 404 on the public port (spec 022 T062-T065,
T067, T070; main_test.go /metrics changes approved under T002). The HTML
templates are placeholders until T068.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Add telemetry-receiver/telemetry-dashboard.pen (HeroUI kit copy,
re-themed to the shared pink tokens from web/src/styles/globals.css)
with the receiver login, refused login, overview (basic and extended
sections), empty state and no-extended-data frames, plus their JSON,
PNG and token exports (spec 022 T066, T075).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…roach and sign-offs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Replace the ticker reporter with a persisted-schedule reporter that
claims each slot through ClaimTelemetryDue, never sends before the
notice is seen on a default-consent install (FR-004, closes the
interim gap noted in 1ab7ee6), signs extended reports and falls back
to basic-only after a 400. Add ApplyConsent with tx helpers, the
telemetry config save hook (sendMetrics:false also clears extended),
GET/POST /admin/telemetry/notice with RBAC, and the web client
(spec 022 T034-T040, T042). Test rewrites per the T002 sign-off,
TestValidateTelemetry per the 2026-10-07 sign-off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Register the telemetry bucket, ship the receiver image in the E2E image
set, keep CI and dev installs on the bundled receiver, and add
TestTelemetryLifecycle plus upgrade assertions (spec 022 T045-T048).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…ared overflow budget)

The limiters keyed IPv6 by full address and let any source past the
100k-entry cap through untracked, so a host could rotate addresses in
its /64 or flood the table to escape the ingest and login limits. Key
IPv6 sources by /64 (IPv4-mapped equals IPv4) and send sources beyond
the cap to one shared overflow budget (security review of 4c742e7).
Also mark spec 022 T034-T048 done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
… pooling overflow

The shared overflow budget from de5d097 let a client that filled the
source table deny every new legitimate source. Both limiters now keep a
recency list and evict the least-recently-used source to admit a new one,
so memory stays bounded, nothing passes untracked and sources are never
pooled. Invalid addresses map to one ordinary tracked key (invalidKey).

Tests cover the cap, LRU order, a fresh budget after eviction and spent
budgets kept by tracked sources. research.md R6 records the decision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
docs/install.md § Telemetry describes the new-install default, the two
tiers and their fields, upgrade effects, opting out, custom and bundled
receivers. docs/security.md gains a Telemetry section (public ingest and
summary, pseudonymous install ID, signing, dashboard auth, refusal
invariant, source handling, pepper). docs/telemetry-provider.md is the
runbook for operating the project receiver. CHANGELOG [Unreleased] carries
the upgrade notes. No receiver host is named until OD-1 is ruled; T099
lists the spots to update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…tall notes

T049: api.telemetry renders --telemetry-disabled and the bundled-receiver
flag; an empty endpoint now means the project default. T069/T080: the
receiver gets its dashboard port 8081 (Service and NetworkPolicy admit
only dashboard.ingressFrom peers and the scrape namespace) and
PUBLIC_SUMMARY. The receiver ServiceMonitor scrapes /metrics on the
dashboard port with the Bearer token and is skipped without one; NOTES.txt
warns about that and about emptyDir storage. T050 plus the T002-approved
CI changes assert every render, including the beta.8 upgrade values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…d designed dashboard

US5 (T072-T074): extended reports are accepted, aggregated once per
install per day, and lapsed and expiring activity is handled in UTC.
US7 (T083): signature, send-time window, first-use claim and replay checks
run before any write or limiter count; refusals change no table. US6
(T079): GET /v1/summary returns the five headline counts from a cached
snapshot. US4 (T068, T076): the dashboard pages follow the
telemetry-dashboard.pen export with server-side SVG charts, a table view,
no inline styles or scripts and the pink theme. Tests cover ingest,
population counts, view performance, the summary, the forgery matrix and
the charts (T077, T081, T086).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…h E2E coverage

T051/T057: GET /admin/telemetry returns destination, consent, install ID,
the exact preview and delivery status. T056: POST
/admin/telemetry/install-id rotates the ID. T084: a 409 id_claimed
replaces the ID (keeping the signing secret), re-signs and resends once in
the same attempt; 403 never rotates. RBAC rows pin config:read and
config:manage on the new routes. E2E (T055, T061, T071, T078, T082, T088)
adds the destination, preview, dashboard, dedupe, summary and forgery
subtests with a signing test client; port-forwards kept by later subtests
now outlive the subtest that opens them. The Makefile e2e timeout rises
to 50m for the longer telemetry bucket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Records the 2026-10-07 rulings. Q11/FR-041: the receiver refuses to start
with a DASHBOARD_TOKEN shorter than 32 characters, since per-source login
limits can be outrun by anyone holding many IPv6 /64s (security review of
0819cec). Q12/FR-039/FR-040: an Anubis-style challenge round trip on
report ingestion, off by default and enabled by the runbook for the
project provider, with a difficulty that follows the challenge rate
(none at or below normal, ceil(2*log2(r/T)) above it, decaying one bit per
5 minutes). Research R21 holds the design, OD-5 the ruled defaults
(target 60/min, max 22 bits, install cap 26), contracts/data-model/
quickstart S10 the surface, and Phase 9b (T101-T109) the work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
T101: PoWHeader and MaxPoWBits (26, OD-5), PoWOK checks that
SHA-256(challenge:nonce) starts with the required zero bits, SolvePoW
searches on one goroutine and honours the context, FormatPoW/ParsePoW
split the header at the last colon. Test vectors pin the hash layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…en minimum

T102/T104: GET /v1/challenge issues MAC'd challenges from its own
per-source bucket; /ingest checks the solution after AUTH_TOKEN and
before reading the body, refusing with 428 pow_required/pow_invalid or
503 pow_busy when the used-challenge set is full. Difficulty follows the
challenge rate (ceil(2*log2(r/T)) above the target, one bit of decay per
5 minutes) and is exported as gameplane_telemetry_pow_bits. INGEST_POW*
is off by default and range-checked at startup. T103: the receiver exits
when DASHBOARD_TOKEN is set but shorter than 32 characters (FR-041).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
T105: before each POST the reporter asks <endpoint dir>/v1/challenge,
solves it within the challenge lifetime and sends the PoW header; any
non-200 sends without it, a difficulty above MaxPoWBits is a failed
attempt, and a 428 or the 409 rotation resend fetches a fresh challenge
once. T106 covers each path. Two existing test servers now answer the
challenge GET with 404 (approved test change) so they still count and
decode only the report POST.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
T107: api.telemetry.receiver.ingestPow.{enabled,targetPerMinute,minBits,
maxBits} render as INGEST_POW* behind hasKey guards; rendering fails on
targetPerMinute < 1, maxBits < minBits or maxBits > 26. CI asserts the
default, an enabled render and each failure with helm template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
T108: pow_receiver_accepts_solved_reports deploys a receiver with
INGEST_POW=true and checks challenges are issued and reports land;
pow_refuses_missing_and_invalid checks 428 pow_required and pow_invalid
leave the reports counter unchanged. The deploy helper takes extra env,
and the dashboard token constant is now 32+ characters (T103).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Security review of fa1dc26. The duplicate branch of recordExtended now
advances activity.last_sent_at, so a captured same-day duplicate cannot
be replayed again or counted as the next day's report. Send times are
stored with RFC3339Nano, so a report sent at a fractional second no
longer looks later than its own stored value on replay. checkClaim fails
closed (500) on an unparsable last_sent_at instead of accepting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7krnvWjW1a6bW5doxiVHB
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
@ValgulNecron ValgulNecron added area: specs spec-kit feature specs and design docs area: web React dashboard type: feature New capability or user-facing addition labels Oct 7, 2026
@coderabbitai

coderabbitai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread telemetry-receiver/views.go Fixed
Comment thread telemetry-receiver/views.go Fixed
Comment thread telemetry-receiver/views.go Fixed
…ent URL

T058: TelemetryCfg gains extended; Telemetry.get() returns the full
GET /admin/telemetry shape (destination, consent, install ID, preview,
status) mirroring the Go JSON; Telemetry.resetInstallId() posts to
/admin/telemetry/install-id. The settings form and test factory defaults
carry extended: false (approved). T095: TELEMETRY_STATEMENT_URL in the new
web/src/lib/links.ts (OD-2), to be used by the notice and settings UI.
T098: draft PR #617 opened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

CI Report - 92313bf

run 37706206091 - attempt 1

0 failed - 25 passed - 0 skipped - 43m19s elapsed

Coverage

Module Measured Gate Margin
web L95.5 S94 B88.61 F91.87 L92 S92 B82 F76 +2.00

Changed

Area Files +/-
telemetry-receiver/ 53 +35286/-297
api/ 34 +6243/-159
(root) 8 +6320/-12
design-export/ 19 +6211/-0
specs/ 12 +2838/-0
telemetryschema/ 16 +2466/-0
test/ 7 +1535/-1
web/ 19 +1256/-20
docs/ 6 +1021/-24
charts/ 5 +263/-28
.github/ 4 +208/-12
hack/ 3 +117/-0
deploy/ 1 +6/-3
.devcontainer/ 1 +1/-1

Slowest jobs

Job Duration
e2e telemetry / arm64 (kind) 22m31s
e2e telemetry / amd64 (kind) 22m31s
e2e multicluster / amd64 (kind x2) 9m55s
e2e multicluster / arm64 (kind x2) 9m32s
e2e game bot / TestGameServer_GarrysModBot_Query (kind) 8m45s

e2e buckets run

api-agent, api-auth, api-mods, api-rbac, api-roles, bot-fast, multicluster, operator, ratelimit, telemetry, upgrade

ValgulNecron and others added 13 commits October 7, 2026 15:54
T041: Gameplane/Telemetry Notice Banner (U8Zugm) lists the basic and
extended fields (stating that a random install ID is included), the
destination host, the actions Keep sharing / Turn off extended / Turn off
all, and links to Admin Settings and the data-handling statement, shown on
Dashboard Home for the default (jmcmS) and bundled (woRBK) destinations.
T052: Admin Settings Telemetry per destination state (default TEBym,
custom DtjyL, bundled uwPVC, disabled Rvv6z, none RT8lU) with both
switches, the install-ID row and Reset ID, the preview JSON and every
status variant, plus the Reset ID confirm (oqm73). Hosts are samples
while OD-1 is unruled. Exported to design-export/ (MANIFEST updated).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The banner's title, destination suffix and field descriptions used auto
text growth, so long copy ran past the banner (most visible with the
bundled receiver host). They now wrap at the banner width. Re-exported
U8Zugm (JSON, PNG) and the two Dashboard Home notice screens (PNG).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
T043/T044: TelemetryNotice shows the pending first-login notice to users
with config:manage, posts seen once, and acks Keep sharing / Turn off
extended / Turn off all, linking to the Telemetry settings and the
data-handling statement. T053/T059/T085: TelemetrySection renders the
destination per kind, the operator-disabled and none states, the basic and
extended switches (extended off and disabled while basic is off), the
install-ID row with a Reset ID confirm, the next-report preview, the status
line and the ID-replaced line, per the T052 design. T054/T060/T087: new
AdminSettings_telemetry tests, the two T002-approved cases rewritten for two
switches, MSW defaults, and pending-notice browser mock datasets. T090:
web/specs.md. Copy beyond the designs approved 2026-10-07.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
OD-1 ruled 2026-10-07: the project domain is gameplane.net and the
default telemetry destination is https://telemetry.gameplane.net/ingest,
so DefaultEndpoint is set and the telemetry default gate passes. The
website moves to gameplane.net, so the data-handling statement URL is
https://gameplane.net/telemetry/ in links.ts and the docs (the website
side is T096). Docs, CHANGELOG upgrade notes, the chart values comment and
the gate's comments name the host; the designs show it in place of the
sample host and are re-exported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The default destination is https://telemetry.gameplane.net/ingest and the
statement URL https://gameplane.net/telemetry/ (ruled 2026-10-07). Plan,
spec, quickstart, research, the install-config contract and the
requirements checklist now say so, and the OD-1 merge gate is marked
satisfied; FR-002's no-placeholder rule is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…ry UI

The Reset ID button drops the plus icon. A new notice test covers a
pending notice with no destination. The in-browser mock gains a stateful
pending-notice dataset and a telemetry-on dataset (config and status on,
install ID, preview, reset), so the notice and settings can be checked in
vite --mode mock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The four Admin Settings telemetry frames (TEBym, DtjyL, uwPVC, oqm73)
showed the outline button's default plus icon on Reset ID; it is hidden,
matching the dashboard. Re-exported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
golangci-lint: checked LRU type assertions, a non-credential name for
the login error message, statically served embedded files (io.Copy keeps
Cache-Control on every response), no builtin shadowing, newBarChart
without its constant argument, and test-side ctx threading, unused
parameters, NewRequestWithContext and sequential limiter calls. CodeQL:
normalizeRange returns the constant range, so no request value sizes an
allocation. The two dashboard tests written for the empty scaffold now
expect the login redirect (303 to /login) and the login page (200);
approved 2026-10-07.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…ures

The install-ID handler passes its request context through (contextcheck).
Reporter tests that collect extended data use telKubeExt(), which
registers the backup schedule, cluster and module source lists, so the
fake client no longer panics; master's telKube is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Telemetry helpers take the subtest context, responses are closed
explicitly, and cleanups use context.WithoutCancel. No assertion changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LB2aggjbVHUmiypnFUwpRT
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…d Traefik

Adds a "Deploy on Kubernetes" section to the provider runbook: namespace,
secrets and a trusted-proxy list (pod CIDR plus Cloudflare's ranges), a
cert-manager DNS-01 ClusterIssuer for Cloudflare, one applyable manifest
(PVC, Deployment, Service, Traefik Ingress for the four public paths,
NetworkPolicy), Cloudflare settings, how the receiver resolves the client
address, verification including an X-Forwarded-For check, dashboard access,
an optional ServiceMonitor, and upgrade/backup notes. Shell snippets keep
comments on their own lines so they paste into zsh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018n3YThwwgc1bRH96e8f2Vi
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Conflict resolutions:
- ci.yaml: master's restructure (change-scoped lint/go matrices, docs job,
  per-arch e2e jobs) plus this branch's telemetryschema module, telemetry
  catalog check (now in the docs job), telemetry e2e bucket on amd64 and
  arm64, and the report-job matchers for it.
- build-e2e-images action: master's per-arch cache scopes plus the
  telemetry-receiver e2e image.
- design-export/MANIFEST.md: both sections kept.
- design.pen: master's file (FBiMN and the qFLfB rename from #584 are
  referenced by web/e2e/screenshots/slice5.spec.ts), with the nine spec 022
  frames rebuilt on it from their exports. Their ids changed; the JSON
  exports were regenerated and proven equal to the previous ones with ids
  remapped, PNGs re-exported, MANIFEST and the TelemetryNotice comment
  updated to the new ids.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018n3YThwwgc1bRH96e8f2Vi
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The telemetry default gate passes on the merged branch (DefaultEndpoint
https://telemetry.gameplane.net/ingest, OD-1 ruled).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018n3YThwwgc1bRH96e8f2Vi
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
ValgulNecron and others added 4 commits October 7, 2026 23:16
- TelemetryNotice.test.tsx: keep the QueryClientProvider on rerender, and
  make the "destination absent" case omit the key (setup(undefined) fell
  back to the default destination).
- adminSettings.spec.ts, slice4.spec.ts: the telemetry switch now reads
  "Send basic usage metrics".
- liveAgentScreens.spec.ts: match the "CPU" tile exactly; the telemetry
  banner's "CPU architecture" text made the locator ambiguous.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018n3YThwwgc1bRH96e8f2Vi
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…live

TestTelemetryLifecycle waited for reports_total to rise while the install
kept an extended ID the receiver had already counted that day. The receiver
acknowledges those same-day reports as duplicates (spec 022 per-day dedupe)
and leaves reports_total unchanged, so api_restart_does_not_resend_early,
preview_matches_received and claimed_id_rotates_and_recovers timed out.

- Wait on reports_total + duplicates_total where any accepted report will
  do; the no-early-resend gap check is unchanged.
- preview_matches_received resets the install ID first and waits on a
  counted report, since it asserts the fleet histograms and version label.
- The old receiver's Deployment and Service are deleted when the whole test
  ends, not when old_receiver_gets_basic returns: operator_disabled_sends_nothing
  port-forwards to it later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018n3YThwwgc1bRH96e8f2Vi
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The security review of the branch (2026-10-08) confirmed no findings; one
candidate (the operator ingest token reaching the default provider when
only GAMEPLANE_TELEMETRY_AUTH is set) was rejected at confidence 4/10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCEuae9std51zttPLx9ZZf
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Brings in the move to the GameplanePanel org (#622), whose renamed test
URL fixes the e2e api-mods failure.

Conflicts (import blocks and one README image line) took this branch's
side; then master's rename was applied to everything this branch adds:
- Go module path github.com/ValgulNecron/gameplane/ -> github.com/GameplanePanel/gameplane/
  (33 files, imports re-sorted with gofmt)
- telemetry-receiver:edge image and the default module source in docs and
  research.md -> ghcr.io/gameplanepanel

Kept on the old owner, as in 946333a: the beta.8 receiver image used by
the e2e old-receiver check, the upgrade-from chart, and historical
spec 022 notes. Design files are untouched, as on master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCEuae9std51zttPLx9ZZf
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
@ValgulNecron
ValgulNecron marked this pull request as ready for review October 8, 2026 00:25
@ValgulNecron
ValgulNecron merged commit 32c2fa8 into master Oct 8, 2026
93 checks passed
@ValgulNecron
ValgulNecron deleted the feat/default-telemetry-dashboard branch October 8, 2026 03:07
Baylem pushed a commit to Baylem/Gameplane that referenced this pull request Oct 9, 2026
GameplanePanel#617 and GameplanePanel/website#13 are merged and
every task is done. Move the spec folder and update the in-repo references
(API and telemetryschema comments, module specs, design-export manifest)
per CLAUDE.md rule 16, and bump the website submodule to main 299251d,
which carries the telemetry statement page and provider guide (T096).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCEuae9std51zttPLx9ZZf
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: api REST/WebSocket gateway area: chart Helm chart and deployment area: e2e kind-based end-to-end suite area: shared netguard, gameaction, gameproto, svcutil and other shared packages area: specs spec-kit feature specs and design docs area: web React dashboard type: feature New capability or user-facing addition

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants