inou/docs/entry-layout.md

17 KiB

Entry Layout Specification

This is the authoritative reference for how entries are structured in inou. All import tools, API endpoints, MCP tools, and portal code MUST conform to this layout. If you change the schema or add a category, UPDATE THIS DOCUMENT.

Design Principles

  1. Type = level/kind name, never data. Type is always a structural identifier (study, series, result, variant), never a data value like an rsID or test name.
  2. Summary = structural/navigational only. NO opinions, findings, or diagnostic language. The LLM must read Data to form conclusions. "Brain MRI report, Dr. Smith, May 2022" is OK. "Brain MRI — mild white matter changes" is FORBIDDEN.
  3. SearchKey = primary machine lookup. Lowercase, packed. Used for exact-match queries (LOINC codes, gene names, rsIDs).
  4. SearchKey2 = secondary machine lookup. Same rules as SearchKey. For categories with two natural search dimensions.
  5. Value = measured/observed value. The actual data point (test result, genotype, measurement). Empty for container entries.
  6. Containers have no Value. Studies, orders, tiers, groups — these organize data, they don't hold measurements.
  7. Depth 1 = category root, RBAC anchor. One root entry per category per dossier. Access grants attach here.
  8. No circular parents. On write, walk ancestors of proposed parent. Reject if the entry is already an ancestor of the target parent.

Removed Fields

  • TimestampEnd — pushed to Data where needed (uploads, hospitalizations). Not a schema field.
  • Tags — removed. All search needs covered by SearchKey + SearchKey2.

Field Definitions

Field Type Encrypted Queryable Purpose
EntryID string No Exact 16-char hex primary key
DossierID string No Exact Whose data
ParentID string No Exact Parent entry (hierarchy)
Category int No Exact, range Category enum (0-27)
Type string Packed Exact Level/kind name — never data
Value string Packed Measured/observed value or empty
Summary string Packed Structural display text — no opinions
SearchKey string Packed Exact Primary machine lookup (lowercase)
SearchKey2 string Packed Exact Secondary machine lookup (lowercase)
Ordinal int No Exact, range Sort/sequence number
Timestamp int64 No Range Event date (Unix seconds)
Status int No Exact 0=active, 1=hidden/deleted
Data string Packed JSON — everything else

Complete Layout

Depth Cat Type Value Summary SearchKey SearchKey2 ParentID Ordinal Timestamp Data
0 0 dossier dossier full name / Sophia Jongsma email / sophia@example.com — (EntryID=DossierID) 0 created / 1708128000 profile / {"dob":"2010-05-14","sex":2,"lang":"en"}
1 any root dossier ID / 3b38234f2b0f7ee6 0 created / 1708128000 — (RBAC grants anchor here)
2 1 imaging study body+modality+date / Brain MRI (May 2022) cat root / f678901234567801 0 study date / 1652616000 {"study_uid":"...","body_part":"BRAIN","modality":"MR","institution":"City Medical"}
3 1 imaging series modality+desc / MR T2 FLAIR SAG BRAIN study / a1b2c3d4e5f67890 series# / 3 study date / 1652616000 {"series_uid":"...","protocol":"T2_SAG","manufacturer":"Siemens"}
4 1 imaging slice orient+pos+dims / AX #42 z=12.5mm 512x512 series / b2c3d4e5f6789012 slice# / 42 study date / 1652616000 {"sop_uid":"...","slice_location":12.5,"wc":40.0,"ww":400.0,"rows":512,"cols":512}
2 2 document subtype / radiology_report source+date only / MRI report, Dr. Smith, May 2022 cat root or parent entry / a1b2c3d4e5f67890 0 doc date / 1652616000 {"text":"Full text...","original_filename":"report.pdf"}
2 3 lab order order name / CBC with Differential source / mychart cat root / f678901234567802 0 collection / 1708128000 {"provider":"Dr. Smith","lab_name":"City Medical Lab","local_time":"2025-02-15T14:30:00-05:00"}
3 3 lab result test value / 14.2 name: value unit / Hemoglobin: 14.2 g/dL LOINC / 718-7 test name / hemoglobin order / e5f6789012345678 0 collection / 1708128000 {"unit":"g/dL","numeric_value":14.2,"si_factor":10.0}
2 4 genome extraction source+stats / 23andme (850K, 456 matched) source / 23andme cat root / f678901234567803 0 import / 1708128000 {"total":850000,"matched":5432,"positive":456}
3 4 genome tier category+count / Traits (100) tier name / traits extraction / c3d4e5f678901234 display order / 1 import / 1708128000 {"shown":100,"hidden":50}
4 4 genome variant genotype / CT SNPedia summary / 1.3x increased risk gene / mthfr rsID / rs1801133 tier / d4e5f67890123456 100-mag*10 / 75 import / 1708128000 {"mag":2.5,"rep":"Bad","sub":"Methylation"}
2 5 upload target / imaging filename / brain.dcm cat root / f678901234567804 0 upload / 1708128000 {"path":"/tank/inou/uploads/...","size":1234567,"status":"uploaded","expires":1708732800}
2 6 journal entry date / Feb 15, 2025 cat root / f678901234567805 0 entry date / 1708128000 {"mood":4,"energy":3,"sleep_hours":7.5,"notes":"Felt good today"}
2 7 consultation subtype / visit provider+date / Dr. Smith, Feb 2025 cat root / f678901234567806 0 visit date / 1708128000 {"provider":"Dr. Smith","specialty":"Cardiology","location":"City Medical"}
2 8 diagnosis subtype / active condition name / Hypertension ICD-10 / i10 cat root / f678901234567807 0 diagnosed / 1708128000 {"icd10":"I10","source":"patient_reported","status":"active"}
2 9 vital subtype / weight vital type label / Weight cat root / f678901234567808 0 created / 1708128000 {"unit":"kg"} (group container)
3 9 vital reading measurement / 75.5 value+unit / 75.5 kg group / aabbccdd11223344 0 measured / 1708128000 {"unit":"kg"}
2 10 exercise subtype / activity activity label / Running cat root / f678901234567809 0 created / 1708128000 (group container)
3 10 exercise entry measurement / 5.2 summary / 5.2 km, 30 min group / aabbccdd11223355 0 activity date / 1708128000 {"distance_km":5.2,"duration_min":30,"calories":320}
2 11 medication subtype / prescription med name+dose / Metformin 500mg cat root / f67890123456780a 0 started / 1708128000 {"dosage":"500mg","frequency":"2x daily","prescriber":"Dr. Smith"}
2 12 supplement subtype / vitamin supplement name / Vitamin D3 2000 IU cat root / f67890123456780b 0 started / 1708128000 {"dosage":"2000 IU","frequency":"daily"}
2 13 nutrition subtype / meal meal label / Lunch cat root / f67890123456780c 0 created / 1708128000 (group container)
3 13 nutrition entry calories / 650 summary / Grilled chicken, rice, salad group / aabbccdd11223366 0 meal time / 1708128000 {"calories":650,"protein_g":45,"carbs_g":60,"fat_g":20}
2 14 fertility subtype / cycle cycle label / Menstrual Cycle cat root / f67890123456780d 0 created / 1708128000 (group container)
3 14 fertility entry date / Feb 15, 2025 group / aabbccdd11223377 0 date / 1708128000 {"day":14,"bbt":36.7,"notes":"..."}
2 15 symptom subtype / chronic symptom name / Headache cat root / f67890123456780e 0 first reported / 1708128000 {"severity":"mild","frequency":"weekly"}
3 15 symptom entry severity / 6 date+severity / Feb 15: severity 6/10 group / aabbccdd11223388 0 reported / 1708128000 {"severity":6,"trigger":"stress","duration_hours":4}
2 16 note subtype / general note title / Follow-up needed cat root / f67890123456780f 0 created / 1708128000 {"text":"Full note text..."}
2 17 history subtype / medical condition / Appendectomy, age 12 cat root / f678901234567810 0 event date / 1708128000 {"age_at_event":12,"source":"patient_reported"}
2 18 family_history subtype / parent relation+condition / Father: Type 2 Diabetes cat root / f678901234567811 0 reported / 1708128000 {"relation":"father","condition":"Type 2 Diabetes","age_onset":55}
2 19 surgery subtype / inpatient procedure+date / Appendectomy, Mar 2020 cat root / f678901234567812 0 surgery date / 1708128000 {"procedure":"Appendectomy","surgeon":"Dr. Lee","facility":"City Hospital"}
2 20 hospital subtype / admission reason+facility / Chest pain, City Hospital cat root / f678901234567813 0 admission / 1708128000 {"reason":"Chest pain","facility":"City Hospital","discharge":1708300000}
2 21 birth subtype / delivery date+type / May 14 2010, vaginal cat root / f678901234567814 0 birth date / 1708128000 {"type":"vaginal","weight_g":3200,"apgar_1":8,"apgar_5":9}
2 22 device subtype / implant device name / Medtronic Micra AV cat root / f678901234567815 0 implanted / 1708128000 {"manufacturer":"Medtronic","model":"Micra AV","serial":"ABC123"}
2 23 therapy subtype / physical therapy+provider / Physical therapy, City Rehab cat root / f678901234567816 0 started / 1708128000 {"provider":"City Rehab","frequency":"2x weekly","goal":"Knee recovery"}
2 24 assessment subtype / screening assessment name / PHQ-9 Depression Screen cat root / f678901234567817 0 date / 1708128000 {"instrument":"PHQ-9","score":4}
2 25 provider subtype / physician name+specialty / Dr. Smith, Cardiology cat root / f678901234567818 0 added / 1708128000 {"name":"Dr. Smith","specialty":"Cardiology","phone":"+1..."}
2 26 question subtype / inquiry question / What does my MTHFR result mean? cat root / f678901234567819 0 asked / 1708128000 {"text":"Full question...","answer":"...","answered_by":"ai"}
2 27 tracker subtype / daily_checkin tracker name / Daily Check-in cat root / f67890123456781a 0 created / 1708128000 (group container)
3 27 tracker response date / Feb 15, 2025 tracker / aabbccdd11223399 0 response date / 1708128000 {"mood":4,"energy":3,"sleep":7.5,"pain":2}

Hierarchy Patterns

3-level: Imaging, Genome

cat root (depth 1) → study/extraction (depth 2) → series/tier (depth 3) → slice/variant (depth 4)

2-level: Labs

cat root (depth 1) → order (depth 2) → result (depth 3)

Group + entries: Vitals, Exercise, Nutrition, Fertility, Symptoms, Trackers

cat root (depth 1) → group container (depth 2) → readings/entries (depth 3)

Group containers hold metadata (units, labels). Individual readings hold values.

Flat: Everything else

cat root (depth 1) → entry (depth 2)

Cross-Category Linking

Documents can be children of entries from other categories:

  • Lab report PDF → ParentID = lab order entry
  • Radiology report → ParentID = imaging study entry

This creates cross-category parent/child relationships. Circular reference prevention is mandatory.

Special Rules

Genome Variant Ordinal

Ordinal = 100 - magnitude * 10 — higher magnitude (more significant) sorts first via ORDER BY Ordinal ASC.

Genome Variant Hiding

Variants with magnitude > 4.0 or repute = "Bad" get Status = 1 (hidden). Consumers filter by Status = 0 by default. An include_hidden flag allows showing all.

Devices vs Wearables

Category 22 (device) is for medical devices — pacemakers, insulin pumps, ventilators, O2 concentrators, CPAP machines. Consumer wearables (Apple Watch, Fitbit) are NOT device entries — they are data sources. Wearable data flows into the categories where it belongs: steps → vital/steps, heart rate → vital/heart_rate, blood oxygen → vital/oxygen. The data source is noted in the reading's Data field as {"source":"apple_watch"}.

Independent Analysis Protocol

This is a CORE ARCHITECTURAL PRINCIPLE of inou. It cannot be circumvented.

Why This Exists

The entire purpose of inou is to give LLMs raw health data so they can form independent medical opinions — not parrot existing doctors' conclusions. A user does not need inou to read back their own medical records. They need inou to independently analyze their imaging, labs, genome, and vitals, and potentially catch things that were missed, see cross-category patterns, or offer a different perspective.

If an LLM sees "Diagnosis: Hypertension" before analyzing blood pressure trends, it anchors on that conclusion. Independent analysis becomes impossible. This is not a theoretical concern — anchoring bias is well-documented in both humans and LLMs.

Data Tiers

All entry categories are classified into two tiers:

Tier 1 — Raw Data (always available):

Cat Name Why
1 Imaging Objective images — LLM looks and interprets
3 Lab Objective numbers — LLM analyzes trends and ranges
4 Genome Objective variants — LLM assesses risk factors
9 Vital Objective measurements — LLM identifies patterns
2 Document Source PDFs — LLM reads full context, not pre-digested summaries
6 Journal Patient's own words — subjective but first-person
18 Family history Factual family medical background
17 History Factual past events (surgeries, conditions)

Tier 2 — Medical Opinions (gated, requires prior raw data review):

Cat Name Why gated
7 Consultation Contains doctor's observations and conclusions
8 Diagnosis Doctor's conclusion — strongest anchoring risk
16 Note May contain clinical opinions
24 Assessment Screening scores are raw; interpretations are opinions

Ungated (no bias risk):

All other categories (medication, supplement, exercise, surgery, hospitalization, birth, device, therapy, provider, question, tracker, upload, nutrition, fertility, symptom) — these are factual records of events, treatments, or patient-reported data without diagnostic conclusions.

MCP Enforcement

The MCP server enforces the Independent Analysis Protocol:

  1. System prompt tells the LLM upfront:

    "You have access to raw health data (imaging, labs, genome, vitals) and medical opinions (diagnoses, assessments, consultation notes). Your role is independent analysis — form your own conclusions from raw data before consulting existing medical opinions. Opinion categories are unlocked after you've reviewed raw data."

  2. Session state tracks which categories the LLM has queried (queriedCategories set).

  3. Gating — when the LLM queries a Tier 2 category before reviewing raw data, the MCP tool returns:

    "Opinion data requires prior review of raw data. Query at least one of: imaging, labs, vitals, or genome first."

  4. After unlock — once the LLM has queried raw data, Tier 2 is available. The LLM can compare its independent analysis against existing medical opinions.

Rules for Contributors

  • NEVER bypass the gating mechanism. It is equivalent to RBAC — a hard access control, not a suggestion.
  • NEVER include diagnostic conclusions in Summary fields. Summary is structural/navigational only.
  • NEVER pre-digest medical opinions into structured fields that the LLM sees by default. If a doctor's conclusion exists, it lives in a Tier 2 category or inside a document's full text.
  • ALWAYS present raw data in a way that supports independent analysis: numbers, images, variants — not interpretations.
  • When adding new categories, classify them as Tier 1 or Tier 2 and update this document.

Schema Changes Checklist

When modifying this layout:

  1. Update this document FIRST
  2. Update lib/types.go (CategoryTypes, Entry struct)
  3. Update import tools (import-dicom, import-genome, import-lab)
  4. Update lib/dbcore.go (Filter struct, entryQuery)
  5. Run migration on staging AND production
  6. Update MCP tools if query patterns changed
  7. Update portal display code