Class AnnotationSetTriage

java.lang.Object
ubic.gemma.model.common.AbstractIdentifiable
ubic.gemma.model.common.auditAndSecurity.curation.AnnotationSetTriage
All Implemented Interfaces:
Identifiable

@Entity public class AnnotationSetTriage extends AbstractIdentifiable
One judge's standing ruling on how much an AnnotationSet matters.

A row per judgement, not a column per judge. Columns on AnnotationSet would hard-code the set of judges into the schema — agent and curator today, a second-opinion reviewer or an external collaborator tomorrow, each one a migration. Rows make the judge data, and they answer questions columns cannot: has any human ever ruled on this, do two curators disagree, which agent build gets overruled most.

One standing judgement per judgeUNIQUE(annotationSet, judgedBy), upserted when a judge changes their mind. The question is what a judge currently thinks, not an append-only log of every time they toggled. Drop the constraint if the toggle history ever becomes the point.

The effective verdict is the most recent judgementeffective(Collection). Deliberately not "curator outranks agent": a curator ruling after the agent already wins by recency, and when two curators disagree the later one wins, which is the same answer the rest of this workflow gives to contention. judgeKind still records who, so ranking by role stays possible without re-deciding it here.

There is no stored "pending": an un-triaged set has no row. See TriageVerdict.

  • Constructor Details

    • AnnotationSetTriage

      public AnnotationSetTriage()
  • Method Details

    • effective

      public static Optional<AnnotationSetTriage> effective(@Nullable Collection<AnnotationSetTriage> judgements)
      The most recent ruling among judgements, or empty when nobody has ruled.

      Ties on judgedAt break on id, so two judgements written in the same millisecond still resolve to one answer rather than to whichever the collection happened to yield first.

    • reviewedByHuman

      public static boolean reviewedByHuman(@Nullable Collection<AnnotationSetTriage> judgements)
      Returns:
      whether a person has ruled on this set — the distinction between a reviewed set and one only a machine has seen.
    • getAnnotationSet

      public AnnotationSet getAnnotationSet()
    • setAnnotationSet

      public void setAnnotationSet(AnnotationSet annotationSet)
    • getVerdict

      public TriageVerdict getVerdict()
    • setVerdict

      public void setVerdict(TriageVerdict verdict)
    • getJudgedBy

      public String getJudgedBy()
    • setJudgedBy

      public void setJudgedBy(String judgedBy)
    • getJudgeKind

      public TriageJudgeKind getJudgeKind()
    • setJudgeKind

      public void setJudgeKind(TriageJudgeKind judgeKind)
    • getJudgedAt

      public Date getJudgedAt()
    • setJudgedAt

      public void setJudgedAt(Date judgedAt)
    • getNote

      @Nullable public String getNote()
    • setNote

      public void setNote(@Nullable String note)
    • hashCode

      public int hashCode()
      Constant, deliberately.

      The business key here is (annotationSet, judgedBy), and hashing it would mean hashing annotationSet — a LAZY proxy whose hashCode() can force initialization outside a session. An id-based hash is worse still: the id flips from null to a value on persist, so a judgement added to a HashSet while transient ends up in the wrong bucket and contains() then answers false for an element that is in the set.

      The cost is that one bucket degrades to a linear scan. A set carries a handful of judgements — one per judge — so that is not measurable here.

      Specified by:
      hashCode in class AbstractIdentifiable
    • equals

      public boolean equals(Object o)
      By id once both sides have one, otherwise by the business key. The annotation set is compared by id rather than by object so a lazy proxy on either side does not have to be initialized to answer.
      Specified by:
      equals in class AbstractIdentifiable