From a6d8d568dd2a649024d97845a281be1c5c5abb90 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 11 Jun 2026 23:44:06 +0000 Subject: [PATCH] V_epsilon: author did_v1 active-conversion docs for deprecated families Document the direct did_v1 -> V_epsilon active conversion of the five deprecated families (the team retargeted the pipeline straight to V_epsilon rather than adding a V_delta -> V_epsilon pass). Each doc is the authoritative routing/field-mapping reference for its DID-matlab migrator: - treatment.md - the split routing table (thermal/procedural/ environmental + Dab target-location + numeric companion; non-manipulation records quarantine) - treatment_drug.md - -> injection (kind=drug) - virus_injection.md - -> injection (kind=virus) - treatment_transfer.md - -> biological_transfer - subject_group.md - -> subject(is_group) + group_assignment - stimulus_bath.md - re-rooted under bath Update _index.md with the active subject_interaction-family conversion table and V_epsilon_notes.md to record the decision and remaining work. https://claude.ai/code/session_01F737KLMaAzotg1uXeZFQuX --- .../conversions/from_did_v1/_index.md | 19 +- .../conversions/from_did_v1/stimulus_bath.md | 60 +++++ .../conversions/from_did_v1/subject_group.md | 58 +++++ .../conversions/from_did_v1/treatment.md | 232 +++++------------- .../conversions/from_did_v1/treatment_drug.md | 62 +++++ .../from_did_v1/treatment_transfer.md | 65 +++++ .../from_did_v1/virus_injection.md | 61 +++++ schemas/V_epsilon_notes.md | 23 +- 8 files changed, 402 insertions(+), 178 deletions(-) create mode 100644 schemas/V_epsilon/conversions/from_did_v1/stimulus_bath.md create mode 100644 schemas/V_epsilon/conversions/from_did_v1/subject_group.md create mode 100644 schemas/V_epsilon/conversions/from_did_v1/treatment_drug.md create mode 100644 schemas/V_epsilon/conversions/from_did_v1/treatment_transfer.md create mode 100644 schemas/V_epsilon/conversions/from_did_v1/virus_injection.md diff --git a/schemas/V_epsilon/conversions/from_did_v1/_index.md b/schemas/V_epsilon/conversions/from_did_v1/_index.md index 453d264..5a57baf 100644 --- a/schemas/V_epsilon/conversions/from_did_v1/_index.md +++ b/schemas/V_epsilon/conversions/from_did_v1/_index.md @@ -44,10 +44,27 @@ field-level changes on top. | `hartley_reverse_correlation` | NDIcalc-vis-matlab `neuro/hartley_reverse_correlation` | drafted | [hartley_reverse_correlation.md](hartley_reverse_correlation.md) | | `hartley_calc` | NDIcalc-vis-matlab `calc/hartley_calc` | drafted | [hartley_calc.md](hartley_calc.md) | | `probe_location` | legacy NDI/DID `probe_location` (V_alpha shape) | drafted | [probe_location.md](probe_location.md) | -| `treatment` | legacy NDI/DID `treatment` (V_alpha shape) | drafted | [treatment.md](treatment.md) | | `ontology_image` | legacy NDI/DID `ontologyImage` (V_alpha shape) | drafted | [ontology_image.md](ontology_image.md) | | `ontology_label` | legacy NDI/DID `ontologyLabel` (V_alpha shape) | drafted | [ontology_label.md](ontology_label.md) | +## V_epsilon subject_interaction-family conversions (active) + +V_epsilon converts the five deprecated families **actively** into the new +observation / manipulation / annotation classes (not passively into their +deprecated shapes). These conversions fan out — one did_v1 document can +mint several V_epsilon documents (a manipulation plus a `time_reference`, +a `subject` plus a `group_assignment`, etc.). They are implemented in +DID-matlab's `+did2/+convert/+migrators/`. + +| did_v1 source | V_epsilon target(s) | Status | Doc | +|---|---|---|---| +| `treatment` | `temperature_` / `procedural_` / `environmental_manipulation` (+ companion `generic_scalar_observation`) | applied-in-tooling | [treatment.md](treatment.md) | +| `treatment_drug` | `injection` (kind=drug) (+ `utc_reference`) | applied-in-tooling | [treatment_drug.md](treatment_drug.md) | +| `virus_injection` | `injection` (kind=virus) (+ `utc_reference`) | applied-in-tooling | [virus_injection.md](virus_injection.md) | +| `treatment_transfer` | `biological_transfer` (+ `utc_reference`) | applied-in-tooling | [treatment_transfer.md](treatment_transfer.md) | +| `subject_group` | `subject` (is_group) (+ `group_assignment`) | applied-in-tooling | [subject_group.md](subject_group.md) | +| `stimulus_bath` | `stimulus_bath` v2 (re-rooted under `bath`) | applied-in-tooling | [stimulus_bath.md](stimulus_bath.md) | + ## Notes - **Not migrated:** `stimloopsplitter_calc` (deprecated per domain owner diff --git a/schemas/V_epsilon/conversions/from_did_v1/stimulus_bath.md b/schemas/V_epsilon/conversions/from_did_v1/stimulus_bath.md new file mode 100644 index 0000000..1f56619 --- /dev/null +++ b/schemas/V_epsilon/conversions/from_did_v1/stimulus_bath.md @@ -0,0 +1,60 @@ +# Conversion: did_v1 → V_epsilon — `stimulus_bath` (re-rooted under `bath`) + +## Identity + +- **V_epsilon target class:** `stimulus_bath` (v2.0.0), now a concrete + subclass of `bath` (← `pharmacological_manipulation` ← `manipulation` + ← `subject_interaction`). Moved from `stable/` to `draft/`. +- **V_epsilon tier:** `draft` +- **did_v1 source:** + `ndi_common/schema_documents/stimulus/stimulus_bath_schema.json`: + `location` (structure), `mixture_table` (CSV); superclasses + `[base, epochid]`; depends_on `stimulus_element_id` (req). +- **Status:** `applied-in-tooling` + (`DID-matlab/+did2/+convert/+migrators/stimulus_bath.m`) + +## Summary + +V_epsilon re-roots `stimulus_bath` into the pharmacological-manipulation +tree. The legacy `epochid` superclass is dropped (timing now lives in +`time_reference` documents). Fields redistribute across the inherited +blocks; the migration is 1:1 (no companion) because the legacy class +carries neither a subject nor a wall-clock time. + +## Field mapping + +| did_v1 field | V_epsilon field | Transformation | +|---|---|---| +| `mixture_table` | `pharmacological_manipulation.mixture` | CSV → records `{chemical, amount:concentration}`; empty ⇒ one blank backfill record | +| `location` | `bath.location` | `{ontologyNode→node, name}` | +| — | `bath.kind` | constant `"drug"` default (legacy has no kind; backfill vehicle/wash/tracer) | +| `stimulus_element_id` | `stimulus_element_id` | carried | +| (epochid fields) | — | dropped; timing → `time_reference` (backfill) | +| — | `subject_id` | omitted — legacy carries no subject; backfill | + +## Default values for new fields + +`bath.kind = "drug"`; `stimulus_bath` block is empty (no own fields). +`subject_id` and `time_reference` dependencies are omitted (the did2 +validator enforces field/block shape, not depends_on cardinality), and +flagged for curator backfill. + +## Worked example + +`stimulus_bath` (location LGN, one-row `mixture_table` for a blocker, +`stimulus_element_id → E`) → `stimulus_bath` v2 with `mixture` on the +`pharmacological_manipulation` block, `bath.location = LGN`, +`bath.kind = "drug"`, and `stimulus_element_id → E`. + +## Open questions + +- `bath.kind` defaulting to `"drug"` is a heuristic; wash/vehicle baths + need curator confirmation. +- Whether `stimulus_bath` should also gain a `stimulus_presentation` + link (vs the bare `stimulus_element_id`) is open in `Bath_Proposal.md`. + +## Cross-references + +- `Bath_Proposal.md`, `Injection_Proposal.md` +- Migrator: `DID-matlab/src/did/+did2/+convert/+migrators/stimulus_bath.m` +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_epsilon/conversions/from_did_v1/subject_group.md b/schemas/V_epsilon/conversions/from_did_v1/subject_group.md new file mode 100644 index 0000000..9e14106 --- /dev/null +++ b/schemas/V_epsilon/conversions/from_did_v1/subject_group.md @@ -0,0 +1,58 @@ +# Conversion: did_v1 → V_epsilon — `subject_group` → `subject` + `group_assignment` + +## Identity + +- **V_epsilon target classes:** `subject` (with `is_group = true`) and, + when a member is named, a companion `group_assignment`. + `subject_group` moves to `deprecated/`. +- **V_epsilon tier:** `stable` (`subject`), `draft` (`group_assignment`), + `deprecated` (`subject_group`) +- **did_v1 source:** + `ndi_common/schema_documents/subject_group_schema.json`: no fields; + depends_on `subject_id` (opt) — an optional member reference. +- **Status:** `applied-in-tooling` + (`DID-matlab/+did2/+convert/+migrators/subject_group.m`) + +## Summary + +With `subject` carrying `is_group`, the standalone `subject_group` +identity class is redundant (`Placement_and_Group_Assignment_Proposal.md` +§2). The migration rewrites the group into a `subject{is_group:true}`, +**carrying the legacy `base.id` forward so references to the group still +resolve**, and re-expresses any named member as an event-sourced +`group_assignment`. + +## Field mapping + +| did_v1 field | V_epsilon field | Transformation | +|---|---|---| +| (identity) | `subject` document | `base.id` carried; `subject.is_group = true`, `is_biological = false`, `local_identifier`/`description` empty | +| depends_on `subject_id` (member) | companion `group_assignment` | `group_assignment.depends_on`: `subject_id` = the member, `group_id` = the new subject's `base.id` | +| — | `group_assignment.batch_id` | empty | +| — | `group_assignment.time_reference_#` | omitted — legacy has no assignment time; backfill | + +## Default values for new fields + +`subject.is_group = true` (the whole point), `is_biological = false`. The +`subject` keeps the legacy `base.id` and `session_id`; the +`group_assignment` mints a fresh id and shares the `session_id`. + +## Worked example + +`subject_group` (id `G`, member `M`) → `subject{is_group:true}` with +`base.id = G`, plus `group_assignment{subject_id:M, group_id:G}`. + +## Open questions + +- The real legacy `subject_group` carries at most one optional member; a + group with many members was represented by many `subject_group` docs or + by member-side links. Multi-member groups may need a corpus-specific + pass to mint one `group_assignment` per member. +- "Migrate-then-tighten": `group_assignment.group_id` targets `subject`; + the migration must complete before any tightening of that reference. + +## Cross-references + +- `Placement_and_Group_Assignment_Proposal.md` §2, `Subject_Document_Proposal.md` +- Migrator: `DID-matlab/src/did/+did2/+convert/+migrators/subject_group.m` +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_epsilon/conversions/from_did_v1/treatment.md b/schemas/V_epsilon/conversions/from_did_v1/treatment.md index 5929481..329f68e 100644 --- a/schemas/V_epsilon/conversions/from_did_v1/treatment.md +++ b/schemas/V_epsilon/conversions/from_did_v1/treatment.md @@ -1,187 +1,83 @@ -# Conversion: did_v1 → V_delta — `treatment` +# Conversion: did_v1 → V_epsilon — `treatment` (split) ## Identity -- **V_delta `class_name`:** `treatment` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/treatment.json` -- **did_v1 source:** legacy NDI/DID `treatment` document type - (`_classname: "treatment"`). Schema-shape ancestor in this repository - is `schemas/V_alpha/treatment.json`; `schemas/V_beta/treatment.json` - is the same shape with naming-convention housekeeping applied - (`ontologyName` → `ontology_name`). -- **Status:** `drafted` +- **V_epsilon target classes:** `temperature_manipulation`, + `procedural_manipulation`, `environmental_manipulation` (plus a + companion `generic_scalar_observation` when a numeric value is + present). `treatment` itself moves to `deprecated/`. +- **V_epsilon tier:** `draft` (targets); `deprecated` (`treatment`) +- **did_v1 source:** legacy NDI/DID `treatment` + (`ndi_common/schema_documents/treatment_schema.json`): fields + `ontologyName`, `name`, `numeric_value` (matrix), `string_value`; + depends_on `subject_id` (req), `manipulation_id` (opt), + `protocol_id` (opt). +- **Status:** `applied-in-tooling` + (`DID-matlab/+did2/+convert/+migrators/treatment.m`) ## Summary -`treatment` records a treatment applied to a subject (drug, stimulation, -etc.) keyed by ontology term and carrying an optional numeric value and -an optional free-form string value. did_v1 stored the ontology identity -as a pair of `char` fields (`ontologyName` + `name`); V_delta collapses -those into a single `treatment_name` field of the `ontology_term` -composite type. The `numeric_value` and `string_value` fields carry over -unchanged. - -## Field mapping - -Beyond these fields, the universal renames listed in -[`_universal_renames.md`](_universal_renames.md) apply (snake-case -ontology-annotation reshape, superclass-reference reshape, class-scoped -property block keyed by `treatment`). - -| did_v1 field | V_delta field | Transformation | Notes | -|---|---|---|---| -| `treatment.ontologyName` (char) | `treatment.treatment_name.node` | composed into `ontology_term`; snake-case rename of the carrier field | CURIE. See "Transformations in detail". | -| `treatment.name` (char) | `treatment.treatment_name.name` | composed into `ontology_term` | Human-readable label snapshot. | -| — | `treatment.treatment_name` (ontology_term) | new composite field | Created by composing the two did_v1 chars above. | -| `treatment.numeric_value` (matrix) | `treatment.numeric_value` (matrix) | identity | | -| `treatment.string_value` (char) | `treatment.string_value` (char) | identity | | -| `depends_on[subject_id]` | `depends_on[subject_id]` | identity | | -| `depends_on[manipulation_id]` | `depends_on[manipulation_id]` | identity | | -| `depends_on[protocol_id]` | `depends_on[protocol_id]` | identity | | - -## Transformations in detail - -- **Collapse two coordinated chars into one `ontology_term`.** did_v1's - `ontologyName` (the ontology CURIE-or-name) and `name` (the - human-readable label) merge into V_delta's `treatment_name` composite: - - treatment_name = { - "node": , - "name": - } - - This is the same merge rule as `probe_location` (see - [`probe_location.md`](probe_location.md)); the *carrier* field is - renamed from `.name` to `.treatment_name` so it does - not collide with `base.name`. (Under V_delta's class-scoped property - blocks, `base.name` and `treatment.name` would in principle be - distinct, but renaming the carrier here makes the migrated documents - easier to read and matches the V_gamma `class_version: 2.0.0` shape - the V_delta schemas inherit — see `V_gamma_notes.md` § "Class-version - bumps".) - -- **camelCase → snake_case of the source field name.** did_v1's - `ontologyName` is camelCase; the V_beta-era housekeeping snake-cased - field names. The migrator reads the value from either spelling and - writes it to `treatment_name.node`. See - [`_universal_renames.md`](_universal_renames.md) for the - cross-cutting snake_case rule. - -- **`numeric_value` and `string_value` are identity passes.** Both are - declared identically in did_v1 and V_delta (matrix and char, - respectively). No type or semantic change. - -- **Document-instance shape.** V_delta uses class-scoped property - blocks. The three carrier fields live at `treatment.treatment_name`, - `treatment.numeric_value`, `treatment.string_value`. +`treatment` is a catch-all spanning thermal, surgical/minor-procedure, +and husbandry/behavioral interventions (and a few non-manipulation +records). V_epsilon retires it by **splitting on `name`/`ontologyName`** +into the dedicated manipulation families. This is an active, fan-out +conversion: a single `treatment` becomes one manipulation document, plus +a companion observation when it carried a numeric value. + +## Routing table + +Dispatch on the (lowercased) `name`; first match wins. `manipulation_id` +(stale) and `protocol_id` are dropped on every branch. + +| Branch test (on `name`) | Target class | Notes | +|---|---|---| +| contains `date of birth`, `non-survival`, `experiment time` | — (quarantine) | Not a manipulation; route manually to an observation / session metadata. | +| ends with `target location` **and** `string_value` is a CURIE | `procedural_manipulation` | Dab-corpus convention: `string_value` → `target_structure` (ontology_term), `name` minus the "Target Location" suffix → `procedure.name`. | +| heat / cool / cold / thermal / temperature / warm | `temperature_manipulation` | `applied_property` = {ontologyName, name}; `value` = temperature composite from `numeric_value` (source-only; unit backfill). | +| dark rear / rearing / deprivation / monocular / housing / isolation / enrichment / light cycle / diet / food–water restrict / social / training / exposure | `environmental_manipulation` | `factor` = {ontologyName, name}; `string_value` → `notes`. | +| craniotomy / durotomy / implant / lesion / surgery / eye opening / ear notch / tail clip / whisker trim / perfusion / dissection / transection / resection / enucleation / suture / blood draw / opening / procedure | `procedural_manipulation` | `procedure` = {ontologyName, name}; `string_value` → `notes`. | +| otherwise | — (quarantine) | Unresolvable; curator review queue. | + +## Field mapping (per target) + +| did_v1 field | target field | Transformation | +|---|---|---| +| `ontologyName` + `name` | `procedure` / `factor` / `applied_property` (ontology_term) | `{node: ontologyName, name: name}`; blank node ⇒ backfill | +| `string_value` (prose) | `.notes` (procedural/environmental) | identity | +| `string_value` (CURIE, target-location case) | `procedural_manipulation.target_structure[0]` | `{node: string_value, name: ""}` | +| `numeric_value` | companion `generic_scalar_observation.value` | source-only `{source_unit:"", source_value:, approximate:true}`; consumed into `temperature_manipulation.value` on the thermal branch | +| `subject_id` | `subject_id` (inherited) | carried | +| `manipulation_id` | — | dropped (stale) | +| `protocol_id` | — | dropped (tier-level commonality, issue #8 Option C) | +| — | `time_reference_#` | **omitted** — legacy carries no timing; curator backfill | ## Default values for new fields -V_delta introduces no required field on this class beyond what did_v1 -documents already supply. The global `schema_version` tag lives at -`document_class.schema_version` (see `_universal_renames.md` § 10) and -is set to `"V_delta"` by the dispatcher rather than the per-class -migrator. +- `temperature_manipulation`/`scalar_manipulation` blocks: `notes` from + `string_value`; `target_structure` empty (backfill). +- The companion observation gets a fresh `base.id` and the source's + `base.session_id`; the primary keeps the source's `base.id`. ## Worked example -### Before (did_v1) - -```json -{ - "document_class": { - "class_name": "treatment", - "class_version": "1.0.0", - "superclasses": [ - { "class_name": "base", "class_version": "1.0.0" } - ] - }, - "depends_on": [ - { "name": "subject_id", "document_id": "aabb1122ccdd3344_aabb1122ccdd3344" }, - { "name": "manipulation_id", "document_id": "" }, - { "name": "protocol_id", "document_id": "" } - ], - "base": { - "id": "aabb1122ccdd3344_1122334455667788", - "session_id": "aabb1122ccdd3344_9900aabbccddeeff", - "name": "isoflurane_induction", - "datestamp": "2024-06-01T12:00:00.000Z" - }, - "treatment": { - "ontologyName": "chebi:6015", - "name": "isoflurane", - "numeric_value": [2.0], - "string_value": "2 percent in O2" - } -} -``` - -### After (V_delta) - -```json -{ - "document_class": { - "class_name": "treatment", - "class_version": "1.0.0", - "superclasses": [ - { "class_name": "base", "class_version": "1.0.0" } - ] - }, - "depends_on": [ - { "name": "subject_id", "document_id": "aabb1122ccdd3344_aabb1122ccdd3344" }, - { "name": "manipulation_id", "document_id": "" }, - { "name": "protocol_id", "document_id": "" } - ], - "base": { - "id": "aabb1122ccdd3344_1122334455667788", - "session_id": "aabb1122ccdd3344_9900aabbccddeeff", - "name": "isoflurane_induction", - "datestamp": "2024-06-01T12:00:00.000Z" - }, - "treatment": { - "treatment_name": { - "node": "chebi:6015", - "name": "isoflurane" - }, - "numeric_value": [2.0], - "string_value": "2 percent in O2" - } -} -``` - -## File handling - -This document type does not reference files. The generic file-handling -rules in [`_files.md`](_files.md) do not apply. +did_v1 `treatment` (`name = "Treatment: craniotomy"`, +`string_value = "5 mm window, left hemisphere"`) → +`procedural_manipulation` with `procedure = {node:"NCIT:C15329", +name:"Treatment: craniotomy"}`, `notes = "5 mm window, left hemisphere"`, +`target_structure = []`, and `depends_on.subject_id` carried. ## Open questions -- **TODO-domain:** what is the canonical CURIE prefix family for - treatments? Drugs typically resolve under `chebi:` or `drugbank:`; - stimulation protocols may not have a single canonical source. The - V_delta schema's `ontology` slot for `treatment_name` is `null`, - leaving the choice to documents. -- **TODO-domain:** `numeric_value` is a matrix and `mustBeScalar: - false`. Confirm whether did_v1 documents in the wild ever carry - multi-element matrices here, or only scalars / 1-element arrays. The - migrator should pass the value through unchanged in either case, but - knowing the shape distribution affects downstream tooling - assumptions. -- **TODO-domain:** the relationship between `numeric_value` / - `string_value` and `treatment_name` is not enforced (any of the - three can be empty). Confirm whether the V1 freeze should add a - semantic constraint (at least one non-empty), or leave it to - consumer policy. +- The keyword routing lists are heuristic and intended to run + report-only first against each corpus before rewrite (per + `Procedural_Manipulation_Proposal.md`). Bottom out per-corpus before + promoting `treatment` to deletion. +- Non-manipulation records (DOB, experiment time) currently quarantine; + a dedicated observation/metadata mapping is a follow-up. ## Cross-references +- `Procedural_Manipulation_Proposal.md`, `Environmental_Manipulation_Proposal.md`, + `Thermal_Manipulation_Proposal.md`, `Boundary_Mapping_Proposal.md` §5 +- Migrator: `DID-matlab/src/did/+did2/+convert/+migrators/treatment.m` - General file-handling rules: [`_files.md`](_files.md) -- Universal did_v1 → V_delta renames: [`_universal_renames.md`](_universal_renames.md) -- V_delta schema file: [`schemas/V_delta/stable/treatment.json`](../../stable/treatment.json) -- Related conversions that follow the same two-char-to-`ontology_term` - pattern: [`probe_location.md`](probe_location.md), - [`ontology_image.md`](ontology_image.md), - [`ontology_label.md`](ontology_label.md) -- Subclass: `treatment_drug` (still at `class_version: 1.0.0`; this - conversion doc's rules apply to its `treatment` block). diff --git a/schemas/V_epsilon/conversions/from_did_v1/treatment_drug.md b/schemas/V_epsilon/conversions/from_did_v1/treatment_drug.md new file mode 100644 index 0000000..a0f2591 --- /dev/null +++ b/schemas/V_epsilon/conversions/from_did_v1/treatment_drug.md @@ -0,0 +1,62 @@ +# Conversion: did_v1 → V_epsilon — `treatment_drug` → `injection` + +## Identity + +- **V_epsilon target class:** `injection` (kind = `"drug"`). + `treatment_drug` moves to `deprecated/`. +- **V_epsilon tier:** `draft` (`injection`); `deprecated` (`treatment_drug`) +- **did_v1 source:** + `ndi_common/schema_documents/treatment/treatment_drug_schema.json`: + `location_ontologyName`, `location_name`, `mixture_table` (CSV), + `administration_onset_time` (ISO), `administration_offset_time` (ISO), + `administration_duration` (days); depends_on `subject_id` (req). +- **Status:** `applied-in-tooling` + (`DID-matlab/+did2/+convert/+migrators/treatment_drug.m`) + +## Summary + +A pharmacological administration maps to the `injection` family with +`kind = "drug"` (`Injection_Proposal.md`). Active fan-out: produces the +`injection` plus a companion `utc_reference` when an onset time exists. + +## Field mapping + +| did_v1 field | V_epsilon field | Transformation | +|---|---|---| +| `mixture_table` | `pharmacological_manipulation.mixture` | CSV `ontologyName,name,value,ontologyUnit,unitName` → records `{chemical:{node,name}, amount:concentration{source_unit,source_value}}`. Empty ⇒ one blank backfill record (mixture is required non-empty). | +| `location_ontologyName` + `location_name` | `injection.target_structure[0]` | `{node,name}` when present; else empty array | +| `administration_onset_time` | companion `utc_reference.start` | ISO timestamp | +| `administration_offset_time` | companion `utc_reference.end` | ISO timestamp (interval) | +| `administration_duration` | — | dropped; onset/offset interval is canonical | +| `subject_id` | `subject_id` (inherited) | carried | +| — | `injection.kind` | constant `"drug"` | +| — | `injection.volume` | source-only blank composite (legacy has none; backfill) | +| — | `injection.route` | blank ontology_term (legacy has none; backfill) | + +## Default values for new fields + +`kind = "drug"`; `volume`/`route` present but source-empty for curator +backfill. The injection keeps the source `base.id`; the companion +`utc_reference` mints a fresh id and shares `base.session_id`. The +injection's `time_reference_1` depends_on points at the companion; when +no onset time exists the dependency is omitted (backfill). + +## Worked example + +`treatment_drug` with a one-row `mixture_table` for ketamine and +`administration_onset_time = "2024-05-15T09:22:00Z"` → +`injection{kind:"drug"}` with that chemical in `mixture`, plus a +`utc_reference{start:"2024-05-15T09:22:00Z"}` wired as `time_reference_1`. + +## Open questions + +- Legacy `treatment_drug` records dose/concentration only inside + `mixture_table`; rows without a unit leave concentration canonicals + empty (source preserved). `route` and `volume` are not in the legacy + shape and always need curator backfill. + +## Cross-references + +- `Injection_Proposal.md` (Migration §) +- Migrator: `DID-matlab/src/did/+did2/+convert/+migrators/treatment_drug.m` +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_epsilon/conversions/from_did_v1/treatment_transfer.md b/schemas/V_epsilon/conversions/from_did_v1/treatment_transfer.md new file mode 100644 index 0000000..e59ad82 --- /dev/null +++ b/schemas/V_epsilon/conversions/from_did_v1/treatment_transfer.md @@ -0,0 +1,65 @@ +# Conversion: did_v1 → V_epsilon — `treatment_transfer` → `biological_transfer` + +## Identity + +- **V_epsilon target class:** `biological_transfer` (a + `procedural_manipulation` subclass). `treatment_transfer` moves to + `deprecated/`. +- **V_epsilon tier:** `draft` (`biological_transfer`); `deprecated` + (`treatment_transfer`) +- **did_v1 source:** + `ndi_common/schema_documents/treatment/treatment_transfer_schema.json`: + `timestamp` (double), `clocktype`, `entity_name`, + `entity_ontologyNode`, `method_name`, `method_ontologyNode`; + depends_on `recipient_id` (req), `donor_id` (opt). +- **Status:** `applied-in-tooling` + (`DID-matlab/+did2/+convert/+migrators/treatment_transfer.m`) + +## Summary + +A donor→recipient transfer maps to `biological_transfer` +(`Biological_Transfer_Proposal.md`). The legacy `method_*` pair lands on +the **inherited** `procedural_manipulation.procedure` (not a separate +`method`); `entity_*` becomes `entity`; the recipient becomes +`subject_id`; the donor carries forward as `donor_id`. + +## Field mapping + +| did_v1 field | V_epsilon field | Transformation | +|---|---|---| +| `method_name` + `method_ontologyNode` | `procedural_manipulation.procedure` | `{node: method_ontologyNode, name: method_name}` (required) | +| `entity_name` + `entity_ontologyNode` | `biological_transfer.entity` | `{node: entity_ontologyNode, name: entity_name}` (required) | +| `entity_name` | `biological_transfer.kind` | bucket: blood/plasma/serum→`blood`; cell/marrow→`cells`; graft/tissue/explant→`tissue_graft`; else→`lysate` | +| `recipient_id` | `subject_id` (inherited) | rename | +| `donor_id` | `donor_id` (added) | carried (optional) | +| `timestamp` + `clocktype` | companion `utc_reference.start` | only when `clocktype` is a global/UTC clock and `timestamp > 0`: datenum → ISO. Local-clock timing ⇒ omitted (backfill). | +| — | `procedural_manipulation.target_structure` | empty (legacy none; backfill) | +| — | `procedural_manipulation.notes` | empty | + +## Default values for new fields + +`kind` is assigned from `entity_name` (ambiguous ⇒ `"lysate"`, flagged). +`target_structure` empty. The transfer keeps the source `base.id`; the +companion `utc_reference` shares `base.session_id`. + +## Worked example + +`treatment_transfer` (recipient R, donor D, `entity_name = "blood"`, +`method_name = "blood transfusion"`, global-clock `timestamp`) → +`biological_transfer` with `subject_id = R`, `donor_id = D`, +`procedure = {NCIT:C15325, "blood transfusion"}`, `kind = "blood"`, +`entity = {UBERON:0000178, "blood"}`, and a `utc_reference` from the +datenum. + +## Open questions + +- `kind` bucketing from free-text `entity_name` is heuristic; ambiguous + entries default to `lysate` and should be curator-confirmed. +- Local-clock transfers need an `epoch_relative_reference` rather than a + `utc_reference`; deferred (current migrator omits timing for those). + +## Cross-references + +- `Biological_Transfer_Proposal.md`, `Boundary_Mapping_Proposal.md` §4a +- Migrator: `DID-matlab/src/did/+did2/+convert/+migrators/treatment_transfer.m` +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_epsilon/conversions/from_did_v1/virus_injection.md b/schemas/V_epsilon/conversions/from_did_v1/virus_injection.md new file mode 100644 index 0000000..1411b34 --- /dev/null +++ b/schemas/V_epsilon/conversions/from_did_v1/virus_injection.md @@ -0,0 +1,61 @@ +# Conversion: did_v1 → V_epsilon — `virus_injection` → `injection` + +## Identity + +- **V_epsilon target class:** `injection` (kind = `"virus"`). + `virus_injection` moves to `deprecated/`. +- **V_epsilon tier:** `draft` (`injection`); `deprecated` (`virus_injection`) +- **did_v1 source:** + `ndi_common/schema_documents/treatment/virus_injection_schema.json`: + `virus_OntologyName`, `virus_name`, `virusLocation_OntologyName`, + `virusLocation_name`, `virus_AdministrationDate` (YYYY-MM-DD), + `virus_AdministrationPND`, `dilution`, `diluent_OntologyName`, + `diluent_name`; depends_on `subject_id` (req). +- **Status:** `applied-in-tooling` + (`DID-matlab/+did2/+convert/+migrators/virus_injection.m`) + +## Summary + +A viral-vector administration maps to `injection` with `kind = "virus"` +(`Injection_Proposal.md`, resolving the earlier "subclass under +biological_transfer" sketch). The construct becomes a `mixture` entry; +serotype is encoded in the construct ontology node, not a separate field. + +## Field mapping + +| did_v1 field | V_epsilon field | Transformation | +|---|---|---| +| `virus_OntologyName` + `virus_name` | `pharmacological_manipulation.mixture[1].chemical` | `{node,name}` | +| `dilution` | `mixture[1].amount` | source-only `{source_unit:"dilution_factor", source_value:}` (legacy has no titer) | +| `diluent_OntologyName` + `diluent_name` | `mixture[2]` | second record when present; `amount` blank | +| `virusLocation_OntologyName` + `virusLocation_name` | `injection.target_structure[0]` | `{node,name}` | +| `virus_AdministrationDate` | companion `utc_reference.start` (approximate) | date-only ⇒ `is_approximate = true` | +| `virus_AdministrationPND` | — | postnatal day; not timing-convertible without DOB; backfill | +| `subject_id` | `subject_id` (inherited) | carried | +| — | `injection.kind` | constant `"virus"` | +| — | `injection.volume` / `route` | source-empty (legacy has none; backfill) | + +## Default values for new fields + +`kind = "virus"`; `volume`/`route` source-empty. The injection keeps the +source `base.id`; the companion `utc_reference` shares `base.session_id`. + +## Worked example + +`virus_injection` (AAV construct, `dilution = 0.5`, +`virus_AdministrationDate = "2021-05-01"`, location "primary visual +cortex") → `injection{kind:"virus"}` with the construct in `mixture` +(amount `dilution_factor 0.5`), `target_structure` = the location, and an +approximate `utc_reference{start:"2021-05-01"}`. + +## Open questions + +- Real `virus_injection` carries `dilution` (not titer); it is preserved + as a labelled source-only amount. Titer/volume/route need backfill. +- Serotype → ontology-node mapping is a curator lookup (not mechanical). + +## Cross-references + +- `Injection_Proposal.md` (Migration §; Example 4) +- Migrator: `DID-matlab/src/did/+did2/+convert/+migrators/virus_injection.m` +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_epsilon_notes.md b/schemas/V_epsilon_notes.md index 6207523..4fc159e 100644 --- a/schemas/V_epsilon_notes.md +++ b/schemas/V_epsilon_notes.md @@ -132,15 +132,20 @@ and coherent, but they are the most likely to change: indexer/adapter, out of scope for the schema set. - **`element` channel-identity list** and the full daqless-element rewrite — deferred with the provisional channel model above. -- **Conversion docs.** Per-class `conversions/from_did_v1/` and - `from_v_delta/` migration markdowns for the new and deprecated classes - are not written. The deprecation→replacement mapping in - `V_epsilon_SPEC.md` §8 and the per-proposal migration notes are the - current reference. A follow-up should populate `conversions/` and add a - `from_v_delta/` path for the treatment-family split, the - `virus_injection`/`treatment_drug` → `injection` merge, the - `treatment_transfer` → `biological_transfer` move, and the - `subject_group` → `group_assignment` migration. +- **Conversion docs.** The deprecated-family conversions are now + authored and **applied in tooling** as a direct did_v1 → V_epsilon + active conversion (the team chose to retarget the did_v1 → V_delta + pipeline straight to V_epsilon rather than build a separate + V_delta → V_epsilon pass, since V_delta was a sandbox with no frozen + corpora). `conversions/from_did_v1/` now carries `treatment.md` (the + split routing table), `treatment_drug.md`, `virus_injection.md`, + `treatment_transfer.md`, `subject_group.md`, and `stimulus_bath.md`, + each cross-referenced to its DID-matlab migrator under + `+did2/+convert/+migrators/`. No `from_v_delta/` path is needed. + Remaining: conversion docs for the *new* (non-deprecated) draft + classes that have a did_v1 analog, and per-corpus finalization of the + `treatment` keyword routing (the migrator runs report-only-first and + quarantines unresolvable / non-manipulation records). - **CI checks.** An `index.json` ↔ disk consistency check, a superclass/`must_refer_to` resolution check, and a tier/`maturity_level` agreement check (all of which were run manually for this PR and pass)