Skip to content

feat(experiments): add experiment activity endpoint and MCP tool - #73446

Merged
jurajmajerik merged 6 commits into
masterfrom
experiments/experiment-activity-mcp
Jul 24, 2026
Merged

feat(experiments): add experiment activity endpoint and MCP tool#73446
jurajmajerik merged 6 commits into
masterfrom
experiments/experiment-activity-mcp

Conversation

@jurajmajerik

Copy link
Copy Markdown
Contributor

Problem

There is no way to see an experiment's change history through the API or MCP. The data is already there (the Experiment model logs to the activity log), and feature flags already expose the same thing via their activity endpoint and MCP tool.

Changes

  • New endpoint GET /api/projects/:id/experiments/:id/activity, same pattern as the feature flag one. Returns paginated activity log entries for the experiment, scoped by activity_log:read.
  • New MCP tool experiment-activity in the experiments tools.yaml, plus regenerated tool handlers and frontend types.

Design notes:

  • Holdouts and shared metrics also log under the Experiment scope, so their changes show up when they share the experiment's item id lookup. The tool description points agents to the feature flag activity tool for rollout/targeting changes, since those log on the flag.
  • I left out mcp_version: 1 to match feature-flags-activity-retrieve, which also omits it. If we want v2 agents to use system.activity_logs via SQL instead, we should sweep both tools together.

How did you test this code?

  • Added one test: test_activity_endpoint_returns_only_this_experiments_changes. It creates and updates two experiments and asserts the endpoint returns only the first one's entries, newest first. Catches a wrong scope string or a dropped item_ids filter, which would return another experiment's history or nothing. No existing test hits this endpoint.
  • Repo-wide mypy and ci:preflight --strict pass.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Written with Claude Code. Skills invoked: /improving-drf-endpoints, /implementing-mcp-tools, /writing-tests. The endpoint mirrors the feature flag activity action (same query serializer shape, same activity_page_response helper). The scaffolded tool key was renamed from experiments-activity-retrieve to experiment-activity to match the product's existing singular tool names.

@jurajmajerik jurajmajerik self-assigned this Jul 24, 2026
@jurajmajerik
jurajmajerik marked this pull request as ready for review July 24, 2026 08:14
@github-actions
github-actions Bot requested a deployment to preview-pr-73446 July 24, 2026 08:14 In progress
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds — a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
🛠️ Admin inspect & debug state in hogland
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit 46c98b0 · box box-ecf50b9c43e7 · ready in 847s (push → usable) · build log · rebuilds on every push, torn down on close

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team July 24, 2026 08:14
Comment thread products/experiments/backend/presentation/views.py Outdated
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Bundle size — 🔺 +307 B (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 64.38 MiB · 🔺 +307 B (+0.0%)

No file changed by more than 1000 B.

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.24 MiB · 22 files no change ███░░░░░░░ 27.5% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.07 MiB · 3,010 files 🔺 +441 B (+0.0%) ████████░░ 83.1% of 9.71 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
281.5 KiB ../node_modules/.pnpm/posthog-js@1.407.2/node_modules/posthog-js/dist/rrweb.js
267.7 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
236.0 KiB src/taxonomy/core-filter-definitions-by-group.json
226.1 KiB ../node_modules/.pnpm/posthog-js@1.407.2/node_modules/posthog-js/dist/module.js
154.3 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
105.8 KiB src/lib/api.ts
94.0 KiB ../packages/quill/packages/quill/dist/index.js
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

Toolbar bundle — eager 2.18 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.18 MiB · 17 files no change ████░░░░░░ 38.1% of 5.72 MiB
Deferred (lazy) 2.07 MiB · 33 files no change n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
713.8 KiB dist/toolbar/toolbar-app-HLTHZTTF.css
545.0 KiB dist/toolbar/chunk-chunk-JGF7ZYC3.js
484.2 KiB dist/toolbar/chunk-chunk-YMFODIKP.js
133.6 KiB dist/toolbar/chunk-chunk-YSVTUFEA.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.0 KiB dist/toolbar/toolbar-app-Y3ZKEAFE.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-ALQOU6WO.js
20.9 KiB dist/toolbar/chunk-chunk-VMBXRLPQ.js
12.2 KiB dist/toolbar/chunk-chunk-PIK3PADE.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

Dist folder size — 🔺 +10.7 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1352.23 MiB · 🔺 +10.7 KiB (+0.0%)

ℹ️ MCP UI apps size — 32 app(s), 17065.5 KB JS

Built size of each MCP UI app (main.js + styles.css).

App JS CSS
debug 599.5 KB 187.7 KB
action 457.8 KB 187.7 KB
action-list 564.3 KB 187.7 KB
cohort 456.8 KB 187.7 KB
cohort-list 563.3 KB 187.7 KB
email-template 456.6 KB 187.7 KB
error-details 472.4 KB 187.7 KB
error-issue 457.5 KB 187.7 KB
error-issue-list 564.2 KB 187.7 KB
experiment 561.5 KB 187.7 KB
experiment-list 565.1 KB 187.7 KB
experiment-results 563.2 KB 187.7 KB
feature-flag 567.1 KB 187.7 KB
feature-flag-list 570.9 KB 187.7 KB
feature-flag-testing 461.0 KB 187.7 KB
insight-actors 562.1 KB 187.7 KB
invite-email-preview 456.0 KB 187.7 KB
llm-costs 559.5 KB 187.7 KB
session-recording 458.6 KB 187.7 KB
session-summary 463.9 KB 187.7 KB
survey 458.4 KB 187.7 KB
survey-global-stats 562.2 KB 187.7 KB
survey-list 565.0 KB 187.7 KB
survey-stats 562.2 KB 187.7 KB
trace-span 457.2 KB 187.7 KB
trace-span-list 564.2 KB 187.7 KB
workflow 457.1 KB 187.7 KB
workflow-list 563.7 KB 187.7 KB
loops-review 461.2 KB 187.7 KB
query-results 745.5 KB 187.7 KB
render-ui 826.2 KB 187.7 KB
visual-review-snapshots 461.6 KB 187.7 KB
⚠️ MCP snapshots — 1 updated (0 modified, 1 added, 0 deleted)

Snapshots: MCP unit test snapshots updated

Changes: 1 snapshots (0 modified, 1 added, 0 deleted)

What this means:

  • Snapshots have been automatically updated to match current output

Next steps:

  • Review the changes to ensure they're intentional
  • If unexpected, investigate what caused the output to change

Review snapshot changes →

@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
products/experiments/backend/presentation/views.py:643-646
**Child activity records are excluded**

When a holdout or shared metric changes, its activity record uses the child object's ID, but this query filters only by the parent experiment ID, causing those changes to be silently omitted from the API and MCP history promised by the endpoint.

Reviews (1): Last reviewed commit: "feat(experiments): add experiment activi..." | Re-trigger Greptile

Comment thread products/experiments/backend/presentation/views.py Outdated
Comment thread products/experiments/backend/presentation/views.py Outdated
@veria-ai

veria-ai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions
github-actions Bot requested a deployment to preview-pr-73446 July 24, 2026 08:19 In progress
@github-actions
github-actions Bot requested a deployment to preview-pr-73446 July 24, 2026 08:24 In progress
@github-actions
github-actions Bot requested a deployment to preview-pr-73446 July 24, 2026 08:26 In progress

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The IDOR-style flaw three security-focused reviewers (hex-security-app, greptile, veria-ai) flagged — unrelated holdout/saved-metric activity leaking via item_id collision — is fixed in the current diff with a type-discriminated query, a targeted regression test for the exact collision scenario, and bot confirmation that no security concerns remain; author is on the owning team.

  • Author wrote 0% of the modified lines and has 33 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot], hex-security-app[bot].
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 109L, 6F substantive, 381L/12F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (381L, 12F, two-areas, feat)
stamphog 2.0.0b3 .stamphog/policy.yml @ 080c246 · reviewed head 46c98b0

@jurajmajerik
jurajmajerik enabled auto-merge (squash) July 24, 2026 08:54
@jurajmajerik
jurajmajerik merged commit 5f444ac into master Jul 24, 2026
381 of 396 checks passed
@jurajmajerik
jurajmajerik deleted the experiments/experiment-activity-mcp branch July 24, 2026 09:14
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 24, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-24 09:50 UTC Run
prod-us ✅ Deployed 2026-07-24 10:13 UTC Run
prod-eu ✅ Deployed 2026-07-24 10:12 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant