Skip to content

feat: onboard a new non-LF organization as one project with every repository in one call (lfx-cdp-insights-ops#817) - #5030

Merged
ulemons merged 6 commits into
mainfrom
feat/issue-817-organization-single-project
Oct 20, 2026
Merged

ulemons merged 6 commits into
mainfrom
feat/issue-817-organization-single-project

Conversation

@ulemons

@ulemons ulemons commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

First half of the last #817 step (after #5015, #5026 and #5027). Today a GitHub organization that resolves to a new non-LF project goes to the CDP team as a by-hand card, because approving it would have created one project per repository. This PR adds the onboarding side: one project, every repository, one integration call. Nothing changes for users yet; the next PR replaces the by-hand card with one evaluation per organization and an Approve button that lands here.

What changes

One project for the organization. onboardOrganizationProject resolves one segment for the whole list and connects every repository through the existing connectReposToSegment path (one github-nango-connect call, existing repositories sent back on their segments). The project name is the requested one, otherwise derived from the owner (ai-dynamo → Ai Dynamo); when that name already belongs to another connected project the fallback is Name (github.com/owner), each candidate with its own slug so the fallback cannot collide on the first candidate's slug.

Retries land on the same project. resolveProjectSegment now takes the list of requested repositories: a segment left by a failed earlier attempt, connected to some of them, is reused instead of raising the "already used by a project with a GitHub integration" error. Single-repository behaviour is unchanged (list of one).

Worker. groupOnboardingUnits groups the create_segment rows of an organization like the update_integration / create_integration ones; runOrganizationProposedAction sends such a group to onboardOrganizationProject and still refuses a mixed group.

Fork lookups. fetchGithubOrgsSettings ran one GitHub request per repository at once; they now go through mapWithConcurrency (new in @crowd/common, five at a time, stops scheduling after the first failure).

Out of scope (next PR)

  • Remove the by-hand routing in classifyAndRoute and evaluate a new non-LF organization once, sharing the verdict with the sibling rows.
  • Organization review reason that shows the name the project would get.

Tests

  • onboardOrganizationProject: new project, owner-derived name, retry on an existing segment, fallback name, empty / non-GitHub list, missing configuration.
  • resolveProjectSegment with a subset of the requested repositories already connected.
  • runOrganizationProposedAction creation group, groupOnboardingUnits with create_segment rows.
  • mapWithConcurrency: order, peak concurrency, failure propagation.

Refs linuxfoundation/lfx-cdp-insights-ops#817

🤖 Generated with Claude Code

…ository in one call

- onboardOrganizationProject creates one segment (requested name, else the
  owner's; "Name (github.com/owner)" when the name belongs to another
  project, each candidate with its own slug) and connects every repository
  with one integration call
- resolveProjectSegment reuses a segment left by a failed attempt when its
  repositories are among the requested ones
- the onboarding worker groups the create_segment rows of an organization
  into one unit; mixed groups stay refused
- GitHub fork lookups run at most five at a time through mapWithConcurrency
  in @crowd/common

Refs linuxfoundation/lfx-cdp-insights-ops#817

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI balanced review requested due to automatic review settings October 19, 2026 17:31
@ulemons ulemons self-assigned this Oct 19, 2026
@cursor

cursor Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes core onboarding, segment resolution, and integration wiring with new locking; mistakes could create duplicate projects or corrupt repo-to-segment mappings, though behavior is heavily tested.

Overview
Adds organization-wide onboarding for new non-LF projects: repos with create_segment in the same GitHub org are grouped and handled by onboardOrganizationProject, which resolves one segment, names it from the request or owner (with owner-qualified fallback), and connects all repos in a single integration call instead of one project per repo.

resolveProjectSegment now works over multiple repo URLs (and optional org owner) so retries reuse a segment already tied to some of those repos or other repos from the same owner. The automatic onboarding worker groups create_segment org rows like join-existing flows, routes homogeneous groups through the new onboarder, and still rejects mixed proposed actions.

Concurrency and races: new mapWithConcurrency caps parallel GitHub fork lookups; lockProjectCatalogOnboardingTarget accepts arbitrary lock keys (including organization:<owner>), with claims for new-org creation taken under that lock in one transaction so parallel runs cannot split one org across multiple projects.

Reviewed by Cursor Bugbot for commit 248a712. Bugbot is set up for automated code reviews on this repo. Configure here.

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

Concurrent claims can split organizations across projects, while singleton routing and slug collisions can prevent the intended project creation.

3 open issues
What changed in this PR

Adds the onboarding foundation for creating one non-LF project per GitHub organization, extending the existing grouped integration flow. User-facing approval remains deferred.

Changes:

  • Adds organization-wide project creation, naming fallback, and partial-retry reuse.
  • Routes grouped create_segment rows through the new onboarding path.
  • Adds bounded fork lookups and focused tests.
File Description
services/​libs/​project-onboarding/​src/​types.ts Defines organization onboarding input.
services/​libs/​project-onboarding/​src/​organizationGrouping.ts Recognizes organization creation actions.
services/​libs/​project-onboarding/​src/​organizationGroup.ts Exports grouping helpers.
services/​libs/​project-onboarding/​src/​onboarder.ts Adds organization creation and bounded lookups.
services/​libs/​project-onboarding/​src/​onboarder.test.ts Tests creation, naming, retries, and validation.
services/​libs/​common/​src/​index.ts Exports concurrency helper.
services/​libs/​common/​src/​concurrency.ts Implements bounded asynchronous mapping.
services/​libs/​common/​src/​concurrency.test.ts Tests ordering, concurrency, and failures.
services/​apps/​automatic_onboarding_worker/​src/​onboardingUnits.ts Groups organization creation rows.
services/​apps/​automatic_onboarding_worker/​src/​onboardingUnits.test.ts Tests creation grouping.
services/​apps/​automatic_onboarding_worker/​src/​activities/​proposedAction.ts Dispatches organization creation actions.
services/​apps/​automatic_onboarding_worker/​src/​activities/​proposedAction.test.ts Tests dispatch and mixed-group rejection.
services/​apps/​automatic_onboarding_worker/​src/​activities/​activities.ts Wires organization onboarding dependency.

Review effort: Balanced

Comment on lines +116 to +118
if (projects.every(createsNewProject)) {
const [lead] = projects
return deps.onboardOrganizationProject({
Comment thread services/apps/automatic_onboarding_worker/src/onboardingUnits.ts
Comment on lines +314 to +316
return deriveOrganizationProjectNameCandidates(owner, projectName).map((name) => ({
name,
slug: deriveProjectSlug(name),
…repo creation unit whole

- a creation group whose rows were claimed in part by another run releases
  its claims instead of creating a second project for the rest
- an organization with one repository still goes through
  onboardOrganizationProject, so the requested name is used

Refs linuxfoundation/lfx-cdp-insights-ops#817

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI balanced review requested due to automatic review settings October 20, 2026 07:24

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

Claim races can split an organization across projects, and fork lookups can exceed the configured concurrency limit.

3 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity First fork lookup bypasses shared concurrency limiter

services/​libs/​project-onboarding/​src/​onboarder.ts:473

The first repository's fork lookup runs outside the limiter through fetchGithubOrgSettings, so an organization with at least six repositories can issue six concurrent fork requests despite the limit of five. Each owner also gets a separate pool, multiplying concurrency for multi-owner inputs. Run all repositories' fork lookups through one shared mapper, then group the results and fetch each owner's logo.

1 resolved since last review

Review effort: Balanced

Comment thread services/apps/automatic_onboarding_worker/src/activities/activities.ts Outdated
…ing group

A run reads the organization without the rows another run holds at that moment, so a
creation group is re-read and claimed under an advisory lock on the organization; the
lock helper takes any target, not only a PCC project id.

Refs linuxfoundation/lfx-cdp-insights-ops#817

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI balanced review requested due to automatic review settings October 20, 2026 07:35

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread services/apps/automatic_onboarding_worker/src/activities/activities.ts Outdated
Comment thread services/apps/automatic_onboarding_worker/src/activities/activities.ts Outdated

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

Workflow replay compatibility, expanded-group failure handling, and the shared fork-lookup limit need correction.

3 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Version grouping changes with a Temporal patch for workflow determinism

services/​apps/​automatic_onboarding_worker/​src/​onboardingUnits.ts:18

Version this grouping change with a new Temporal patch. A lone organization row with create_segment previously scheduled onboardAndUpdateProject; it now schedules skipRowsOfDeletedProjects and onboardAndUpdateOrganization. Such rows can already reach onboarding because the manual-routing guard in classifyAndRoute.ts:74 excludes single-repository organizations. Replaying an existing workflow that scheduled the old activity can therefore fail with nondeterminism. The existing issue-817-organization-onboarding marker in workflows/onboardProjects.ts:71 covers both implementations; preserve the previous grouping for histories without a new marker.

Medium severity Enforce one concurrency limit for all repository fork lookups

services/​libs/​project-onboarding/​src/​onboarder.ts:473

The first repository's fork lookup runs outside mapWithConcurrency, so an organization with six or more repositories can start six fork requests despite the limit of five. Each owner also gets a separate pool, so multi-owner inputs have no shared limit. Run every repository's fork lookup through one bounded map, then group the results by owner.

1 resolved since last review

Review effort: Balanced

Comment thread services/apps/automatic_onboarding_worker/src/activities/activities.ts Outdated
… that already holds it

- the claims of a creation group are taken under the organization lock in one
  transaction, before any external call, so no transaction spans GitHub or
  backend requests
- a candidate project already connected to repositories of the same owner is
  that organization's project: a row left behind by a dead claim or a failed
  attempt joins it instead of creating a second one

Refs linuxfoundation/lfx-cdp-insights-ops#817

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI balanced review requested due to automatic review settings October 20, 2026 07:47

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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 f0a970d. Configure here.

Comment thread services/libs/project-onboarding/src/onboarder.ts
…ation's

Refs linuxfoundation/lfx-cdp-insights-ops#817

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>

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

Shared-target updates can lose repositories, existing workflow histories can fail replay, and fork lookups exceed the configured concurrency limit.

4 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Version organization grouping changes with a Temporal patch marker

services/​apps/​automatic_onboarding_worker/​src/​onboardingUnits.ts:36

Replaying a history that onboarded a lone organization create_segment row now schedules skipRowsOfDeletedProjects instead of the recorded onboardAndUpdateProject. Such rows are already possible: newOrganizationProjectByHand leaves single-repository organizations unchanged. The existing issue-817-organization-onboarding patch marker predates this grouping change, so it does not protect those histories from a replay mismatch. Gate the new grouping with a fresh Temporal patch marker and preserve the previous grouping for old histories.

Medium severity Route all fork lookups through the shared limiter

services/​libs/​project-onboarding/​src/​onboarder.ts:482

The first repository's fork lookup runs inside fetchGithubOrgSettings, outside the limiter. An organization with at least six repositories can therefore run six fork requests at once despite the configured limit of five. Separate pools per owner multiply the limit for multi-owner inputs. Route all fork lookups, including the first repository, through one shared pool before assembling the organization settings.

Review effort: Balanced

Comment on lines +314 to +317
return qx.tx(async (tx) => {
await lockProjectCatalogOnboardingTarget(tx, organizationKey)
return claimOrganizationRows(tx, projects, outcome)
})
Copilot AI balanced review requested due to automatic review settings October 20, 2026 07:55
…ganization

Two requests for one organization join the same project and the backend replaces the
integration's repository list on every connect, so their resolution and connect run under
one lock keyed by the organization, like the PCC project lock for existing projects.

Refs linuxfoundation/lfx-cdp-insights-ops#817

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>

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.

🔵 Needs a closer look

Changed workflow grouping needs a new Temporal patch marker to preserve replay compatibility.

3 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Organization creation grouping causes Temporal replay nondeterminism

services/​apps/​automatic_onboarding_worker/​src/​onboardingUnits.ts:18

This changes the activity sequence for existing Temporal histories containing organization create_segment rows. workflows/onboardProjects.ts:71–73 calls this helper under the existing issue-817-organization-onboarding patch: those rows previously scheduled onboardAndUpdateProject, but now schedule skipRowsOfDeletedProjects and onboardAndUpdateOrganization, even for a single row. Replaying such a history after deployment can fail with nondeterminism. Add a new workflow patch marker for creation-group handling and preserve the previous grouping when that marker is absent from a replayed history.

1 resolved since last review

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 20, 2026 08:01
@ulemons
ulemons merged commit c301c3e into main Oct 20, 2026
14 checks passed
@ulemons
ulemons deleted the feat/issue-817-organization-single-project branch October 20, 2026 08:07

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.

🔵 Needs a closer look

Owner-based locking does not prevent different organizations requesting the same name from concurrently adopting one project.

3 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Prevent cross-organization segment reuse during concurrent resolution

services/​apps/​automatic_onboarding_worker/​src/​activities/​proposedAction.ts:141

Different organizations requesting the same project name take different owner locks but can still resolve to the same segment. If one run creates Acme and has not connected its integration yet, another organization's run can reuse that segment because resolveProjectSegment accepts segments with no GitHub integration. Both groups can then connect to one project instead of the second using its owner-qualified fallback, and their integration writes are not serialized. Serialize shared candidate-name resolution through connection, or lock the resolved segment and revalidate ownership before connecting.

Medium severity Include initial repository lookup in the concurrency limiter

services/​libs/​project-onboarding/​src/​onboarder.ts:482

For an organization with at least six repositories, this can start six fork lookups concurrently: five through the limiter and one inside fetchGithubOrgSettings(first, ...). The first repository therefore bypasses the configured five-lookup cap. Include all of the organization's repositories in the limiter and fetch its logo separately.

Review effort: Balanced

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