Skip to content

fix(loops): accept event.action shorthand and show trigger events - #73094

Merged
charlesvien merged 4 commits into
masterfrom
fix/loop-github-trigger-events
Jul 23, 2026
Merged

fix(loops): accept event.action shorthand and show trigger events#73094
charlesvien merged 4 commits into
masterfrom
fix/loop-github-trigger-events

Conversation

@charlesvien

@charlesvien charlesvien commented Jul 23, 2026

Copy link
Copy Markdown
Member

Problem

Agents creating loops through MCP keep writing GitHub triggers as events: ["issues.opened"], the GitHub Actions shorthand. The API only accepts bare webhook events with the action expressed as a filter, so creation fails with a validation error surfaced in the review card. Nothing in the tool schema told the agent which events are allowed, and the review card's Runs line only showed the repository, not which events fire the loop.

Changes

  • The loops serializer folds event.action shorthand into the bare event plus an actions filter, matching its existing tolerance for singular filter keys. Shorthand is limited to a single event per trigger and cannot mix with bare events: the folded actions filter applies to every event in the trigger, so anything broader would fire event/action pairs nobody asked for.
  • The trigger config help text now enumerates the allowed events and documents the shorthand. Regenerated the OpenAPI-derived schemas and MCP tool snapshots so the tool descriptions carry this.
  • The loop review card's Runs line now spells out the trigger, e.g. GitHub (posthog/code: issues opened) instead of GitHub (posthog/code), including action, branch and label filters. No screenshot since the card renders inside MCP agent hosts; the output strings are asserted in the jest suite.
  • Removes the internal loops docs (products/tasks/docs/LOOPS*.md) from the repo.

How did you test this code?

  • New parameterized DRF tests for the folding (bare events, dotted shorthand, duplicates, merging with explicit filters.actions, the singular action alias) and for the rejections (unknown events, empty action suffix, shorthand mixed with bare events, shorthand spanning multiple events). The github trigger config validation had no API test coverage before. Full test_loops_api.py passes locally on a fresh test database.
  • Extended the LoopReviewView jest suite with github trigger cases covering events, each filter kind, singular aliases and dotted shorthand.
  • MCP unit suite passes with regenerated tool schema snapshots (2413 tests).
  • ruff, mypy and oxfmt on the touched files, plus tsgo --noEmit in services/mcp, are all clean.

Automatic notifications

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

Docs update

N/A. The internal loops docs are removed from the repo in this PR.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Authored with Claude Code from a bug report of a failed loop creation. Normalizing at save time was chosen over only teaching the agent the right shape, because agents will keep reaching for GitHub's own issues.opened notation. Review bots (veria, Greptile, Graphite) correctly flagged that the first cut flattened shorthand actions across different events, which would over-fire a credentialed loop; the follow-up commit restricts shorthand to one event per trigger instead of preserving per-event pairs, keeping the stored filter shape unchanged. The docs removal commit is by Charles directly.

@charlesvien charlesvien self-assigned this Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 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 873c3e8 · box box-e5fc6be9e528 · ready in 884s (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 23, 2026 08:50
@trunk-io

trunk-io Bot commented Jul 23, 2026

Copy link
Copy Markdown

😎 This pull request was merged.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

Bundle size — no change

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

Total: 64.66 MiB · no change

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.21 MiB · 3,002 files no change ████████░░ 84.6% 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.1/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.1/node_modules/posthog-js/dist/module.js
167.1 KiB src/queries/validators.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

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-HY7HJI4V.css
545.0 KiB dist/toolbar/chunk-chunk-RQ4FN27S.js
484.2 KiB dist/toolbar/chunk-chunk-QS5AHYGW.js
133.6 KiB dist/toolbar/chunk-chunk-SYFILNLU.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.0 KiB dist/toolbar/toolbar-app-IWQPCR2K.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-ZOYUTNIC.js
20.9 KiB dist/toolbar/chunk-chunk-IIQH4XLX.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 — 🔺 +717 B (+0.0%)

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

Total: 1357.64 MiB · 🔺 +717 B (+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 — skipped stale run for 8b4d0d5

Skipped the snapshot commit because the branch advanced to 7ad67f3 while the workflow was testing 8b4d0d5.

The new commit will trigger its own snapshot update workflow. If a fresh run does not start, merge master or push an empty commit.

Comment thread products/tasks/backend/presentation/serializers_loops.py
@veria-ai

veria-ai Bot commented Jul 23, 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

@greptile-apps

greptile-apps Bot commented Jul 23, 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/tasks/backend/presentation/serializers_loops.py:207-210
**Event-action associations are lost**

When a trigger contains shorthand for multiple event types, such as `issues.opened` and `pull_request.synchronize`, normalization merges both actions into one trigger-wide filter. This also accepts `issues.synchronize` and `pull_request.opened`, causing the loop to fire for webhook combinations that were not requested.

Reviews (1): Last reviewed commit: "show github trigger events in loop revie..." | Re-trigger Greptile

Comment thread products/tasks/backend/presentation/serializers_loops.py
Comment thread products/tasks/backend/presentation/serializers_loops.py

@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 fix correctly restricts the event.action shorthand to a single event per trigger, resolving the exact cross-event action-leak bug all three bot reviewers flagged; tests cover both the folding and the rejection cases, and the author (STRONG familiarity, owning team) plus three independent bot reviews provide assurance over this security-relevant trigger-matching logic.

  • Author wrote 100% of the modified lines and has 10 merged PRs in these paths (familiarity STRONG).
  • 👍 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 123L, 3F substantive, 963L/15F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (963L, 15F, two-areas, fix)
stamphog 2.0.0b3 .stamphog/policy.yml @ 24c0565 · reviewed head 873c3e8

@charlesvien
charlesvien enabled auto-merge (squash) July 23, 2026 09:09
@charlesvien
charlesvien disabled auto-merge July 23, 2026 09:34
@charlesvien
charlesvien enabled auto-merge (squash) July 23, 2026 09:41
@charlesvien
charlesvien merged commit 66f495c into master Jul 23, 2026
357 of 431 checks passed
@charlesvien
charlesvien deleted the fix/loop-github-trigger-events branch July 23, 2026 09:48
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 23, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-23 10:16 UTC Run
prod-us ✅ Deployed 2026-07-23 10:36 UTC Run
prod-eu ✅ Deployed 2026-07-23 10:37 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.

2 participants