From 6490a75a0d10f6327c45bf9be14f68e7d5231a8b Mon Sep 17 00:00:00 2001 From: Lissan <150966211+DataForSolution@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:54:51 -0400 Subject: [PATCH 1/6] fix(order-helper): normalize rules.json (dash mojibake, array/comma/braces), validate JSON --- order-helper/data/rules.json | 581 ++++++++++++++++++++++++++++++++++- 1 file changed, 580 insertions(+), 1 deletion(-) diff --git a/order-helper/data/rules.json b/order-helper/data/rules.json index e659811..093dc98 100644 --- a/order-helper/data/rules.json +++ b/order-helper/data/rules.json @@ -1,4 +1,583 @@ -[ + +{ + "schema_version": "1.1", + "generated_at": "2025-08-19", + "modalities": { + "X-Ray": { + "regions": [ + "Chest", + "Abdomen (KUB)", + "Pelvis", + "Skull", + "Cervical spine", + "Thoracic spine", + "Lumbar spine", + "Scoliosis series", + "Upper extremity", + "Lower extremity", + "Shoulder", + "Elbow", + "Wrist/Hand", + "Hip", + "Knee", + "Ankle/Foot", + "Skeleton survey" + ], + "contexts": [ + "Acute", + "Trauma", + "Follow-up", + "Infection", + "Metastatic survey", + "Pre-operative", + "Post-operative" + ], + "conditions": [ + "Fracture", + "Dislocation", + "Osteoarthritis", + "Evaluation for pneumonia", + "Effusion", + "Foreign body", + "Osteomyelitis", + "Metastasis", + "Scoliosis" + ], + "indication_templates": [ + "X-Ray {region} — {context} for {condition}", + "X-Ray {region} — rule out {condition}" + ], + "notes": [ + "Use two views (minimum) for trauma if possible.", + "Skeleton survey used for myeloma or metastatic disease patterns (consider bone scan if broader sensitivity is needed).", + "No contrast used for plain radiography." + ] +} + + "CT": { + "regions": [ + "Head/Brain", + "Sinuses", + "Maxillofacial/Facial Bones", + "Temporal Bones/IAC", + "Neck", + "Chest", + "Low‑Dose Lung CT (Screening)", + "Abdomen", + "Pelvis", + "Abdomen/Pelvis", + "CT Urogram", + "CT Enterography", + "Spine – Cervical", + "Spine – Thoracic", + "Spine – Lumbar", + "Upper Extremity", + "Lower Extremity", + "Cardiac Coronary CTA", + "Angiography – Head/Neck CTA", + "Angiography – Chest CTA (PE)", + "Angiography – Aorta CTA", + "Angiography – Run‑off CTA (LE)" + ], + "contrast_options": [ + { "value": "with_iv", "label": "With IV contrast" }, + { "value": "without_iv", "label": "Without IV contrast" }, + { "value": "oral", "label": "Add oral contrast (abd/pelvis)" }, + { "value": "none", "label": "None / Not applicable" } + ], + "contexts": [ + "Initial evaluation", + "Acute symptoms", + "Follow‑up", + "Pre‑operative planning", + "Post‑operative complication", + "Oncology staging", + "Oncology restaging / surveillance", + "Trauma", + "Screening", + "Infection / inflammation" + ], + "conditions": [ + "Headache (sudden / thunderclap)", + "Head trauma", + "Stroke symptoms / TIA", + "Sinusitis", + "Neck mass", + "Pulmonary embolism suspected", + "Aortic dissection / aneurysm suspected", + "Lung nodule", + "Pneumonia complication", + "Abdominal pain RLQ (appendicitis)", + "Kidney stone / renal colic", + "Pancreatitis", + "Liver lesion characterization", + "Diverticulitis", + "Inflammatory bowel disease flare", + "Bowel obstruction", + "Post‑op abdomen", + "Hematuria", + "Cancer staging (specify primary)", + "Metastatic disease restaging", + "Spine trauma", + "Cervical radiculopathy", + "Spinal stenosis", + "Extremity fracture", + "Suspected osteomyelitis", + "Peripheral arterial disease (LE run‑off)" + ], + "indication_templates": [ + "CT {region} – {context} for {condition}", + "CT {region} – rule out {condition}", + "CT {region} {contrast_text} – {context} ({condition})" + ], + "contrast_recommendations": [ + { "match": ["kidney stone", "renal colic"], "suggest": "without_iv" }, + { "match": ["appendicitis", "rlq"], "suggest": "with_iv" }, + { "match": ["pe", "pulmonary embolism"], "suggest": "with_iv" }, + { "match": ["aortic", "dissection", "aneurysm"], "suggest": "with_iv" }, + { "match": ["liver lesion", "pancreatitis"], "suggest": "with_iv" }, + { "match": ["bowel obstruction"], "suggest": "without_iv" }, + { "match": ["trauma"], "suggest": "with_iv" }, + { "match": ["low‑dose lung ct", "screening"], "suggest": "without_iv" } + ], + "notes": [ + "CTA exams require IV contrast.", + "Oral contrast is site‑dependent for abdomen/pelvis—offered as an option.", + "This tool structures ordering; it is not medical advice." + ] + } + }, + "records": [ + { + "id": "PET-SB-MT-ONC", + "modality": "PET/CT", + "study_name": "FDG PET/CT — Skull Base to Mid-Thigh", + "cpt": ["78815"], + "icd10_common": ["C34.90", "C18.9", "C50.919", "C43.9", "C32.9", "C81.90", "C85.90"], + "contrast": "Radiotracer (± IV contrast on CT)", + "header_coverage": "Skull base → mid-thigh", + "contexts": ["staging", "restaging", "treatment response", "surveillance"], + "keywords": ["lymphoma", "nsclc", "lung cancer", "breast cancer", "colorectal", "colon cancer", "melanoma", "head and neck", "hnscc", "gastric", "pancreatic"], + "reasons": [ + "FDG PET/CT for {context} of {condition}; evaluate disease extent, nodal involvement, and FDG-avid distant metastases." + ], + "prep": "Fast 4–6 h; avoid strenuous exercise 24 h; glucose <200 mg/dL.", + "supporting_docs": [ + "Clinic note documenting diagnosis and clinical question.", + "Prior imaging/report.", + "Therapy timeline (chemo/radiation/surgery) and relevant labs." + ], + "flags": [ + "Recent G-CSF can increase marrow uptake.", + "Hyperglycemia lowers tumor-to-background contrast." + ], + "prior_auth": { "requires_prior_auth": true, "step_imaging_required": true }, + "tags": ["oncology-general"] + }, + { + "id": "PET-WHOLEBODY", + "modality": "PET/CT", + "study_name": "FDG PET/CT — Whole Body (Vertex to Toes)", + "cpt": ["78816"], + "icd10_common": ["C43.9", "C49.9", "C90.00", "M31.7", "R50.9"], + "contrast": "Radiotracer (± IV contrast on CT)", + "header_coverage": "Vertex → toes", + "contexts": ["staging", "restaging", "surveillance"], + "keywords": ["melanoma", "myeloma", "sarcoma", "vasculitis", "fever of unknown origin", "fuo"], + "reasons": [ + "FDG PET/CT whole body for {context} of {condition}; evaluate for extremity involvement and FDG-avid metastatic/inflammatory disease." + ], + "prep": "Standard FDG fasting; keep patient warm to limit brown fat uptake.", + "supporting_docs": ["Referring note with suspicion/diagnosis.", "Biopsy/pathology if available.", "Prior imaging for correlation."], + "flags": ["Include extremities for melanoma/myeloma.", "Consider inflammatory patterns in vasculitis/FOU."], + "prior_auth": { "requires_prior_auth": true }, + "tags": ["whole-body"] + }, + { + "id": "PET-BRAIN-FDG", + "modality": "PET", + "study_name": "FDG Brain PET", + "cpt": ["78608"], + "icd10_common": ["F03.90", "G30.9", "G31.09", "G40.909"], + "contrast": "Radiotracer only", + "header_coverage": "Brain", + "contexts": ["dementia", "epilepsy"], + "keywords": ["alzheim", "frontotemporal", "ftd", "epilepsy", "seizure", "temporal lobe"], + "reasons": [ + "FDG brain PET to evaluate cerebral metabolic patterns in {condition}; correlate with clinical and prior imaging." + ], + "prep": "Quiet, dim environment pre-injection; NPO; epilepsy timing per protocol.", + "supporting_docs": ["Neurology note with symptoms & question.", "Prior MRI/EEG."], + "flags": ["FDG patterns vary by dementia subtype.", "Medication/timing affects epilepsy localization."], + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["neuro"] + }, + { + "id": "PET-CARDIAC-FDG-VIABILITY", + "modality": "PET", + "study_name": "PET Cardiac FDG — Viability", + "cpt": ["78459", "78491", "78492"], + "icd10_common": ["I25.10", "I42.9"], + "contrast": "Radiotracer only", + "header_coverage": "Heart", + "contexts": ["viability"], + "keywords": ["viability", "ischemic cardiomyopathy", "hibernating myocardium"], + "reasons": [ + "FDG PET to assess myocardial viability in ischemic cardiomyopathy; correlate with perfusion and echocardiography." + ], + "prep": "Glucose loading/insulin protocol per SOP; coordinate with perfusion.", + "supporting_docs": ["Cardiology note on revascularization decision.", "Echo/perfusion/coronary imaging reports."], + "flags": ["Glycemic control critical for image quality."], + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["cardiac"] + }, + { + "id": "PET-INFECTION-SB-MT", + "modality": "PET/CT", + "study_name": "FDG PET/CT — Infection/Inflammation (Skull Base to Mid-Thigh)", + "cpt": ["78815"], + "icd10_common": ["M86.9", "T84.59XA", "I33.0", "R50.9"], + "contrast": "Radiotracer (± IV contrast on CT)", + "header_coverage": "Skull base → mid-thigh", + "contexts": ["suspected infection"], + "keywords": ["osteomyelitis", "prosthetic joint", "infection", "endocarditis", "fuo"], + "reasons": [ + "FDG PET/CT to evaluate suspected infection/inflammation related to {condition}; assess extent and possible sites of involvement." + ], + "prep": "Standard FDG fasting; review recent antibiotics.", + "supporting_docs": ["Clinical notes with symptoms/duration.", "WBC, CRP/ESR, cultures.", "Prior imaging for comparison."], + "flags": ["Prosthesis may show inflammatory uptake; interpret with context."], + "prior_auth": { "requires_prior_auth": true }, + "tags": ["infection"] + }, + { + "id": "PET-PSMA", + "modality": "PET/CT", + "study_name": "PSMA PET/CT — Prostate Cancer", + "cpt": ["78815", "78816"], + "icd10_common": ["C61", "R97.21"], + "contrast": "Radiotracer (PSMA) ± IV contrast CT", + "header_coverage": "Skull base → mid-thigh or whole body", + "contexts": ["staging", "biochemical recurrence"], + "keywords": ["prostate", "psa"], + "reasons": [ + "PSMA PET/CT for {context} in prostate cancer; localize recurrence/metastases to guide therapy." + ], + "prep": "Hydration; void frequently; follow tracer-specific guidance.", + "supporting_docs": ["PSA level and trend.", "Prior therapy and pathology."], + "flags": [], + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["prostate"] + }, + { + "id": "PET-DOTATATE", + "modality": "PET/CT", + "study_name": "DOTATATE PET/CT — Neuroendocrine Tumor", + "cpt": ["78815", "78816"], + "icd10_common": ["C7A.8", "C7B.8", "D3A.8"], + "contrast": "Radiotracer (Ga-68/Lu-177) ± IV contrast CT", + "header_coverage": "Skull base → mid-thigh or whole body", + "contexts": ["staging", "restaging", "surveillance"], + "keywords": ["NET", "neuroendocrine tumor", "carcinoid"], + "reasons": [ + "DOTATATE PET/CT to stage/restage neuroendocrine tumor and evaluate metastases/recurrence." + ], + "prep": "Hydration; withhold long-acting somatostatin analogs per protocol.", + "supporting_docs": ["Pathology and tumor grade if known.", "Prior imaging for comparison."], + "flags": [], + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["NET"] + }, + { + "id": "CT-HEAD-WO", + "modality": "CT", + "study_name": "CT Head without Contrast", + "cpt": ["70450"], + "icd10_common": ["I63.9", "S06.9X9A", "R51.9", "R42"], + "contrast": "Without", + "header_coverage": "Head", + "reasons": ["Acute stroke/TIA evaluation.", "Head trauma.", "Severe headache/new neuro deficit."], + "prep": "Remove metal; pregnancy screen PRN.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["neuro", "emergency"] + }, + { + "id": "CTA-HEAD-NECK", + "modality": "CT", + "study_name": "CTA Head & Neck (Stroke/Aneurysm)", + "cpt": ["70496", "70498"], + "icd10_common": ["I65.23", "I67.1", "I63.9", "G45.9"], + "contrast": "With (arterial bolus)", + "header_coverage": "Head & Neck arteries", + "reasons": ["Large-vessel occlusion/aneurysm/stenosis evaluation."], + "prep": "Creatinine per policy; 18–20G IV.", + "prior_auth": { "requires_prior_auth": true }, + "tags": ["neuro", "vascular"] + }, + { + "id": "CT-PE-CTPA", + "modality": "CT", + "study_name": "CT Pulmonary Angiography (PE Protocol)", + "cpt": ["71275"], + "icd10_common": ["I26.99", "R06.02", "R07.9", "R79.1"], + "contrast": "With (arterial bolus)", + "header_coverage": "Chest (PE protocol)", + "reasons": ["Suspected pulmonary embolism with elevated clinical probability or D-dimer."], + "prep": "Check creatinine; allergy premedication if needed.", + "prior_auth": { "requires_prior_auth": true }, + "tags": ["chest", "vascular"] + }, + { + "id": "CT-ABD-PEL-W", + "modality": "CT", + "study_name": "CT Abdomen/Pelvis with Contrast", + "cpt": ["74177"], + "icd10_common": ["R10.9", "K56.60", "C18.9", "K57.30", "N20.0"], + "contrast": "With", + "header_coverage": "Abdomen & Pelvis", + "reasons": ["Acute abdomen pain/obstruction.", "Cancer staging.", "Suspected appendicitis/diverticulitis."], + "prep": "NPO 3–4 h; oral contrast per protocol.", + "prior_auth": { "requires_prior_auth": true }, + "tags": ["abdomen", "oncology"] + }, + { + "id": "CT-UROGRAM", + "modality": "CT", + "study_name": "CT Urogram (A/P w & w/o)", + "cpt": ["74178"], + "icd10_common": ["R31.9", "R31.0", "N28.89", "C67.9"], + "contrast": "With & Without", + "header_coverage": "Kidneys, ureters, bladder", + "reasons": ["Hematuria evaluation (risk-stratified).", "Suspected upper tract urothelial carcinoma."], + "prep": "Hydration; renal labs per policy.", + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["gu"] + }, + { + "id": "MRI-BRAIN-WWO", + "modality": "MRI", + "study_name": "MRI Brain w & w/o Contrast", + "cpt": ["70553"], + "icd10_common": ["G35", "R56.9", "G45.9", "C71.9", "F03.90"], + "contrast": "With & Without", + "header_coverage": "Brain", + "reasons": ["Tumor, MS, seizures, subacute stroke, dementia workup."], + "prep": "Metal screen; GFR if CKD.", + "prior_auth": { "requires_prior_auth": true }, + "tags": ["neuro"] + }, + { + "id": "MRI-IAC", + "modality": "MRI", + "study_name": "MRI IAC / Temporal Bone", + "cpt": ["70553"], + "icd10_common": ["H91.90", "H93.19", "D33.3", "H81.399"], + "contrast": "With & Without", + "header_coverage": "IACs/CPA", + "reasons": ["Asymmetric SNHL, vestibular schwannoma, complex vertigo."], + "prep": "Standard MRI screening; GFR as needed.", + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["neuro", "ent"] + }, + { + "id": "MRI-TMJ", + "modality": "MRI", + "study_name": "MRI Temporomandibular Joints", + "cpt": ["70336"], + "icd10_common": ["M26.609", "R68.84"], + "contrast": "Without (± With if tumor/infection)", + "header_coverage": "Bilateral TMJs with open/closed mouth", + "reasons": ["TMJ dysfunction, locking, pain refractory to conservative care."], + "prep": "Remove dental metal; bite blocks per protocol.", + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true, "step_imaging_required": true }, + "tags": ["msk", "ent", "dental"] + }, + { + "id": "MRI-BRACHIAL-PLEXUS", + "modality": "MRI", + "study_name": "MRI Brachial Plexus w & w/o", + "cpt": ["73223"], + "icd10_common": ["G54.0", "S14.3XXA", "C47.3"], + "contrast": "With & Without", + "header_coverage": "Roots to cords", + "reasons": ["Traction injury, tumor, radiation plexopathy."], + "prep": "Consider sedation if needed.", + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["neuro", "msk"] + }, + { + "id": "MR-NEUROGRAPHY-LE", + "modality": "MRI", + "study_name": "MR Neurography — Lower Extremity", + "cpt": ["73720"], + "icd10_common": ["G57.00", "G57.10", "G57.90"], + "contrast": "Without (± With for mass/inflammation)", + "header_coverage": "Target nerve course", + "reasons": ["Entrapment/neuropathy after failed conservative therapy; traumatic nerve injury."], + "prep": "Standard MRI screening.", + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true, "step_imaging_required": true }, + "tags": ["neuro", "msk"] + }, + { + "id": "MRI-LSPINE-WWO", + "modality": "MRI", + "study_name": "MRI Lumbar Spine w & w/o", + "cpt": ["72158"], + "icd10_common": ["M54.16", "M48.061", "G95.9", "M51.36"], + "contrast": "With & Without", + "header_coverage": "Lumbar spine", + "reasons": ["Radiculopathy/stenosis with neuro deficits or failed 4–6 wks conservative therapy; infection; tumor."], + "prep": "Metal screen; GFR if CKD.", + "prior_auth": { "requires_prior_auth": true, "step_imaging_required": true }, + "tags": ["spine"] + }, + { + "id": "MRI-PROSTATE-PI-RADS", + "modality": "MRI", + "study_name": "MRI Prostate (PI-RADS) w & w/o", + "cpt": ["72197"], + "icd10_common": ["R97.20", "C61"], + "contrast": "With & Without", + "header_coverage": "Prostate & seminal vesicles", + "reasons": ["Elevated PSA/biochemical recurrence; staging prior to therapy."], + "prep": "NPO 3–4 h; rectal prep per site.", + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["gu", "oncology"] + }, + { + "id": "US-ABD-COMP", + "modality": "Ultrasound", + "study_name": "Abdominal Ultrasound — Complete", + "cpt": ["76700"], + "icd10_common": ["R10.11", "K80.20", "K76.0", "K74.60"], + "contrast": "None", + "header_coverage": "Abdomen", + "reasons": ["RUQ pain/gallstones; liver disease; abnormal LFTs."], + "prep": "NPO 6–8 h.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["abdomen"] + }, + { + "id": "US-PELVIC-TV", + "modality": "Ultrasound", + "study_name": "Pelvic Ultrasound (Transabdominal + Transvaginal)", + "cpt": ["76856", "76830"], + "icd10_common": ["N93.9", "N83.209", "D25.9", "R10.2", "Z32.01"], + "contrast": "None", + "header_coverage": "Pelvis", + "reasons": ["AUB, pelvic pain, ovarian cyst, fibroids, early pregnancy viability."], + "prep": "Full bladder for TA; empty for TV; document LMP.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["gyn"] + }, + { + "id": "US-CAROTID", + "modality": "Ultrasound", + "study_name": "Carotid Duplex (Bilateral)", + "cpt": ["93880"], + "icd10_common": ["I65.23", "G45.9", "R09.89"], + "contrast": "None", + "header_coverage": "Carotid arteries", + "reasons": ["TIA/stroke symptoms, carotid bruit/stenosis follow-up."], + "prep": "None.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["vascular"] + }, + { + "id": "US-LE-VENOUS", + "modality": "Ultrasound", + "study_name": "Lower Extremity Venous Duplex (DVT) — Bilateral", + "cpt": ["93970"], + "icd10_common": ["I82.4Z3", "M79.89", "R22.40"], + "contrast": "None", + "header_coverage": "LE veins", + "reasons": ["Leg swelling/pain; rule out DVT."], + "prep": "None.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["vascular"] + }, + { + "id": "XR-CHEST-2V", + "modality": "X-Ray", + "study_name": "Chest X-ray (2 Views)", + "cpt": ["71046"], + "icd10_common": ["R05.9", "R06.02", "R07.9", "J18.9"], + "contrast": "None", + "header_coverage": "Chest", + "reasons": ["Cough/SOB/chest pain; pneumonia; trauma baseline."], + "prep": "None.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["chest"] + }, + { + "id": "XR-KUB", + "modality": "X-Ray", + "study_name": "Abdomen X-ray (KUB)", + "cpt": ["74018"], + "icd10_common": ["R10.9", "K59.00", "R14.0", "N20.0", "K56.60"], + "contrast": "None", + "header_coverage": "Abdomen", + "reasons": ["Obstruction/constipation/stone follow-up."], + "prep": "None.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["abdomen"] + }, + { + "id": "NM-HIDA", + "modality": "Nuclear Medicine", + "study_name": "HIDA (± Ejection Fraction)", + "cpt": ["78226", "78227"], + "icd10_common": ["K81.0", "K82.8", "R10.11"], + "contrast": "Radiotracer", + "header_coverage": "Hepatobiliary", + "reasons": ["Acute cholecystitis; biliary dyskinesia (with EF)."], + "prep": "NPO 4–6 h; withhold opiates 4–6 h.", + "prior_auth": { "requires_prior_auth": true }, + "tags": ["hepatobiliary"] + }, + { + "id": "NM-BONE-WB", + "modality": "Nuclear Medicine", + "study_name": "Bone Scan — Whole Body", + "cpt": ["78306", "78320"], + "icd10_common": ["C79.51", "M84.48XA", "M86.9"], + "contrast": "Radiotracer", + "header_coverage": "Whole skeleton", + "reasons": ["Bone metastases evaluation; occult fractures; osteomyelitis."], + "prep": "Hydration; frequent voiding.", + "prior_auth": { "requires_prior_auth": true }, + "tags": ["msk", "oncology"] + }, + { + "id": "IR-PARACENTESIS", + "modality": "IR", + "study_name": "US-Guided Paracentesis", + "cpt": ["49083"], + "icd10_common": ["R18.8", "K70.31", "K74.60"], + "contrast": "None", + "header_coverage": "Peritoneal cavity", + "reasons": ["Diagnostic or therapeutic removal of ascites."], + "prep": "Consent; INR/platelets; anticoagulant plan.", + "prior_auth": { "requires_prior_auth": false }, + "tags": ["procedure"] + }, + { + "id": "IR-LUNG-BIOPSY", + "modality": "IR", + "study_name": "CT-Guided Lung Biopsy", + "cpt": ["32408"], + "icd10_common": ["R91.1", "C34.90"], + "contrast": "None", + "header_coverage": "Target lung lesion", + "reasons": ["Tissue diagnosis of pulmonary nodule/mass."], + "prep": "Consent; INR/platelets; post-procedure CXR per policy.", + "prior_auth": { "requires_prior_auth": true, "specialist_referral_required": true }, + "tags": ["procedure", "oncology"] + } + ] +} + +[ { "modality": "PET/CT", "region": "Skull base to mid-thigh", From 9bda63ff442e0cb50a8ec0cef655d198042570d5 Mon Sep 17 00:00:00 2001 From: Lissan <150966211+DataForSolution@users.noreply.github.com> Date: Fri, 19 Sep 2025 19:29:40 -0400 Subject: [PATCH 2/6] feat(order-helper): centralize OH metas in default layout; remove duplicates from index.html --- _layouts/default.html | 9 +++++++-- order-helper/index.html | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/_layouts/default.html b/_layouts/default.html index 2d8abf3..dc864fc 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -65,10 +65,11 @@ gtag('js', new Date()); gtag('config','G-FKVXD8061R',{ send_page_view:true }); - + {% if page.custom_css %} {% endif %} + {% if page.url contains '/order-helper/' %} + + + + + {% endif %} -
diff --git a/order-helper/index.html b/order-helper/index.html index b0edc98..d3a7867 100644 --- a/order-helper/index.html +++ b/order-helper/index.html @@ -3,6 +3,7 @@ title: OraDigit Order Helper permalink: /order-helper/ description: Evidence-based PET/CT, CT, MRI, US, X-Ray — structured order helper with validation and PDF export. No PHI. Educational use only. +oh_loader: true --- From 7f1f1882bca7f7ad626193da4afd52e6c2c68760 Mon Sep 17 00:00:00 2001 From: Lissan <150966211+DataForSolution@users.noreply.github.com> Date: Wed, 17 Sep 2025 10:51:14 -0400 Subject: [PATCH 3/6] feat(order-helper): add public rules loader to default layout --- _layouts/default.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/_layouts/default.html b/_layouts/default.html index dc864fc..cb8ebb3 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -69,6 +69,15 @@ {% if page.custom_css %} {% endif %} +{% if page.url contains '/order-helper/' %} + + +{% endif %} {% if page.url contains '/order-helper/' %} From a9041f6f726e43c49ca71571be70242b0bdf138c Mon Sep 17 00:00:00 2001 From: Lissan <150966211+DataForSolution@users.noreply.github.com> Date: Thu, 18 Sep 2025 10:49:29 -0400 Subject: [PATCH 4/6] feat(order-helper): add non-destructive rules loader shim + cascades --- order-helper/app.js | 120 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/order-helper/app.js b/order-helper/app.js index 2ca2150..b1d427f 100644 --- a/order-helper/app.js +++ b/order-helper/app.js @@ -714,3 +714,123 @@ } })(); +/* ===== OH loader shim (non-destructive) ===== */ +(() => { + // Wait for DOM if this script isn’t loaded with `defer` + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init, { once: true }); + } else { + init(); + } + + function init() { + // Namespace (won't clobber your existing code) + window.OH = window.OH || {}; + const $ = (s) => document.querySelector(s); + const setText = (el, msg) => { if (el) el.textContent = msg; }; + + // Elements (adjust IDs only if yours differ) + const els = { + status: $('#status'), + modality: $('#modality'), + region: $('#region'), + bodyPart: $('#bodyPart'), + contrast: $('#contrast'), + laterality: $('#laterality'), + context: $('#context'), + }; + + // Use the exact meta path (you already include ?v=20250913) + const RULES_URL = + document.querySelector('meta[name="oh-rules-path"]')?.content || + '/order-helper/data/rules.json'; + + const FALLBACK = Object.freeze({ + schema_version: '1.1', + modalities: { + 'PET/CT': { + regions: ['Skull base to mid-thigh', 'Whole body'], + body_parts: ['Head/Neck', 'Chest', 'Abdomen/Pelvis'], + contrast: ['None'], + laterality: ['N/A'], + contexts: ['Staging','Restaging','Treatment response','Surveillance','Acute'], + }, + 'CT': { + regions: ['Head/Brain','Chest','Abdomen/Pelvis'], + body_parts: ['Head','Chest','Abdomen','Pelvis'], + contrast: ['None','IV','Oral','IV + Oral'], + laterality: ['N/A','Right','Left','Bilateral'], + contexts: ['Acute','Follow-up','Staging'], + }, + 'MRI': { + regions: ['Brain','Spine','MSK'], + body_parts: ['Brain','Cervical','Lumbar','Hip'], + contrast: ['None','Gadolinium'], + laterality: ['N/A','Right','Left','Bilateral'], + contexts: ['Acute','Follow-up','Staging'], + } + } + }); + + const validate = (cat) => !!(cat && typeof cat === 'object' && cat.modalities && typeof cat.modalities === 'object'); + + function setOptions(selectEl, items, placeholder) { + if (!selectEl) return; + const list = Array.isArray(items) ? items : []; + selectEl.innerHTML = ''; + const ph = document.createElement('option'); + ph.value = ''; + ph.textContent = placeholder || 'Select…'; + ph.disabled = true; ph.selected = true; + selectEl.appendChild(ph); + for (const v of list) { + const opt = document.createElement('option'); + opt.value = v; opt.textContent = v; + selectEl.appendChild(opt); + } + } + + function bindCascades(cat) { + if (!els.modality) return; + const modalities = Object.keys(cat.modalities || {}); + setOptions(els.modality, modalities, 'Select modality…'); + + els.modality.addEventListener('change', () => { + const m = els.modality.value; + const spec = (cat.modalities || {})[m] || {}; + setOptions(els.region, spec.regions, 'Select region…'); + setOptions(els.bodyPart, spec.body_parts, 'Select body part…'); + setOptions(els.contrast, spec.contrast, 'Select contrast…'); + setOptions(els.laterality, spec.laterality, 'Select laterality…'); + setOptions(els.context, spec.contexts, 'Select context…'); + }); + } + + async function loadCatalog() { + setText(els.status, 'Loading rules…'); + try { + const res = await fetch(RULES_URL, { cache: 'no-store' }); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + const json = await res.json(); + if (!validate(json)) throw new Error('Invalid rules schema'); + setText(els.status, 'Rules loaded.'); + return json; + } catch (err) { + console.warn('[OH] rules load failed, using fallback:', err); + setText(els.status, 'Using built-in defaults (rules.json unavailable).'); + return FALLBACK; + } + } + + // Expose for the rest of your app (non-breaking) + window.OH.loadCatalog = loadCatalog; + + // Boot: load then bind; announce readiness + loadCatalog().then(cat => { + window.OH.catalog = cat; + bindCascades(cat); + document.dispatchEvent(new CustomEvent('oh:catalog-ready', { detail: { catalog: cat } })); + }); + } +})(); + From 25b4bcc97dae879e0f963a8bab7b7a14a5e7409c Mon Sep 17 00:00:00 2001 From: Lissan <150966211+DataForSolution@users.noreply.github.com> Date: Mon, 8 Sep 2025 11:40:55 -0400 Subject: [PATCH 5/6] OH: robust app init (new rules loader + fallbacks); live preview always on --- order-helper/app.js | 963 ++++++++-------------------------------- order-helper/index.html | 357 +++++++++------ 2 files changed, 398 insertions(+), 922 deletions(-) diff --git a/order-helper/app.js b/order-helper/app.js index b1d427f..a57065f 100644 --- a/order-helper/app.js +++ b/order-helper/app.js @@ -1,836 +1,251 @@ - - -/* ===== OH loader shim (non-destructive) ===== */ -(() => { - // Wait for DOM if this script isn’t loaded with `defer` - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', init, { once: true }); + // Run after parse + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); } else { init(); } - - function init() { - // Namespace (won't clobber your existing code) - window.OH = window.OH || {}; - const $ = (s) => document.querySelector(s); - const setText = (el, msg) => { if (el) el.textContent = msg; }; - - // Elements (adjust IDs only if yours differ) - const els = { - status: $('#status'), - modality: $('#modality'), - region: $('#region'), - bodyPart: $('#bodyPart'), - contrast: $('#contrast'), - laterality: $('#laterality'), - context: $('#context'), - }; - - // Use the exact meta path (you already include ?v=20250913) - const RULES_URL = - document.querySelector('meta[name="oh-rules-path"]')?.content || - '/order-helper/data/rules.json'; - - const FALLBACK = Object.freeze({ - schema_version: '1.1', - modalities: { - 'PET/CT': { - regions: ['Skull base to mid-thigh', 'Whole body'], - body_parts: ['Head/Neck', 'Chest', 'Abdomen/Pelvis'], - contrast: ['None'], - laterality: ['N/A'], - contexts: ['Staging','Restaging','Treatment response','Surveillance','Acute'], - }, - 'CT': { - regions: ['Head/Brain','Chest','Abdomen/Pelvis'], - body_parts: ['Head','Chest','Abdomen','Pelvis'], - contrast: ['None','IV','Oral','IV + Oral'], - laterality: ['N/A','Right','Left','Bilateral'], - contexts: ['Acute','Follow-up','Staging'], - }, - 'MRI': { - regions: ['Brain','Spine','MSK'], - body_parts: ['Brain','Cervical','Lumbar','Hip'], - contrast: ['None','Gadolinium'], - laterality: ['N/A','Right','Left','Bilateral'], - contexts: ['Acute','Follow-up','Staging'], - } - } - }); - - const validate = (cat) => !!(cat && typeof cat === 'object' && cat.modalities && typeof cat.modalities === 'object'); - - function setOptions(selectEl, items, placeholder) { - if (!selectEl) return; - const list = Array.isArray(items) ? items : []; - selectEl.innerHTML = ''; - const ph = document.createElement('option'); - ph.value = ''; - ph.textContent = placeholder || 'Select…'; - ph.disabled = true; ph.selected = true; - selectEl.appendChild(ph); - for (const v of list) { - const opt = document.createElement('option'); - opt.value = v; opt.textContent = v; - selectEl.appendChild(opt); - } - } - - function bindCascades(cat) { - if (!els.modality) return; - const modalities = Object.keys(cat.modalities || {}); - setOptions(els.modality, modalities, 'Select modality…'); - - els.modality.addEventListener('change', () => { - const m = els.modality.value; - const spec = (cat.modalities || {})[m] || {}; - setOptions(els.region, spec.regions, 'Select region…'); - setOptions(els.bodyPart, spec.body_parts, 'Select body part…'); - setOptions(els.contrast, spec.contrast, 'Select contrast…'); - setOptions(els.laterality, spec.laterality, 'Select laterality…'); - setOptions(els.context, spec.contexts, 'Select context…'); - }); - } - - async function loadCatalog() { - setText(els.status, 'Loading rules…'); - try { - const res = await fetch(RULES_URL, { cache: 'no-store' }); - if (!res.ok) throw new Error(`HTTP ${res.status}`); - const json = await res.json(); - if (!validate(json)) throw new Error('Invalid rules schema'); - setText(els.status, 'Rules loaded.'); - return json; - } catch (err) { - console.warn('[OH] rules load failed, using fallback:', err); - setText(els.status, 'Using built-in defaults (rules.json unavailable).'); - return FALLBACK; - } - } - - // Expose for the rest of your app (non-breaking) - window.OH.loadCatalog = loadCatalog; - - // Boot: load then bind; announce readiness - loadCatalog().then(cat => { - window.OH.catalog = cat; - bindCascades(cat); - document.dispatchEvent(new CustomEvent('oh:catalog-ready', { detail: { catalog: cat } })); - }); - } })(); - diff --git a/order-helper/index.html b/order-helper/index.html index d3a7867..20d97a4 100644 --- a/order-helper/index.html +++ b/order-helper/index.html @@ -2,24 +2,26 @@ layout: default title: OraDigit Order Helper permalink: /order-helper/ -description: Evidence-based PET/CT, CT, MRI, US, X-Ray — structured order helper with validation and PDF export. No PHI. Educational use only. -oh_loader: true +description: Evidence-based PET/CT, CT, and MRI order helper with validation and export. No PHI. Educational use only. --- - - - + + + @@ -30,200 +32,259 @@ if (!s) return; try { const url = document.querySelector('meta[name="oh-rules-path"]')?.content; - if (!url) { s.textContent = 'Missing oh-rules-path meta.'; s.className = 'oh-status error'; return; } + if (!url) { s.textContent = 'Missing oh-rules-path meta.'; s.className = 'status error'; return; } s.textContent = 'Boot check… fetching rules…'; const r = await fetch(url, { cache: 'no-store' }); - if (r.ok) { s.textContent = 'Boot check OK. Loading app…'; s.className = 'oh-status success'; } - else { s.textContent = `Rules fetch failed (${r.status}). Check path/case: ` + url; s.className = 'oh-status error'; } + if (r.ok) { s.textContent = 'Boot check OK. Loading app…'; s.className = 'status success'; } + else { s.textContent = `Rules fetch failed (${r.status}). Check path/case: ` + url; s.className = 'status error'; } } catch (e) { s.textContent = 'Rules fetch error: ' + e.message; - s.className = 'oh-status error'; + s.className = 'status error'; } }); -- Structure payer-ready imaging orders. Select modality and context; we’ll generate a professional - clinical indication, show prep/flags, and export a PDF. All client-side. No PHI. +
+ Structure clear, payer-ready imaging orders. Select modality and context; we’ll generate + a professional clinical indication and surface prep/flags. All client-side. No PHI.
-