Conversation
Set related_name="+" on the 12 workflows relations to Team and User, with a state-only AlterField migration, and remove the 12 reverse-accessor rows from the crossings baseline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 90c83620-aeca-40af-ad31-307e8edf458b
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
🤖 CI report
|
| First copy | Second copy | Lines | Tokens |
|---|---|---|---|
products/workflows/backend/models/hog_flow/hog_flow.py:150 |
products/workflows/backend/models/hog_flow/hog_flow_template.py:45 |
14 | 105 |
✅ 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.
⚠️ Backend coverage — 96.0% of changed backend lines covered — 2 uncovered
🧪 Backend test coverage
Patch coverage — changed backend lines (products + core): ███████████████████░ 96.0% (54 / 56)
| File | Patch | Uncovered changed lines |
|---|---|---|
products/workflows/backend/providers/twilio.py |
80.0% | 51 |
products/workflows/backend/facade/api.py |
83.3% | 287 |
🤖 Agents: add a test covering the lines above, or note why under "How did you test this code?". Machine-readable gap list: the patch-coverage artifact on this run (gh run download 538501421566200 -n patch-coverage), or the coverage-data block at the end of this comment.
Per-product line coverage (touched products)
| Product | Coverage | Lines |
|---|---|---|
warehouse_sources_queue |
██░░░░░░░░░░░░░░░░░░ 10.5% |
187 / 1,777 |
platform_features |
██░░░░░░░░░░░░░░░░░░ 12.1% |
7 / 58 |
demo |
███████████░░░░░░░░░ 52.8% |
1,411 / 2,673 |
data_tools |
████████████░░░░░░░░ 61.2% |
90 / 147 |
ai_gateway |
███████████████░░░░░ 75.0% |
9 / 12 |
aeo |
███████████████░░░░░ 76.3% |
617 / 809 |
batch_exports |
████████████████░░░░ 81.2% |
21,528 / 26,502 |
apm |
█████████████████░░░ 84.1% |
1,306 / 1,553 |
cdp |
██████████████████░░ 88.2% |
4,545 / 5,155 |
ml_inference |
██████████████████░░ 88.4% |
509 / 576 |
mcp_analytics |
██████████████████░░ 89.2% |
5,038 / 5,651 |
product_tours |
██████████████████░░ 89.3% |
1,331 / 1,491 |
dashboards |
██████████████████░░ 89.5% |
6,904 / 7,714 |
data_warehouse |
██████████████████░░ 90.0% |
14,027 / 15,589 |
notebooks |
██████████████████░░ 90.2% |
15,297 / 16,964 |
signals |
██████████████████░░ 90.2% |
57,836 / 64,097 |
cohorts |
██████████████████░░ 90.4% |
8,420 / 9,316 |
streamlit_apps |
██████████████████░░ 90.8% |
2,684 / 2,956 |
managed_warehouse |
██████████████████░░ 91.0% |
10,252 / 11,263 |
tasks |
██████████████████░░ 91.1% |
75,525 / 82,874 |
data_modeling |
██████████████████░░ 91.4% |
10,554 / 11,543 |
exports |
██████████████████░░ 91.6% |
9,680 / 10,562 |
engineering_analytics |
██████████████████░░ 91.7% |
11,032 / 12,030 |
ai_training |
██████████████████░░ 92.2% |
356 / 386 |
business_knowledge |
██████████████████░░ 92.2% |
7,684 / 8,330 |
conversations |
███████████████████░ 92.5% |
28,734 / 31,062 |
early_access_features |
███████████████████░ 92.6% |
1,332 / 1,439 |
managed_migrations |
███████████████████░ 92.7% |
1,581 / 1,705 |
visual_review |
███████████████████░ 92.8% |
9,247 / 9,969 |
stamphog |
███████████████████░ 92.8% |
8,109 / 8,742 |
canvas |
███████████████████░ 92.8% |
6,873 / 7,405 |
approvals |
███████████████████░ 93.0% |
3,974 / 4,271 |
mcp_registry |
███████████████████░ 93.1% |
1,670 / 1,794 |
notifications |
███████████████████░ 93.2% |
1,145 / 1,229 |
error_tracking |
███████████████████░ 93.2% |
16,359 / 17,547 |
surveys |
███████████████████░ 93.3% |
6,571 / 7,040 |
slack_app |
███████████████████░ 93.4% |
13,995 / 14,989 |
autoresearch |
███████████████████░ 93.6% |
8,481 / 9,061 |
context_layer |
███████████████████░ 93.9% |
3,415 / 3,638 |
web_analytics |
███████████████████░ 94.0% |
21,815 / 23,218 |
alerts |
███████████████████░ 94.0% |
8,570 / 9,114 |
billing_alerts |
███████████████████░ 94.1% |
2,094 / 2,226 |
mcp_store |
███████████████████░ 94.4% |
8,940 / 9,472 |
ai_observability |
███████████████████░ 94.5% |
24,473 / 25,896 |
workflows |
███████████████████░ 94.6% |
15,249 / 16,120 |
wizard |
███████████████████░ 94.7% |
6,150 / 6,496 |
reminders |
███████████████████░ 94.8% |
760 / 802 |
review_hog |
███████████████████░ 95.0% |
11,507 / 12,119 |
endpoints |
███████████████████░ 95.1% |
9,206 / 9,681 |
annotations |
███████████████████░ 95.1% |
817 / 859 |
customer_analytics |
███████████████████░ 95.2% |
25,636 / 26,938 |
legal_documents |
███████████████████░ 95.2% |
2,311 / 2,427 |
marketing_analytics |
███████████████████░ 95.3% |
19,566 / 20,528 |
posthog_ai |
███████████████████░ 95.3% |
2,488 / 2,610 |
experiments |
███████████████████░ 95.4% |
32,457 / 34,020 |
actions |
███████████████████░ 95.5% |
756 / 792 |
logs |
███████████████████░ 95.5% |
15,399 / 16,130 |
data_catalog |
███████████████████░ 95.5% |
4,401 / 4,606 |
tracing |
███████████████████░ 95.6% |
3,536 / 3,699 |
replay_vision |
███████████████████░ 95.6% |
27,675 / 28,939 |
growth |
███████████████████░ 95.7% |
11,228 / 11,734 |
messaging |
███████████████████░ 95.8% |
3,798 / 3,963 |
skills |
███████████████████░ 95.8% |
6,972 / 7,274 |
product_analytics |
███████████████████░ 96.0% |
28,470 / 29,647 |
access_control |
███████████████████░ 96.3% |
7,113 / 7,386 |
revenue_analytics |
███████████████████░ 96.4% |
1,876 / 1,946 |
user_interviews |
███████████████████░ 96.5% |
2,867 / 2,971 |
feature_flags |
███████████████████░ 96.5% |
25,588 / 26,509 |
warehouse_sources |
███████████████████░ 97.3% |
458,451 / 471,303 |
data_quality |
████████████████████ 97.6% |
7,587 / 7,774 |
links |
████████████████████ 97.9% |
234 / 239 |
security |
████████████████████ 98.0% |
1,286 / 1,312 |
metrics |
████████████████████ 98.0% |
4,084 / 4,166 |
analytics_platform |
████████████████████ 98.3% |
2,784 / 2,833 |
pulse |
████████████████████ 98.5% |
2,046 / 2,078 |
live_debugger |
████████████████████ 99.2% |
626 / 631 |
field_notes |
████████████████████ 99.4% |
172 / 173 |
Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.
⚠️ Django migration SQL — 1 new migration to review
We've detected new migrations on this PR. Review the SQL output for each migration:
products/workflows/backend/migrations/0027_seal_reverse_accessors.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-09-29T18:47:48.241841Z [error ] Path must be a valid database or directory containing databases. [posthog.exceptions_capture] pid=11345 tid=140417331678080
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;
--
-- Alter field created_by on hogflow
--
-- (no-op)
--
-- Alter field team on hogflow
--
-- (no-op)
--
-- Alter field created_by on hogflowbatchjob
--
-- (no-op)
--
-- Alter field team on hogflowbatchjob
--
-- (no-op)
--
-- Alter field created_by on hogflowrevision
--
-- (no-op)
--
-- Alter field team on hogflowrevision
--
-- (no-op)
--
-- Alter field team on hogflowschedule
--
-- (no-op)
--
-- Alter field created_by on hogflowtemplate
--
-- (no-op)
--
-- Alter field team on hogflowtemplate
--
-- (no-op)
--
-- Alter field team on teamworkflowsconfig
--
-- (no-op)
--
-- Alter field resolved_by on workflowproposal
--
-- (no-op)
--
-- Alter field team on workflowproposal
--
-- (no-op)
COMMIT;Last updated: 2026-09-29 18:48 UTC (da807bc)
✅ Django migration risk — migration analysis complete
We've analyzed your migrations for potential risks.
Summary: 0 Safe | 1 Needs Review | 0 Blocked
⚠️ Needs Review
May have performance impact
workflows.0027_seal_reverse_accessors
└─ #1 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflow, field: created_by, field_type: ForeignKey
└─ #2 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflow, field: team, field_type: ForeignKey
└─ #3 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflowbatchjob, field: created_by, field_type: ForeignKey
└─ #4 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflowbatchjob, field: team, field_type: ForeignKey
└─ #5 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflowrevision, field: created_by, field_type: ForeignKey
└─ #6 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflowrevision, field: team, field_type: ForeignKey
└─ #7 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflowschedule, field: team, field_type: ForeignKey
└─ #8 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflowtemplate, field: created_by, field_type: ForeignKey
└─ #9 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: hogflowtemplate, field: team, field_type: ForeignKey
└─ #10 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: teamworkflowsconfig, field: team, field_type: OneToOneField
└─ #11 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: workflowproposal, field: resolved_by, field_type: ForeignKey
└─ #12 ⚠️ AlterField
Field alteration may cause table locks or data loss (check if changing type or constraints)
model: workflowproposal, field: team, field_type: ForeignKey
Last updated: 2026-09-29 18:49 UTC (da807bc)
|
[Critical risk] Database schema changes to seal reverse accessors on workflow models. The PR appears safe to merge. Reviews (2) · Last reviewed commit: "chore(workflows): drop stale resolved_wo..." |
|
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 configurationConfiguration used: Repository: PostHog/posthog/.coderabbit.yaml Review profile: QUIET Plan: Enterprise Run ID: 📒 Files selected for processing (8)
💤 Files with no reviewable changes (1)
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughWorkflow model relationships to teams and users now set Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to This change disables unused reverse accessors on workflow relations and adds a migration that produces no SQL. There is no expected user-facing change, and no concrete merge-blocking risk remains. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change removes ways to reach workflow records from Team and User objects without changing the forward relationships or their deletion policies. No new security exposure was identified, but use of the removed names and deployment behavior are not fully established. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Sealing WorkflowProposal.resolved_by with related_name="+" hides the reverse relation, so User._meta.get_fields() no longer lists it and the User activity-log exclusion can never match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: f923bab8-96e1-44de-be46-3be7a5d3e83f
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
Re-add the stamphog label to request another review once you have addressed this.
Two gates refused this pull request. The deny-list gate flagged it because it adds a migration (products/workflows/backend/migrations/0027_seal_reverse_accessors.py, along with the max_migration.txt update), and migrations always need a human reviewer. The tier gate classified it as T2-never (180 lines across 11 files, spanning two areas: the workflows models plus posthog/models/activity_logging/activity_log.py and the crossings baseline), a tier that is never auto-approved.
Please ask a human reviewer, ideally someone who owns migrations or the workflows product, to take a look. The size gate passed, so splitting the change is not required for size reasons.
- 👍 on the PR from greptile-apps[bot].
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 166L, 9F substantive, 180L/11F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (180L, 11F, two-areas, chore) |
| stamphog 2.3.1 | .stamphog/policy.yml @ unknown · reviewed head 67b009a |
👀 Auto-assigned reviewersThese soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:
Soft owners come from each directory's |
…eal-reverse-accessors
…og/workflows-seal-reverse-accessors
…og/workflows-seal-reverse-accessors

Problem
team.hogflow_set, without an import.lint-importscheck imports only, so they cannot see this coupling.Refs #84402
Changes
TeamandUsernow userelated_name="+". Django no longer creates the reverse accessors or the reverse query names.workflows.0027records the change as 12AlterFieldoperations.sqlmigrateshows each one as a no-op, becauserelated_nameis a Python-only attribute.reverse-accessorrows, so a new unsealed relation fails CI.WorkflowProposal.resolved_byloses its explicit nameresolved_workflow_proposals. No code uses it.TeamandUserstill work, because Django keeps the hidden relations for deletion.Note
The migration risk analyzer marks this migration "Needs Review", because each
AlterFieldis on a foreign key. It generates no SQL, so it takes no lock onposthog_teamorposthog_user. Earlier sealing migrations in other products have the same shape, for exampleweb_analytics.0012.How did you test this code?
makemigrations --checkreports no changes.sqlmigrate workflows 0027shows a no-op for all 12 operations.The migration applied to the dev database and to the prewarmed
test_posthogdatabase before the test run.A search of all non-migration Python found no use of the removed accessors or of their
__query forms.Tests run against the migrated database:
products/workflows, the team and user deletion tests inposthog/api/test/test_team.py,test_user.pyandposthog/models/test/test_team_model.py, and the hogli product check tests.hogli product:lint workflowsalso passes.Manual checks on the local dev stack, with CDP, Temporal and a Temporal worker running, and no mocks:
TeamandUserTeamandUsercreated_byandresolved_bybecome nullHogFlowBatchJobexistsNot run: repo-wide mypy and the full backend suite. CI runs both.
Note
The manual checks found a separate bug that is also on master. Both foreign keys on
HogFlowBatchJobuseon_delete=DO_NOTHING. An account delete for a user who created a batch job returns a 500IntegrityError. A project delete for a project with a batch job makes the Temporal delete workflow retry without end. This PR does not changeon_delete, and master fails in the same way.Release status
Automatic notifications
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: PostHog Desktop (Claude Code), Claude Opus 5.5 (
claude-opus-5-5)/django-migrations,/writing-pr-descriptions.team_workflows_config.pyon other lines and adds no workflows migration, so the two do not conflict.Created with PostHog Desktop
🤖 Generated with Claude Code