Class CurationDraftDispositions

java.lang.Object
ubic.gemma.model.common.auditAndSecurity.curation.CurationDraftDispositions

public final class CurationDraftDispositions extends Object
Derive per-element CurationDraftDispositions.Disposition for a DRAFT AnnotationSet by diffing its payload against the PROPOSAL it was seeded from, and consulting AnnotationSet.getParkedElements().

The diff is shallow: both payloads are expected to be JSON objects whose top-level keys are opaque element identifiers (e.g. "factor:42:0", "tag:42:3") and whose values are the element contents. Elements appearing only in the draft are NEW (not a disposition signal — skipped). Elements appearing only in the proposal are REJECTED. Elements in both with equal content are RETAINED; with different content, EDITED. The parked list overrides everything: any key named in parkedElements gets PARKED regardless of the diff.

Dispositions are derived, never stored. Accept, edit and reject all fall out of one comparison, so there is no per-element status column to drift out of sync with the payload it describes. What the curator deliberately set aside is the one thing the diff cannot see — a parked element leaves the payload unchanged, exactly like an untouched one — which is why parkedElements needs explicit storage and the rest does not. See AnnotationSet#getParkedElements().

🛑 This is per-element bookkeeping within one draft, not the per-finding audit disposition (pending | accepted | dismissed | needs_more_info) the curation-agents side stores, nor AnnotationSetTriage. Three different questions at three scopes: what did the curator do to this element, what did they rule on that finding, and how much does this whole set matter.

This class is pure — no Spring, no DB, no transactions. It is safe to call from REST handlers or from unit tests. The string overload exists so a caller that already holds both payloads does not have to reach through a lazy parent association to use it.

History: this existed before, keyed to the retired CurationDraft entity and its embedded proposalSnapshotJson copy, and was deleted in fa4363e24f when AgentProposal / CurationDraft were folded into AnnotationSet. The lineage is now the parent pointer rather than an embedded copy, so the proposal payload is read through it.

  • Method Details

    • derive

      public static Map<String, CurationDraftDispositions.Disposition> derive(@Nullable AnnotationSet draft)
      Derive dispositions for a draft, reading the proposal payload through the draft's parent.

      ⚠️ parent is a LAZY association. Call this inside the transaction that loaded the draft, or use derive(String, String, String) with a payload the caller already has.

      Returns:
      a map keyed by element identifier; entries with no useful signal (new-in-draft only) are omitted. Empty when the draft is null or was not seeded from a proposal.
    • derive

      public static Map<String, CurationDraftDispositions.Disposition> derive(@Nullable String proposalPayloadJson, @Nullable String draftPayloadJson, @Nullable String parkedElements)
      Derive dispositions from the three payloads directly.
      Parameters:
      proposalPayloadJson - the PROPOSAL payload the draft was seeded from; null / blank means there is no diff baseline, in which case only parked elements can be reported
      draftPayloadJson - the draft's current payload
      parkedElements - JSON array of parked element keys