-
-
Notifications
You must be signed in to change notification settings - Fork 0
Domain Model
Author: Ciprian Ștefan Pleșca
This page documents the typed core defined in src/openlongevity/models.py, plus the closely related Publication/Provenance shapes from providers/base.py. These are frozen (immutable) dataclasses: once constructed, a record cannot be mutated in place, which makes accidental silent corruption of scientific data structurally harder.
classDiagram
class StudyType {
<<enumeration>>
SYSTEMATIC_REVIEW
RCT
CLINICAL
OBSERVATIONAL
ANIMAL
IN_VITRO
COMPUTATIONAL
}
class RetractionStatus {
<<enumeration>>
ACTIVE
CORRECTED
EXPRESSION_OF_CONCERN
RETRACTED
UNKNOWN
}
class FindingDirection {
<<enumeration>>
POSITIVE
NULL
NEGATIVE
MIXED
}
class ReviewStatus {
<<enumeration>>
UNREVIEWED
MACHINE_EXTRACTED
HUMAN_REVIEWED
VERIFIED
DISPUTED
}
class EvidenceRecord {
+str identifier
+str title
+StudyType study_type
+str species
+str endpoint
+str source
+str~ publication_date
+int~ sample_size
+float confidence
+tuple~str~ limitations
+str replication_status
+RetractionStatus retraction_status
+tuple~str~ tags
+dict metadata
+FindingDirection direction
+ReviewStatus review_status
+str~ reviewed_by
+tuple provenance_history
+__post_init__() validates identifier, title, source, confidence range, sample_size
}
class ResearchGap {
+str topic
+str kind
+str rationale
+str priority
+tuple~str~ supporting_record_ids
+float confidence
+dict details
}
class Contradiction {
+str topic
+tuple~str~ supporting_record_ids
+tuple~str~ contradicting_record_ids
+str explanation
}
class Provenance {
+str source_provider
+str source_identifier
+str source_url
+str retrieved_at
+str~ source_updated_at
+str~ license
+str~ checksum
+str normalization_version
+str parser_version
}
class Publication {
+str identifier
+str title
+str abstract
+tuple~str~ authors
+str~ journal
+str~ publication_date
+str~ doi
+tuple~str~ publication_types
+tuple~str~ mesh_terms
+int~ citation_count
+Provenance~ provenance
+str retraction_status
+tuple corrections
}
EvidenceRecord --> StudyType
EvidenceRecord --> RetractionStatus
EvidenceRecord --> FindingDirection
EvidenceRecord --> ReviewStatus
Publication --> Provenance
EvidenceRecord, Publication, Provenance, ResearchGap, and Contradiction are all declared with @dataclass(frozen=True). In a research-evidence system, in-place mutation of a graded record is a correctness hazard: a caller could hold a reference, grade it, and then have the underlying values change without re-grading. Immutability forces any transformation (for example, incrementing a revision) to happen through an explicit, auditable code path — in this codebase, that path is PublicationRepository, which constructs new payload dictionaries rather than mutating a live Publication.
EvidenceRecord.__post_init__ enforces three invariants unconditionally:
flowchart LR
A[EvidenceRecord constructed] --> B{identifier, title, source all non-empty?}
B -- no --> E1[raise ValueError]
B -- yes --> C{0.0 <= confidence <= 1.0 ?}
C -- no --> E2[raise ValueError]
C -- yes --> D{sample_size is None or >= 0 ?}
D -- no --> E3[raise ValueError]
D -- yes --> OK[Valid, immutable record]
This means an EvidenceRecord cannot exist in an invalid state anywhere in the system — there is no code path that produces a record with a negative sample size or an out-of-range confidence value, because the object itself refuses to be built.
A deliberate modeling choice is that EvidenceRecord (an evidentiary claim: a study design, a species, an endpoint, a confidence value) is a distinct type from Publication (a bibliographic record with a title, authors, and a DOI). The README states this directly: "A publication's bibliographic envelope is insufficient to establish that a specific outcome was reported accurately." In the current implementation, only Publication records flow through the persistence layer; EvidenceRecord instances exist solely as demonstration fixtures inside api.py. Any future feature that extracts an EvidenceRecord from a Publication would need its own provenance and review workflow — the type boundary already anticipates that requirement.
ReviewStatus (UNREVIEWED → MACHINE_EXTRACTED → HUMAN_REVIEWED / VERIFIED / DISPUTED) models a review pipeline that the README explicitly calls a "proposed" future integration, illustrated in the research-pipeline diagram as Human review pipeline: proposed -. future integration .-> D. Encoding the enum now, ahead of the pipeline that will populate it, lets every consumer of EvidenceRecord already branch on review state defensively, even before human review is implemented.
Provenance is attached to every Publication and is the mechanism by which a normalized record remains traceable to its origin:
| Field | Purpose |
|---|---|
source_provider |
Which adapter produced this record (pubmed, europe_pmc, …) |
source_identifier |
The upstream identifier (e.g., a PMID) |
source_url |
A resolvable link back to the original record |
retrieved_at |
Retrieval timestamp — explicitly excluded from the content hash so re-fetching identical content does not create a false revision |
checksum |
SHA-256 of the canonicalized source payload, used to detect real content changes |
normalization_version / parser_version
|
Lets a consumer know which transformation logic produced this shape, so a later parser fix can be distinguished from a change in the underlying data |
PublicationRepository.save refuses to persist any Publication whose provenance is None or whose checksum is empty — provenance is not optional metadata, it is a precondition for storage.
See Evidence-Grading-Engine for how EvidenceRecord values are turned into grades and scores, or Persistence-and-Data-Governance for how Publication/Provenance are persisted with revision history.
© 2026 Ciprian Ștefan Pleșca. All rights reserved.
Licensed under the Apache License 2.0 — see LICENSE in the repository root.
OpenLongevity is research software. It does not provide medical advice, diagnosis, or clinical treatment recommendations.