MemberJunction / MemberJunction/MJ
Lists: write ListDetail.RecordID as the compact CompositeKey segment, and sweep remaining hardcoded-ID key construction (follow-up to #4184)
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
## Summary
#4184 establishes the contract that a record id carried in `SearchResult.RecordID`, `MJ: List Details.RecordID` and `MJ: User Record Logs` is a **compact `CompositeKey` segment** — the bare value for a single-column key (whatever the column is called), `F1|v1||F2|v2` for a composite key — and moves the search navigation sites, the recents lookups and the list form's `openRecord` onto `CompositeKey.FromURLSegment(entityInfo, recordId)` / `FromEntityRecord(entityInfo, row)`.
Two things remain, both called out in that PR's description as follow-ups.
## 1. List Details are still *written* with a hardcoded `ID`
The read side now resolves any key, but the write side still assumes the column is `ID`, so adding a record from an entity whose key is `individual_id` (or composite) to a list stores an empty or wrong `RecordID`:
| site | writes |
|---|---|
| `packages/Angular/Explorer/core-entity-forms/src/lib/custom/Lists/list-form.component.ts:748` | `listDetail.RecordID = record.ID` |
| `packages/Angular/Explorer/core-entity-forms/src/lib/custom/Lists/list-form.component.ts:885` | `listDetail.RecordID = recordID` (caller-supplied) |
| `packages/Angular/Explorer/explorer-core/src/lib/single-list-detail/single-list-detail.component.ts:961` | `newDetail.RecordID = recordId` |
| `packages/Actions/CoreActions/src/custom/lists/add-records-to-list.action.ts:109` | `listDetail.RecordID = recordId` |
| `packages/Actions/CoreActions/src/custom/lists/create-list.action.ts:103` | `listDetail.RecordID = recordId` |
| `packages/AI/Providers/Recommendations-Rex/src/provider.ts:308` | `listDetail.RecordID = recordID` |
Fix: build the value with `CompositeKey.FromEntityRecord(entityInfo, row).ToCompactURLSegment()` where a row is in hand, and document on the action inputs that a caller-supplied id must be the compact segment. With #4184's read side in place each of these is a one-liner.
## 2. Repo-wide sweep of the same anti-pattern, plus a guard
`CompositeKey.FromID(...)` and `{ FieldName: 'ID', Value: ... }` on a **variable** entity (as opposed to a literal MJ core entity that really is keyed by `ID`) still appear at roughly 146 sites under `packages/Angular` alone. #4184 proposes a `PrimaryKeyCompliance` guard test in MJCore modelled on `MultiProviderCompliance` so new occurrences are caught in CI. The sweep should distinguish the two cases rather than rewrite everything: a literal core entity (`'MJ: Lists'`, `'MJ: Users'`, …) with `FromID` is fine; an entity name that comes from data is not.
## Why it matters
Silent data loss, not an error: a `RecordID` of `''` is dropped by fusion/dedup on the read path, so the record simply never shows up in the list it was added to. Reported originally in #4179 for search navigation; the write side is the same defect one layer down.
## Related
- #4184 — the contract and the read-side fix (approved)
- #4179 — the original report
Contributor guide
Research direction
Start with the six listed ListDetail.RecordID assignments in the list form, single-list detail, actions, and Recommendations-Rex provider, then review #4184's compact CompositeKey contract. Verify row-based writes use the entity record and caller-supplied ids are compact segments. Next search packages/Angular for variable-entity CompositeKey.FromID and { FieldName: 'ID' } uses, distinguishing literal MJ core entities, and add the proposed PrimaryKeyCompliance guard modeled on MultiProviderCompliance.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- full-stack
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100