Skip to content

fix(stats): surface real MCP client labels (drop k-anonymity floor; allowlist labels are public)#80

Merged
LakshmanTurlapati merged 1 commit into
mainfrom
fix/stats-popular-agents-no-k-anonymity-on-public-allowlist
May 25, 2026
Merged

fix(stats): surface real MCP client labels (drop k-anonymity floor; allowlist labels are public)#80
LakshmanTurlapati merged 1 commit into
mainfrom
fix/stats-popular-agents-no-k-anonymity-on-public-allowlist

Conversation

@LakshmanTurlapati

Copy link
Copy Markdown
Collaborator

Summary

/stats "Popular agents" tab shows 100% "Other" instead of real MCP client names. Live evidence:

$ curl https://full-selfbrowsing.com/api/public-stats/global
"popular_mcp_clients": [{"label": "Other", "uniq": 3}]

Three distinct installs today, each with a different mcp_client, each at uniq=1, each below K_ANONYMITY_FLOOR=2 in showcase/server/src/telemetry/housekeeper.js:31, so the housekeeper collapses them all to "Other".

Root cause

K-anonymity floor was designed for free-form labels where a unique entry could fingerprint a single user. But MCP_CLIENT_ALLOWLIST in showcase/server/src/routes/telemetry.js:47 is a fixed public 13-label set (Claude, Codex, ChatGPT, Perplexity, Windsurf, Cursor, Antigravity, OpenCode, OpenClaw, OpenClaw 🦀, Grok, Gemini, Hermes, plus unknown). The labels themselves leak no identifying value -- only the install count does, which is already exposed via the total_users headline anyway.

Fix

Lower K_ANONYMITY_FLOOR from 2 to 1 in housekeeper. The aggregation math is preserved verbatim and becomes a no-op at floor=1:

  • selectPopularMcpForDayRange GROUP BY mcp_client always emits uniq >= 1 rows
  • With floor=1: above = popularMcpRaw (everything), belowInstalls = 0, "Other" bucket suppressed
  • All real labels surface

Rewrote the two explanatory comment blocks in housekeeper.js to cite the new rationale (public allowlist → no identifying value at uniq=1). Updated tests/server-telemetry-housekeeper.test.js to pin K_ANONYMITY_FLOOR === 1 as a regression guard and assert that two distinct mcp_client labels with uniq=1 surface as separate rows (not a single "Other" bucket).

Non-impact

  • Extension: zero changes (user constraint).
  • API contract: popular_mcp_clients shape ([{label, uniq}]) unchanged.
  • DB schema: no migration -- the hourly housekeeper UPSERT will overwrite the stale Other JSON in telemetry_global_aggregates.popular_mcp_json on first tick after deploy (boot-tick fires via setImmediate in startHousekeeper, so within ~1 min of deploy).
  • Frontend: already renders whatever labels arrive; no changes needed.

Test plan

  • node tests/server-telemetry-housekeeper.test.js -> 25 passed
  • node tests/server-public-stats-headline.test.js -> 33 passed (API contract unchanged)
  • node tests/server-telemetry-allowlist.test.js -> 15 passed (orthogonal: tests 'Other' as a rejected ingest value)
  • node tests/fsb-telemetry-service.test.js -> 68 passed
  • git diff --name-only extension/ -> empty (constraint satisfied)
  • CI green
  • Post-deploy: curl https://full-selfbrowsing.com/api/public-stats/global returns real label names within ~1 min of fly.io rollout

🤖 Generated with Claude Code

…keeper

- showcase/server/src/telemetry/housekeeper.js: K_ANONYMITY_FLOOR 2 -> 1
- Rewrite top-of-file + inline comment blocks documenting v0.9.69 -> v0.9.70 -> next-version floor transition and the public-allowlist rationale (MCP_CLIENT_ALLOWLIST is a fixed PUBLIC 13-label set; the label set itself carries no identifying information beyond per-label install counts, which are already exposed via total_users)
- tests/server-telemetry-housekeeper.test.js: destructure K_ANONYMITY_FLOOR from housekeeper exports; replace single k=2 "Other" bucket assertion with two assertions pinning K_ANONYMITY_FLOOR === 1 and asserting both real labels (Claude + Codex) surface as separate rows with uniq=1 (no "Other" bucket)
- Fixes live /stats "Popular agents" doughnut showing 100% "Other" (3 distinct installs, 3 distinct mcp_client labels, each uniq=1 collapsed into a single "Other" bucket)
- No extension/** changes; no API contract changes (popular_mcp_clients [{label,uniq}] shape unchanged); no DB schema changes
- All four required tests exit 0: server-telemetry-housekeeper (25 passed), server-public-stats-headline (33 passed), server-telemetry-allowlist (15 passed), fsb-telemetry-service (68 passed)
@LakshmanTurlapati LakshmanTurlapati merged commit d5c916e into main May 25, 2026
8 checks passed
@LakshmanTurlapati LakshmanTurlapati deleted the fix/stats-popular-agents-no-k-anonymity-on-public-allowlist branch May 25, 2026 07:52
LakshmanTurlapati pushed a commit that referenced this pull request Jul 4, 2026
Brings main's 62 post-branch-point commits into the FSB v0.9.90 / MCP v0.10.0
release branch and resolves the 62 resulting conflicts. Merge direction is
main -> automation so PR #91 (automation -> main) can fast-forward afterward.

Versioning & rebrand:
- Keep automation's versions (FSB 0.9.90, MCP 0.10.0); reverse-DNS
  io.github.fullselfbrowsing/fsb-mcp-server already matched on both sides.
- Adopt main's fullselfbrowsing org repo URLs (root package.json homepage/
  repository/bugs, README + mcp/README shields/links); keep the personal
  author profile and the ClawHub URL (clawhub.ai/lakshmanturlapati/...).
- Union mcp/CHANGELOG (0.10.0 -> 0.9.3 -> 0.9.2).

Server-side data-correctness fixes carried from main:
- Telemetry K_ANONYMITY_FLOOR 2->1 (#80) + popular_mcp heartbeat-row
  exclusion (RCA 260530-19i), keeping automation's region k-floor apparatus.
- Locale-prefixed prerender routing (#76) grafted onto automation's fuller
  marketing/client-shell route sets (incl. /legal, /lattice, /phantom-stream).

Skills / Hermes:
- Adopt main's skills/FSB Skill/ -> skills/fsb/ rename and Hermes support
  (print-hermes-yaml.mjs, hermes-tool-prefix.md, install-host Hermes block);
  port automation's tool-decision-tree tweak; extend the skill-spec token
  allowlist for automation's capability/trigger tokens.

Extension runtime:
- Graft main's owned-tab chat-input lock, storage.onChanged live refresh, and
  canonical MCP client labels onto automation's rewritten sidepanel/popup;
  owner-chip exports both label helpers (lookupClientLabel + clientLabelFor).

Showcase (automation's redesign wins UI; carry only main's data/logic):
- Keep automation's globe /stats, PhantomStream dashboard, redesigned privacy
  pages, and routes; reconcile the dashboard-runtime-state test to
  automation's eager CDN-loader API. Regenerate llms-full.txt.

Validated locally: validate:extension, full npm test (200+ files),
showcase build (6 locales, no missing translations), lint:i18n, mcp smoke,
CI-02 i18n extraction, and a simulated-Node-20 run of the catalog gate all pass.
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