From 4532b3cdc5baaacf30d9a641ad88322be6f86281 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 5 Jun 2026 10:20:11 +0000 Subject: [PATCH] docs(splat-native): address review feedback on #471 (5 fixes) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to PR #471 (merged). Addresses five reviewer findings from codex P2 and CodeRabbit Major/Minor: ## Fixes in this PR ### Fix 1 — StepDomain alignment (codex P2, plan §10.10) The §10.10 cross-repo coordination section referenced `StepDomain::{Codec, Thinking, Query, Semantic, Persistence, Inference, Learning}` as the "existing" shipped taxonomy. That is incorrect — the shipped contract at `crates/lance-graph-contract/src/orchestration.rs:37` defines exactly EIGHT variants: `Crew, Ladybug, N8n, LanceGraph, Ndarray, Smb, Medcare, Kanban`. Rewrites the paragraph to: (a) name the actual shipped variants verbatim with file:line citation; (b) state that `SplatFit/SplatRender` are NEW variants ADDED to the shipped enum (extends, not parallel); (c) declare the splat ingest route as `SplatFit → Ndarray → LanceGraph → Medcare`; (d) declare the `from_step_type` step-type prefixes (`splat_fit.*`, `splat_render.*`). ### Fix 2 — STATUS_BOARD canonical status (CodeRabbit Major) The 14 D-SPLAT-* rows had Status values like `**Queued — P1 sprint 1-2**` that mixed the canonical status enum (`Queued | In progress | In PR | Shipped`) with sprint timing. Adds a dedicated `Sprint` column; Status now holds only `**Queued**` (canonical) for each row. Table header updated; all 14 row cells split. ### Fix 3 — `pose_se3` byte width 16 → 24 (CodeRabbit Major) The lance-graph plan's `Gaussian3D` carrier showed `pose_se3: FixedSizeBinary(16)` while describing a payload of 3 translation + 9 rotation entries in `f16` = 12 × 2 = 24 bytes. Corrects to `FixedSizeBinary(24)` and annotates the byte arithmetic inline. Companion fix landing in `MedCare-rs/.claude/handovers/ 2026-06-05-splat-native-medcare-hipaa-wire.md`. ### Fix 4 — PHI classification normative rule (CodeRabbit Major) Lines 268 and 443 stated mutually contradictory positions on whether splat coordinates carry PHI. Introduces a single normative rule **NR-SPLAT-PHI** at §3.10 and references it from: - §3.10 (raw RF/IQ paragraph) - §7 risk-matrix row "HIPAA PHI leak via splat coordinates" (downgraded HIGH→MEDIUM since coordinates per NR-SPLAT-PHI are non-identifying on their own) - §8 success-criteria sole-writer paragraph The rule: > Scanner-frame splat geometry (the `mu`/`sigma_packed` columns; > `pose_se3` in scanner frame) is non-identifying on its own. > The link between `patient_ref` and a splat volume — i.e. the row > in `memory.ultrasound_frame.lance` — IS PHI. > Atlas-aligned annotations that name patient-specific landmarks > (e.g. `class_id` resolving to "this patient's left biceps > brachii at scanner-pose P") ARE PHI. > Raw RF/IQ is PHI by default and is never persisted (it does not > enter the MedCare wire). ### Fix 5 — MD040 fenced-code language tags (CodeRabbit Minor) Adds `text` language identifier to the two unlabeled opening fences: - `## 5. Dependencies graph (textual)` (was line 403) - `## 10.8 The interconnect map (visual)` (was line 659) ### Bonus consistency fix — IVD-MDR → MDR Annex VIII Rule 11 D-SPLAT-14 row + plan footer cited "IVD-MDR Rule 11" which is the wrong regulation (IVDR is for in-vitro diagnostics). For ultrasound SaMD the correct citation is **MDR Annex VIII Rule 11**. Same correction landing in OGAR follow-up PR (closes codex P2 there). ## What's NOT in this PR - Source code: still none. Plan-spec only. - The `pose_se3` companion fix in `MedCare-rs/.claude/handovers/...` ships as a separate PR (per cross-repo coordination protocol). - The IVD-MDR consistency fix in OGAR `docs/SPLAT-NATIVE-CUSTOMER.md` ships as a separate PR. - The ndarray opacity-blend ray-segmentation + Mahalanobis scratch-buf fixes ship as a separate PR. ## Test plan - [x] Plan file passes markdown lint (MD040 cleared on both fences). - [x] STATUS_BOARD canonical-status invariant restored (only `Queued | In progress | In PR | Shipped` appear in Status column). - [x] StepDomain text cites the actual shipped enum (`orchestration.rs:37` verified pre-edit). - [x] NR-SPLAT-PHI declared once, referenced from three other sections. - [x] `pose_se3` byte-arithmetic consistent (24 B = 12 × `f16`). - [ ] Codex + CodeRabbit re-review on this PR. --- .claude/board/STATUS_BOARD.md | 32 ++++++++++----------- .claude/plans/splat-native-ultrasound-v1.md | 18 ++++++------ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 297549f7..ae0017ee 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -2,22 +2,22 @@ Plan path: `.claude/plans/splat-native-ultrasound-v1.md`. Companions: ndarray `.claude/plans/splat-native-ultrasound-simd-substrate-v1.md`; OGAR `docs/SPLAT-NATIVE-CUSTOMER.md`; MedCare-rs `.claude/handovers/2026-06-05-splat-native-medcare-hipaa-wire.md`. Customer of OGAR PR #30 §6 FMA bones-rendering litmus + ADR-022 SaMD audit-controls evidence base. -| D-id | Title | Crate(s) / repo | ~LOC | Risk | Status | PR / Evidence | -|---|---|---|---|---|---|---| -| D-SPLAT-1 | `Gaussian3D` carrier (`mu`/`sigma_packed`/`amplitude`/`opacity`/`sh[16]`/`frame_idx`/`class_id`; 80 B/row) | `lance-graph-contract::splat` | 120 | LOW | **Queued — P1 sprint 1-2** | gates on `MailboxSoAHeader` (D-MBX-10) or own feature flag | -| D-SPLAT-2 | `ndarray::simd::splat` batch ops — `batched_cholesky_3x3` / `batched_mahalanobis` / `batched_opacity_blend` / `batched_sh_eval_l3` / `batched_se3_transform`; all three backends (AVX-512/NEON/scalar) | `ndarray::src/simd_splat.rs` | 600 | MED | **Queued — P1 sprint 1-2** | foundation; none | -| D-SPLAT-3 | `SplatBatch` SoA carrier (per-column slices for SIMD sweep; inherits MailboxSoAHeader versioning) | `lance-graph-contract::splat` | 150 | LOW | **Queued — P1 sprint 1-2** | gates on D-SPLAT-1 | -| D-SPLAT-4 | SH-aware palette extension in `crates/bgz17` (256×256×2B compose table; SH-basis-id per centroid) | `bgz17::sh_palette` | 250 | MED | **Queued — P3 sprint 4-5** | gates on D-SPLAT-1 | -| D-SPLAT-5 | Splat-to-splat registration math — Σ-sandwich Mahalanobis ICP + SE(3) Levenberg-Marquardt | `lance-graph::splat::registration` | 400 | HIGH | **Queued — P4 sprint 6-7** | gates on D-SPLAT-2 + D-SPLAT-3 | -| D-SPLAT-6 | `crates/splat-fit` engine — RF/IQ → beamformed → local-maxima → PSF estimate → SH projection → emit Gaussian3D batch | `crates/splat-fit` (new standalone, 0-dep, ndarray-hpc feature) | 1500 | HIGH | **Queued — P2 sprint 3** | gates on D-SPLAT-1 + D-SPLAT-2 + OQ-SPLAT-3 | -| D-SPLAT-7 | Splat actors — `SplatFitActor`/`PoseAccumulatorActor`/`RegistrationActor`, each owns one `MailboxSoA`; consumes bardioc #17 Rubicon kanban verbatim | `crates/splat-actors` (or `ractor_actors`) | 500 | MED | **Queued — P3 sprint 4-5** | gates on D-SPLAT-3 + D-SPLAT-6 + bardioc #17 (shipped) | -| D-SPLAT-8 | FMA atlas hydrator — TTL → `fma_class.lance` + `fma_relation.lance` + `fma_atlas_splat.lance` (~150M Gaussians full body) | `lance-graph-ontology` + `crates/fma-hydrator` | 800 | HIGH | **Queued — P4 sprint 7-8** | gates on OGAR PR #30 Phase 8 + D-SPLAT-3 + ndarray PR #189 (shipped) | -| D-SPLAT-9 | `fma_blueprint::style_recipe` D-Atom catalogue (AnatomicalRegion, OrganSystem, Innervation, Vasculature, Joint, Muscle, Bone, OrganParenchyma, Tract); mirrors PR #433 Odoo pattern | `lance-graph-ontology::fma_blueprint` | 400 | LOW | **Queued — P4 sprint 7-8** | gates on D-SPLAT-8 | -| D-SPLAT-10 | `memory.ultrasound_frame.lance` + `memory.ultrasound_splat.lance` datasets via `soa_mapping.rs`; new `SensitivityReason::UltrasoundRawPHI`/`UltrasoundAnonymized` variants in `column_mask_bridge` | MedCare-rs `crates/medcare-analytics` | 250 | MED | **Queued — P5 sprint 9-10** | gates on D-SPLAT-3 + MedCare PR #162 (shipped) | -| D-SPLAT-11 | `commit_event` audit chain for splat ingest via `LanceMembrane::commit_event` (callcenter PR #467, sole-writer membrane); `KnowableFromStore::register("ogit-medcare/ultrasound_ingest", Some(ddl_hint))` | MedCare-rs `crates/medcare-analytics` | 100 | LOW | **Queued — P5 sprint 9-10** | gates on D-SPLAT-10 + PR #467 (shipped) + OGAR #25/#31 (shipped) | -| D-SPLAT-12 | AR splat renderer — HoloLens OpenXR (clinical AR target) + Cesium ion + Three.js (browser fallback) + headless PNG (regression); CPU does math, GPU only paints | `crates/splat-render` (new) | 1200 | HIGH | **Queued — P6 sprint 11-13** | gates on D-SPLAT-2 + D-SPLAT-3 + D-SPLAT-5 | -| D-SPLAT-13 | IMU/POSE 4D accumulator — VIO against splat features at IMU rate (~200 Hz); splat-corrected pose at frame rate (~30 Hz); Planning-column readiness at t = −550ms | `splat-actors::PoseAccumulatorActor` | 200 | MED | **Queued — P3 sprint 4-5** | gates on D-SPLAT-7 | -| D-SPLAT-14 | SaMD documentation track — research-tool → clinical-study → Class IIa (IEC 62366 / IEC 80001 / ISO 14971 / IVD-MDR Rule 11). ADR-022 firewall IS the audit-controls evidence base | `q2`/`quarto` or `docs/` | 600 | LOW | **Queued — P7 sprint 14+ (parallel through P4-P6)** | gates on none architecturally; v1/v2/v3 phased | +| D-id | Title | Crate(s) / repo | ~LOC | Risk | Sprint | Status | PR / Evidence | +|---|---|---|---|---|---|---|---| +| D-SPLAT-1 | `Gaussian3D` carrier (`mu`/`sigma_packed`/`amplitude`/`opacity`/`sh[16]`/`frame_idx`/`class_id`; 80 B/row) | `lance-graph-contract::splat` | 120 | LOW | P1 sprint 1-2 | **Queued** | gates on `MailboxSoAHeader` (D-MBX-10) or own feature flag | +| D-SPLAT-2 | `ndarray::simd::splat` batch ops — `batched_cholesky_3x3` / `batched_mahalanobis` / `batched_opacity_blend` / `batched_sh_eval_l3` / `batched_se3_transform`; all three backends (AVX-512/NEON/scalar) | `ndarray::src/simd_splat.rs` | 600 | MED | P1 sprint 1-2 | **Queued** | foundation; none | +| D-SPLAT-3 | `SplatBatch` SoA carrier (per-column slices for SIMD sweep; inherits MailboxSoAHeader versioning) | `lance-graph-contract::splat` | 150 | LOW | P1 sprint 1-2 | **Queued** | gates on D-SPLAT-1 | +| D-SPLAT-4 | SH-aware palette extension in `crates/bgz17` (256×256×2B compose table; SH-basis-id per centroid) | `bgz17::sh_palette` | 250 | MED | P3 sprint 4-5 | **Queued** | gates on D-SPLAT-1 | +| D-SPLAT-5 | Splat-to-splat registration math — Σ-sandwich Mahalanobis ICP + SE(3) Levenberg-Marquardt | `lance-graph::splat::registration` | 400 | HIGH | P4 sprint 6-7 | **Queued** | gates on D-SPLAT-2 + D-SPLAT-3 | +| D-SPLAT-6 | `crates/splat-fit` engine — RF/IQ → beamformed → local-maxima → PSF estimate → SH projection → emit Gaussian3D batch | `crates/splat-fit` (new standalone, 0-dep, ndarray-hpc feature) | 1500 | HIGH | P2 sprint 3 | **Queued** | gates on D-SPLAT-1 + D-SPLAT-2 + OQ-SPLAT-3 | +| D-SPLAT-7 | Splat actors — `SplatFitActor`/`PoseAccumulatorActor`/`RegistrationActor`, each owns one `MailboxSoA`; consumes bardioc #17 Rubicon kanban verbatim | `crates/splat-actors` (or `ractor_actors`) | 500 | MED | P3 sprint 4-5 | **Queued** | gates on D-SPLAT-3 + D-SPLAT-6 + bardioc #17 (shipped) | +| D-SPLAT-8 | FMA atlas hydrator — TTL → `fma_class.lance` + `fma_relation.lance` + `fma_atlas_splat.lance` (~150M Gaussians full body) | `lance-graph-ontology` + `crates/fma-hydrator` | 800 | HIGH | P4 sprint 7-8 | **Queued** | gates on OGAR PR #30 Phase 8 + D-SPLAT-3 + ndarray PR #189 (shipped) | +| D-SPLAT-9 | `fma_blueprint::style_recipe` D-Atom catalogue (AnatomicalRegion, OrganSystem, Innervation, Vasculature, Joint, Muscle, Bone, OrganParenchyma, Tract); mirrors PR #433 Odoo pattern | `lance-graph-ontology::fma_blueprint` | 400 | LOW | P4 sprint 7-8 | **Queued** | gates on D-SPLAT-8 | +| D-SPLAT-10 | `memory.ultrasound_frame.lance` + `memory.ultrasound_splat.lance` datasets via `soa_mapping.rs`; new `SensitivityReason::UltrasoundRawPHI`/`UltrasoundAnonymized` variants in `column_mask_bridge` | MedCare-rs `crates/medcare-analytics` | 250 | MED | P5 sprint 9-10 | **Queued** | gates on D-SPLAT-3 + MedCare PR #162 (shipped) | +| D-SPLAT-11 | `commit_event` audit chain for splat ingest via `LanceMembrane::commit_event` (callcenter PR #467, sole-writer membrane); `KnowableFromStore::register("ogit-medcare/ultrasound_ingest", Some(ddl_hint))` | MedCare-rs `crates/medcare-analytics` | 100 | LOW | P5 sprint 9-10 | **Queued** | gates on D-SPLAT-10 + PR #467 (shipped) + OGAR #25/#31 (shipped) | +| D-SPLAT-12 | AR splat renderer — HoloLens OpenXR (clinical AR target) + Cesium ion + Three.js (browser fallback) + headless PNG (regression); CPU does math, GPU only paints | `crates/splat-render` (new) | 1200 | HIGH | P6 sprint 11-13 | **Queued** | gates on D-SPLAT-2 + D-SPLAT-3 + D-SPLAT-5 | +| D-SPLAT-13 | IMU/POSE 4D accumulator — VIO against splat features at IMU rate (~200 Hz); splat-corrected pose at frame rate (~30 Hz); Planning-column readiness at t = −550ms | `splat-actors::PoseAccumulatorActor` | 200 | MED | P3 sprint 4-5 | **Queued** | gates on D-SPLAT-7 | +| D-SPLAT-14 | SaMD documentation track — research-tool → clinical-study → Class IIa (IEC 62366 / IEC 80001 / ISO 14971 / MDR Annex VIII Rule 11). ADR-022 firewall IS the audit-controls evidence base | `q2`/`quarto` or `docs/` | 600 | LOW | P7 sprint 14+ (parallel through P4-P6) | **Queued** | gates on none architecturally; v1/v2/v3 phased | --- diff --git a/.claude/plans/splat-native-ultrasound-v1.md b/.claude/plans/splat-native-ultrasound-v1.md index 9d717ffa..3cb2bf93 100644 --- a/.claude/plans/splat-native-ultrasound-v1.md +++ b/.claude/plans/splat-native-ultrasound-v1.md @@ -259,13 +259,13 @@ New SoA mapping entry per the existing pattern in `soa_mapping.rs`. Columns: - `patient_ref: FixedSizeBinary(8)` — anonymized patient ID (per `column_mask_bridge` Hash mode for unauthorized roles) - `frame_idx: u32` — monotonic frame counter - `acquisition_ts: TimestampMicros` — frame acquisition time -- `pose_se3: FixedSizeBinary(16)` — packed SE(3) pose (3 translation + 9 rotation matrix, both `f16`) +- `pose_se3: FixedSizeBinary(24)` — packed SE(3) pose (3 translation + 9 rotation matrix, both `f16`; 12 × 2 = 24 B) - `splat_batch_handle: Binary` — pointer into the splat-volume storage (NOT the splats themselves; those live in `ultrasound_splat.lance` to keep this table queryable) - `splat_count: u32` - `mean_amplitude: f32` - `quality_score: f32` — ICP residual after registration; below threshold ⇒ frame is pruned (kanban col 4) -**Raw RF/IQ stays out of MedCare-rs entirely** — only fitted splats land. PHI is in the splat coordinates + atlas-aligned annotations, not in the raw signal. The `column_mask_bridge` extension adds: +**Raw RF/IQ stays out of MedCare-rs entirely** — only fitted splats land. Per **NR-SPLAT-PHI** (normative rule, see below): scanner-frame splat geometry is non-identifying on its own; the link `patient_ref ↔ splat_volume` in `memory.ultrasound_frame.lance` IS PHI; atlas-aligned anatomical annotations carrying patient-specific landmarks ARE PHI. The `column_mask_bridge` extension adds: ```rust pub enum SensitivityReason { @@ -283,6 +283,8 @@ pub enum SensitivityReason { **Owner:** `MedCare-rs` (`crates/medcare-analytics`). **~100 LOC + tests.** **Risk: LOW.** +**NR-SPLAT-PHI (normative rule, single source of truth):** *Scanner-frame splat geometry (the `mu`/`sigma_packed` columns; `pose_se3` in scanner frame) is non-identifying on its own. The link between `patient_ref` and a splat volume — i.e. the row in `memory.ultrasound_frame.lance` — IS PHI. Atlas-aligned annotations that name patient-specific landmarks (e.g. `class_id` resolving to "this patient's left biceps brachii at scanner-pose P") are PHI. Raw RF/IQ is PHI by default and is never persisted (it does not enter the MedCare wire). All §3.10 (`column_mask_bridge`) and §7 (risk-matrix HIPAA row) policy decisions cite this rule.* + Every splat ingest writes one `CognitiveEventRow` via `LanceMembrane::commit_event` (callcenter PR #467, the sole-writer membrane). Carries: `actor` (the `SplatFitActor`), `action: "ultrasound_ingest"`, `target_class: "memory.ultrasound_frame"`, `target_row_id`, `version` (the Lance row-version from `KnowableFromStore::register`), `subject` (clinician identity), `consent_evidence` (the patient consent chain). Inner-side; no JSONL audit sink (per MedCare CLAUDE.md Iron Rule 7). **Tests:** every ingest produces exactly one `CognitiveEventRow`; row-version monotonic; consent-chain non-empty. @@ -400,7 +402,7 @@ Three docs: ## 5. Dependencies graph (textual) -``` +```text OGAR #30 Phase 8 (FMA hydrate prep) ─────────┐ ▼ ndarray D-SPLAT-2 (SIMD splat ops) ──► D-SPLAT-8 (FMA atlas) ──┐ @@ -440,7 +442,7 @@ D-SPLAT-4 (SH palette) ─────────────────── | FMA atlas splat pre-computation too large (~5 GB) | MED | Region-on-demand loading (per OQ-SPLAT-X); only the regions matching `class_id` of fitted live splats need to be paged in. Lance versioning + `KnowableFromStore` registry handles the on-demand path. | | Registration convergence basin too narrow (live ≠ atlas anatomy) | HIGH | Coarse-to-fine multi-resolution ICP (lower SH degree first); patient-specific atlas pre-registration during clinical-study phase. | | HoloLens OpenXR compute budget exhausted | MED | Render-at-IMU-rate (200 Hz) is not required; render-at-frame-rate (30 Hz) is. Backpressure via the renderer mailbox. | -| HIPAA PHI leak via splat coordinates | HIGH | Splat coordinates are in *scanner frame*, not patient-identifying frame. Patient identity stays in `patient_ref` (Hashed for non-clinical roles per `column_mask_bridge`). | +| HIPAA PHI leak via splat coordinates | MEDIUM | Per **NR-SPLAT-PHI** (§3.10): scanner-frame splat coordinates are non-identifying on their own; PHI lives in the `patient_ref ↔ splat_volume` link and in atlas-aligned annotations carrying patient-specific landmarks. Default `column_mask_bridge` mode for `patient_ref` is `Hash` for non-clinical roles; splat coordinate columns require no masking. | | SaMD Class IIa technical-file gap | MED | Build the audit-controls evidence chain during P5 (HIPAA wire); the chain IS the certification evidence base. | --- @@ -600,7 +602,7 @@ This plan touches **seven repositories**. Each owns a piece of the splat-native **Critical interconnect:** - **Raw RF/IQ NEVER enters MedCare storage** — verified by `grep` audit. This is a hard invariant (Iron Rule 7 + Iron Rule from MedCare CLAUDE.md): audit witness stays inner; raw signal stays at the splat-fit boundary; only fitted Gaussians cross into MedCare. - The MedCare ultrasound dataset is **append-only from the SplatFitActor's perspective** — the actor is the sole writer; MedCare only reads + redacts on query. This preserves the sole-writer membrane discipline from PR #467. -- The patient-identity boundary is `patient_ref` only; splat coordinates are in *scanner frame*, not patient-identifying frame. No PHI in the geometry itself. +- Per **NR-SPLAT-PHI** (§3.10): the patient-identity boundary is the `patient_ref ↔ splat_volume` LINK (Hashed for non-clinical roles); splat coordinates are in *scanner frame* and are not patient-identifying on their own; atlas-aligned annotations carrying patient-specific landmarks ARE PHI and inherit `patient_ref`'s sensitivity class via foreign-key join. **Sprint commitment:** sprint 9-10 (P5, after FMA atlas + registration land upstream). 1 PR (D-SPLAT-10 + D-SPLAT-11 bundled). @@ -656,7 +658,7 @@ This plan touches **seven repositories**. Each owns a piece of the splat-native ## 10.8 The interconnect map (visual) -``` +```text ┌──────────────────────────────────────────┐ │ ndarray (D-SPLAT-2) │ │ SIMD substrate: Cholesky, Mahalanobis, │ @@ -750,11 +752,11 @@ This plan touches **seven repositories**. Each owns a piece of the splat-native Per the workspace's standing autoattend pattern + lance-graph's two-layer A2A discipline: -**Layer-1 (runtime / code-level):** the `OrchestrationBridge` + `StepDomain` taxonomy already handles cross-domain dispatch. Splat-native adds two `StepDomain` variants: +**Layer-1 (runtime / code-level):** the `OrchestrationBridge` + `StepDomain` taxonomy already handles cross-domain dispatch. The shipped contract (`crates/lance-graph-contract/src/orchestration.rs:37`) defines exactly eight variants: `Crew, Ladybug, N8n, LanceGraph, Ndarray, Smb, Medcare, Kanban`. Splat-native lands as **two new `StepDomain` variants ADDED to that shipped enum** (extending the single-source-of-truth taxonomy, not parallel to it): - `StepDomain::SplatFit` (the engine consumes RF/IQ → emits SoA) - `StepDomain::SplatRender` (the renderer consumes SoA → emits pixels) -These compose with existing `StepDomain::{Codec, Thinking, Query, Semantic, Persistence, Inference, Learning}` per OrchestrationBridge contract. +These compose with the existing variants per the `from_step_type` dispatch — splat ingest routes `SplatFit → Ndarray → LanceGraph → Medcare` (fit → SIMD → registration → HIPAA wire); splat render routes `SplatRender ← LanceGraph` (read-only consumer). The two new variants land in the same PR as D-SPLAT-1 (`Gaussian3D` carrier) so the contract stays single source of truth. **Step-type prefixes** for `from_step_type`: `splat_fit.*` → `SplatFit`, `splat_render.*` → `SplatRender`. **Layer-2 (session / Claude-code-level):** each per-repo doc has a `READ BY:` header naming which session-tier agents bootload it: