Skip to content

LLM-734: signup funnel — guide events, connection and tool-call stamps, admin view - #374

Merged
jeffdafoe merged 3 commits into
mainfrom
LLM-734-signup-funnel
Oct 9, 2026
Merged

jeffdafoe merged 3 commits into
mainfrom
LLM-734-signup-funnel

Conversation

@jeffdafoe

Copy link
Copy Markdown
Owner

LLM-734

For any outside account we can now answer: which client did they pick on the signup guide, did they connect, when did they first use a tool, and are they still using it.

Data (migration MEM-150)

  • signup_events (actor_id, event, value, created_at): guide_shown (with the tab open at the time), client (tab picked), copy (button pressed). Insert-only, cascades on account delete.
  • actors.first_connected_at, first_tool_call_at, last_tool_call_at, tool_call_count.
  • config.signup_funnel_since = migration time. first_* are stamped only for accounts created at or after it, so an old account's next use never reads as its first. Backfill from the 7-day request_log seeds only last_tool_call_at and a partial count (tool calls only: no initialize, ping, or any x/y method).

Writers

  • MCP auth heartbeat (already an UPDATE on every authenticated /mcp request) also stamps first_connected_at.
  • MCP tools/call handler stamps first/last/count, fire-and-forget, before the handler runs.
  • POST /v1/agent/signup-event, called by register.html with the API key it was just handed. Fixed event names, value ^[a-z][a-z0-9_-]{0,31}$, accepted only in the account's first 24 h, capped at 100 events per account (dropped events return recorded: false, not an error).

Reader

  • POST /v1/admin/funnel (access read permission) and a Signup Funnel sub-tab on the Access panel: stage counts (tracked accounts only, with all-time beside them) and one row per outside account. Outside = self-registered (created_by = id), not jeff, not zbbs-*, not virtual.
  • For a tracked account, "connected" is first_connected_at only — the guide's own events use the new key, so key use cannot count. Pre-tracking accounts fall back to agent_api_keys.last_used_at.

Tests

  • signup-funnel.test.js (9): validation, tracking start, row mapping, connected rule, stage counts. Full suite 291 pass.
  • SQL checked against a schema-only copy of production in a local scratch DB: migration up → down → up with request_log fixtures (backfill counted only tool calls), events, window, cap, cascade, stamps (first never moves; pre-tracking accounts never get first_*), funnel rows and summary. A mutation (stamping first for every account) fails that check.
  • access.html compiles clean with @vue/compiler-dom; vite build passes.

Agent: Home

🤖 Generated with Claude Code

jeffdafoe and others added 3 commits October 9, 2026 17:00
…s, admin view

We could not tell which client a new user picked, whether they connected,
when they first used a tool, or whether they kept using it: request_log is
purged after 7 days and nothing else recorded it.

- MEM-150: signup_events table (guide shown / client tab / copy button);
  actors.first_connected_at, first_tool_call_at, last_tool_call_at,
  tool_call_count; config.signup_funnel_since. Backfill seeds only the last
  tool call and a partial count from request_log.
- first_* are stamped only for accounts created after tracking began, so an
  old account's next use never reads as its first.
- MCP auth heartbeat stamps the first connection; the tools/call handler
  stamps tool use (initialize / tools/list do not count).
- POST /v1/agent/signup-event, called by the signup guide with the new API
  key; accepted only in the account's first 24 hours, capped at 100 events.
- POST /v1/admin/funnel and a Signup Funnel sub-tab on the Access panel.
  Outside accounts = self-registered, not jeff, not zbbs-*, not virtual.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g start

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… for the cap and boundary

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jeffdafoe

Copy link
Copy Markdown
Owner Author

Review round 2 follow-ups: a failed ROLLBACK now destroys the client (release(true)), with unit tests; new opt-in signup-funnel.pg.test.js (skipped unless TEST_DATABASE_URL names a scratch DB with MEM-150) covers the parallel-burst cap and the same-second tracking boundary. It fails with the advisory lock removed and passes with it.

@jeffdafoe
jeffdafoe merged commit 2590ab0 into main Oct 9, 2026
9 checks passed
@jeffdafoe
jeffdafoe deleted the LLM-734-signup-funnel branch October 9, 2026 21:16
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