Skip to content

Composer: count each Current the door admits or refuses, by host app and refusal code - #762

Draft
sdcarlson wants to merge 2 commits into
mainfrom
telemetry/composer-counts
Draft

sdcarlson wants to merge 2 commits into
mainfrom
telemetry/composer-counts

Conversation

@sdcarlson

@sdcarlson sdcarlson commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Update 2026-11-04: main merged in (8f45346). Main's #767 removed Gate 0, the witness log and handleLive from worker/mcp-server.mjs and changed dispatch to dispatch(message, origin, card = null). The merge keeps main's version and threads this PR's counter through as a fourth parameter, count = () => {}: tools/call returns call(id, params, count) and handleMcp derives host and count as before. Against main, the diff is this PR's original change apart from those three lines. FAST_TEST_FILES is now 158 (main's 157 plus worker/telemetry.test.js).

Checks on 8f45346: fast suite 158 files, 3790 tests (3786 passed, 4 skipped, 0 failed); vite build; first load 62.5 of 64.0 KB brotli; e2e gate 72 passed, 3 skipped; both wrangler dry runs, production listing EVENTS; CI green on GitHub. Main's #767 moved PRIVACY.md's "Last updated" to 2 November 2026; it still needs the date these sentences publish. The 169 to 170 note and the test counts below describe the PR as first opened.

What changed

  • telemetry/events.json (new): the telemetry.v1 allowlist. Two events, both owned by Composer: rise.current.admitted (blob host; doubles beats, scenes) and rise.current.refused (blobs host, code). Every blob is a closed list. The refusal codes are the door's closed set: the 35 codes the validator it calls can throw (src/core/rise-current.js, beats.js, current-validation.js, src/scenes/manifests.js), five the door refuses with itself (MCP_ARGUMENTS, MCP_TOO_LARGE, SCENE_COLLECTION, SCENE_CODE_ADMISSION, SCENE_SVG_ADMISSION), and other.
  • worker/telemetry.mjs (new): reads the allowlist and builds the data point, indexes: [event], blobs: [event, release, ...values in allowlist order], doubles: [1, ...counts in allowlist order], or nothing for any event, field, value or number the allowlist does not name. countEvent writes it with env.EVENTS?.writeDataPoint(...) inside try/catch, never awaited.
  • worker/mcp-server.mjs: beside logQuality, the door writes one point per rise_present call. Admitted carries beats and scenes from pictureCadence, the same numbers as the rise.quality log line; refused carries the refusal's code. hostOf names the host. The size refusal's Error carries code: 'MCP_TOO_LARGE' and sceneRefusals returns its code beside repair. No response changes.
  • wrangler.production.jsonc: "analytics_engine_datasets": [{ "binding": "EVENTS", "dataset": "syberlabs_events" }]. No other wrangler.*.jsonc gets it.
  • worker/production-config.test.js: pins the binding in production and its absence from every other configuration.
  • PRIVACY.md: one sentence in "RISE inside ChatGPT or Claude" and one in section 11. public/PRIVACY.md and public/privacy.html regenerated with npm run build:legal.
  • vitest.fast.config.js: worker/telemetry.test.js joins the fast list; FAST_TEST_FILES goes from 169 to 170.

Why

This is the approved SyberLabs telemetry design (telemetry.v1): counts of what happened, as closed enums and numbers, never text or identifiers. These two show which host apps use the connector and which refusals their models meet.

How host and release are derived

  • host: claude when the client address (CF-Connecting-IP) is in Anthropic's published connector egress, 160.79.104.0/21. That is the existing inAnthropicEgress check the rate limiter already uses. Otherwise chatgpt when the User-Agent begins openai-mcp/, and otherwise other. Neither the address nor the string is written.
  • release: 'unknown'. The Worker cannot know the deployed commit: CI writes it into dist/release.txt after wrangler has bundled the Worker. Naming it would take a deploy-time --var or --tag or a version-metadata binding, which is a workflow change outside this packet.

Tests

  • Fast suite, the list the required CI check runs (npx vitest run --config vitest.fast.config.js): 170 files collected, equal to FAST_TEST_FILES. 3927 tests: 3923 passed, 4 skipped, 0 failed. Baseline on main 19aabc7: 169 files, 3903 tests (3899 passed, 4 skipped).
  • worker/telemetry.test.js (23 tests):
    • the allowlist's shape;
    • every code the door can refuse with is listed, and none it cannot (read from the validator's sources);
    • the data point's shape, and nothing written for anything unlisted;
    • exactly one point per admitted Current (7 fixtures) and per refusal (11 kinds, each under its code);
    • an unlisted code or an unexpected error is counted as other;
    • no point for initialize, the lists, the guide, an unknown tool, a notification, the server switched off, a foreign Origin or a rate-limited request;
    • no address, User-Agent or Current text in any point;
    • every response byte-identical with the binding absent, recording, throwing, null, or lacking writeDataPoint, for Claude and ChatGPT requests alike.
  • Mutation checks, each reverted. Each of these failed the intended test: removing the writer's try/catch, writing the admitted point twice, matching openai-mcp/ anywhere in the string, dropping one code from the allowlist.
  • Also run locally, all passing:
    • node scripts/ci-hygiene.mjs, npm run roadmap:check, npm run test:roadmap, npm run security:compat;
    • npm run docs:diagram, with docs/specs/ARCHITECTURE.md unchanged;
    • npm run verify:legal, npx vite build;
    • npm run measure:first-load: 63.4 of 64.0 KB brotli, unchanged, since this PR changes no client code;
    • both wrangler deploy --dry-run bundles. Production lists env.EVENTS (syberlabs_events) Analytics Engine Dataset.
    • A local wrangler dev --local of the production configuration answered one admitted and one refused call with the local dataset bound and no runtime error.
  • Not run locally: npm run security:audit and the browser gate. CI runs both.
  • The private dependency-evidence server (GitHits) failed to connect in this session, so no version-grounded documentation lookup ran. The binding's shape was checked against the installed wrangler 4.144.0 configuration schema and its dry run instead.

Needs a human key

  • Seth: wrangler.production.jsonc floors at keys, because it is the production deploy. Merging deploys rise.syberlabs.io with the dataset bound. Please confirm that Workers Analytics Engine is enabled for the Cloudflare account first; this PR cannot check that.
  • Mateo: the two PRIVACY.md sentences and their generated copies. Section 14 says a material change updates the "Last updated" date. It is left at 26 October 2026 for Mateo to set.

Deliberately not done, and limitations

  • PRIVACY.md is otherwise unchanged, as asked. Three places still read as though the page-view counts are the only analytics: section 6 ("Page-view counts only … no other analytics"), section 9's list of server processing, and section 10's bases. Mateo may want them to name the tool counts too. The browser-counts packet amends sections 6 and 10, but only for its own counts.
  • ChatGPT detection has not been checked against a live ChatGPT request. If its connector does not send a User-Agent beginning openai-mcp/, its calls are counted as other: an undercount, never a wrong host. Calls from Claude clients outside Anthropic's egress, such as a local connector, are also counted as other.
  • Not included: any query, dashboard or reading of the counts; any client change or new dependency; any change to another Worker configuration. The rise.quality log line is unchanged.
  • No task record: the tracker has no task for this work, and this PR does not create one.
  • Overlap: draft Support MCP 2026-07-28 alongside legacy RISE Composer #729 rewrites much of worker/mcp-server.mjs, including sceneRefusals, dispatch and handleMcp, so whichever merges second needs a rebase. Draft Separate private-provider deployment from public releases #751 appends to worker/production-config.test.js; this PR's test sits inside the first describe to stay clear of that hunk.

Next

The browser-counts packet (telemetry/browser-counts, a draft) builds on this branch's worker/telemetry.mjs.


Generated by Claude Code

…and refusal code

One Analytics Engine data point per rise_present call: rise.current.admitted
with its beats and scenes, rise.current.refused with the refusal's code from
the door's closed set. Only what telemetry/events.json names is written, and
every answer is byte-identical with the binding absent, present or throwing.
EVENTS is bound in wrangler.production.jsonc alone. PRIVACY.md says so in the
ChatGPT and Claude list and in section 11.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHrJ4hmTtR1RFNpc215EK7
@netlify

netlify Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for rise-v2-symbolic-experience ready!

Name Link
🔨 Latest commit 8f45346
🔍 Latest deploy log https://app.netlify.com/projects/rise-v2-symbolic-experience/deploys/6aeaf7aaf4db37502eee1ad3
😎 Deploy Preview https://deploy-preview-762--rise-v2-symbolic-experience.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-31T02:15:14.091539Z c64f1bb PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Bring this branch up to date with main's dead-code sweeps (#765, #766,
#767) so it can merge. Two files conflicted:

- worker/mcp-server.mjs: main deleted Gate 0 and the witness log, made
  dispatch take the card as its third argument
  (dispatch(message, origin, card = null)) and deleted handleLive. All
  of that is kept as main has it. This branch's count callback becomes
  dispatch's fourth argument (count = () => {}): dispatch passes it to
  call() for rise_present, and handleMcp still derives the host with
  hostOf and writes through countEvent. No response changes.
- vitest.fast.config.js: main lowered FAST_TEST_FILES from 169 to 157
  after deleting test files, and this branch adds
  worker/telemetry.test.js. The merged list collects 158 files
  (vitest list --filesOnly, and the fast run's JSON report), so
  FAST_TEST_FILES is 158.

PRIVACY.md, public/PRIVACY.md, public/privacy.html,
worker/production-config.test.js and wrangler.production.jsonc merged
without conflict; npm run verify:legal confirms the generated copies
still match PRIVACY.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHrJ4hmTtR1RFNpc215EK7
sdcarlson pushed a commit that referenced this pull request Nov 4, 2026
Bring this branch up to date with main's dead-code sweeps (#765, #766,
#767). It merges the updated telemetry/composer-counts (8f45346), which
already merges main at bce75dc, so this one merge brings in both.

Two files conflicted:

- vitest.fast.config.js: #762's merge set FAST_TEST_FILES to 158, and
  this branch had raised it from 170 to 174 for its four test files.
  The merged list collects 162 files (vitest list --filesOnly, and the
  fast run's JSON report), so FAST_TEST_FILES is 162.
- docs/specs/ARCHITECTURE.md: only the generated diagram conflicted.
  Took main's and regenerated it with npm run docs:diagram, which adds
  this branch's src/core/telemetry.js to core's module count and its
  imports to the audio, components and live edges into core.

One break git could not see: main (#767) deleted
worker/live-realtime.mjs, whose readText worker/count.mjs imports, and
moved readText unchanged into worker/mcp-server.mjs as a private
function. worker/mcp-server.mjs now exports it and worker/count.mjs
imports it from there. It is the same function count.mjs used before,
so the 512-byte and UTF-8 limits on a beacon are unchanged.

PRIVACY.md, public/PRIVACY.md, public/privacy.html, src/audio/engine.js,
src/audio/engine.lifecycle.test.js, src/components/Home.js,
src/components/read/Chamber.js, src/core/error-boundary.js,
src/live/host/LiveHost.js, src/live/host/LiveHost.test.js,
worker/index.mjs, worker/production-config.test.js and
wrangler.production.jsonc merged without conflict; npm run verify:legal
confirms the generated legal copies still match PRIVACY.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHrJ4hmTtR1RFNpc215EK7

This branch has not been deployed

No deployments
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.

2 participants