Skip to content

docs(capture): specify capture v1 delivery for server SDKs - #146

Open
eli-r-ph wants to merge 6 commits into
mainfrom
eli/capture-v1-specs
Open

eli-r-ph wants to merge 6 commits into
mainfrom
eli/capture-v1-specs

Conversation

@eli-r-ph

@eli-r-ph eli-r-ph commented Oct 25, 2026 •

Copy link
Copy Markdown

⚠️ DO NOT MERGE prior to v1 SDK public release! ⚠️

Problem

  • The next SDK to port to capture v1 has no contract to copy: the canonical capture, retry-queue, http-client and event-batcher specs still describe the legacy wire (/batch/, api_key in the body, $lib stamped into properties, global defaults overwriting the call, 429 retried, batches shrunk on 413).
  • posthog-python 8.0, posthog-go v2, posthog-rs 1.0 and posthog-node 6.0 already share one capture v1 contract on their v1 branches, worked out during the ports.

Changes

  • capture gains the capture v1 wire contract: the endpoint, the body envelope, strict field types, the required headers and which ones change on a retry, and the per-event results map with duplicates_dropped.
  • capture gains per-event options, the hoisting of the four legacy option properties after before_send, and global and context options where an SDK has global and context properties.
  • capture gains the server event-building order: the call wins, context and global values fill only unset keys, SDK values fill last, before_send has the final say. This folds in the flag-property rule from docs(capture): place server feature flag properties in the merge order #145.
    • Breaking for posthog-python and posthog-go users whose global defaults used to overwrite the call; both majors already ship the new order.
  • capture gains the rules capture v1 makes observable: blank distinct ids, the $groupidentify fallback id, timestamps at millisecond precision or finer, per-event serialization, $lib owned by the header, fail-open on a missing or personal API key.
  • retry-queue gains the capture v1 status set (404/408/429/500/502/503/504 and network errors retried; 402/413 terminal), four attempts with 100 ms doubling waits and jitter, Retry-After as a clamped floor, and no HTTP-library retries. "429 retryable" and "shrink on 413" are marked legacy.
  • http-client gains bearer auth, the accepted Content-Encoding values, and same-origin 307/308 redirects only.
  • event-batcher gains byte-aware check-before-append batching and the end of 413 batch shrinking.
  • migration/yaml-parity-v1 mirrors the harness capture v1 suite update (posthog-sdk-test-harness#92): 404, 429 and 502 retry scenarios, and the warning result in place of limited, which capture never sends.
  • Every new requirement is scoped to SDKs that deliver through capture v1; legacy SDKs keep the existing rules and the capture_v0* harness features are untouched.

Note

Three open PRs touch the same ground and need a decision before merge: #145 (folded in here), #140 (requires null for non-finite numbers, while posthog-go v2 drops the event locally; this change records both as allowed), #81 (gzip by default, while the v1 server SDKs default to no compression).

How did you test this code?

  • openspec validate add-capture-v1 --type change --strict passed before archiving.
  • openspec validate --specs --strict --no-interactive after archiving: 67 passed, 0 failed, the same totals as main.
  • Every requirement was checked against capture on PostHog/posthog master (rust/capture/src/v1/) and against the four SDK v1 branches, including their open pre-release PRs. Sources are listed in the archived design.md.
  • Harness docs(batching): define replay session and identity boundaries #92 branch with SDK_V2_SPECS pointing at this branch: discovery ready with no missing bindings (160 migrated cases), and the retry and outcome features pass against the harness reference hosts. The harness case-count test needs 157 → 160 when the harness bumps its specs pin.
  • Not run: the harness against a real SDK adapter. The scenarios are not opted in with @sdk:server; that needs an end-to-end run against a real adapter.

🤖 Agent context

  • Written by Claude Code (Claude Fable 5.1) with the SDK owner directing scope and decisions.
  • Skills invoked: writing-pr-descriptions.
  • The session surveyed capture-rs, the four SDK branches and the production ingress config, drafted the change with the OpenSpec CLI, archived it, and synced the narrative notes by hand.

🤖 Generated with Claude Code

@eli-r-ph eli-r-ph self-assigned this Oct 25, 2026
@eli-r-ph
eli-r-ph marked this pull request as ready for review October 25, 2026 18:24
@eli-r-ph
eli-r-ph requested a review from a team as a code owner October 25, 2026 18:24
eli-r-ph and others added 4 commits October 27, 2026 09:01
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o v2 sends it

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

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@eli-r-ph
eli-r-ph force-pushed the eli/capture-v1-specs branch from 6c6daa2 to 41b4023 Compare October 27, 2026 16:05
…rors

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…arning result

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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