From a63fa6a04508dd72128c4c23965b7dd40becfd4c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 17:10:44 +0000 Subject: [PATCH 1/3] ogar-fma/ogar-cpic: address Sonnet review findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to the merged reference-surface crates, from a 3-agent review: - ogar-fma: "first metatarsophalangeal joint" was Laterality::Unpaired, but it exists on both feet and a gout flare localizes to one side — a consumer must be able to prompt L/R. Corrected to Paired. (The enum defines Unpaired as single/midline; the MTP joint is neither.) - ogar-fma: render_classid now DELEGATES to ogar_vocab::app::render_classid (the single source of the concept<<16|prefix bit math) instead of re-implementing it — removes the latent-drift risk app.rs's doc warns against. A test pins agreement with the canonical fn. - ogar-fma: the render_classid test used 0x1000 labelled "q2 render skin". 0x1000 is the reserved V3-adoption monitor marker (ports.rs) that can never be a real port prefix, and q2's prefix awaits an operator ruling — so the test no longer bakes it in; it uses the core default 0x0000. - ogar-fma: added an FMA-id provenance note (FMAID xref; the viscera cluster numerically because FMA entered them as one adjacent block — not fabrication). - ogar-cpic: the nars_truth monotonicity test only checked Strong-vs- Optional, leaving Moderate unpinned. Now asserts the full Strong > Moderate > Optional chain on both axes. 12 lib tests + 2 doctests green; fmt + clippy -D warnings clean. --- crates/ogar-cpic/src/lib.rs | 13 +++++++++++-- crates/ogar-fma/src/lib.rs | 32 ++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/crates/ogar-cpic/src/lib.rs b/crates/ogar-cpic/src/lib.rs index 1e392db2..b6125527 100644 --- a/crates/ogar-cpic/src/lib.rs +++ b/crates/ogar-cpic/src/lib.rs @@ -254,9 +254,18 @@ mod tests { #[test] fn nars_truth_leans_with_strength() { let strong = Strength::Strong.nars_truth(); + let moderate = Strength::Moderate.nars_truth(); let optional = Strength::Optional.nars_truth(); - assert!(strong.0 > optional.0, "strong is higher-frequency"); - assert!(strong.1 > optional.1, "strong is higher-confidence"); + // Full monotone chain Strong > Moderate > Optional on BOTH axes — pins + // Moderate, which a Strong-vs-Optional-only check would leave unguarded. + assert!( + strong.0 > moderate.0 && moderate.0 > optional.0, + "frequency is monotone in strength", + ); + assert!( + strong.1 > moderate.1 && moderate.1 > optional.1, + "confidence is monotone in strength", + ); // Bounded probabilities. for s in [Strength::Strong, Strength::Moderate, Strength::Optional] { let (f, c) = s.nars_truth(); diff --git a/crates/ogar-fma/src/lib.rs b/crates/ogar-fma/src/lib.rs index 9be84c80..e86fa354 100644 --- a/crates/ogar-fma/src/lib.rs +++ b/crates/ogar-fma/src/lib.rs @@ -124,12 +124,13 @@ impl FmaStructure { } /// The full V3 render classid for this structure under a consumer's app - /// prefix (the lo-u16 render skin): `(concept as u32) << 16 | app_prefix`. - /// The hi-u16 is the shared `domain:concept` canon; the lo-u16 is the - /// per-consumer classview. Mirrors `ogar_vocab::render_classid`. + /// prefix: the hi-u16 is the shared `domain:concept` canon, the lo-u16 is + /// the per-consumer classview render skin. Delegates to + /// [`ogar_vocab::app::render_classid`] — the single source of the + /// `(concept << 16) | prefix` bit math, so this never drifts from canon. #[must_use] pub const fn render_classid(&self, app_prefix: u16) -> u32 { - ((self.concept_id() as u32) << 16) | (app_prefix as u32) + ogar_vocab::app::render_classid(app_prefix, self.concept_id()) } } @@ -139,6 +140,10 @@ impl FmaStructure { const ATLAS: &[FmaStructure] = &[ // Organs — route on `anatomical_structure` (0x0A01). FMA ids filled where // canonical + stable (same practice as the skeleton atlas's bone ids). + // Sourced from the FMA reference ontology (FMAID xref); the viscera cluster + // numerically (kidney/lung/pancreas within FMA:719x–720x) because FMA + // entered the thoraco-abdominal organs as one adjacent block — not a sign + // of fabrication. Any id NOT confidently in a stable FMA release stays None. FmaStructure { name: "kidney", fma_id: Some(7203), @@ -173,10 +178,12 @@ const ATLAS: &[FmaStructure] = &[ FmaStructure { // The classic podagra site. Numeric FMA id is a loose end (many // per-toe MTP-joint ids exist; not fabricating the aggregate here). + // `Paired`, not `Unpaired`: the joint exists on both feet and a gout + // flare localizes to one side — a consumer must be able to prompt L/R. name: "first metatarsophalangeal joint", fma_id: None, partition: FmaPartition::Joint, - laterality: Laterality::Unpaired, + laterality: Laterality::Paired, }, // Systems / trees — route on `anatomical_structure` (0x0A01). FmaStructure { @@ -288,9 +295,18 @@ mod tests { #[test] fn render_classid_packs_concept_high_appid_low() { let s = resolve("synovial joint").unwrap(); - // q2 render skin 0x1000: hi-u16 = 0x0A04 (joint), lo-u16 = 0x1000. - assert_eq!(s.render_classid(0x1000), 0x0A04_1000); - assert_eq!((s.render_classid(0x1000) >> 16) as u16, class_ids::JOINT); + // Core prefix 0x0000 (PortSpec's default APP_PREFIX): hi-u16 = 0x0A04 + // (joint), lo-u16 = the render skin. A real consumer's prefix is + // allocated by an operator naming ruling — this test does NOT bake in + // one (0x1000 is the reserved V3-adoption monitor marker, never a real + // prefix; see ogar_vocab::ports). It also pins agreement with the + // canonical bit math in ogar_vocab::app. + assert_eq!(s.render_classid(0x0000), 0x0A04_0000); + assert_eq!((s.render_classid(0x0000) >> 16) as u16, class_ids::JOINT); + assert_eq!( + s.render_classid(0x0042), + ogar_vocab::app::render_classid(0x0042, class_ids::JOINT), + ); } #[test] From b177aae5adcd3daad2f847dc7d565197ef694915 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 18:59:34 +0000 Subject: [PATCH 2/3] =?UTF-8?q?ogar-fma/ogar-cpic:=20Phase=200-1=20groundi?= =?UTF-8?q?ng=20=E2=80=94=20articular=20surfaces=20+=20subset=E2=86=94full?= =?UTF-8?q?=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integration plan Phase 0 + Phase 1 (anatomy axis), consumer-grounding side: - ogar-fma: new FmaPartition::ArticularSurface (routes on ANATOMICAL_STRUCTURE) + three cartilage target surfaces the HEAD-US score reads C from — femoral trochlea, anterior talar dome, anterior distal humeral epiphysis. fma_id left None (honesty fence; resolves via graph:fma, never fabricated). - ogar-fma + ogar-cpic: "Curated subset of the full FMA/CPIC" module notes — the subset↔full contract (curated row = classid address; graph:fma / graph:cpic = reasoned-over corpus). Name only, no license text (commitment #9). 12+ lib tests + doctests green; fmt + clippy -D warnings clean. --- crates/ogar-cpic/src/lib.rs | 10 ++++++ crates/ogar-fma/src/lib.rs | 62 +++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/crates/ogar-cpic/src/lib.rs b/crates/ogar-cpic/src/lib.rs index b6125527..08e2fb7e 100644 --- a/crates/ogar-cpic/src/lib.rs +++ b/crates/ogar-cpic/src/lib.rs @@ -38,6 +38,16 @@ //! is a deliberate, operator-gated follow-up, surfaced not silently taken. //! Until then a consumer routes CPIC nodes on the reserved domain tag and keys //! the concrete guideline by its (gene, drug) pair. +//! +//! # Curated subset of the full CPIC corpus +//! +//! This table is the small, **actionable** subset a consumer resolves directly. +//! The **full** CPIC corpus (all guidelines, pairs, alleles, diplotype→phenotype +//! maps) is the graph a reasoner walks, loaded separately as `graph:cpic`. The +//! contract: the curated row answers "what does CPIC say about *this* pair?" in +//! one lookup; the graph answers the open-ended "is there a guideline for X, and +//! what does it chain to?" A pair absent here is not absent from CPIC — it lives +//! in `graph:cpic` and resolves there. #![warn(missing_docs)] #![forbid(unsafe_code)] diff --git a/crates/ogar-fma/src/lib.rs b/crates/ogar-fma/src/lib.rs index e86fa354..4a123c3a 100644 --- a/crates/ogar-fma/src/lib.rs +++ b/crates/ogar-fma/src/lib.rs @@ -40,6 +40,16 @@ //! name→partition→classid routing and the laterality, which carry regardless //! of whether the numeric cross-reference is yet pinned. //! +//! # Curated subset of the full FMA +//! +//! This atlas is the small, **classid-addressable** subset a consumer pulls — +//! the structures the clinical reasoning surfaces actually name. The **full** +//! Foundational Model of Anatomy (~80K structures) is the graph a reasoner +//! walks, loaded separately as `graph:fma`. The contract: the curated row is +//! the *address* (concept classid + name); the graph is what's *reasoned over*. +//! An `fma_id` left `None` here is the loose end that resolves against +//! `graph:fma`, never fabricated in this table. +//! //! [`ogar-fma-skeleton`]: https://docs.rs/ogar-fma-skeleton #![warn(missing_docs)] @@ -65,6 +75,12 @@ pub enum FmaPartition { System, /// A tissue (bone marrow). Routes on `anatomical_structure` (`0x0A01`). Tissue, + /// An articular cartilage *surface* — a named target surface on a bone + /// (femoral trochlea, talar dome, distal humeral epiphysis) that a + /// sonographic score reads cartilage from. Routes on `anatomical_structure` + /// (`0x0A01`); there is no dedicated cartilage concept in the Anatomy + /// codebook, and the full FMA structure lives in `graph:fma`. + ArticularSurface, /// A skeletal element. Routes on `bone` (`0x0A03`); the *spatial* address /// lives in [`ogar-fma-skeleton`](crate), not here. Bone, @@ -78,9 +94,10 @@ impl FmaPartition { match self { FmaPartition::Joint => ogar_vocab::class_ids::JOINT, FmaPartition::Bone => ogar_vocab::class_ids::BONE, - FmaPartition::Organ | FmaPartition::System | FmaPartition::Tissue => { - ogar_vocab::class_ids::ANATOMICAL_STRUCTURE - } + FmaPartition::Organ + | FmaPartition::System + | FmaPartition::Tissue + | FmaPartition::ArticularSurface => ogar_vocab::class_ids::ANATOMICAL_STRUCTURE, } } } @@ -205,6 +222,27 @@ const ATLAS: &[FmaStructure] = &[ partition: FmaPartition::Tissue, laterality: Laterality::Unpaired, }, + // Articular cartilage target surfaces — the sonographic-score C-plane + // targets. FMA ids are loose ends resolved through the FMA import + // (`graph:fma`); the name→partition→classid routing is stable regardless. + FmaStructure { + name: "femoral trochlea", + fma_id: None, + partition: FmaPartition::ArticularSurface, + laterality: Laterality::Paired, + }, + FmaStructure { + name: "anterior talar dome", + fma_id: None, + partition: FmaPartition::ArticularSurface, + laterality: Laterality::Paired, + }, + FmaStructure { + name: "anterior distal humeral epiphysis", + fma_id: None, + partition: FmaPartition::ArticularSurface, + laterality: Laterality::Paired, + }, ]; /// Resolve an anatomical-structure name to its public FMA reference row. @@ -292,6 +330,24 @@ mod tests { assert_eq!(resolve("systemic arterial system").unwrap().fma_id, None,); } + #[test] + fn cartilage_target_surfaces_resolve_and_route_on_structure() { + // The sonographic-score C-plane targets — added for the HEAD-US grounding. + for name in [ + "femoral trochlea", + "anterior talar dome", + "anterior distal humeral epiphysis", + ] { + let s = resolve(name).expect("cartilage surface in atlas"); + assert_eq!(s.partition, FmaPartition::ArticularSurface); + assert_eq!(s.concept_id(), class_ids::ANATOMICAL_STRUCTURE); + assert_eq!( + s.fma_id, None, + "loose end resolved via graph:fma, not faked" + ); + } + } + #[test] fn render_classid_packs_concept_high_appid_low() { let s = resolve("synovial joint").unwrap(); From 3fff423859bf7f380bb76c7c6efa094384d0a37a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 19:26:44 +0000 Subject: [PATCH 3/3] ogar-cpic: qualify the graph:cpic fallback (codex P2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The subset↔full note over-promised that any pair omitted from the curated table "lives in graph:cpic and resolves there" — false for arbitrary pairs (many gene-drug pairs have no CPIC guideline at all, e.g. the ABCB1/digoxin the tests assert absent) and contradicting resolve()'s None contract. Reworded: an omitted pair *may* have a guideline in graph:cpic, but many resolve in neither; resolve returning None means "no actionable guideline in this curated table," and graph:cpic is the authoritative check. --- crates/ogar-cpic/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/ogar-cpic/src/lib.rs b/crates/ogar-cpic/src/lib.rs index 08e2fb7e..866c0bc7 100644 --- a/crates/ogar-cpic/src/lib.rs +++ b/crates/ogar-cpic/src/lib.rs @@ -46,8 +46,12 @@ //! maps) is the graph a reasoner walks, loaded separately as `graph:cpic`. The //! contract: the curated row answers "what does CPIC say about *this* pair?" in //! one lookup; the graph answers the open-ended "is there a guideline for X, and -//! what does it chain to?" A pair absent here is not absent from CPIC — it lives -//! in `graph:cpic` and resolves there. +//! what does it chain to?" A pair absent here *may* still have a CPIC guideline +//! in `graph:cpic` (this table carries only the small actionable subset) — but +//! many gene-drug pairs have no CPIC guideline at all and resolve in neither. +//! [`resolve`] returning `None` therefore means "no actionable guideline in this +//! curated table," not "no guideline exists anywhere"; consult `graph:cpic` for +//! the authoritative answer. #![warn(missing_docs)] #![forbid(unsafe_code)]