Conversation
…ging Signed-off-by: Uroš Marolt <uros@marolt.me>
There was a problem hiding this comment.
Pull request overview
This PR addresses edge cases in the data sink member-merge flow (especially “two-way” no-merge relationships) and improves observability by attaching more specific error metadata for identity-merge conflicts, which is then used for better error grouping in the cron reporting job.
Changes:
- Fix no-merge detection to handle bidirectional (A↔B) no-merge rows without throwing.
- Enhance verified-identity conflict handling by treating “identity already belongs to this member” as a no-op and by setting more explicit
metadata.errorMessagevalues when merges are blocked or fail. - Update integration error reporting to group errors by
error.metadata.errorMessagewhen present.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| services/apps/data_sink_worker/src/service/member.service.ts | Adjusts no-merge detection to avoid exceptions when multiple matching rows exist (two-way no-merge). |
| services/apps/data_sink_worker/src/service/activity.service.ts | Adds special-case handling for stale prefetch identity conflicts and enriches metadata error messaging around merge attempts. |
| services/apps/cron_service/src/jobs/integrationResultsReporting.job.ts | Groups error breakdown by error.metadata.errorMessage for more actionable aggregation in Slack reports. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Uroš Marolt <uros@marolt.me>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Uroš Marolt <uros@marolt.me>
Signed-off-by: Uroš Marolt <uros@marolt.me>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Uroš Marolt <uros@marolt.me>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…tic identity Signed-off-by: Uroš Marolt <uros@marolt.me>
Signed-off-by: Uroš Marolt <uros@marolt.me>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Uroš Marolt <uros@marolt.me>
Signed-off-by: Uroš Marolt <uros@marolt.me>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
services/libs/data-access-layer/src/members/identities.ts:596
findMembersByIdentitiescan generate invalid SQL when called with default args (nomemberIdToIgnoreandonlyVerified=false):conditionsstays empty, so the query becomesWHEREwith nothing after it. Consider either adding a guard that pushes aTRUEcondition whenconditions.length === 0, or conditionally omitting the WHERE clause.
on mi.platform = i.platform
and lower(mi.value) = lower(i.value)
and mi.type = i.type
and mi."deletedAt" is null
where ${conditions.join(' and ')}
`,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Uroš Marolt <uros@marolt.me>
Signed-off-by: Uroš Marolt <uros@marolt.me>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
services/libs/data-access-layer/src/members/identities.ts:597
findMembersByIdentitiescan generate invalid SQL whenconditionsis empty (nomemberIdToIgnoreandonlyVerified=false): it will renderwherewith nothing after it. Also, ifidentitiesis empty,values ${identityParams}becomesvalueswhich is invalid. Consider early-returning an empty Map whenidentities.length === 0and only adding theWHEREclause when there are conditions (or usewhere true).
export async function findMembersByIdentities(
qx: QueryExecutor,
identities: IMemberIdentity[],
memberIdToIgnore?: string,
onlyVerified = false,
): Promise<Map<string, string>> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const params: any = {}
const conditions: string[] = []
if (memberIdToIgnore) {
conditions.push('mi."memberId" <> $(memberIdToIgnore)')
params.memberIdToIgnore = memberIdToIgnore
}
if (onlyVerified) {
conditions.push('mi.verified = true')
}
const identityTuples = identities.map((identity, i) => {
params[`ip${i}`] = identity.platform
params[`iv${i}`] = identity.value.trim()
params[`it${i}`] = identity.type
return `($(ip${i}), $(iv${i}), $(it${i}))`
})
const identityParams = identityTuples.join(', ')
const result = await qx.select(
`
with input_identities (platform, value, type) as (
values ${identityParams}
)
select "memberId", i.platform, i.value, i.type
from "memberIdentities" mi
inner join input_identities i
on mi.platform = i.platform
and lower(mi.value) = lower(i.value)
and mi.type = i.type
and mi."deletedAt" is null
where ${conditions.join(' and ')}
`,
params,
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 69748ed. Configure here.
Signed-off-by: Uroš Marolt <uros@marolt.me>

Note
Medium Risk
Touches member identity insertion/merge paths and activity processing redirect behavior, which can affect deduplication and data integrity for members. Changes are scoped but involve constraint/merge edge cases and new redirect loops that could mis-route identities if flawed.
Overview
Improves how the data sink worker handles verified identity conflicts by introducing redirect-aware identity insertion and post-merge identity syncing, and by treating stale-prefetch conflicts as no-op successes.
MemberService.create/updatecan now return a redirect memberId after auto-merge, andActivityServicecaches these redirects across the batch (and skips redundant updates, including the actor==objectActor case) to avoid updating already-absorbed rows.Error metadata for identity conflicts is made more robust (no Postgres
detailparsing), includes explicitmetadata.errorMessagevalues for merge/no-merge outcomes, and the cron Slack report now groups errors usingerror.metadata.errorMessagewhen present.findMembersByIdentitiesnow parameterizes theVALUEStuples instead of string-interpolating identity values, improving correctness and safety.Reviewed by Cursor Bugbot for commit e5b9112. Bugbot is set up for automated code reviews on this repo. Configure here.