Skip to content

Route supersession through a first-class Action.SUPERSEDE #854

Description

@bencap

Supersession is authorized ad hoc at each call site. For calibrations, validate_superseded_score_calibration checks Action.READ, which passes for any published calibration. For score sets, create_score_set passes owner_or_contributor to fetch_score_set_by_urn, where the narrowing collapses against only_published. Neither spelling is the rule we want, and neither is reachable from the front end, so no supersede affordance can be rendered.

Action.UPDATE is not a substitute. _handle_update_action denies updates on published calibrations to everyone except admins, and only published calibrations may be superseded, so requiring UPDATE would make supersession admin-only.

Proposed behavior

Add SUPERSEDE to the Action enum and a _handle_supersede_action for both score_set and score_calibration.

Calibration predicate — permitted if any of:

  • an active admin role
  • entity.created_by_id == user_data.user.id
  • entity.investigator_provided and the user is a contributor to the score set

user_is_contributor_to_score_set keeps its existing definition in lib/permissions/score_calibration.py: the user's ORCID is in entity.score_set.contributors, or the user is the score set's created_by or modified_by.

Score set predicate — admin, or owner, or contributor.

A score set contributor may not supersede a community calibration on their own score set. Ranking is the team's tool for an unwanted community contribution; declaring their own calibration its successor asserts a scientific succession that isn't theirs to make.

Business invariants stay out of the permission handler and remain in the validators, since they hold regardless of who is asking:

  • the target is published (private is False) — a private calibration has no permitted superseder, including its owner and admins; edit it instead
  • the target is not already superseded
  • the target is on the same score set as the new calibration

Document one asymmetry in the handler's docstring: investigator_provided is frozen at creation while contributor status is evaluated per request, so adding someone to a score set grants them supersede rights over every investigator-provided calibration already on it, and removing them leaves their own calibrations superseded-able through the owner leg.

Acceptance criteria

  • permissions/user-is-permitted/{model_name}/{urn}/{action} answers supersede for score_set and score_calibration
  • validate_superseded_score_calibration asserts Action.SUPERSEDE instead of Action.READ
  • create_score_set asserts Action.SUPERSEDE on the superseded score set rather than relying on fetch_score_set_by_urn's owner_or_contributor argument
  • a non-contributor is denied supersession of a published calibration and of a published score set
  • a score set contributor is permitted on an investigator-provided calibration and denied on a community one
  • test_can_create_superseding_score_calibration_in_public_score_set_as_non_contributor is updated to assert denial

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app: backendTask implementation touches the backend

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions