Class AnnotationSetDisposition
- All Implemented Interfaces:
Identifiable
One ruling on one finding inside an AnnotationSet.
A curator working an audit rules on each finding in turn —
FindingDisposition.ACCEPTED / FindingDisposition.DISMISSED /
FindingDisposition.NEEDS_MORE_INFO, with a reason. The finding is
named by findingId when the producer supplies one and by
targetId otherwise; both are the producer's own strings. Gemma does
not parse the payload and so cannot validate either.
🛑 Set, finding and element are three scopes and this is the middle
one. AnnotationSetTriage rules on the whole set;
CurationDraftDispositions.Disposition classifies one element within
one draft and is derived rather than stored. All three read like
dispositions and none of them substitutes for another.
Append-only, latest wins — deliberately the opposite choice from
AnnotationSetTriage, which keys UNIQUE(set, judge) and
upserts. There, the question is what a judge currently thinks about a whole
set. Here the sequence is itself the record: a finding that was accepted,
then dismissed after a second look, is a different history from one
dismissed outright, and an audit's value depends on being able to see that a
ruling moved. standing(Collection) applies the latest-wins fold on
read.
judgeKind reuses TriageJudgeKind rather than declaring a
second enum with the same two values. Its name says triage and its meaning —
did a person or a machine decide this — is the same question in both
places.
No unique constraint, so nothing here stops two rows with the same
(set, targetId, decidedBy). That is the point.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final Comparator<AnnotationSetDisposition> Most recent first, id breaking a same-millisecond tie. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionbooleanBy id once both sides have one, otherwise by(set, targetId, decidedBy, decidedAt).inthashCode()Constant, deliberately — the same choice, for the same reasons, asAnnotationSetTriage.hashCode().voidsetAnnotationSet(AnnotationSet annotationSet) voidsetDecidedAt(Date decidedAt) voidsetDecidedBy(String decidedBy) voidsetDisposition(FindingDisposition disposition) voidsetFindingId(String findingId) voidsetJudgeKind(TriageJudgeKind judgeKind) voidvoidsetTargetId(String targetId) static List<AnnotationSetDisposition> standing(Collection<AnnotationSetDisposition> rulings) The standing ruling under eachstandingKey()— the most recent row per finding, or per target for rows carrying no finding id.The key this ruling supersedes others under: the finding when it has one, the target when it does not.Methods inherited from class AbstractIdentifiable
getId, setId, toString
-
Field Details
-
NEWEST_FIRST
Most recent first, id breaking a same-millisecond tie. The same ordering the DAO applies in SQL, kept here so an in-memory fold cannot disagree with a query.
-
-
Constructor Details
-
AnnotationSetDisposition
public AnnotationSetDisposition()
-
-
Method Details
-
standing
public static List<AnnotationSetDisposition> standing(@Nullable Collection<AnnotationSetDisposition> rulings) The standing ruling under eachstandingKey()— the most recent row per finding, or per target for rows carrying no finding id.Ties on
decidedAtbreak on id, so two rulings written in the same millisecond still resolve to one answer rather than to whichever the collection happened to yield first.- Returns:
- the standing rulings, most recent first. Findings nobody has ruled on are simply absent.
-
getAnnotationSet
-
setAnnotationSet
-
getTargetId
-
setTargetId
-
getFindingId
-
setFindingId
-
standingKey
The key this ruling supersedes others under: the finding when it has one, the target when it does not.🛑 The two are deliberately NOT coalesced into one namespace. A ruling on a finding and a ruling on a target are not rulings on the same thing, so a finding id that happened to equal some target id must not make one supersede the other — that would invent a supersession nobody performed. The discriminating prefix is what guarantees it, rather than an argument that the two id spaces never collide.
-
getDisposition
-
setDisposition
-
getDecidedBy
-
setDecidedBy
-
getJudgeKind
-
setJudgeKind
-
getDecidedAt
-
setDecidedAt
-
getReason
-
setReason
-
hashCode
public int hashCode()Constant, deliberately — the same choice, for the same reasons, asAnnotationSetTriage.hashCode().Hashing the business key would mean hashing
annotationSet, aLAZYproxy whosehashCode()can force initialization outside a session. An id-based hash is worse: the id flips from null to a value on persist, so a ruling added to aHashSetwhile transient lands in the wrong bucket andcontains()then answers false for an element that is in the set.The cost is one bucket degrading to a linear scan. An audit carries tens of findings, not thousands.
- Specified by:
hashCodein classAbstractIdentifiable
-
equals
By id once both sides have one, otherwise by(set, targetId, decidedBy, decidedAt). 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.The fallback includes
decidedAtbecause these rows are append-only: without it, a curator's second ruling on the same finding would compare equal to their first and silently collapse in aSet.- Specified by:
equalsin classAbstractIdentifiable
-