Skip to content

test(node): read capture events from either wire format - #5414

Merged
eli-r-ph merged 4 commits into
capture-v1from
capture-v1-test-port
Oct 27, 2026
Merged

eli-r-ph merged 4 commits into
capture-v1from
capture-v1-test-port

Conversation

@eli-r-ph

Copy link
Copy Markdown
Contributor

Problem

posthog-node's tests read sent events from the legacy /batch/ request body. Moving the SDK to capture v1 would rewrite hundreds of assertions in the same PR as the behavior change, which hides the real changes. This is the first PR stacked on the posthog-node 6 branch (#5407).

Changes

  • New test helpers in packages/node/src/__tests__/utils/index.ts (sentEvents, lastSentBatch, captureRequests, sentEventsOf, anyCaptureUrl) read sent events from either wire format. They return v1 events in the legacy shape: options, session_id, window_id and the library from the PostHog-Sdk-Info header go back into properties.
  • The node tests use these helpers. Their assertions do not change.
  • The @posthog/ai cassette collector accepts both legacy and v1 requests.
  • The convex example tests read events from either capture endpoint.
  • No production code changes.

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common

Checklist

  • All commits are signed (see Commit signing)
  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Authored with Claude Code (Claude Opus 5.5), directed by @eli-r-ph.

  • With the helpers in place, the next PR changes only tests of behavior that it changes.
  • Local checks: 1238 posthog-node tests pass; check-types, format, oxlint, the @posthog/ai cassette harness and the convex tests pass.

🤖 Generated with Claude Code

eli-r-ph and others added 3 commits October 23, 2026 20:56
Add shared helpers that find analytics capture requests on the legacy
/batch/ endpoint or the capture v1 analytics endpoint, and return their
events in the legacy shape. A v1 event's options, session and window
ids and SDK info header map back to the properties they replace, so one
assertion holds for both formats.

Port the tests that read events off the wire to these helpers, and
answer capture requests with a body that both senders accept. The same
tests pass on the legacy default and with POSTHOG_CAPTURE_MODE=v1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The collector accepted only the legacy /batch/ request. It now also
accepts the capture v1 analytics and AI endpoints with a bearer token,
and returns their events in the legacy shape, so the replay tests hold
for both wire formats.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The example tests read events only from /batch/ calls and checked the
api_key in the body. Read them from the legacy or the capture v1
analytics endpoint, and accept the project key from the body or the
bearer token.

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

Copy link
Copy Markdown
Contributor
⚠️ 2 packages modified but this PR has no changeset

This is informational — the PR is not blocked. Click the triangle above to collapse, or push a fix and this comment will auto-delete.

Modified in this PR but no changeset added:

  • @posthog/ai
  • posthog-node

If this change should ship, run pnpm changeset and select a bump level.
If it isn't user-facing (refactor with no behavior change, internal tooling, generated files), no action needed.

@github-actions

Copy link
Copy Markdown
Contributor

📝 No Changeset Found

This PR doesn't include a changeset. A changeset is required to release a new version.

How to add a changeset

Run this command and follow the prompts:

pnpm changeset

Remember: Never use major version bumps for posthog-js as it's autoloaded by clients.

@github-actions

Copy link
Copy Markdown
Contributor

Coherence

4 spec problems · 0 failing chokepoints · 2 spec gaps · 0 guard failures

44 components, 7 bullets (5 invariants, 2 requirements), 4 problems

Spec problems (spec --check)

  • packages/ai/src/otel/Otel.spec.md:7 an invariant bullet starts with <name>: <sentence>
  • packages/ai/src/otel/Otel.spec.md:8 an invariant bullet starts with <name>: <sentence>
  • Posthog-js.practice.md:20 practice add an invariant cites 187a5c5, which is no commit in this repository
  • Posthog-js.practice.md:20 practice add an invariant cites 8922ab2, which is no commit in this repository

Chokepoints: none declared.

Spec gaps: 2 entrances with outside or unknown trust and no traced control, and 10 more held by the adoption baseline

  • packages/web/Web.spec.md entrance public api (trust host-app): packages/web
  • packages/webpack-plugin/Webpack-plugin.spec.md entrance webpack plugin (trust build): packages/webpack-plugin

Close one with guard: <chokepoint>, an invariant that names it on its entrances: line, or control: none — <reason>; scaffold control proposes it.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Node SDK compliance v2

Commit: fac9423
Workflow run and artifacts

Capture v0 — acceptance

✅ 28 passed / ❌ 3 non-passing / ⚠️ 853 not selected

Drill-down: run artifacts → node-v2-v0 → acceptance/report.json.diagnostics.json (match case_id below).

❌ server_snapshot_payload_false — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_zero — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_null — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:

Harness exit: 1; report validation exit: 1.

Capture v1 — acceptance

✅ 28 passed / ❌ 3 non-passing / ⚠️ 853 not selected

Drill-down: run artifacts → node-v2-v1 → acceptance/report.json.diagnostics.json (match case_id below).

❌ server_snapshot_payload_false — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_zero — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_null — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:

Harness exit: 1; report validation exit: 1.

Capture v0 — migration

✅ 55 passed / ❌ 1 non-passing / ⚠️ 101 not selected

Drill-down: run artifacts → node-v2-v0 → reports/report.json.diagnostics.json (match case_id below).

❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

Capture v1 — migration

✅ 120 passed / ❌ 1 non-passing / ⚠️ 36 not selected

Drill-down: run artifacts → node-v2-v1 → reports/report.json.diagnostics.json (match case_id below).

❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

@eli-r-ph
eli-r-ph marked this pull request as ready for review October 24, 2026 04:59
@eli-r-ph
eli-r-ph requested a review from a team as a code owner October 24, 2026 04:59
@eli-r-ph eli-r-ph self-assigned this Oct 24, 2026

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good for the capture-v1 stack. The normalization stays in tests/private tooling and preserves the existing assertions. One optional recorded-call type consistency fix is noted inline. The outstanding Next.js installation failure is unrelated to this diff.

AI-assisted review.

…e requires

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eli-r-ph
eli-r-ph merged commit c716deb into capture-v1 Oct 27, 2026
70 of 72 checks passed
@eli-r-ph
eli-r-ph deleted the capture-v1-test-port branch October 27, 2026 03:43
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