Removed control and data plane from code logic - #20
Conversation
|
Warning Review limit reached
Next review available in: 29 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (6)
Note
|
| Layer / File(s) | Summary |
|---|---|
Typed domain and repository contracts libs/domain/src/domain/models.py, services/api/src/api/domain/models.py, services/api/src/api/ports/*, services/api/src/api/adapters/* |
Adds typed partner statuses, route directions, route-list entities, and API token list results. |
Dedicated UnitOfWork wiring services/api/src/api/core/uow.py, services/api/src/api/dependencies.py, services/api/src/api/core/services/__init__.py |
Replaces aggregate control/data-plane wiring with feature-specific repositories and optional tenant transactions. |
Direction-specific route services services/api/src/api/core/services/*route_service.py, services/api/src/api/routers/routes.py |
Separates inbound and outbound route CRUD and listing, including destination resolution and typed results. |
Partner and webhook repository migration services/api/src/api/core/services/*partner_service.py, services/api/src/api/core/services/webhook_service.py, services/api/src/api/routers/trading_partners/*, services/api/src/api/routers/webhooks/* |
Routes partner, webhook, partnership, and EDI header operations through dedicated repositories and the outbox publisher. |
Token and transaction persistence services/api/src/api/core/services/api_token_service.py, services/api/src/api/services/*receiver_service.py, services/api/src/api/routers/{transactions,explorer}.py |
Adds token cache invalidation and moves transaction and receiver persistence to transaction and outbox repositories. |
Backend fake stores and validation services/api/tests/* |
Updates fakes, fixtures, and tests for the dedicated repository and UnitOfWork structure. |
Certificate editor workflow
| Layer / File(s) | Summary |
|---|---|
Editor capabilities and certificate input frontend/web/src/components/ui/edi-editor-pane.tsx, frontend/web/src/features/partners/components/CertificateInput.tsx, frontend/web/package.json |
Adds configurable Monaco behavior, direct drag-and-drop listeners, certificate detection, empty-state actions, and the Radix switch dependency. |
Partner certificate UI frontend/web/src/components/ui/switch.tsx, frontend/web/src/features/partners/components/{As2PartnerDetails,CreatePartnerModal,PartnershipDetails}.tsx |
Updates certificate creation and rotation dialogs, local/remote switching, and certificate generation actions. |
Estimated code review effort: 5 (Critical) | ~120 minutes
Sequence Diagram(s)
sequenceDiagram
participant Router
participant RouteService
participant UnitOfWork
participant Repository
participant Outbox
Router->>RouteService: create or list route
RouteService->>UnitOfWork: access direction-specific repository
UnitOfWork->>Repository: persist or load route
RouteService->>Outbox: publish provisioning event
RouteService-->>Router: return typed route result
Possibly related PRs
- pramodnarayana/soopaedi#5: Overlaps with route-service and routing API changes.
- pramodnarayana/soopaedi#9: Overlaps with certificate input and partner form changes.
- pramodnarayana/soopaedi#11: Covers related control-plane and data-plane decoupling.
Poem
A rabbit hops through routes anew,
With typed-up tokens in its view.
Certificates sparkle, switches gleam,
Outboxes carry every stream.
Dedicated stores now guide the way—
Hop, hop, and ship the change today!
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 25.31% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title accurately captures the main refactor away from control/data plane logic toward direct repository usage. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
refactor-control-data-plane
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
There was a problem hiding this comment.
Actionable comments posted: 12
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/web/src/components/ui/edi-editor-pane.tsx`:
- Around line 125-133: Update the certificate-detected condition in the EDI
editor status bar so it only displays for a valid certificate PEM block: require
matching BEGIN/END certificate markers and reject private-key or other PEM block
types. Preserve the existing error, value, and showCertDetected guards.
- Around line 80-98: Update the onDrop handler inside handleEditorMount to call
e.stopPropagation() after preventing the default event, ensuring Monaco drops do
not reach the wrapper onDrop handler and applyFile runs only once.
In `@frontend/web/src/features/partners/components/As2PartnerDetails.tsx`:
- Around line 234-243: The certificate-generation dialog remains open after a
successful mutation, allowing repeated rotations. Update the rotateCertificates
mutation’s onSuccess callback used by handleGenerateCertificate to close the
dialog and reset its associated form or state, while preserving the existing
pending-state behavior.
In `@frontend/web/src/features/partners/components/CertificateInput.tsx`:
- Around line 22-26: Remove the duplicate showEmptyState prop from the JSX
component props in CertificateInput, leaving a single showEmptyState={false}
attribute while preserving the surrounding extraActions, fontSize, and
showCertDetected props.
In `@frontend/web/src/features/partners/components/CreatePartnerModal.tsx`:
- Around line 159-177: Update the Public Certificate section in
CreatePartnerModal so local partners are not shown a CertificateInput whose
value is discarded by the save payload. For isLocal, replace the editor with
generation-only UI; otherwise preserve the existing certificate input and value
handling for non-local partners.
In `@services/api/src/api/core/services/inbound_route_service.py`:
- Line 62: The route services currently query aggregate routes, causing
duplicate queries and model materialization. In
services/api/src/api/core/services/inbound_route_service.py lines 62-62, update
the inbound service to use uow.inbound_routes; in
services/api/src/api/core/services/outbound_route_service.py lines 68-68, add or
use an outbound-only listing operation; and in
services/api/src/api/routers/routes.py lines 44-45, retain composition of the
two direction-specific service results without adding another query.
In `@services/api/src/api/core/services/sftp_partner_service.py`:
- Around line 71-77: In the update flow containing update_hash and
publish_outbox_event, replace Python’s process-randomized hash(str(cmd)) with a
deterministic hashlib.sha256 digest of the same command representation. Keep the
resulting stable hash in the SFTP_PARTNER_UPDATED idempotency_key generation and
add the required hashlib import.
In `@services/api/src/api/core/uow.py`:
- Line 49: Replace the direct nullable assignment to transactions in the
unit-of-work class with a typed property that returns the repository when a
tenant session exists and raises a descriptive error otherwise. Update
initialization and consumers such as explore_edi_json and list_transactions to
use this property without type ignores, preserving existing repository behavior
for valid sessions.
In `@services/api/src/api/routers/developers/api_tokens.py`:
- Line 70: Update the ApiTokenListItem.model_validate call in the token list
response construction to enable object-based validation with
from_attributes=True, so ApiTokenListEntity instances convert successfully while
preserving the existing response structure.
In `@services/api/src/api/routers/trading_partners/__init__.py`:
- Around line 35-41: The tenant SFTP partner retrieval in the trading-partners
endpoint is incorrectly gated by uow.global_session. Move the sftp_partners
lookup outside the global-session conditional so tenant-specific SFTP partners
are always fetched, while keeping global AS2 partner retrieval conditional on
the optional session.
In `@services/api/src/api/routers/webhooks/__init__.py`:
- Around line 67-68: Replace the double-negative global-session checks with
direct None checks so each endpoint uses `if uow.global_session is None:`. Apply
this in services/api/src/api/routers/webhooks/__init__.py at lines 67-68, 83-84,
96-97, 116-117, 132-133, and 148-149;
services/api/src/api/routers/trading_partners/sftp.py at lines 163-164 and
205-206; and services/api/src/api/routers/webhooks/webhook.py at lines 58-59,
without changing the existing error handling.
In `@services/api/src/api/routers/webhooks/webhook.py`:
- Around line 58-60: Remove the duplicate create_webhook implementation from the
webhook router module, retaining a single authoritative endpoint definition in
services/api/src/api/routers/webhooks/__init__.py. Ensure router registration
and imports continue to reference the consolidated implementation, including the
shared _validate_webhook_url logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 052b32b5-c80b-4e28-95f2-6a4d1205b33a
⛔ Files ignored due to path filters (1)
frontend/web/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (53)
frontend/web/package.jsonfrontend/web/src/components/ui/edi-editor-pane.tsxfrontend/web/src/components/ui/switch.tsxfrontend/web/src/features/partners/components/As2PartnerDetails.tsxfrontend/web/src/features/partners/components/CertificateInput.tsxfrontend/web/src/features/partners/components/CreatePartnerModal.tsxfrontend/web/src/features/partners/components/PartnershipDetails.tsxlibs/domain/src/domain/models.pyservices/api/src/api/adapters/api_token_repository.pyservices/api/src/api/adapters/outbound_route_repository.pyservices/api/src/api/adapters/repository.pyservices/api/src/api/core/services/__init__.pyservices/api/src/api/core/services/api_token_service.pyservices/api/src/api/core/services/as2_partner_service.pyservices/api/src/api/core/services/as2_partnership_service.pyservices/api/src/api/core/services/edi_header_service.pyservices/api/src/api/core/services/inbound_route_service.pyservices/api/src/api/core/services/outbound_route_service.pyservices/api/src/api/core/services/route_service.pyservices/api/src/api/core/services/sftp_partner_service.pyservices/api/src/api/core/services/webhook_service.pyservices/api/src/api/core/uow.pyservices/api/src/api/dependencies.pyservices/api/src/api/domain/models.pyservices/api/src/api/ports/api_token_repository.pyservices/api/src/api/ports/control_plane_aggregator.pyservices/api/src/api/ports/repository.pyservices/api/src/api/routers/developers/api_tokens.pyservices/api/src/api/routers/explorer.pyservices/api/src/api/routers/routes.pyservices/api/src/api/routers/trading_partners/__init__.pyservices/api/src/api/routers/trading_partners/as2.pyservices/api/src/api/routers/trading_partners/platform/as2_partners.pyservices/api/src/api/routers/trading_partners/platform/as2_partnerships.pyservices/api/src/api/routers/trading_partners/sftp.pyservices/api/src/api/routers/transactions.pyservices/api/src/api/routers/webhooks/__init__.pyservices/api/src/api/routers/webhooks/webhook.pyservices/api/src/api/services/api_receiver_service.pyservices/api/src/api/services/as2_receiver_service.pyservices/api/tests/api_fakes.pyservices/api/tests/test_api_receiver_service.pyservices/api/tests/test_as2_partner_service.pyservices/api/tests/test_as2_receive.pyservices/api/tests/test_as2_receiver_service.pyservices/api/tests/test_platform_as2.pyservices/api/tests/test_provisioning_core.pyservices/api/tests/test_routers_as2.pyservices/api/tests/test_routers_explorer.pyservices/api/tests/test_routers_partners.pyservices/api/tests/test_routers_transactions.pyservices/api/tests/test_uow.pyservices/api/tests/test_webhooks.py
💤 Files with no reviewable changes (5)
- services/api/src/api/ports/repository.py
- services/api/src/api/ports/control_plane_aggregator.py
- services/api/src/api/adapters/repository.py
- services/api/src/api/core/services/route_service.py
- services/api/src/api/dependencies.py
| showEmptyState={false} | ||
| extraActions={extraActions} | ||
| fontSize={14} | ||
| showCertDetected | ||
| showEmptyState={false} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
file="$(fd -a '^CertificateInput\.tsx$' | head -n 1)"
rg -n 'showEmptyState=' "$file"Repository: pramodnarayana/soopaedi
Length of output: 229
Remove the duplicate showEmptyState prop. This JSX repeats the same attribute twice, which causes a TypeScript compile error.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/web/src/features/partners/components/CertificateInput.tsx` around
lines 22 - 26, Remove the duplicate showEmptyState prop from the JSX component
props in CertificateInput, leaving a single showEmptyState={false} attribute
while preserving the surrounding extraActions, fontSize, and showCertDetected
props.
| if not uow.global_session is not None: | ||
| raise HTTPException(status_code=500, detail="Control plane not initialized") | ||
| partner = await uow.control_plane.get_webhook(tenant_id, _.partner_id) | ||
| partner = await uow.webhooks.get_webhook(tenant_id, _.partner_id) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Duplicate webhook creation logic.
This create_webhook endpoint implementation appears to be an exact duplicate of the one defined in services/api/src/api/routers/webhooks/__init__.py, with the only difference being that the URL validation logic is inline here rather than extracted to _validate_webhook_url. Consider removing this file or consolidating to avoid maintaining duplicated router endpoints.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@services/api/src/api/routers/webhooks/webhook.py` around lines 58 - 60,
Remove the duplicate create_webhook implementation from the webhook router
module, retaining a single authoritative endpoint definition in
services/api/src/api/routers/webhooks/__init__.py. Ensure router registration
and imports continue to reference the consolidated implementation, including the
shared _validate_webhook_url logic.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
services/api/tests/api_fakes.py (1)
61-64: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winFake update operations report success without persisting changes.
services/api/tests/api_fakes.py#L61-L64: applyUpdateSFTPPartnerCmdto the matching tenant-scoped record and return failure when absent.services/api/tests/api_fakes.py#L80-L83: implementUpdateAS2PartnershipCmdinstead of usingpass.services/api/tests/api_fakes.py#L209-L217: apply webhook patches and returnFalsefor unknown webhooks.Otherwise, tests can pass while production update flows leave stale data.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@services/api/tests/api_fakes.py` around lines 61 - 64, Update services/api/tests/api_fakes.py at lines 61-64 in update_sftp_partner to find the tenant-scoped partner, apply UpdateSFTPPartnerCmd, and return False when absent; implement the missing UpdateAS2PartnershipCmd handling at lines 80-83 with the same matching and failure behavior; update webhook handling at lines 209-217 to apply patches to the matching webhook and return False for unknown webhooks.frontend/web/src/components/ui/edi-editor-pane.tsx (1)
136-142: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winPrevent drag-and-drop flickering by disabling pointer events on the overlay.
When the drag-over overlay renders, it covers the Monaco editor. This causes the browser to fire a
dragleaveevent on the editor, which immediately hides the overlay and creates a rapid, unusable flickering loop.Adding
pointer-events-noneallows the drag events to pass through cleanly to the Monaco editor beneath it, maintaining a stable drag state while allowing Monaco's nativedrophandler to successfully receive the file.🐛 Proposed fix
{/* Drag-over full-screen overlay */} {isDragging && ( - <div className="absolute inset-0 bg-indigo-50/90 z-20 flex flex-col items-center justify-center border-2 border-indigo-400 border-dashed m-2 rounded-lg backdrop-blur-sm transition-all duration-200"> + <div className="absolute inset-0 bg-indigo-50/90 z-20 flex flex-col items-center justify-center border-2 border-indigo-400 border-dashed m-2 rounded-lg backdrop-blur-sm transition-all duration-200 pointer-events-none"> <UploadCloud className="w-10 h-10 text-indigo-500 mb-3 animate-bounce" /> <span className="text-indigo-700 font-semibold text-lg tracking-tight">Drop file to load</span> </div> )}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/web/src/components/ui/edi-editor-pane.tsx` around lines 136 - 142, Update the drag-over overlay rendered by the isDragging condition in EdiEditorPane to include the Tailwind pointer-events-none utility, allowing drag events and Monaco’s native drop handler to pass through without triggering flickering.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@services/api/src/api/core/services/inbound_route_service.py`:
- Around line 59-64: Move InboundRouteDomainModel and OutboundRouteDomainModel
imports to module scope; in
services/api/src/api/core/services/inbound_route_service.py lines 59-64 and
services/api/src/api/core/services/outbound_route_service.py lines 65-70, remove
redundant local annotations from the list assignments. Update
inbound_route_service.py lines 96-105 to type _resolve_destination’s r as
InboundRouteDomainModel and access r.webhook_id directly; update
outbound_route_service.py lines 94-101 to type r as OutboundRouteDomainModel.
In `@services/api/src/api/routers/trading_partners/sftp.py`:
- Around line 163-164: Update the post-creation, post-update, and deletion
data-plane checks in services/api/src/api/routers/trading_partners/sftp.py at
lines 163-164, 205-206, and 236-237 to validate uow.tenant_session instead of
uow.global_session, preserving the existing HTTPException behavior.
In `@services/api/tests/api_fakes.py`:
- Around line 264-268: Update list_inbound_routes and list_outbound_routes to
return only routes matching the provided tenant_id, and ensure the fake
route-creation flow stores tenant_id on each created route. Preserve the
existing empty-list fallback when no routes are stored.
---
Outside diff comments:
In `@frontend/web/src/components/ui/edi-editor-pane.tsx`:
- Around line 136-142: Update the drag-over overlay rendered by the isDragging
condition in EdiEditorPane to include the Tailwind pointer-events-none utility,
allowing drag events and Monaco’s native drop handler to pass through without
triggering flickering.
In `@services/api/tests/api_fakes.py`:
- Around line 61-64: Update services/api/tests/api_fakes.py at lines 61-64 in
update_sftp_partner to find the tenant-scoped partner, apply
UpdateSFTPPartnerCmd, and return False when absent; implement the missing
UpdateAS2PartnershipCmd handling at lines 80-83 with the same matching and
failure behavior; update webhook handling at lines 209-217 to apply patches to
the matching webhook and return False for unknown webhooks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 32d178c1-58fe-4c2b-9523-cb9f096fe830
📒 Files selected for processing (22)
frontend/web/src/components/ui/edi-editor-pane.tsxfrontend/web/src/features/partners/components/As2PartnerDetails.tsxfrontend/web/src/features/partners/components/CertificateInput.tsxfrontend/web/src/features/partners/components/CreatePartnerModal.tsxservices/api/src/api/adapters/inbound_route_repository.pyservices/api/src/api/adapters/outbound_route_repository.pyservices/api/src/api/core/services/inbound_route_service.pyservices/api/src/api/core/services/outbound_route_service.pyservices/api/src/api/core/services/sftp_partner_service.pyservices/api/src/api/core/uow.pyservices/api/src/api/ports/inbound_route_repository.pyservices/api/src/api/ports/outbound_route_repository.pyservices/api/src/api/routers/developers/api_tokens.pyservices/api/src/api/routers/explorer.pyservices/api/src/api/routers/trading_partners/__init__.pyservices/api/src/api/routers/trading_partners/sftp.pyservices/api/src/api/routers/transactions.pyservices/api/src/api/routers/webhooks/__init__.pyservices/api/src/api/routers/webhooks/webhook.pyservices/api/src/api/services/api_receiver_service.pyservices/api/tests/api_fakes.pyservices/api/tests/test_routers_transactions.py
💤 Files with no reviewable changes (2)
- services/api/src/api/services/api_receiver_service.py
- frontend/web/src/features/partners/components/CertificateInput.tsx
| async def list_inbound_routes(self, tenant_id: int) -> list[InboundRouteListEntity]: | ||
| from domain.models import InboundRouteDomainModel | ||
|
|
||
| inbound: list[InboundRouteDomainModel] = await self.uow.inbound_routes.list_inbound_routes( | ||
| tenant_id | ||
| ) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Move domain model imports to the module level and improve type hints.
Both service classes use inline imports for domain models, redundant variable annotations, and Any for local helper parameters. Moving the imports to the top of the file cleans up the function body and enables proper type checking for _resolve_destination.
services/api/src/api/core/services/inbound_route_service.py#L59-L64: Movefrom domain.models import InboundRouteDomainModelto the top of the file and replace the inline-annotated assignment withinbound = await self.uow.inbound_routes.list_inbound_routes(tenant_id).services/api/src/api/core/services/inbound_route_service.py#L96-L105: Replacer: Anywithr: InboundRouteDomainModeland replace defensivegetattr(r, "webhook_id", None)withr.webhook_idsince the Pydantic model guarantees the field's presence.services/api/src/api/core/services/outbound_route_service.py#L65-L70: Movefrom domain.models import OutboundRouteDomainModelto the top of the file and replace the inline-annotated assignment withoutbound = await self.uow.outbound_routes.list_outbound_routes(tenant_id).services/api/src/api/core/services/outbound_route_service.py#L94-L101: Replacer: Anywithr: OutboundRouteDomainModel.
📍 Affects 2 files
services/api/src/api/core/services/inbound_route_service.py#L59-L64(this comment)services/api/src/api/core/services/inbound_route_service.py#L96-L105services/api/src/api/core/services/outbound_route_service.py#L65-L70services/api/src/api/core/services/outbound_route_service.py#L94-L101
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@services/api/src/api/core/services/inbound_route_service.py` around lines 59
- 64, Move InboundRouteDomainModel and OutboundRouteDomainModel imports to
module scope; in services/api/src/api/core/services/inbound_route_service.py
lines 59-64 and services/api/src/api/core/services/outbound_route_service.py
lines 65-70, remove redundant local annotations from the list assignments.
Update inbound_route_service.py lines 96-105 to type _resolve_destination’s r as
InboundRouteDomainModel and access r.webhook_id directly; update
outbound_route_service.py lines 94-101 to type r as OutboundRouteDomainModel.
Summary by CodeRabbit