ENG-3299: Add CorrespondenceMetadata model and table#7867
ENG-3299: Add CorrespondenceMetadata model and table#7867JadeCara wants to merge 19 commits intoENG-3299/enums-scopes-encryptionfrom
Conversation
Create correspondence_metadata table (1:1 with comment) for delivery tracking and threading. Fields: message_id (unique, idempotency key), in_reply_to, reply_to_address, delivery_status, delivered_at, bounce_reason, sender_email, recipient_email. CASCADE delete from comment ensures cleanup. delivery_status uses varchar (not PG enum) to avoid cross-migration enum dependencies. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
Tests the constraints the TLA+ spec relies on: - message_id UNIQUE (idempotency guard) - comment_id UNIQUE (1:1 relationship) - CASCADE delete (PR deletion cleanup) - Default delivery_status is "pending" (FSM initial state) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## ENG-3299/enums-scopes-encryption #7867 +/- ##
=================================================================
Coverage 85.07% 85.07%
=================================================================
Files 629 630 +1
Lines 40879 40904 +25
Branches 4748 4749 +1
=================================================================
+ Hits 34776 34800 +24
Misses 5030 5030
- Partials 1073 1074 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review — PR #7867: Add CorrespondenceMetadata table
The overall design is solid: the 1:1 relationship between Comment and CorrespondenceMetadata, the cascade behavior, and the deletion guard for correspondence comments are all well-structured and well-tested. There are a couple of bugs that would cause runtime failures and one structural issue to address before merge.
Critical (must fix)
1. server_default generates invalid DDL in both the model and the migration.
server_default in SQLAlchemy treats its argument as a raw SQL expression, not a Python string. Passing "pending" (or CorrespondenceDeliveryStatus.pending, which evaluates to the string "pending") generates DEFAULT pending in the DDL — an unquoted identifier. PostgreSQL will reject this because pending is not a known column or function. The migration will fail to apply.
- In the migration: change
server_default="pending"→server_default=sa.text("'pending'") - In the model: change
server_default=CorrespondenceDeliveryStatus.pending→server_default="'pending'"
The pattern is already used correctly above in the same migration for created_at/updated_at (sa.text("now()")).
2. CorrespondenceDeliveryStatus is defined twice.
The enum is defined in comment.py (pre-existing) and again in correspondence_metadata.py (new). These are separate Python classes — they happen to have the same values but are not equal. correspondence_metadata.py should import the enum from comment.py rather than redefining it.
Minor
3. Deprecated import + unconventional declared_attr usage.
from sqlalchemy.ext.declarative import declared_attr is deprecated (moved to sqlalchemy.orm). Additionally, @declared_attr for __tablename__ is a mixin pattern; a concrete model should use a plain class attribute (__tablename__ = "correspondence_metadata").
What looks good
- The
UniqueConstraint("reference_id")+UniqueConstraint("message_id")correctly enforce the 1:1 relationship and idempotency invariants. cascade="all, delete-orphan"onComment.correspondence_metadatais correctly set and tested.- The deletion guard in
Comment.delete()and the filter indelete_comments_for_reference_and_type()are both correct and have good test coverage. - The
CORRESPONDENCE_COMMENT_TYPESfrozenset is a clean way to centralise the type guard. - Dataset YAML and changelog are both present.
🔬 Codegraph: connected (46297 nodes)
💡 Write /code-review in a comment to re-run this review.
…atus enum Import CorrespondenceDeliveryStatus from comment.py instead of redefining it in correspondence_metadata.py, avoiding two separate incompatible enum classes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ticket ENG-3299
Description Of Changes
PR 2 of 2 for ENG-3299. Creates the
CorrespondenceMetadatatable with a 1:1 relationship toCommentfor delivery tracking and email threading.Table fields:
comment_id— FK tocomment.id, UNIQUE (1:1), CASCADE deletemessage_id— UNIQUE, indexed (idempotency key for deduplication)in_reply_to— threading reference to parent messagereply_to_address— indexed for inbound routingdelivery_status— varchar with defaultpending(values: pending/sent/delivered/bounced/failed)delivered_at,bounce_reason,sender_email,recipient_emailDesign decision:
delivery_statususes varchar (not a PG enum) to avoid cross-migration enum type dependencies. Validation happens at the Python model layer viaCorrespondenceDeliveryStatusenum.Code Changes
src/fides/api/models/comment.py— AddedCorrespondenceMetadatamodel with 1:1 relationship toCommentsrc/fides/api/db/base.py— RegisteredCorrespondenceMetadatafor Alembic discoverycorrespondence_metadatatable with indexes and constraintsSteps to Confirm
alembic upgrade head— verify table createdalembic downgrade -1thenalembic upgrade head— verify full cycle\d correspondence_metadatashows all columns, UNIQUE oncomment_idandmessage_id, FK tocomment.idwith CASCADEpytest tests/ctl/models/test_comment.py— all passPre-Merge Checklist
CHANGELOG.mdupdatedmaindowngrade()migration is correct and works