Skip to content

feat!: add option defaults; event values always win - #359

Merged
eli-r-ph merged 16 commits into
v1from
v1-options-parity
Oct 22, 2026
Merged

eli-r-ph merged 16 commits into
v1from
v1-options-parity

Conversation

@eli-r-ph

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

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Stacked on #361.

In 1.x, DefaultEventProperties overwrote the event's own values, and there was no way to set options for every event or request.
This PR makes defaults fill only what the event left unset, on every message type.

Changes

  • Order: the event's values, then the request context, then client defaults, then SDK values.
  • BeforeSend sees every filled value and has the final say.
  • New Config.DefaultEventOptions and RequestContext.Options; a nil option counts as unset.
  • Defaults and request context now reach Exception, Identify, Alias and GroupIdentify.
  • Identify, Alias and GroupIdentify gain an EventProperties field.
  • The request context's session ID never fills GroupIdentify.
  • NewRequestContextMiddleware reads the X-PostHog-* headers only with WithCaptureTracingHeaders(true), because any client can set them.
  • $set, $set_once, $groups and $group_set merge one level deep.
  • The personless default is now a process_person_profile option that any layer can override.
  • posthogmcp gains ToolCall.Options and EventContext.Options and takes RequestContext.Options.
  • A caller-set $lib or $lib_version is removed before send.

💚 How did you test it?

  • Table tests cover each layer, each message type, and the BeforeSend view.
  • Middleware tests cover default, off and on for the tracing headers.
  • go vet, go test -race and make api-diff pass in all three modules.

🤖 Agent context

Autonomy: Human-driven (agent-assisted). Written with Claude Code.

🤖 Generated with Claude Code

@eli-r-ph

eli-r-ph commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai review

@eli-r-ph
eli-r-ph marked this pull request as ready for review October 7, 2026 20:44
@eli-r-ph
eli-r-ph requested a review from a team as a code owner October 7, 2026 20:44
Comment thread posthog.go Outdated
@veria-ai

veria-ai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 1 · PR risk: 0/10

@eli-r-ph
eli-r-ph force-pushed the v1-options-parity branch 2 times, most recently from bad06b9 to 84df98b Compare October 9, 2026 18:28
@eli-r-ph eli-r-ph changed the title feat!: add default and request-context options; event values win over defaults feat!: add option defaults; event values always win Oct 13, 2026
Base automatically changed from v1-sync-main to v1 October 18, 2026 17:47

@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.

I reproduced the four inline event-composition cases against this head and stack tip #368, using real SDK clients and a local recording server. The inlines include executed results, passing controls, base comparisons and suggested regression coverage.

AI-assisted review.

Comment thread posthogmcp/event.go Outdated
Comment thread posthogmcp/analytics.go
Comment thread properties.go
Comment thread request_context.go
@dustinbyrne
dustinbyrne requested a review from a team October 20, 2026 02:47

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated advisory code review.

Comment thread posthog.go Outdated
Comment thread request_context.go
@marandaneto
marandaneto requested a review from a team October 21, 2026 12:53

@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.

The composition fixes and regression coverage look good. Two non-blocking comments inline: preserving the spec/peer-aligned tracing-header default, and correcting the request-option scope in the migration guide.

AI-assisted review.

Comment thread request_context.go
Comment thread docs/migration-v2.md
Comment thread request_context.go
eli-r-ph and others added 15 commits October 21, 2026 17:43
$mcp_unknown_tool, $mcp_input_required and $mcp_missing_capability now carry the process_person_profile option and RequestContext.Options, like tool calls.
Request-context properties and options, Config.DefaultEventProperties,
Config.DefaultEventOptions and the personless process_person_profile
option now fill in after BeforeSend, only for keys the event and the hook
left unset. An option counts as unset when it is missing or nil; a
property only when its key is missing. The request-context distinct ID
still resolves before the hook.

DefaultEventProperties and DefaultEventOptions now also reach Exception,
Identify, Alias and GroupIdentify events, as event properties and
options, never in $set or $group_set.

DisableGeoIP no longer adds $geoip_disable to DefaultEventProperties.
Every message already sets it before BeforeSend, and as a default it
would come back after a hook removed it. A default $geoip_disable is
still forced to true.
Request-context properties and options, Config.DefaultEventProperties,
Config.DefaultEventOptions and the personless process_person_profile
option now fill before BeforeSend, still only into keys the event left
unset. BeforeSend sees every value and has the final say, including
removing a default. $set, $set_once, $groups and $group_set fill one
level deep when both values are maps. Capture.Groups merges into a
$groups map key by key, and Identify and GroupIdentify Properties merge
over a $set or $group_set in the event properties.

Identify, Alias and GroupIdentify gain an EventProperties field for the
event's own properties, which the defaults fill before the hook. It
replaces the unexported default field. Hoisting still runs once, after
the hook.
$is_server, $geoip_disable, system context and SendFeatureFlags properties
now fill only keys the event, request context and DefaultEventProperties
left unset, before BeforeSend. The SDK fills them last, so a
DefaultEventProperties $geoip_disable: false wins over Config.DisableGeoIP.

posthogmcp merges the sanitized request context under the call for every
client and enqueues with an empty request context, so the client does not
fill the unsanitized values again.
billing_limit_exceeded is a request-level 402 code. capture never puts it
in a per-event drop result; the per-event tags are exceptions_over_quota,
survey_responses_over_quota and llm_events_over_quota.
Capture sets both from the PostHog-Sdk-Info header and appends them after
the event's keys, so a copy left in properties is a duplicate JSON key.
…racing headers are opt-in

Request-context properties and options now fill Identify, Alias and
GroupIdentify like Capture and Exception: below the event's own values, above
the client defaults. The context session ID fills Identify and Alias but never
GroupIdentify, whose distinct ID is not the session's person. Context ids never
change an Identify or Alias.

NewRequestContextMiddleware no longer reads the X-PostHog-Distinct-Id and
X-PostHog-Session-Id headers unless WithCaptureTracingHeaders(true) is set,
because any client can send them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…yed map

- posthogmcp: a nil or typed-nil option no longer hides a legacy opt-out
  or erases a request-context option.
- $set, $set_once, $groups and $group_set merge one level deep for any
  map with string keys, such as map[string]string.
- A request-context $session_id set to nil now blocks a default session.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ons inherit

Context and default properties now beat SDK-generated feature flag
properties, matching the documented event > context > defaults > SDK
order, and a nil child request-context option keeps the parent's value.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@eli-r-ph
eli-r-ph merged commit 5172221 into v1 Oct 22, 2026
32 checks passed
@eli-r-ph
eli-r-ph deleted the v1-options-parity branch October 22, 2026 14:59
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.

3 participants