Scope committee_member.sfid forward mapping key by committee - #135
Scope committee_member.sfid forward mapping key by committee#135jordane wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Scopes committee-member mappings by committee to prevent cross-committee collisions and adds migration support.
Changes:
- Uses committee-scoped forward keys for create/delete paths.
- Adds a one-shot migration job with dry-run support.
- Documents and tests the new key format.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
README.md |
Documents scoped mappings and migration. |
manifests/backfill-committee-member-forward-mappings-job.yaml |
Defines the migration job. |
cmd/lfx-v1-sync-helper/main.go |
Registers and runs the backfill flag. |
cmd/lfx-v1-sync-helper/ingest_indexer.go |
Applies scoped keys to synchronization paths. |
cmd/lfx-v1-sync-helper/backfill_committee_member_forward_mappings.go |
Implements migration logic. |
cmd/lfx-v1-sync-helper/backfill_committee_member_forward_mappings_test.go |
Tests classification and key generation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The v2->v1 create path keyed the forward mapping on the v1 API MemberID (contact SFID) alone, which the same contact reuses across every committee it belongs to. Adding that contact to a second committee silently overwrote the first committee's forward mapping, orphaning it so a later v1-WAL delete couldn't find it. Scope the create-path key by committee SFID and update the delete path to look up the scoped key. Add a one-shot backfill to migrate existing flat keys to the scoped format and tombstone stale entries whose committee can no longer be resolved. Issue: LFXV2-2709 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
cmd/lfx-v1-sync-helper/backfill_committee_member_forward_mappings.go:387
splitTwoPartsaccepts any non-empty strings after the first colon, including extra fields (for example,<committee-uuid>:<member-uuid>:extra). Such entries are classified as migratable instead of malformed; when the resulting lookup fails, the destructive unresolved branch tombstones the flat mapping. Since both v2 IDs are UUIDs, validate both fields here so unexpected values remain in the non-destructivemalformedpath.
committeeUID, memberUID, ok := splitTwoParts(string(data))
if !ok || committeeUID == "" || memberUID == "" {
return forwardMappingClassification{outcome: forwardMappingMalformed}
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
cmd/lfx-v1-sync-helper/backfill_committee_member_forward_mappings.go:303
- A successful rollback at lines 226–228 leaves
scopedKeycontaining the custom!delmarker while the flat key remains live. On the next run, this branch treats that tombstone as an unexpected destination and reports a conflict forever, so a transient post-create liveness-read failure makes the documented retry unable to finish the migration. TreatisTombstonedMapping(entry.Value())as a recreatable destination: revive it with a revision-guardedUpdate, return the new revision as owned by this run, and mirror that behavior in the dry-run destination check.
case getErr == nil:
// Holds something else (tombstoned, or a different committee/member pairing) —
// don't overwrite a value we don't understand.
return true, false, 0, nil
Key structure across the two flows, and why they need to matchTracing through both directions of committee-member sync, here's the forward (v1→v2) and reverse (v2→v1) mapping each one writes today: Forward-creation (v1 WAL upsert with no existing mapping → v2 API create,
Critically, Reverse-creation (v2 "created" indexer event → v1 API create,
This PR rescopes that forward key to The bigger problem this doesn't addressThe reverse-creation flow's forward mapping is keyed differently ( So when a v2-created member is pushed to v1 via this create call, and the resulting Put differently: the two flows need to write their forward mapping under the same key format, since that key is the sole mechanism Proposed fix
If that holds up, the cleanest fix is for If it turns out Given the impact (possible duplicate v2 committee members on WAL echo), I'd like to resolve which of these two paths is correct before merging. |
Summary
committee_member.sfidforward mapping on the v1 API MemberID (contact SFID) alone, which the same contact reuses across every committee it belongs to — adding that contact to a second committee silently overwrote the first committee's forward mapping.Issue: LFXV2-2709