|
| 1 | +--- |
| 2 | +next_step: 4-event-capture.md |
| 3 | +--- |
| 4 | + |
| 5 | +# Step 3 — Identification |
| 6 | + |
| 7 | +This step resolves four identification checks **in parallel**, one subagent per check: |
| 8 | + |
| 9 | +- `identify-stable-distinct-id` |
| 10 | +- `identify-not-late` |
| 11 | +- `cross-runtime-distinct-id` |
| 12 | +- `identify-reset-on-logout` |
| 13 | + |
| 14 | +Each subagent owns its own grep, reads, evaluates its single rule, and emits one `audit_resolve_checks` call with one update. The ledger's mutex serializes concurrent writes — there's no race. |
| 15 | + |
| 16 | +## Status |
| 17 | + |
| 18 | +Emit before dispatching: |
| 19 | + |
| 20 | +``` |
| 21 | +[STATUS] Auditing identification |
| 22 | +``` |
| 23 | + |
| 24 | +## Action — dispatch four subagents in one message |
| 25 | + |
| 26 | +Make **four `Task` tool calls in a single message** so they run concurrently. Wait for all four to return, then continue to `4-event-capture.md`. Do not run any other tools between dispatch and the next step. |
| 27 | + |
| 28 | +The bundled `identify-users.md` reference holds PostHog's authoritative guidance on `distinct_id`, `identify()` ordering, and cross-runtime identity. It's typically at `.claude/skills/audit/references/identify-users.md`; if that path doesn't exist, discover it with `Glob` `**/skills/audit/references/identify-users.md`. Each subagent reads it once before judging. |
| 29 | + |
| 30 | +### Task A — `identify-stable-distinct-id` |
| 31 | + |
| 32 | +`description`: `Audit identify-stable-distinct-id` |
| 33 | + |
| 34 | +`prompt`: |
| 35 | +``` |
| 36 | +You are an audit subagent. Resolve exactly one rule and return: identify-stable-distinct-id. |
| 37 | +
|
| 38 | +Read this skill's bundled `identify-users.md` reference once (typically `.claude/skills/audit/references/identify-users.md`; otherwise discover with `Glob` `**/skills/audit/references/identify-users.md`). |
| 39 | +
|
| 40 | +Run **one** Grep: `posthog\.identify\(`. Read each file that contains a hit, once. Inspect the first argument passed to identify(). |
| 41 | +
|
| 42 | +Rule: |
| 43 | +- distinct_id must be a stable identifier (auth user id, account id), not a session UUID, ephemeral cookie, or device-only id. |
| 44 | +- pass: sources from authenticated user (session.user.id, auth.uid(), etc.) |
| 45 | +- error: sources from a session, request, or device id that resets |
| 46 | +- warning: source unclear — flag for human review |
| 47 | +
|
| 48 | +Emit one `mcp__wizard-tools__audit_resolve_checks` call with a single update for id `identify-stable-distinct-id`, including `file` (path:line) and `details` (one-line explanation). Return when the call completes. Do not write the audit report. |
| 49 | +``` |
| 50 | + |
| 51 | +### Task B — `identify-not-late` |
| 52 | + |
| 53 | +`description`: `Audit identify-not-late` |
| 54 | + |
| 55 | +`prompt`: |
| 56 | +``` |
| 57 | +You are an audit subagent. Resolve exactly one rule and return: identify-not-late. |
| 58 | +
|
| 59 | +Read this skill's bundled `identify-users.md` reference once (typically `.claude/skills/audit/references/identify-users.md`; otherwise discover with `Glob` `**/skills/audit/references/identify-users.md`). |
| 60 | +
|
| 61 | +Run **two** Greps in parallel: |
| 62 | +- `posthog\.identify\(` — where identity is established |
| 63 | +- `posthog\.capture\(|getFeatureFlag\(|isFeatureEnabled\(` — where captures and flag evals happen |
| 64 | +
|
| 65 | +Read each file that contains a hit, once. Compare the timing/ordering of identify() against the surrounding capture / flag-eval calls. |
| 66 | +
|
| 67 | +Rule: |
| 68 | +- identify() must be called before any posthog.capture for that user, and before any feature-flag eval depending on user identity. |
| 69 | +- pass: identify runs at session start / right after login. Captures and flag evals come after. |
| 70 | +- warning: identify runs lazily (e.g. settings-page mount), so early captures and flag evals are anonymous. |
| 71 | +
|
| 72 | +Emit one `mcp__wizard-tools__audit_resolve_checks` call with a single update for id `identify-not-late`, including `file` (path:line of the identify call) and `details` (one-line explanation). Return when the call completes. Do not write the audit report. |
| 73 | +``` |
| 74 | + |
| 75 | +### Task C — `cross-runtime-distinct-id` |
| 76 | + |
| 77 | +`description`: `Audit cross-runtime-distinct-id` |
| 78 | + |
| 79 | +`prompt`: |
| 80 | +``` |
| 81 | +You are an audit subagent. Resolve exactly one rule and return: cross-runtime-distinct-id. |
| 82 | +
|
| 83 | +Read this skill's bundled `identify-users.md` reference once (typically `.claude/skills/audit/references/identify-users.md`; otherwise discover with `Glob` `**/skills/audit/references/identify-users.md`). |
| 84 | +
|
| 85 | +Run **one** Grep: `posthog\.init\(|new PostHog\(|posthog\.Posthog\(|Posthog\(` — locate every PostHog initialization across runtimes. Read each file that contains a hit, once. Determine whether both client and server runtimes initialize PostHog, and if so, how distinct_id flows between them. |
| 86 | +
|
| 87 | +Rule: |
| 88 | +- If both client and server runtimes call PostHog, the same distinct_id must be used on both sides for the same user. |
| 89 | +- pass: server-side captures source the client's distinct_id (cookie, session token, or explicit hand-off). |
| 90 | +- error: server-side captures use a different identifier scheme. |
| 91 | +- Skip (`pass` with details: "single runtime"): only one runtime initializes PostHog. |
| 92 | +
|
| 93 | +Emit one `mcp__wizard-tools__audit_resolve_checks` call with a single update for id `cross-runtime-distinct-id`, including `file` (path:line of the most relevant init or capture site) and `details` (one-line explanation). Return when the call completes. Do not write the audit report. |
| 94 | +``` |
| 95 | + |
| 96 | +### Task D — `identify-reset-on-logout` |
| 97 | + |
| 98 | +`description`: `Audit identify-reset-on-logout` |
| 99 | + |
| 100 | +`prompt`: |
| 101 | +``` |
| 102 | +You are an audit subagent. Resolve exactly one rule and return: identify-reset-on-logout. |
| 103 | +
|
| 104 | +Read this skill's bundled `identify-users.md` reference once (typically `.claude/skills/audit/references/identify-users.md`; otherwise discover with `Glob` `**/skills/audit/references/identify-users.md`). |
| 105 | +
|
| 106 | +Locate logout, sign-out, and account-switching flows by issuing whatever `Grep` and `Read` calls are needed in parallel. Determine whether those flows clear PostHog state with `posthog.reset()`. |
| 107 | +
|
| 108 | +Rule: |
| 109 | +- Logout or account-switching flows should call `posthog.reset()`. Without a reset, when user B logs in on the same device after user A, PostHog's anonymous ID is shared and the next `identify()` can merge both accounts into one person. |
| 110 | +- pass: every detected logout/account-switch flow calls `posthog.reset()`. |
| 111 | +- error: a logout/account-switch flow is missing `posthog.reset()`. |
| 112 | +- Skip (`pass` with details: "no logout/account-switch flow found"): no detectable logout/account-switch flow exists. |
| 113 | +- note: `posthog.reset(true)` is valid when a completely clean device ID reset is required. |
| 114 | +
|
| 115 | +Emit one `mcp__wizard-tools__audit_resolve_checks` call with a single update for id `identify-reset-on-logout`, including `file` (path:line of the most relevant logout or reset site) and `details` (one-line explanation). Return when the call completes. Do not write the audit report. |
| 116 | +``` |
0 commit comments