Skip to content

feat(dashboards): add tile groups and badges to the dashboard API and MCP - #114783

Merged
trunk-io[bot] merged 8 commits into
masterfrom
posthog-self-driving/featdashboards-add-tile-groups-and-bd7045
Oct 11, 2026
Merged

trunk-io[bot] merged 8 commits into
masterfrom
posthog-self-driving/featdashboards-add-tile-groups-and-bd7045

Conversation

@posthog

@posthog posthog Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Problem

  • MCP agents and API users cannot group dashboard tiles or mark one tile in a group as the winner.
  • Today the result of a tile comparison can only go into a title or a description. A machine cannot read it, and people miss it.

This is layer 1 of 2. It stores the fields and exposes them in the API and MCP. Nothing draws them yet. Layer 2 (#114811) adds the UI and closes the issue. Refs #114760.

Origin

  • Issues: #114760
  • Scout: a custom scout
  • First signal: 2026-10-09
  • Inbox report: open
  • Likely cause: 8e23010
  • Task started by: auto-start, after the report was rated P3 and ready to fix

Changes

  • A tile can now carry a group_key and a badge (winner or cheeky-hog). The dashboard PATCH and the MCP update tools set them.
  • A dashboard can name each group with customization.group_titles. Keys are stripped like tile keys. Blank keys, duplicate keys and more than 100 titles are rejected.
  • Duplicating a whole dashboard keeps group_key and badge, and the titles come with it. Copying or moving one tile to another dashboard drops its group_key and keeps the badge, because a group belongs to the tile and its dashboard.
  • A group can hold more than one winner. The API help text says so.
  • A PATCH with a bad badge or group_key on any tile returns 400 before anything is saved. A null character in a group key or title key also returns 400. Only null clears a badge, and an empty string is rejected.
  • Marking widget tiles no longer loads each widget on its own.
  • The new dashboard tile marking changed event fires when a PATCH changes a tile's badge or group_key.
  • The migration adds two nullable columns with no default, so it needs no table rewrite and can run before the code. It is the riskiest part to review.
  • Mechanical: generated API and MCP types, MCP tool schema snapshots, the tile SQL snapshot and the resource transfer field snapshot.

No UI changes in this layer, so there are no screenshots.

How did you test this code?

Test rationale: The group title tests catch a padded title key that saves but never matches a tile, and the rejection cases catch blank, duplicate and over-limit input. The existing group title test only covered the length check.

  • test_dashboard.py, parameterized: group title keys (padded keys match, old padded keys read back stripped, blank, duplicate, too long and null character rejected); tile group_key and badge set, kept on duplicate, cleared and rejected; a bad marking on one tile saves nothing, also when the tile edits text; single tile copy and move drop group_key and keep the badge.
  • test_dashboard_widgets.py: marking widget tiles loads no widget on its own; widget copy and move drop group_key.
  • The DashboardTile field snapshot and the MCP tool schema snapshots cover the new fields.
  • Ran the dashboard API tests, the widget tests, makemigrations --check and hogli build:openapi locally. The only failures are test_shared_dashboard and test_shared_dashboard_does_not_expose_where_it_is_filed, which need a frontend build in the sandbox.

Release status

  • No feature flag controls this change

Docs update

None. The MCP tool descriptions carry the new fields.

🤖 Agent context

Autonomy: Human-driven (agent-assisted). A self-driving run opened this PR, and a person then took it over.

Agent: Claude Code, Sonnet 5 (main loop and runners) and Opus 5.5 (one review and one frontend fix runner)

  • Skills invoked: /stacking-prs, /writing-pr-descriptions, plus pr-shepherd, qa-swarm and engineering-systems-thinking from the PostHog skills store.
  • This PR started as one change from a self-driving run. It is now the backend layer. The UI moved to feat(dashboards): show winner crown, cheeky hog and group titles on tiles #114811, and the review fixes for both halves landed here and there.
  • Two layers, not three: the tile serializer excludes fields by name, so a migration-only layer would still change the API schema and repeat the same generated files.

Created with PostHog Desktop

@posthog posthog Bot added the self-driving label Oct 9, 2026
@trunk-io

trunk-io Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

😎 This pull request was merged.

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

Two gates refused this pull request: the deny-list gate, because it touches migrations (0026_dashboardtile_group_key_badge.py and max_migration.txt) and public API surface (the dashboard PATCH serializers, generated API schemas, and MCP tool definitions), and the tier gate, which classified it as T2-never given its size and cross-cutting reach (781 lines across 23 files, including backend, frontend, and MCP). This decision is final and is not a judgment on the quality of the change.

The author can ask a human reviewer to look at it. Splitting it up, for example into the migration and model change, then the API and MCP changes, then the UI, would also make each piece easier to review.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 378L, 13F substantive, 781L/23F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (781L, 23F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head af5dc8d

@stamphog stamphog Bot added the reviewhog ($$$) Reviews pull requests before humans do label Oct 9, 2026
@posthog

posthog Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor Author

🦔 PostHog Review reviewed this pull request

Nothing worth raising this time. Enjoy the moment:

A happy dog on a sunny path

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

Two gates refused this pull request: the deny-list gate and the tier gate.

  • Deny-list: the PR touches protected areas. It adds a migration (0026_dashboardtile_group_key_badge.py, plus max_migration.txt) and changes the public API surface (the dashboard PATCH, the generated API schemas and the MCP tool definitions).
  • Tier: it was classified as T2-never because it is a cross-cutting feature, at 781 lines across 23 files.

A human reviewer needs to look at this one. The author can request a review from a team member. Splitting it up would help too, for example the migration and model change in one PR, the API and MCP changes in another, and the UI decorations in a third. That would not clear the deny-list match on its own, but it would give reviewers smaller pieces.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 378L, 13F substantive, 781L/23F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (781L, 23F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head 2d0dfc2

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Trunk lane — backend Python lane

This PR is assigned to the backend Python lane. It runs backend Python tests and may merge in parallel with PRs in other lanes.

✅ Complexity (TypeScript) — clean

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Duplication (TypeScript) — clean

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Bundle size — no change

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

Total: 75.57 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.67 MiB · 23 files no change █████████░ 90.6% of 1.84 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
3.83 MiB · 675 files no change █████████░ 95.0% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.79 MiB · 2,463 files no change █████████░ 93.4% of 8.34 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.94 MiB · 3,529 files no change █████████░ 91.1% of 10.92 MiB
today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
7.80 MiB · 2,473 files no change █████████░ 90.9% of 8.58 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.55 MiB · 3,373 files no change █████████░ 90.9% of 10.51 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
12.36 MiB · 4,204 files no change ████████░░ 78.6% of 15.72 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/activity/explore/EventsScene.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/index.tsx
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
839 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
317.7 KiB ../node_modules/.pnpm/posthog-js@1.438.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
220.8 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
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
101.6 KiB src/products.tsx
99.6 KiB src/lib/api.ts
69.0 KiB src/lib/lemon-ui/icons/icons.tsx
40.7 KiB src/lib/utils/eventUsageLogic.ts
38.7 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
29.0 KiB ../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/schemas.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
317.7 KiB ../node_modules/.pnpm/posthog-js@1.438.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
153.7 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
112.1 KiB ../packages/quill/packages/quill/dist/index.js
101.6 KiB src/products.tsx
99.6 KiB src/lib/api.ts
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
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
317.7 KiB ../node_modules/.pnpm/posthog-js@1.438.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
181.9 KiB src/queries/validators.js
153.7 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
112.1 KiB ../packages/quill/packages/quill/dist/index.js
101.6 KiB src/products.tsx
99.6 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
Size File
317.7 KiB ../node_modules/.pnpm/posthog-js@1.438.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
153.7 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
112.1 KiB ../packages/quill/packages/quill/dist/index.js
101.6 KiB src/products.tsx
99.6 KiB src/lib/api.ts
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
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
Size File
317.7 KiB ../node_modules/.pnpm/posthog-js@1.438.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
181.9 KiB src/queries/validators.js
153.7 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
112.1 KiB ../packages/quill/packages/quill/dist/index.js
101.6 KiB src/products.tsx
99.6 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
317.7 KiB ../node_modules/.pnpm/posthog-js@1.438.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
316.0 KiB ../node_modules/.pnpm/posthog-js@1.438.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
181.9 KiB src/queries/validators.js
153.7 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
112.1 KiB ../packages/quill/packages/quill/dist/index.js
101.6 KiB src/products.tsx
99.6 KiB src/lib/api.ts

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.24 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.24 MiB · 19 files no change ████░░░░░░ 39.2% of 5.72 MiB
Deferred (lazy) 2.19 MiB · 44 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
865.8 KiB dist/toolbar/toolbar-app-URUTSZGS.css
671.1 KiB dist/toolbar/chunk-chunk-L74JAGOA.js
259.5 KiB dist/toolbar/chunk-chunk-K2FSNWIW.js
138.9 KiB dist/toolbar/chunk-chunk-QRZBNVWO.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-6GJ26EEZ.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-2A27PFLG.js
21.7 KiB dist/toolbar/chunk-chunk-CQDVTV3N.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

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

✅ Dist folder size — no change

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

Total: 1007.71 MiB · no change

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

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

App JS CSS
debug 597.9 KB 203.4 KB
action 454.2 KB 203.4 KB
action-list 564.3 KB 203.4 KB
cohort 453.2 KB 203.4 KB
cohort-list 563.3 KB 203.4 KB
email-template 453.0 KB 203.4 KB
error-details 469.7 KB 203.4 KB
error-issue 454.6 KB 203.4 KB
error-issue-list 564.9 KB 203.4 KB
experiment 561.4 KB 203.4 KB
experiment-list 565.0 KB 203.4 KB
experiment-results 566.4 KB 203.4 KB
feature-flag 566.9 KB 203.4 KB
feature-flag-list 570.6 KB 203.4 KB
feature-flag-testing 457.4 KB 203.4 KB
inline-scan 453.7 KB 203.4 KB
insight-actors 562.4 KB 203.4 KB
llm-costs 559.4 KB 203.4 KB
session-recording 455.4 KB 203.4 KB
survey 454.8 KB 203.4 KB
survey-global-stats 562.0 KB 203.4 KB
survey-list 565.0 KB 203.4 KB
survey-stats 562.0 KB 203.4 KB
trace-span 453.6 KB 203.4 KB
trace-span-list 564.2 KB 203.4 KB
vision-observation-list 563.4 KB 203.4 KB
workflow 453.5 KB 203.4 KB
workflow-list 563.6 KB 203.4 KB
loops-review 457.9 KB 203.4 KB
query-results 813.9 KB 203.4 KB
render-ui 897.5 KB 203.4 KB
visual-review-snapshots 458.0 KB 203.4 KB
ℹ️ MCP agent API — agent-facing tool changes

What this PR changes for agents, from the tool schema snapshots and tool definitions.

Tools changed (2):

Tool Params Scopes Annotations Schema chars
dashboard-create +group_titles 3,314 -> 3,671
dashboard-update +group_titles description changed 19,697 -> 20,827
⚠️ Playwright — 2 flaky

🎭 Playwright report · View test results →

⚠️ 2 flaky tests:

  • Logout in another tab results in logout in the current tab too (chromium)
  • Creating a SQL insight with a variable and overriding it on a dashboard (chromium)

These issues are not necessarily caused by your changes.
Annoyed by this section? Help fix flakies and failures and it will go green!

⚠️ Backend snapshots — 1 updated (1 modified, 0 added, 0 deleted)

Query snapshots: Backend query snapshots updated

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

What this means:

  • Query snapshots have been automatically updated to match current output
  • These changes reflect modifications to database queries or schema

Next steps:

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

Review snapshot changes →

⚠️ Django migration SQL — 1 new migration to review

We've detected new migrations on this PR. Review the SQL output for each migration:

products/dashboards/backend/migrations/0026_dashboardtile_group_key_badge.py

/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/anyio/from_thread.py:119: SyntaxWarning: 'return' in a 'finally' block
  return result
/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/structlog/stdlib.py:1166: UserWarning: Remove `format_exc_info` from your processor chain if you want pretty exceptions.
  ed = p(logger, meth_name, ed)  # type: ignore[arg-type]
2026-10-10T18:32:37.281377Z [error    ] Path must be a valid database or directory containing databases. [posthog.exceptions_capture] pid=5482 tid=139987938036608
Traceback (most recent call last):
  File "/home/runner/work/posthog/posthog/posthog/geoip.py", line 15, in <module>
    geoip: Optional[GeoIP2] = GeoIP2(cache=8)
                              ~~~~~~^^^^^^^^^
  File "/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/django/contrib/gis/geoip2.py", line 116, in __init__
    raise GeoIP2Exception(
        "Path must be a valid database or directory containing databases."
    )
django.contrib.gis.geoip2.GeoIP2Exception: Path must be a valid database or directory containing databases.
/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/sshtunnel.py:1040: SyntaxWarning: 'return' in a 'finally' block
  return (ssh_host,
/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/langchain_core/_api/deprecation.py:27: UserWarning: Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater.
  from pydantic.v1.fields import FieldInfo as FieldInfoV1
System check identified some issues:

WARNINGS:
?: (axes.W001) You are using the django-axes cache handler for login attempt tracking. Your cache configuration is however invalid and will not work correctly with django-axes. This can leave security holes in your login systems as attempts are not tracked correctly. Reconfigure settings.AXES_CACHE and settings.CACHES per django-axes configuration documentation.
?: (staticfiles.W004) The directory '/home/runner/work/posthog/posthog/frontend/dist' in the STATICFILES_DIRS setting does not exist.
BEGIN;
--
-- Add field badge to dashboardtile
--
ALTER TABLE "posthog_dashboardtile" ADD COLUMN "badge" varchar(20) NULL;
--
-- Add field group_key to dashboardtile
--
ALTER TABLE "posthog_dashboardtile" ADD COLUMN "group_key" varchar(100) NULL;
COMMIT;

Last updated: 2026-10-10 18:33 UTC (8a40127)

✅ Django migration risk — migration analysis complete

We've analyzed your migrations for potential risks.

Summary: 1 Safe | 0 Needs Review | 0 Blocked

✅ Safe

Brief or no lock, backwards compatible

dashboards.0026_dashboardtile_group_key_badge
  └─ #1 ✅ AddField
     Adding nullable field requires brief lock
     model: dashboardtile, field: badge
  └─ #2 ✅ AddField
     Adding nullable field requires brief lock
     model: dashboardtile, field: group_key

📚 How to Deploy These Changes Safely

AddField:

This operation acquires a brief lock but doesn't rewrite the table.

Deployment uses lock timeouts with automatic retries, so lock contention will cause retries rather than connection pile-up.

Last updated: 2026-10-10 18:33 UTC (8a40127)

✅ ClickHouse migration SQL — none

No ClickHouse migrations in the latest push.

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

stamphog can't auto-approve this pull request because two gates refused it. The deny-list gate matched it on migrations (the new 0026_dashboardtile_group_key_badge.py and its max_migration.txt update) and on public API (the dashboard PATCH and MCP tool changes). The tier gate classified it as T2-never because it is a cross-cutting feature spanning 23 files and 785 lines.

The author should ask a human reviewer to look at it. Splitting it up, for example the migration and model change, the API and MCP surface, and the UI decorations as separate pull requests, would also make it easier to review.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 382L, 13F substantive, 785L/23F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (785L, 23F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head bcc6068

@posthog

posthog Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

Comment thread products/dashboards/frontend/dashboardTileGroups.ts Outdated
Comment thread products/dashboards/backend/api/dashboard.py Outdated
Comment thread frontend/src/scenes/dashboard/DashboardItems.tsx Outdated
Comment thread frontend/src/scenes/dashboard/DashboardItems.tsx Outdated
@posthog posthog Bot removed the reviewhog ($$$) Reviews pull requests before humans do label Oct 9, 2026
@posthog

posthog Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

👋 Visual changes detected for this PR.

Review and approve in PostHog Visual Review

If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix.

Install the Visual Review Chrome extension to see visual review results at the top of your pull requests.

@trunk-io

trunk-io Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
Dashboards › Creating a SQL insight with a variable and overriding it on a dashboard The test failed because the page URL did not match the expected URL. Logs ↗︎
Auth › Logout in another tab results in logout in the current tab too The page reload was aborted, possibly because the frame was detached. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

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

QA Swarm review complete. See inline comments and the summary comment.

Comment thread products/dashboards/frontend/dashboardTileGroups.ts Outdated
Comment thread products/dashboards/backend/api/dashboard.py Outdated
Comment thread frontend/src/scenes/dashboard/DashboardItems.tsx Outdated

pauldambra commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Note

🤖 Automated comment by QA Swarm — not written by a human

Review of this layer by one stronger-model reviewer (opus) or a cheap first pass (sonnet). This PR now holds the backend layer only. The UI is in #114811.

Verdict: ✅ APPROVE (round 3 @ e5d845b)

No blocking findings. The review found three issues in the API, and all three are fixed. One item is left for a person on the UI layer.

Key findings

  • 🟡 Fixed The widget loaded once per marked widget tile (repo bot). The tile now loads with its widget.
  • 🟡 Fixed A NUL character in a group key or title key returned a 500 (repo bot). It now returns a 400.
  • 🟡 Fixed A bad badge or group key returned a 400 after earlier tiles and the group titles were saved (repo bot, and the same finding on the earlier version of this PR). Every tile in the PATCH, including tiles that edit text, a button or a widget, is now checked before any write.
  • 🟢 Fixed Copying or moving a single tile to another dashboard kept its group_key but not the title. It now drops the key and keeps the badge. Whole-dashboard duplication keeps both.
  • 🟢 Fixed badge allowed an empty string in the generated types, but the API rejects it. The column is new, so the migration is edited in place.
  • 🟢 Open on feat(dashboards): show winner crown, cheeky hog and group titles on tiles #114811 Copying a decorated tile as a PNG clips the crown and the group title.

Checked and clean

Migration 0026 (nullable, no default, no hot table), edit permission and tenancy on the PATCH path, partial updates, clearing a badge with null, copy and transfer of both fields, the analytics event carries no free text, and the MCP text.

Previous rounds (2)

round 1 @ bcc6068: REQUEST CHANGES on the one-PR version: clipped decorations in view mode, a __proto__ key crash, unstripped title keys. All fixed.

round 2 @ 5e9cc36: APPROVE, LOW and NIT items only. The PR was then split into this backend layer and the UI layer #114811. The split reviews (two rounds on the layers) found and fixed the items above.


Automated by QA Swarm — not a human review

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

stamphog can't auto-approve this pull request. The deny-list gate refused it because it adds a database migration (0026_dashboardtile_group_key_badge.py) and changes the public API surface (the dashboard PATCH, the MCP tool definitions, and the generated API schemas). The tier gate also classified it as T2-never, because it is a cross-cutting feature touching 28 files and about 1,000 lines once docs, generated files and snapshots are counted.

Please ask a human reviewer to look at it. Splitting it into a migration and API change, plus a separate frontend change, would also make it easier to review.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 458L, 15F substantive, 1009L/28F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (1009L, 28F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head 5e9cc36

@stamphog stamphog Bot added the reviewhog ($$$) Reviews pull requests before humans do label Oct 9, 2026

Copy link
Copy Markdown
Member

Note

🤖 Automated comment by PR Shepherd — not written by a human

Screenshots: tile decorations in view mode

These are real renders of the dashboard scene in Storybook, using fake data. The first column is the PR before commit 5e9cc36. The second column is after. In view mode the crown, group title and hog were clipped by content-visibility: auto.

Before After
Winner crown and group title Before: crown is a thin stroke and the title is cut in half After: crown at the top left and the full group title
Cheeky hog on hover Before: no hog on hover After: hog peeks over the top edge

At about 520px wide (after the fix):

Crown and title Hog on hover
Crown and title at 520px Hog on hover at 520px

The crown overhangs the card's left edge into the page margin at this width, but it is not cut off.

Not checked in a browser: groups whose top-left tile is a hidden widget, and compaction with stored vertical gaps. Unit tests cover both.

@pauldambra
pauldambra marked this pull request as ready for review October 9, 2026 21:40
@parameterai

parameterai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Risk: No findings

The delta since the last review is a two-line generated-type addition (url?: string | null on HogQLNoticeApi) with no runtime code; it introduces no new security surface and nothing in this PR consumes it.

Sentinel reviewed 8a40127 · Review settings

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T21:45:15.484164Z 5e9cc36 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team October 9, 2026 21:41

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e9cc36bce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread products/dashboards/backend/api/dashboard.py
Comment thread frontend/src/types.ts Outdated
Comment thread frontend/src/scenes/dashboard/DashboardItems.tsx Outdated
@posthog posthog Bot removed the reviewhog ($$$) Reviews pull requests before humans do label Oct 9, 2026

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

stamphog can't auto-review this pull request. Two gates refused it: the deny-list gate matched it on migrations (products/dashboards/backend/migrations/0026_dashboardtile_group_key_badge.py) and on public API (the dashboard PATCH and MCP tool schema changes). The tier gate classified it as T2-never because it is a cross-cutting feature touching 29 files and 1013 lines.

The author should ask a human reviewer to look at it. Splitting it could also help, for example the migration and model change in one pull request and the API/MCP and UI changes in another.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 458L, 15F substantive, 1013L/29F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (1013L, 29F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head 33eb6e4

Comment thread products/dashboards/mcp/tools.yaml
@posthog posthog Bot removed the reviewhog ($$$) Reviews pull requests before humans do label Oct 10, 2026

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

stamphog can't auto-review this pull request because two gates refused it. The deny-list gate flagged it for touching migrations (0026_dashboardtile_group_key_badge.py and max_migration.txt) and public API surface (the dashboard API and the generated API and MCP schemas). The tier gate classified it as T2-never: a cross-cutting feature across 25 files and 912 lines. The size gate itself passed.

Please ask a human reviewer to look at it. Splitting the migration and the public API changes into separate, smaller pull requests may also make review easier.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 300L, 10F substantive, 912L/25F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (912L, 25F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head b0ba45a

@stamphog stamphog Bot added the reviewhog ($$$) Reviews pull requests before humans do label Oct 10, 2026
@pauldambra pauldambra added the stamphog Request AI approval (no full review) label Oct 10, 2026 — with PostHog
@stamphog

stamphog Bot commented Oct 10, 2026

Copy link
Copy Markdown

stamphog does not review bot-authored pull requests, so the trigger label has been removed. This change needs a human reviewer.

@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Oct 10, 2026
@posthog posthog Bot removed the reviewhog ($$$) Reviews pull requests before humans do label Oct 10, 2026

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

stamphog can't auto-review this pull request because two gates refused it. The deny-list gate flagged it for touching migrations (products/dashboards/backend/migrations/0026_dashboardtile_group_key_badge.py) and public API surface (the dashboard API in products/dashboards/backend/api/dashboard.py and the MCP tool definitions). The tier gate also classified it as T2-never, since it is a cross-cutting feature change spanning 25 files and 914 lines. The size gate itself passed.

The next step is to ask a human reviewer to look at it, with extra attention on the migration. Splitting the schema change from the API and MCP changes could also make the review easier.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 300L, 10F substantive, 914L/25F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (914L, 25F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head 13b701e

@stamphog stamphog Bot added the reviewhog ($$$) Reviews pull requests before humans do label Oct 10, 2026
@posthog posthog Bot removed the reviewhog ($$$) Reviews pull requests before humans do label Oct 10, 2026

@sampennington sampennington 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 like it, it's fun, but I am still wondering a bit where this will be used by users 😆
I can't think of much other than doing a/b tests and tracking it on a dashboard and not in experiments
We can see if it gets used, I guess? :)

pauldambra and others added 8 commits October 10, 2026 19:29
… MCP

Dashboard tiles get an optional group_key and a badge (winner or cheeky-hog).
A dashboard can give each group key a title through customization.group_titles.
The columns are nullable, so the migration is safe to run before the code.
The dashboard PATCH and the MCP tools can set all three. Nothing draws them yet.

Generated-By: PostHog Desktop
Task-Id: a0588627-3b8c-4fc5-b331-716af1994715
…group keys

Address review findings on the tile groups API.

- Load the widget with the tile when a PATCH marks widget tiles, so each marked tile no longer costs a query
- Reject NUL characters in group keys and group title keys with a 400, not a 500
- Validate every tile badge and group key before any write, so a bad value cannot leave earlier tiles saved

Generated-By: PostHog Desktop
Task-Id: a0588627-3b8c-4fc5-b331-716af1994715
The early check only covered tiles that edit display fields.
A tile that also edited text, a button or a widget could carry a bad badge or group key, and the 400 came after the dashboard and the content were saved.
Every tile in the payload is now checked before any write.

Generated-By: PostHog Desktop
Task-Id: a0588627-3b8c-4fc5-b331-716af1994715
…oved

A group belongs to a tile and its dashboard, and the group titles live on the dashboard.
Copying or moving one tile to another dashboard breaks that pairing, so the tile arrives without a group key.
Whole dashboard duplication keeps the key, because the titles are copied with the dashboard.
The badge is kept in every case.

Generated-By: PostHog Desktop
Task-Id: a0588627-3b8c-4fc5-b331-716af1994715
…ts types

The API only clears a badge with null, but blank=True made the generated types accept an empty string.
The column is new and unmerged, so the migration is edited in place.
Generated API and MCP types are regenerated.

Generated-By: PostHog Desktop
Task-Id: a0588627-3b8c-4fc5-b331-716af1994715
The badge column no longer allows an empty string, so the tile inline in the Django admin made the badge a required field.
Every unmarked tile then failed to save with "This field is required".
The inline now treats the badge as optional, and a blank choice saves as null.

Generated-By: PostHog Desktop
Task-Id: a0588627-3b8c-4fc5-b331-716af1994715
The test class for the tile inline reads no row, so it extends SimpleTestCase.
The repo check for test classes that take a database they never use failed on the base class.

Generated-By: PostHog Desktop
Task-Id: a0588627-3b8c-4fc5-b331-716af1994715
@pauldambra
pauldambra force-pushed the posthog-self-driving/featdashboards-add-tile-groups-and-bd7045 branch from 13b701e to 8a40127 Compare October 10, 2026 18:29

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

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

stamphog can't auto-review this pull request because two gates refused it. The deny-list gate flagged it for touching migrations (products/dashboards/backend/migrations/0026_dashboardtile_group_key_badge.py and max_migration.txt) and for changing the public API (the dashboard serializers and the generated API and MCP schemas). The tier gate classified it as T2-never: it is a cross-cutting feat of 914 lines across 25 files, and that class is never auto-reviewed.

Please ask a human reviewer to take it. Splitting the migration and model change from the API and MCP changes could make each piece easier to review, though the migration and public API changes would still need a human either way.

  • sampennington reviewed the current head.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: migrations, public_api
size ✓ 300L, 10F substantive, 914L/25F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (914L, 25F, cross-cutting, feat)
stamphog 2.4.1 .stamphog/policy.yml @ unknown · reviewed head 8a40127

@stamphog stamphog Bot added the reviewhog ($$$) Reviews pull requests before humans do label Oct 10, 2026
@posthog posthog Bot removed the reviewhog ($$$) Reviews pull requests before humans do label Oct 10, 2026
@trunk-io

trunk-io Bot commented Oct 10, 2026

Copy link
Copy Markdown

Stacked PR 114881 failed testing in the merge queue. Please investigate the failure and re-submit the stack.

@trunk-io
trunk-io Bot merged commit c02bd9e into master Oct 11, 2026
315 checks passed
@trunk-io
trunk-io Bot deleted the posthog-self-driving/featdashboards-add-tile-groups-and-bd7045 branch October 11, 2026 05:25
@trunk-io

trunk-io Bot commented Oct 11, 2026

Copy link
Copy Markdown

This pull request was merged into master as part of stacked PR 114881.

@deployment-status-posthog

deployment-status-posthog Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-10-11 05:44 UTC Run
prod-us ✅ Deployed 2026-10-11 05:58 UTC Run
prod-eu ✅ Deployed 2026-10-11 05:58 UTC Run

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants