Skip to main content

Big-Little bulk operations (admin)

The chapter-level Big-Little flow (one mentee proposes, the mentor accepts) is great for normal recruitment, but it breaks down in two real scenarios:

  1. Onboarding an org with legacy data. A new tenant arrives with hundreds of historical big/little pairs in a spreadsheet. Re-creating each pairing through on-behalf-of proposals isn't feasible.
  2. Fixing misassignments. A pair was set up incorrectly, a member relocated, or a misclick stuck two members in the wrong family branch. There's no member-side affordance to undo it.

Both of those are now backed by direct admin actions, available to national and platform admins.

Reverse a Big-Little pairing

Use this when an existing pair needs to be unwound — relocation, misassignment, etc. The action clears MemberProfile.big for the chosen member.

Where to find it

Open the member detail page for the little (the one with a big set) and click the Reverse pairing action in the Big-Little card. National/platform admin only; the action is hidden for everyone else.

What it does

  • Sets the little's big to null.
  • Audit-logged with the actor, target member, prior big, and a timestamp.
  • Idempotent — calling it on a member who already has no big returns 400 with a clear message rather than silently succeeding.

What it doesn't do

  • Does not delete the big member's other relationships (their other littles stay).
  • Does not move the little's downstream littles (their family tree below them is preserved; only the link upward is cleared).
  • Does not notify the affected members.

If you want to re-pair them, you can use the regular member-side proposal flow or the bulk import below.

Bulk import pairings (XLSX / CSV)

Use this when onboarding a tenant with historical Big-Little data, or any time you need to set many pairings at once.

File format

Upload an XLSX or CSV with one row per pairing. Columns:

ColumnIdentifier kindRequired
little_email or little_org_member_nameEmail lookup or fallback org_member_name lookupYes (one of the two)
big_email or big_org_member_nameSameYes (one of the two)

Use email when you have it — it's the most reliable. Fall back to org_member_name (the fraternal / sorority name) when you don't, but expect more "could not resolve" errors.

Where to find it

Open Org → Members → Big-Little Bulk Import, then upload the file. The page is gated to national/platform admin.

Response

The import returns a structured result:

{
"paired": 142,
"skipped": 3,
"errors": [
{"row": 17, "reason": "could not resolve little email 'old@stale.example'"},
{"row": 38, "reason": "cycle detected: A → B → A"},
{"row": 91, "reason": "little already has a big — pass overwrite=true to replace"}
]
}

paired is the count of new pairings created. skipped is rows that were valid but produced no change (already pointing at the proposed big). errors is per-row, with the spreadsheet row number so you can fix the source file and re-upload.

Cycle detection

The import walks up the proposed big's ancestor chain before committing each row. If the chain reaches back to the proposed little, the row is rejected with a cycle detected error. Family trees should always be DAGs — cycles indicate bad source data.

Overwriting existing pairings

By default, rows that would overwrite an existing big are rejected with a per-row error. Set the overwrite=true form field (or check the Overwrite existing checkbox in the UI) to replace existing pairings with the new ones from the file. Use sparingly — this can mass-reset family trees with no undo.

Per-batch progress

For large imports the resolution phase (mapping emails / names to memberships and walking ancestry) can take a while. The admin UI polls bulk_import.result_summary["relationship_resolution"] every 25 rows and updates a progress indicator ("Pass 2: relationship resolution 142 of 312") so you don't see a stuck progress bar.

Retry on transient errors

The second-pass save uses a 3-attempt retry with linear backoff for transient OperationalErrors (concurrent imports, signal cascades briefly raising PG locks). A row that fails three times in a row propagates the error rather than silently dropping — you'll see it in the response's errors array.

Audit log

Both reverse and bulk-import operations write to the platform audit log:

  • Reverse: operation="big_little_reverse", resource_type="member", with the prior big_id in metadata.
  • Bulk import: operation="big_little_bulk_import", with the paired count, skipped count, and a summary of the first 50 errors in metadata. The file itself is not retained.

Open Settings → Audit Log to review.

Common failure modes

  • "Could not resolve email" — the email isn't in your org's user roster. Either add the member first or use org_member_name if you only have the fraternal name.
  • "Cycle detected" — fix the source data; family trees shouldn't loop.
  • "Little already has a big" without overwrite=true — review whether you actually want to replace, then re-upload with the flag set.
  • "Cross-org pair rejected" — both the big and the little must be in chapters of your organization. Cross-org pairings aren't allowed.

Last verified against v0.63.39 (2026-06-26). Reverse + bulk import + per-batch progress + retry shipped v0.63.36.