MemberJunction / MemberJunction/MJ
Orphan sweep hard-deletes records and ignores DeleteBehavior
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
## Issue
`DeleteOrphanedRecords` deletes physically regardless of the entity map's `DeleteBehavior`.
- `packages/Integration/engine/src/IntegrationEngine.ts:2072-2075` — called with no `DeleteBehavior` check
- `:2762` — `entity.Delete()` unconditionally
Contrast `DeleteRecord` at `:3734`/`:3750`, which **does** honour `DeleteBehavior` and soft-deletes
where configured. So the two delete paths disagree, and the one that ignores the setting is the
automatic one.
## Why it is dangerous
Scope is rows carrying a record-map entry for that `(CompanyIntegration, EntityID)` — but
`UpdateRecord` (`:3622-3635`) **writes a record-map row for any row matched by key fields**,
including rows that pre-existed and were never created by the integration. So a key-field match
onto existing data enrols it, and if the source later stops returning that ExternalID on a full
sync, that pre-existing row is hard-deleted.
This is mostly latent while entity maps point at connector-generated staging tables. It becomes
serious the moment a map targets a real business entity — mapping a connector at a shared
`Person`/`Organization` entity means a vendor-side deletion can hard-delete records the integration
did not create, with `DeleteBehavior: 'SoftDelete'` or `'DoNothing'` configured and ignored.
## Related
Soft-delete also silently no-ops when the target lacks the tombstone columns: `:3751-3757` sets
nothing, `entity.Save()` short-circuits on `!Dirty`, and the engine records a successful archive
that never happened.
## Environment
MJ 5.51.0.
Contributor guide
Research direction
Start in packages/Integration/engine/src/IntegrationEngine.ts at DeleteOrphanedRecords (2072-2075) and entity.Delete() (2762), then compare DeleteRecord at 3734 and 3750. Trace UpdateRecord at 3622-3635 and the soft-delete path at 3751-3757; done means orphan cleanup consistently respects DeleteBehavior and does not report a soft-delete that made no change.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100