Skip to content

fix(api): reject non-object conversation settings - #108162

Open
pauldambra wants to merge 4 commits into
posthog/fix-widget-token-collisionsfrom
posthog/validate-conversation-settings-shape
Open

pauldambra wants to merge 4 commits into
posthog/fix-widget-token-collisionsfrom
posthog/validate-conversation-settings-shape

Conversation

@pauldambra

Copy link
Copy Markdown
Member

[Robot] Prepared by PostHog Desktop.

Problem

Project settings accept conversation settings with the wrong JSON type.

Changes

Return a validation error for arrays and scalar values. Keep objects and null valid.

This fixes existing behavior before the module split in #99248.

How did you test this code?

Parameterized serializer tests cover both project and environment endpoints. The focused tests ran against both module layouts. The full type check covers the combined fixes.

Release status

  • No feature flag controls this change

Automatic notifications

  • Publish to changelog?

Docs update

No existing document under docs/ covers this validation detail.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: PostHog Desktop / Codex, GPT-6

Tools: Git, GitHub CLI, hogli, pytest, Ruff, mypy, and CodeRabbit.
Skills: stacking-prs, improving-drf-endpoints, writing-tests, writing-code-comments, writing-user-facing-copy, setting-up-devbox, running-ci-preflight, reviewing-with-coderabbit, writing-pr-descriptions.
Each existing bug has its own layer below the refactor. No matching open fix appeared in the PR search.
The combined CodeRabbit review found two deployment tradeoffs in the membership layer. That PR records the decisions.


Created with PostHog Desktop

@pauldambra pauldambra self-assigned this Sep 29, 2026
@posthog

posthog Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

🦔 PostHog Review reviewed this pull request

Nothing worth raising this time. Enjoy the moment:

A panda relaxing and waving

@github-actions

github-actions Bot commented Sep 29, 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) — 12 new duplicated blocks (worst 203 tokens)

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.

First copy Second copy Lines Tokens
posthog/temporal/ai_observability/run_aggregate_evaluation.py:692 posthog/temporal/ai_observability/run_trace_evaluation.py:928 38 203
posthog/api/project.py:641 posthog/api/team.py:1870 21 168
products/warehouse_sources/backend/temporal/data_imports/sources/companycam/source.py:1 products/warehouse_sources/backend/temporal/data_imports/sources/wix/source.py:1 21 164
posthog/temporal/ai_observability/run_aggregate_evaluation.py:584 posthog/temporal/ai_observability/run_trace_evaluation.py:855 24 135
products/signals/backend/scout_harness/tools/report.py:1475 products/signals/backend/scout_harness/tools/report.py:1647 21 133
products/signals/backend/scout_harness/tools/report.py:1604 products/signals/backend/scout_harness/tools/report.py:1754 30 118
posthog/temporal/ai_observability/run_session_evaluation.py:466 posthog/temporal/ai_observability/run_trace_evaluation.py:664 24 115
posthog/management/commands/backfill_hogflow_billable_action_types.py:49 posthog/management/commands/refresh_hog_flows.py:69 23 112
products/batch_exports/backend/api/batch_export.py:2092 products/batch_exports/backend/api/batch_export.py:2131 24 112
products/warehouse_sources/backend/temporal/data_imports/sources/pardot/pardot.py:2 products/warehouse_sources/backend/temporal/data_imports/sources/wix/wix.py:1 12 97
products/signals/backend/scout_harness/tools/report.py:1516 products/signals/backend/scout_harness/tools/report.py:1675 12 71
products/signals/backend/scout_harness/tools/report.py:1531 products/signals/backend/scout_harness/tools/report.py:1690 16 70
⚠️ Duplication (TypeScript) — 2 new duplicated blocks (worst 158 tokens)

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.

First copy Second copy Lines Tokens
products/business_knowledge/frontend/scenes/settings/businessKnowledgeSettingsLogic.test.ts:10 products/data_catalog/frontend/certificationsLogic.test.ts:17 23 158
products/business_knowledge/frontend/scenes/settings/businessKnowledgeSettingsLogic.test.ts:10 products/data_quality/frontend/dataQualityGateLogic.test.ts:14 23 158
⚠️ Bundle size — 🔺 +33.8 KiB (+0.0%)

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

Total: 68.92 MiB · 🔺 +33.8 KiB (+0.0%)

File Size Δ vs base
posthog-app/_parent/products/business_knowledge/frontend/scenes/BusinessKnowledgePlaygroundScene.js removed 🟢 -26.2 KiB (-100.0%)
posthog-app/_parent/products/business_knowledge/frontend/scenes/playground/BusinessKnowledgePlaygroundScene.js 26.1 KiB 🔺 +26.1 KiB (new)
posthog-app/_parent/products/business_knowledge/frontend/scenes/BusinessKnowledgeScene.js removed 🟢 -18.7 KiB (-100.0%)
posthog-app/_parent/products/business_knowledge/frontend/scenes/sources/BusinessKnowledgeScene.js 18.6 KiB 🔺 +18.6 KiB (new)
posthog-app/_parent/products/business_knowledge/frontend/scenes/KnowledgeSourceScene.js removed 🟢 -18.0 KiB (-100.0%)
posthog-app/_parent/products/business_knowledge/frontend/scenes/source/KnowledgeSourceScene.js 18.0 KiB 🔺 +18.0 KiB (new)
posthog-app/_parent/products/business_knowledge/frontend/scenes/BusinessKnowledgeSettingsScene.js removed 🟢 -16.8 KiB (-100.0%)
posthog-app/_parent/products/business_knowledge/frontend/scenes/settings/BusinessKnowledgeSettingsScene.js 16.8 KiB 🔺 +16.8 KiB (new)
posthog-app/_parent/products/signals/frontend/inbox/InboxScene.js 488.4 KiB 🔺 +13.6 KiB (+2.9%)
render-query/src/render-query/render-query.js 20.16 MiB 🔺 +6.4 KiB (+0.0%)
posthog-app/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluation.js 87.1 KiB 🔺 +6.0 KiB (+7.4%)
posthog-app/_parent/products/workflows/frontend/Broadcasts/BroadcastScene.js 67.3 KiB 🔺 +3.7 KiB (+5.9%)
posthog-app/_parent/products/stamphog/frontend/scenes/StamphogDigestsScene/StamphogDigestsScene.js 9.5 KiB 🔺 +1.6 KiB (+20.7%)
posthog-app/_parent/products/stamphog/frontend/scenes/StamphogScene/StamphogScene.js 22.1 KiB 🔺 +1.1 KiB (+5.4%)

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.57 MiB · 22 files no change █████████░ 85.5% 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.51 MiB · 629 files 🔺 +1.6 KiB (+0.0%) █████████░ 87.2% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.34 MiB · 2,339 files 🔺 +2.7 KiB (+0.0%) █████████░ 88.0% of 8.34 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/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
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts 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
🟢 [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/index.tsx
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
854 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
301.8 KiB ../node_modules/.pnpm/posthog-js@1.434.14_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
216.9 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
100.5 KiB src/lib/api.ts
88.5 KiB src/products.tsx
69.4 KiB src/lib/lemon-ui/icons/icons.tsx
40.1 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
28.4 KiB src/scenes/scenes.ts
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
301.8 KiB ../node_modules/.pnpm/posthog-js@1.434.14_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
272.2 KiB src/taxonomy/core-filter-definitions-by-group.json
216.9 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
100.5 KiB src/lib/api.ts
98.5 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
88.5 KiB src/products.tsx

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.16 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.16 MiB · 19 files 🔺 +148 B (+0.0%) ████░░░░░░ 37.7% of 5.72 MiB
Deferred (lazy) 2.10 MiB · 44 files 🔺 +528 B (+0.0%) 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
800.5 KiB dist/toolbar/toolbar-app-QUJ43CJ4.css
651.7 KiB dist/toolbar/chunk-chunk-ACEXZHU5.js
259.4 KiB dist/toolbar/chunk-chunk-CV2VU6SQ.js
138.3 KiB dist/toolbar/chunk-chunk-VP2W3YP2.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-PZ4OESK6.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-O7ZEOSI5.js
21.0 KiB dist/toolbar/chunk-chunk-P6OO55L7.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 — 🔺 +650.3 KiB (+0.1%)

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

Total: 946.90 MiB · 🔺 +650.3 KiB (+0.1%)

✅ Playwright — all passed

All tests passed.

View test results →

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

Snapshots: MCP unit test snapshots updated

Changes: 1 snapshots (1 modified, 0 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 →

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: PostHog/posthog/.coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: d5471705-f218-401c-add6-fb82e88d2754

📥 Commits

Reviewing files that changed from the base of the PR and between 8e2c76c and bb5942b.

⛔ Files ignored due to path filters (2)
  • frontend/src/generated/core/api.schemas.ts is excluded by !**/generated/**
  • services/mcp/src/generated/core/api.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • posthog/api/project.py
  • posthog/api/team.py
  • services/mcp/src/api/generated.ts
  • services/mcp/tests/unit/__snapshots__/tool-schemas/project-settings-update.json

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.


📝 Walkthrough

Walkthrough

Both ProjectBackwardCompatSerializer and TeamSerializer now reject non-null conversations_settings values that are not dictionaries. A parameterized test checks that both serializers report validation errors for list, string, integer, and boolean values. Generated API types and the project-settings update schema now describe the field as an object or null.

Priority: ⬇️ Low

Merge Risk: 🔵 Low · up to bb594

Responses for settings containing legacy non-object JSON could contradict the generated object-or-null type. The risk is limited to such records, whose current presence is unconfirmed.

Security Architecture Review

Security architecture risk: 🔵 Low · up to bb594

The change rejects malformed settings without an identified expansion of access or newly introduced security issue. Older saved values, if present, could still appear in responses that now promise an object or null.

Retained concerns

  • Low · architecture · inferred: If non-object settings were previously saved, project or environment responses can still return them despite the newly narrowed object-or-null response contract.
Security review details

Security Blast Radius

  • inferred — The changed validation applies to settings submitted through existing project and environment routes and stored on the associated Team; no new cross-tenant route or service dependency was identified.

Trust Boundaries and Controls

  • observed — Team object access is filtered by user visibility and authenticator organization and team scopes. Settings updates remain subject to the existing admin-field validation.
  • observed — The shared field's object annotation describes the API schema; the new serializer validators, rather than the annotation, enforce the input shape at runtime.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description includes the required Problem, Changes, testing, release status, notifications, docs, and agent context sections. It clearly states the validation change and expected behavior. The fin…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@pauldambra
pauldambra added this pull request to stack #108171 September 29, 2026 08:42
@trunk-io

trunk-io Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
personalAPIKeysLogic preserves the `*` (all access) scope regardless of flag state The test failed because it could not find the specified path 'layout.navigation-3000.themeLogic' in the store. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

Generated-By: PostHog Desktop
Task-Id: 160dfc49-dceb-4887-b9f5-a93b2da017ed
Generated-By: PostHog Desktop
Task-Id: 160dfc49-dceb-4887-b9f5-a93b2da017ed
@pauldambra
pauldambra force-pushed the posthog/validate-conversation-settings-shape branch from 7acfb9a to 8e2c76c Compare September 29, 2026 12:56
@posthog

posthog Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review
PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

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

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

PostHog Review

Found 1 should fix.

Comment thread posthog/api/project.py
@pauldambra
pauldambra marked this pull request as ready for review September 29, 2026 13:07
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 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-09-29T13:11:05.539227Z 8e2c76c 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.

@pauldambra

pauldambra commented Sep 29, 2026 •

Copy link
Copy Markdown
Member Author

[Robot]

Note

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

Verdict: decision pending (round 3 @ bb5942b)

The request schema now matches the object-or-null validation. The two schema findings are fixed. One response compatibility question remains open.

Key findings

  • Existing stored non-object values could conflict with the narrowed response schema. Choose a tolerant response schema or a data cleanup plan before resolving that thread.

Convergence

Both original schema findings identified the same missing request contract. One fix covers both serializers.

Reviewer summaries

Reviewer Assessment
Router (gpt-5.6-sol) No defects in the initial input validation and parameterized tests.
Validator (gpt-6-astra) Accepted the schema fix and generated files. Deferred the historical response question.

Validation: 36 focused API tests, OpenAPI generation, frontend and MCP type checks, Ruff, and commit/push hooks passed. The automatic MCP snapshot update matches the schema change.

Previous rounds

Round 1 at 8e2c76c: no input-validation defects found. Two later bot findings requested a typed API schema.
Round 2 at ccd9b1e: schema fix accepted; historical response compatibility needs a decision.


Automated by QA Swarm — not a human review

@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: 8e2c76c741

ℹ️ 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 posthog/api/project.py
Generated-By: PostHog Desktop
Task-Id: 160dfc49-dceb-4887-b9f5-a93b2da017ed
@github-actions
github-actions Bot requested a deployment to preview-pr-108162 September 29, 2026 14:47 In progress
@github-actions

github-actions Bot commented Sep 29, 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 bb5942b · box box-038c464ac942 · ready in 685s (push → usable) · build log · rebuilds on every push, torn down on close

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

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

PostHog Review

Found 1 should fix.

Comment thread posthog/api/team.py
Comment on lines +1346 to +1347
@extend_schema_field(OpenApiTypes.OBJECT)
class ConversationsSettingsField(serializers.JSONField):

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.

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

Keep response schemas accurate for existing settings

should_fix compatibility

Issue description

This field annotation narrows both request and response schemas to objects or null. But JSONField can still return any stored JSON value, and these endpoints accepted arrays and some scalars before this change. Existing records with those values can therefore produce responses that violate the newly generated object-or-null response type.

Why we think it's a valid issue
  • Checked: Compared the PR changes with the base version and traced ConversationsSettingsField through TeamSerializer and ProjectBackwardCompatSerializer to the project and team response paths.
  • Found: @extend_schema_field(OpenApiTypes.OBJECT) annotates the shared field at posthog/api/team.py:1346-1348. Both serializers use it at posthog/api/team.py:1368-1373 and posthog/api/project.py:632-637. The new validators reject non-dictionaries on input at posthog/api/team.py:1894-1898 and posthog/api/project.py:653-657, but the model stores this setting in a nullable models.JSONField at posthog/models/team/team.py:446. Response serialization does not apply those input validators, and the base serializer previously exposed the value as unknown in the generated schema.
  • Impact: Previously accepted non-object values can remain in stored settings and be returned by these endpoints, despite the narrowed response schema. This is a reachable API compatibility mismatch, so the response schema should remain broad or the stored values should be cleaned before narrowing it.
Suggested fix

Keep the object-or-null constraint on request schemas, but preserve a response schema that matches stored values until existing records are cleaned up. Alternatively, clean up invalid stored values before narrowing the response contract.

Prompt to fix with AI (copy-paste)
## Context
@posthog/api/team.py#L1346-1347

<issue_description>
This field annotation narrows both request and response schemas to objects or null. But `JSONField` can still return any stored JSON value, and these endpoints accepted arrays and some scalars before this change. Existing records with those values can therefore produce responses that violate the newly generated object-or-null response type.
</issue_description>

<issue_validation>
- **Checked:** Compared the PR changes with the base version and traced `ConversationsSettingsField` through `TeamSerializer` and `ProjectBackwardCompatSerializer` to the project and team response paths.
- **Found:** `@extend_schema_field(OpenApiTypes.OBJECT)` annotates the shared field at `posthog/api/team.py:1346-1348`. Both serializers use it at `posthog/api/team.py:1368-1373` and `posthog/api/project.py:632-637`. The new validators reject non-dictionaries on input at `posthog/api/team.py:1894-1898` and `posthog/api/project.py:653-657`, but the model stores this setting in a nullable `models.JSONField` at `posthog/models/team/team.py:446`. Response serialization does not apply those input validators, and the base serializer previously exposed the value as `unknown` in the generated schema.
- **Impact:** Previously accepted non-object values can remain in stored settings and be returned by these endpoints, despite the narrowed response schema. This is a reachable API compatibility mismatch, so the response schema should remain broad or the stored values should be cleaned before narrowing it.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Keep the object-or-null constraint on request schemas, but preserve a response schema that matches stored values until existing records are cleaned up. Alternatively, clean up invalid stored values before narrowing the response contract.
</potential_solution>

@pauldambra pauldambra added the stamphog Request AI approval (no full review) label Sep 29, 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.

Approved.

Small, contained validation tightening on one project-settings field with parameterized tests for both serializers. The one open bot thread is about response-schema typing for legacy non-object values, which is a minor compatibility nit and does not affect runtime.

  • Author wrote 0% of the modified lines and has 92 merged PRs in these paths (familiarity MODERATE).
  • Non-blocking: the open ReviewHog thread on posthog/api/team.py notes that the generated response type now says object-or-null, while any legacy stored array or scalar values would still serialize as-is. This is likely rare and only affects typings.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 20L, 2F substantive, 108L/7F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (108L, 7F, cross-cutting, fix)
stamphog 2.3.0 .stamphog/policy.yml @ bb5942b · reviewed head bb5942b

This branch was successfully deployed

1 active deployment
preview-pr-108162 — bb5942b0 Deployed Sep 29, 2026 by github-actions[bot]
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