Skip to content

fix: refresh segment-only members when blocking orgs - #5169

Merged
skwowet merged 1 commit into
mainfrom
fix/refresh-segment-affiliated-members-on-org-block
Nov 2, 2026
Merged

skwowet merged 1 commit into
mainfrom
fix/refresh-segment-affiliated-members-on-org-block

Conversation

@skwowet

@skwowet skwowet commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Blocking an organization's affiliations soft-deletes its member segment affiliations, then relies on organizationUpdate to refresh members. That workflow only finds members through active memberOrganizations rows, so a member linked to the org solely by a segment affiliation is never refreshed and their activityRelations keep pointing at the blocked org.

This was caught by the Metaplane monitor "Organizations with blocked affiliations that still have activity relations" (Linux Kernel, one member, 1,867 stale rows). A manual memberUpdate cleared it; this PR closes the gap going forward.

Changes

  • Add deleteOrganizationSegmentAffiliations to the data access layer. It soft-deletes an org's segment affiliations and returns only members with no active memberOrganizations row for that org, since organizationUpdate already refreshes the rest. Kept separate from deleteMemberSegmentAffiliations to leave that shared function unchanged.
  • Use it in every org-level blocking path and queue a refresh for the returned members:
    • OrganizationService.update: signals memberUpdate after the transaction commits.
    • SegmentService (org auto-blocked when an LF segment with the same name is created): same, after commit. The post-commit loop that was copied across createProjectGroup, createProject and createSubproject is now one private recalculateBlockedAffiliations.
    • markOrganizationAsFake (profiles_worker): uses the existing triggerMemberAffiliationsRefresh.
    • setOrganizationAffiliationPolicyIfNotBlocked (script_executor_worker): adds the members to the Redis recalculation set the workflow already drains.

Performance

  • The new query hits ix_memberSegmentAffiliations_organizationId plus an index-only probe on memberOrganizations per row; the table is about 16k rows.
  • Only segment-only members get the extra refresh. In production today that is 135 members across 93 orgs; the three orgs with the most segment affiliations would add 4, 16 and 5 refreshes instead of 778, 923 and 463 without the filter.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Performance improvement
  • Chore / dependency update
  • Documentation

Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 14:19
@skwowet skwowet changed the title fix: refresh segment-only affiliated members on organization block fix: refresh segment-only members when blocking orgs Nov 2, 2026
@greptile-apps

greptile-apps Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 3/5

[Medium impact] The PR affects organization blocking and member refresh workflows across the backend and workers.

Fix the lost refreshes on retry and the script's skipped members before merging.

Fix All in Claude CodeFindings

  1. P1 Retries lose pending refreshes ▶
  2. P1 Some members never get refreshed ▶
Fix with agent prompt
### Issue 1
services/apps/profiles_worker/src/activities/organization/fakeAnalysis.ts:135-138
If `triggerMemberAffiliationsRefresh` fails partway through this loop, Temporal retries `markOrganizationAsFake`. But `deleteOrganizationSegmentAffiliations` now returns no members because their rows already have `deletedAt` set. The remaining members never get refreshed, so their activities can keep pointing at the blocked organization.

The Redis path has the same gap: if `markMemberForAffiliationRecalc` fails, the retry exits because the organization is already blocked. Save pending member IDs durably before deleting their affiliations, or keep them available until every refresh has been queued.

### Issue 2
services/apps/script_executor_worker/src/activities/block-project-organization-affiliations.ts:39-42
A member can have an active `memberOrganizations` row with `allowAffiliation=false` and a manual segment affiliation for the same organization. When another eligible member causes this script to block that organization, this call deletes both members' manual affiliations but excludes the already-disallowed member from its result.

`fetchProjectMemberOrganizationsToBlock` also excludes that member, so the later refresh batch misses them too. Unlike the other callers, this script never starts `organizationUpdate` to cover the gap. Their activities can keep pointing at the blocked organization. Return all affected members for this caller, or separately queue members whose existing roles are already disallowed.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR refreshes members linked to a blocked organization only through segment affiliations.

  • Blocking an organization also refreshes members linked only through segments.
  • Automatic organization blocking queues refreshes for segment-only members.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Block organization] --> B[Soft-delete segment affiliations]
  B --> C{Active member role exists?}
  C -->|No| D[Return member ID]
  D --> E[Queue member refresh]
  C -->|Yes| F[Existing organization or script refresh]
  E --> G[Update activity relations]
  F --> G
Loading

Reviews (1) · Last reviewed commit: "fix: refresh segment-only affiliated mem..." · Reviewed by Greptile

Copilot AI 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.

🟡 Changes recommended

Both activities can lose pending member refreshes after enqueue or signal failures because retries cannot recover IDs from deleted affiliations, leaving segment-only members with stale activity relations.

2 open issues
What changed in this PR

This PR closes a gap in organization affiliation blocking: members linked only through segment affiliations now receive an explicit refresh to clear stale activity relations.

Changes:

  • Add a data-access helper that soft-deletes segment affiliations and returns members not covered by organization-level refreshes.
  • Queue those members for refresh across backend and worker blocking paths.
  • Consolidate post-commit refresh logic for LF segment creation.
File Description
services/​libs/​data-access-layer/​src/​member_segment_affiliations/​index.ts Add organization-scoped deletion that returns segment-only members.
services/​apps/​script_executor_worker/​src/​activities/​block-project-organization-affiliations.ts Add returned members to the Redis recalculation set.
services/​apps/​profiles_worker/​src/​activities/​organization/​fakeAnalysis.ts Trigger member refreshes when blocking fake organizations.
backend/​src/​services/​segmentService.ts Centralize post-commit organization and member refreshes.
backend/​src/​services/​organizationService.ts Signal segment-only members after the blocking transaction commits.

Review effort: Balanced

@skwowet
skwowet merged commit b61c842 into main Nov 2, 2026
15 checks passed
@skwowet
skwowet deleted the fix/refresh-segment-affiliated-members-on-org-block branch November 2, 2026 14:27
@skwowet skwowet self-assigned this Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants