qualia_client_core/wellfair/api/anatomy.rs
1//! 3D anatomy asset cache + physiological state
2
3use super::*;
4
5impl WebizenHostApi {
6 // --- 3D Anatomy asset cache (S5.8 — user-triggered real-mesh acquisition) -------------------
7 //
8 // The person triggers a download of the CCF/HRA reference-organ GLB set from the live SPARQL
9 // endpoint; the host fetches + compiles each to a sealed `.10d` and caches both under
10 // `{storage_root}/assets/ccf/{model}/`. Subsequent runs load the cached `.10d` directly — no
11 // re-download. The cache is the person's own, generated on demand.
12
13 /// Whether the body assets for a model are cached + complete (manifest exists + every referenced
14 /// `.10d` is on disk). `model` is `"male"` / `"female"` (case-insensitive).
15 pub fn body_assets_status(
16 &self,
17 model: &str,
18 ) -> Result<super::super::anatomy_assets::BodyAssetsStatus, String> {
19 let m = parse_anatomy_model(model)?;
20 Ok(super::super::anatomy_assets::status(&self.storage_root, m))
21 }
22
23 /// The cached organ keys for a model (empty if not cached).
24 pub fn cached_organ_keys(&self, model: &str) -> Result<Vec<String>, String> {
25 let m = parse_anatomy_model(model)?;
26 Ok(super::super::anatomy_assets::cached_organ_keys(
27 &self.storage_root,
28 m,
29 ))
30 }
31
32 /// Load a cached `.10d` for one organ. Returns the raw container bytes (for the browser portal's
33 /// `load_10d_colored`).
34 pub fn load_cached_organ_10d(&self, model: &str, organ_key: &str) -> Result<Vec<u8>, String> {
35 let m = parse_anatomy_model(model)?;
36 super::super::anatomy_assets::load_cached_10d(&self.storage_root, m, organ_key)
37 }
38
39 /// The per-organ dual-modality percepts for the cached organ set — so the browser portal knows what
40 /// colour to paint each organ (σ → RGBA via `paint_organs`). Returns `(painted, unmapped)`.
41 pub fn cached_body_organ_percepts(
42 &self,
43 model: &str,
44 ) -> Result<(Vec<super::super::anatomy_view::OrganPercept>, Vec<String>), String> {
45 let m = parse_anatomy_model(model)?;
46 let organ_keys = super::super::anatomy_assets::cached_organ_keys(&self.storage_root, m);
47 if organ_keys.is_empty() {
48 return Ok((Vec::new(), Vec::new()));
49 }
50 let report = self.compute_anatomy_view("person", 2)?;
51 let key_refs: Vec<&str> = organ_keys.iter().map(|s| s.as_str()).collect();
52 let (painted, unmapped) = report.paint_organs(&key_refs);
53 let fit = self.body_fit();
54 let painted = painted
55 .into_iter()
56 .filter(|p| !fit.hides(&p.organ_key))
57 .collect();
58 Ok((painted, unmapped))
59 }
60
61 /// The person's declared constitution, or an empty one if they have not authored it.
62 pub fn get_body_constitution(&self) -> wellfare_core::anatomy::BodyConstitution {
63 super::super::body_constitution::load(&self.storage_root).unwrap_or_default()
64 }
65
66 pub fn body_constitution_is_declared(&self) -> bool {
67 super::super::body_constitution::load(&self.storage_root).is_some()
68 }
69
70 pub fn set_body_constitution(
71 &self,
72 body: &wellfare_core::anatomy::BodyConstitution,
73 ) -> Result<(), String> {
74 super::super::body_constitution::save(&self.storage_root, body)
75 }
76
77 pub fn reset_body_constitution(&self) -> Result<(), String> {
78 super::super::body_constitution::clear(&self.storage_root)
79 }
80
81 /// View transform for the current constitution + physiological state.
82 pub fn body_fit(&self) -> wellfare_core::anatomy::BodyFit {
83 let constitution = self.get_body_constitution();
84 let phys = self.get_physiological_state();
85 super::super::body_constitution::fit_for(&constitution, &phys)
86 }
87
88 /// Clear the cache for a model (idempotent). The person can re-acquire later.
89 pub fn clear_body_cache(&self, model: &str) -> Result<(), String> {
90 let m = parse_anatomy_model(model)?;
91 super::super::anatomy_assets::clear_cache(&self.storage_root, m)
92 }
93
94 /// The accumulative, traceable **score-card** + investigable hypotheses over the person's own records —
95 /// the reading they can act on. Forum-internum / `Sanctuary`-class selfhood content; a set of
96 /// **hypotheses** and pathway-starts, never a diagnosis, never a rating. The card is computed at the
97 /// person's **declared physiological state** (their point on the reproductive continuum), or
98 /// [`PhysiologicalState::Baseline`] if they have not declared one.
99 pub fn compute_scorecard(
100 &self,
101 convergence_threshold: usize,
102 ) -> Result<super::super::anatomy_view::WellbeingScorecardReport, String> {
103 let conditions = self.list_journal_by_kind("condition", 256)?;
104 let medications = self.list_journal_by_kind("medication", 256)?;
105 let diet = self.list_journal_by_kind("diet", 256)?;
106 // Read the person through **their own** weight model — their authorship of how they're read — falling
107 // back to the seed *suggestion* only if they have not authored one.
108 let weights = self.get_weight_model();
109 // Read the person at **their declared physiological state** — their own statement of where they are
110 // on the reproductive continuum — falling back to Baseline if they have not declared one.
111 let state = self.get_physiological_state();
112 Ok(
113 super::super::anatomy_view::build_scorecard_report_from_journal_with_weights(
114 &conditions,
115 &medications,
116 &diet,
117 convergence_threshold,
118 &weights,
119 state,
120 ),
121 )
122 }
123
124 /// The person's own score-card **weight model** — the interpretive lens the card uses — or the seed
125 /// *suggestion* if they have not authored one. Theirs to see, edit, or reset; the software offers a
126 /// starting point, it does not *define* how they are read.
127 pub fn get_weight_model(&self) -> wellfare_core::anatomy::WeightModel {
128 super::super::scorecard_prefs::load(&self.storage_root)
129 .unwrap_or_else(wellfare_core::anatomy::seed_weight_model)
130 }
131
132 /// The seed **suggestion** on its own — so a UI can show "this is the starting point; here's yours" and
133 /// let the person compare / adopt / edit.
134 pub fn seed_weight_model(&self) -> wellfare_core::anatomy::WeightModel {
135 wellfare_core::anatomy::seed_weight_model()
136 }
137
138 /// Whether the person has **authored their own** model (vs. still using the seed suggestion).
139 pub fn weight_model_is_authored(&self) -> bool {
140 super::super::scorecard_prefs::load(&self.storage_root).is_some()
141 }
142
143 /// **Set the person's own** weight model — their authorship of how the score-card reads them.
144 pub fn set_weight_model(
145 &self,
146 model: &wellfare_core::anatomy::WeightModel,
147 ) -> Result<(), String> {
148 super::super::scorecard_prefs::save(&self.storage_root, model)
149 }
150
151 /// **Reset** to the seed suggestion (clears the person's authored model — a choice, always reversible by
152 /// re-authoring).
153 pub fn reset_weight_model(&self) -> Result<(), String> {
154 super::super::scorecard_prefs::clear(&self.storage_root)
155 }
156
157 // --- Physiological state (P6 — the reproductive-continuum declaration) -----------------------
158 //
159 // The person's own statement of where they are on the reproductive continuum — their inward knowledge
160 // of their own body. Forum-internum / Sanctuary-class. The score-card is computed at this state so it
161 // reads them at their current life stage, not a neutral baseline.
162
163 /// The person's **declared** physiological state, or [`PhysiologicalState::Baseline`] if they have not
164 /// declared one. Their own statement; the software never assumes.
165 pub fn get_physiological_state(&self) -> wellfare_core::anatomy::PhysiologicalState {
166 super::super::physiology_prefs::load(&self.storage_root)
167 .unwrap_or(wellfare_core::anatomy::PhysiologicalState::Baseline)
168 }
169
170 /// Whether the person has **declared** their physiological state (vs. still at the implicit baseline).
171 pub fn physiological_state_is_declared(&self) -> bool {
172 super::super::physiology_prefs::load(&self.storage_root).is_some()
173 }
174
175 /// **Set** the person's declared physiological state — their own statement of where they are on the
176 /// reproductive continuum. Forum-internum / Sanctuary-class.
177 pub fn set_physiological_state(
178 &self,
179 state: &wellfare_core::anatomy::PhysiologicalState,
180 ) -> Result<(), String> {
181 super::super::physiology_prefs::save(&self.storage_root, state)
182 }
183
184 /// **Clear** the declared state — revert to the implicit [`PhysiologicalState::Baseline`]. Idempotent.
185 pub fn reset_physiological_state(&self) -> Result<(), String> {
186 super::super::physiology_prefs::clear(&self.storage_root)
187 }
188}