Summary
Score sets form supersession chains via a doubly-traversable linked list (superseded_score_set / superseding_score_set relationships). Currently, the API only exposes one hop in each direction on the score set detail response. There is no way to retrieve the full ordered chain without the client walking it manually with N+1 requests.
Problem
When a user views a score set that is part of a supersession chain, the frontend can only show the immediate predecessor and successor. To display the full version history (e.g. "version 2 of 4" or a timeline of all versions), the client must:
- Fetch the current score set
- Follow
superseded_score_set.urn backward, fetching each predecessor
- Follow
superseding_score_set.urn forward, fetching each successor
- Assemble the chain client-side
This is fragile, slow, and requires the client to implement chain-walking logic that already exists server-side in lib/score_sets.py.
Proposed behavior
Add a GET /score-sets/{urn}/supersession-chain endpoint that returns the full ordered supersession chain for the given score set. The response should be an ordered list from oldest to newest, using ShortScoreSet for each entry, plus metadata indicating which entry in the chain corresponds to the requested URN.
ShortScoreSet includes urn, title, short_description, and published_date — sufficient for the frontend to render a rich version timeline without follow-up requests.
Example response shape:
{
"current_urn": "urn:mavedb:00000001-a-2",
"chain": [
{
"urn": "urn:mavedb:00000001-a-1",
"title": "Original submission",
"short_description": "Initial DMS data for BRCA1",
"published_date": "2024-03-15",
"record_type": "Score Set"
},
{
"urn": "urn:mavedb:00000001-a-2",
"title": "Updated scoring",
"short_description": "Corrected normalization",
"published_date": "2024-09-01",
"record_type": "Score Set"
},
{
"urn": "urn:mavedb:00000001-a-3",
"title": "GRCh38 remapping",
"short_description": "Remapped to GRCh38 reference",
"published_date": null,
"record_type": "Score Set"
}
]
}
Permission-aware: entries the requesting user cannot read should be omitted from the chain, consistent with existing behavior in find_superseded_score_set_tail.
Acceptance criteria
Implementation notes
- Chain traversal logic already exists in
lib/score_sets.py (find_superseded_score_set_tail, find_publish_or_private_superseded_score_set_tail). These walk forward via superseding_score_set. The new endpoint needs to walk both directions from the requested URN: backward via superseded_score_set to find the chain head, then forward via superseding_score_set to build the full ordered list.
- The existing traversal functions interleave permission checks with chain walking. The new endpoint should follow the same pattern — skip entries the user cannot read rather than terminating the walk.
- A new response model will be needed (e.g.
SupersessionChainResponse with current_urn: str and chain: list[ShortScoreSet]), defined in view_models/score_set.py.
ShortScoreSet already exists in view_models/score_set.py and includes the fields needed for a rich timeline display. No changes to this model are required.
- Ensure relationships are eagerly loaded to avoid N+1 queries during traversal. Consider using a recursive CTE if chains become long enough to warrant it, though the linked-list walk is likely sufficient for typical chain lengths.
Summary
Score sets form supersession chains via a doubly-traversable linked list (
superseded_score_set/superseding_score_setrelationships). Currently, the API only exposes one hop in each direction on the score set detail response. There is no way to retrieve the full ordered chain without the client walking it manually with N+1 requests.Problem
When a user views a score set that is part of a supersession chain, the frontend can only show the immediate predecessor and successor. To display the full version history (e.g. "version 2 of 4" or a timeline of all versions), the client must:
superseded_score_set.urnbackward, fetching each predecessorsuperseding_score_set.urnforward, fetching each successorThis is fragile, slow, and requires the client to implement chain-walking logic that already exists server-side in
lib/score_sets.py.Proposed behavior
Add a
GET /score-sets/{urn}/supersession-chainendpoint that returns the full ordered supersession chain for the given score set. The response should be an ordered list from oldest to newest, usingShortScoreSetfor each entry, plus metadata indicating which entry in the chain corresponds to the requested URN.ShortScoreSetincludesurn,title,short_description, andpublished_date— sufficient for the frontend to render a rich version timeline without follow-up requests.Example response shape:
{ "current_urn": "urn:mavedb:00000001-a-2", "chain": [ { "urn": "urn:mavedb:00000001-a-1", "title": "Original submission", "short_description": "Initial DMS data for BRCA1", "published_date": "2024-03-15", "record_type": "Score Set" }, { "urn": "urn:mavedb:00000001-a-2", "title": "Updated scoring", "short_description": "Corrected normalization", "published_date": "2024-09-01", "record_type": "Score Set" }, { "urn": "urn:mavedb:00000001-a-3", "title": "GRCh38 remapping", "short_description": "Remapped to GRCh38 reference", "published_date": null, "record_type": "Score Set" } ] }Permission-aware: entries the requesting user cannot read should be omitted from the chain, consistent with existing behavior in
find_superseded_score_set_tail.Acceptance criteria
GET /score-sets/{urn}/supersession-chainreturns the full ordered chain from oldest to newestShortScoreSet(urn,title,short_description,published_date,record_type)current_urnindicates which entry in the chain was requestedImplementation notes
lib/score_sets.py(find_superseded_score_set_tail,find_publish_or_private_superseded_score_set_tail). These walk forward viasuperseding_score_set. The new endpoint needs to walk both directions from the requested URN: backward viasuperseded_score_setto find the chain head, then forward viasuperseding_score_setto build the full ordered list.SupersessionChainResponsewithcurrent_urn: strandchain: list[ShortScoreSet]), defined inview_models/score_set.py.ShortScoreSetalready exists inview_models/score_set.pyand includes the fields needed for a rich timeline display. No changes to this model are required.