Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions crates/ogar-obo/src/crosswalk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,15 @@ impl Crosswalk {
}
}

/// The Uberon anatomy classid (`0x0303`), for a consumer that resolves an FMA
/// zone and wants to confirm the returned address is anatomy.
pub const ANATOMY_CLASSID: u32 = 0x0303_0000;
/// The MONDO disease classid (`0x0301`).
pub const DISEASE_CLASSID: u32 = 0x0301_0000;
/// The Uberon anatomy classid, for a consumer that resolves an FMA zone and
/// wants to confirm the returned address is anatomy. DERIVED from the enum
/// (never a literal), so it moved with the S3 producer flip (#293:
/// `0x0303_0000 -> 0x9303_0000`) instead of silently disagreeing with what
/// [`Crosswalk::resolve_fma`] actually renders — which is exactly how the
/// stale literal was caught (MedCare's conformance suite).
pub const ANATOMY_CLASSID: u32 = (crate::Namespace::Uberon.concept_id() as u32) << 16;
/// The MONDO disease classid (derived, see [`ANATOMY_CLASSID`]).
pub const DISEASE_CLASSID: u32 = (crate::Namespace::Mondo.concept_id() as u32) << 16;

#[cfg(test)]
mod tests {
Expand Down
26 changes: 25 additions & 1 deletion crates/ogar-obo/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,22 @@ const _: () = assert!(OBO_CORE_ROW.edge_lanes.bytes == OBO_CORE_ROW.lane_count *
/// (`ogar-ro`'s relation-BODY classid, whose 512-byte row is `ogar-loco`
/// call-slab shaped, not this schema) and every concept outside the
/// registries. Refused, not guessed.
///
/// Accepts BOTH address forms of an aliased namespace (the reader rule the S3
/// producer flip set for [`Namespace::from_concept_id`]): a pre-flip artifact
/// keyed `0x0301` carries exactly this carve, so its legacy concept id must
/// resolve to the same schema the domain form does.
#[must_use]
pub fn row_schema_of(concept: u16) -> Option<&'static ClassRowSchema> {
// Fold a legacy alias onto its canonical (registry-minted) form before the
// registry probe; a concept without an alias probes as itself.
let canonical =
crate::Namespace::from_concept_id(concept).map_or(concept, crate::Namespace::concept_id);
let known = registry::OBO_CORE
.specs()
.iter()
.chain(registry::META_STUDY_SPINE.specs())
.any(|s| s.concept_id == concept);
.any(|s| s.concept_id == canonical);
known.then_some(&OBO_CORE_ROW)
}

Expand All @@ -131,6 +140,21 @@ mod tests {
}
}

/// A pre-flip artifact's rows carry the legacy ids and EXACTLY this
/// carve — the reader rule (`from_concept_id` accepts both) extends to
/// the schema resolution, or a legacy artifact becomes unreadable the
/// moment the registry mints the domain form.
#[test]
fn legacy_alias_concepts_resolve_to_the_same_schema() {
for legacy in [0x0301u16, 0x0302, 0x0303] {
assert_eq!(
row_schema_of(legacy),
Some(&OBO_CORE_ROW),
"{legacy:#06x} (legacy alias) must resolve the declared carve"
);
}
}

#[test]
fn foreign_concepts_are_refused_not_guessed() {
// 0x0306 is ogar-ro's relation-body classid — call-slab shaped, NOT
Expand Down
Loading