diff --git a/database/schema.sql b/database/schema.sql index 66196c6..c512305 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -245,7 +245,23 @@ CREATE TABLE medication_administrations ( notes TEXT, source TEXT DEFAULT 'manual', created_at TEXT DEFAULT CURRENT_TIMESTAMP, - UNIQUE(datum, medication_name, event_type) + occurred_at TEXT, + medication_id INTEGER REFERENCES medikamente(id), + planned_event_id INTEGER REFERENCES medication_administrations(id), + planned_dose_value TEXT, + planned_dose_unit TEXT, + actual_dose_value TEXT, + actual_dose_unit TEXT, + route_original TEXT, + route_normalized TEXT, + injection_region TEXT, + injection_side TEXT, + injection_detail TEXT, + lot_number TEXT, + corrects_event_id INTEGER REFERENCES medication_administrations(id), + corrected_target_status TEXT, + correction_reason TEXT, + business_revision TEXT ); CREATE TABLE medikamente ( @@ -256,6 +272,10 @@ CREATE TABLE medikamente ( anwendungsform TEXT, erhaltungsform TEXT, ermittlung_datum TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + prescription_status TEXT, + prescription_status_source TEXT, + prescription_status_provenance TEXT, + business_revision TEXT, FOREIGN KEY (dokument_id) REFERENCES dokumente(id) ); diff --git a/scripts/health/assets/health-assets/dashboard-v5-record.js b/scripts/health/assets/health-assets/dashboard-v5-record.js index 9482935..e6e22c2 100644 --- a/scripts/health/assets/health-assets/dashboard-v5-record.js +++ b/scripts/health/assets/health-assets/dashboard-v5-record.js @@ -20,7 +20,7 @@ const FILTER_KEYS = { overview: [], labs: ['q', 'from', 'to', 'status', 'source'], - medications: ['from', 'to'], + medications: ['from', 'to', 'medication', 'status', 'source'], appointments: ['from', 'to', 'order', 'institution'], documents: ['q', 'from', 'to', 'category', 'institution', 'type', 'review_status', 'original_status', 'extraction_status', 'search_status', 'queue', 'sort', 'cursor', 'limit'], report: ['from', 'to', 'sections', 'charts'], @@ -729,16 +729,85 @@ return node; } + const medicationDose = item => { + const actual = [item.actual_dose_value, item.actual_dose_unit].filter(Boolean).join(' '); + const planned = [item.planned_dose_value, item.planned_dose_unit].filter(Boolean).join(' '); + if(item.status==='administered') return actual || (item.legacy_dose ? `Legacy-Freitext (nicht als tatsächliche Dosis strukturiert): ${item.legacy_dose}` : 'Tatsächliche Dosis nicht dokumentiert'); + if(item.status==='planned') return planned || (item.legacy_dose ? `Legacy-Freitext (nicht strukturiert): ${item.legacy_dose}` : 'Geplante Dosis nicht dokumentiert'); + if(item.status==='corrected') { + if(item.effective_status==='administered') return actual || 'Korrigierte tatsächliche Dosis nicht dokumentiert'; + if(item.effective_status==='planned') return planned || 'Korrigierte geplante Dosis nicht dokumentiert'; + return 'Korrigierter Zielstatus: ausgelassen'; + } + return item.legacy_dose ? `Legacy-Freitext (nicht strukturiert): ${item.legacy_dose}` : 'Dosis nicht dokumentiert'; + }; + + function medicationActionDialog(prescription, eventItem = null, mode = 'administered') { + const dialog = document.createElement('dialog'); dialog.className = 'medication-action-dialog'; + const form = document.createElement('form'); form.method = 'dialog'; + const heading = ({administered:'Einnahme oder Verabreichung dokumentieren',missed:'Auslassung dokumentieren',corrected:'Eintrag korrigieren'})[mode]; + form.append(element('h2', heading), element('p', 'Dokumentation ohne medizinische Bewertung oder Änderung der Verordnung.', 'v5-meta')); + const when = document.createElement('input'); when.type='datetime-local'; when.required=true; when.value=document.querySelector("#medication-event-dialog input[name='occurred_at']")?.value || ''; + const actualValue=document.createElement('input'); actualValue.maxLength=40; actualValue.value=eventItem?.actual_dose_value||''; actualValue.required=mode==='administered'; + const actualUnit=document.createElement('input'); actualUnit.maxLength=30; actualUnit.value=eventItem?.actual_dose_unit||''; actualUnit.required=mode==='administered'; + const routeOriginal=document.createElement('input'); routeOriginal.maxLength=60; routeOriginal.value=eventItem?.route_original||''; + const route=document.createElement('select'); [['unknown','Nicht angegeben'],['oral','Oral'],['subcutaneous','Subkutan'],['intravenous','Intravenös'],['intramuscular','Intramuskulär'],['topical','Äußerlich'],['inhaled','Inhalativ'],['other','Andere dokumentierte Route']].forEach(([value,label])=>{const option=element('option',label);option.value=value;option.selected=(eventItem?.route_normalized||'unknown')===value;route.append(option);}); + const region=document.createElement('input');region.maxLength=80;const side=document.createElement('select');[['','Nicht angegeben'],['left','Links'],['right','Rechts'],['unspecified','Seite nicht angegeben']].forEach(([value,label])=>{const option=element('option',label);option.value=value;side.append(option);});const injectionDetail=document.createElement('input');injectionDetail.maxLength=120; + const lot=document.createElement('input');lot.maxLength=80;const note=document.createElement('textarea');note.maxLength=300; + const correctionStatus=document.createElement('select');[['planned','Geplant'],['administered','Verabreicht / eingenommen'],['missed','Ausgelassen']].forEach(([value,label])=>{const option=element('option',label);option.value=value;correctionStatus.append(option);});const correctionReason=document.createElement('textarea');correctionReason.maxLength=300;correctionReason.required=mode==='corrected'; + const planConfirmed=document.createElement('input');planConfirmed.type='checkbox';const deviationConfirmed=document.createElement('input');deviationConfirmed.type='checkbox';const duplicateConfirmed=document.createElement('input');duplicateConfirmed.type='checkbox'; + form.append(formRow('Medikament', element('strong', prescription.name)), formRow('Zeitpunkt', when)); + if(mode!=='missed') form.append(formRow('Tatsächlich dokumentierte Dosis', actualValue),formRow('Einheit',actualUnit),formRow('Originalbezeichnung Applikationsweg',routeOriginal),formRow('Normalisierte Anzeige',route)); + if(mode==='corrected') form.append(formRow('Korrigierter Zielstatus',correctionStatus),formRow('Korrekturbegründung',correctionReason)); + if(mode==='administered') form.append(formRow('Geplante Angabe bewusst bestätigt',planConfirmed),formRow('Abweichende tatsächliche Angabe bewusst bestätigt',deviationConfirmed)); + const extra=document.createElement('details');extra.append(element('summary','Weitere Angaben'));const extraBody=element('div',undefined,'medication-extra-fields');extraBody.append(formRow('Injektionsregion',region),formRow('Seite',side),formRow('Ergänzung zur Injektionsstelle',injectionDetail),formRow('Charge',lot),formRow('Notiz',note),formRow('Möglichen identischen Doppeleintrag nach Prüfung zulassen',duplicateConfirmed));extra.append(extraBody);form.append(extra); + const preview=element('section',undefined,'medication-action-preview');preview.hidden=true;preview.setAttribute('aria-live','polite');form.append(preview); + const controls=element('div',undefined,'record-actions');const cancel=button('Abbrechen',()=>dialog.close());const submit=button('Vorschau prüfen',()=>form.requestSubmit());controls.append(cancel,submit);form.append(controls);dialog.append(form);document.body.append(dialog); + const injectionRoutes=new Set(['subcutaneous','intravenous','intramuscular','other']);const syncInjection=()=>{const enabled=injectionRoutes.has(route.value);[region,side,injectionDetail].forEach(input=>{input.disabled=!enabled;if(!enabled)input.value='';});};route.addEventListener('change',syncInjection);syncInjection(); + let frozen=null;form.addEventListener('input',()=>{if(frozen){frozen=null;preview.hidden=true;submit.textContent='Vorschau prüfen';}}); + form.addEventListener('submit',async event=>{event.preventDefault();if(!frozen){ + if(mode==='administered'&&!planConfirmed.checked&&!deviationConfirmed.checked){status.textContent='Bitte geplante oder abweichende tatsächliche Angabe bewusst bestätigen.';return;} + const revision=mode==='corrected'?eventItem?.correction_preview_revision:(eventItem?.administration_preview_revision||prescription.preview_revision); + if(!revision){status.textContent='Die unveränderliche Vorschau konnte nicht sicher gebunden werden.';return;} + const data={contract:'health.medication_action.v1',status:mode,medication_ref:prescription.id,planned_event_ref:mode!=='corrected'&&eventItem?.status==='planned'?eventItem.id:'',name:prescription.name,planned_dose_value:eventItem?.planned_dose_value||'',planned_dose_unit:eventItem?.planned_dose_unit||'',actual_dose_value:mode==='missed'?'':actualValue.value.trim(),actual_dose_unit:mode==='missed'?'':actualUnit.value.trim(),route_original:mode==='missed'?'':routeOriginal.value.trim(),route_normalized:mode==='missed'?'unknown':route.value,injection_region:region.value.trim(),injection_side:side.value,injection_detail:injectionDetail.value.trim(),lot_number:lot.value.trim(),correction_target_ref:mode==='corrected'?eventItem.id:'',corrected_target_status:mode==='corrected'?correctionStatus.value:'',correction_reason:mode==='corrected'?correctionReason.value.trim():'',note:note.value.trim(),preview_revision:revision,plan_value_confirmed:planConfirmed.checked,deviation_confirmed:deviationConfirmed.checked,duplicate_confirmed:duplicateConfirmed.checked}; + const draft={version:1,action:'capture_entry',capture_type:'medication',request_version:1,idempotency_key:[...crypto.getRandomValues(new Uint8Array(16))].map(value=>value.toString(16).padStart(2,'0')).join(''),occurred_at:when.value,ended_at:null,data,attachments:[],corrects_entry_id:null,withdraws_entry_id:null}; + submit.disabled=true; + try { + const body=new URLSearchParams({csrf_token:shell.dataset.recordCsrf||'',return_to:'v5',payload:JSON.stringify(draft)}); + const response=await fetch('/health-actions/medication-preview',{method:'POST',credentials:'same-origin',headers:{'Accept':'application/json','Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'},body:body.toString()}); + if(!response.ok) throw new Error(`preview_${response.status}`); + const result=await response.json(); + if(!/^[a-f0-9]{64}$/.test(String(result.preview_revision||''))) throw new Error('preview_invalid'); + draft.data.preview_revision=result.preview_revision; + frozen=draft; + } catch(_error) { + status.textContent='Die Vorschau konnte nicht sicher serverseitig gebunden werden. Es wurde nichts vorgemerkt.'; + return; + } finally { + submit.disabled=false; + } + preview.replaceChildren(element('h3','Unveränderliche Vorschau'),element('p',`${when.value} · ${prescription.name} · ${mode==='administered'?'Verabreicht / eingenommen':mode==='missed'?'Ausgelassen':`Korrigiert zu ${correctionStatus.options[correctionStatus.selectedIndex].text}`}`),element('p',`Geplant: ${eventItem?medicationDose(eventItem):(prescription.documented_dose||'nicht strukturiert dokumentiert')} · Tatsächlich: ${actualValue.value||'nicht angegeben'} ${actualUnit.value}`,'v5-meta'),element('p',mode==='corrected'?`Begründung: ${correctionReason.value}`:'Keine Änderung der Verordnung.','v5-meta'));preview.hidden=false;submit.textContent='Verbindlich vormerken';return; + } + const post=document.createElement('form');post.method='post';post.action='/health-actions/capture';post.hidden=true;const fields={csrf_token:shell.dataset.recordCsrf||'',return_to:'v5',payload:JSON.stringify(frozen)};Object.entries(fields).forEach(([name,value])=>{const input=document.createElement('input');input.type='hidden';input.name=name;input.value=value;post.append(input);});document.body.append(post);post.submit(); + }); + dialog.addEventListener('close',()=>dialog.remove(),{once:true});dialog.showModal();when.focus(); + } + async function renderMedications(filters = {}, current) { const node = card('Medikamente'); - const data = await request(`/api/v1/medications?${query(filters)}`, current); - ['planned', 'administered', 'missed', 'corrected'].forEach(kind => { - const section = element('section'); section.append(element('h4', ({ planned: 'Geplant', administered: 'Tatsächlich verabreicht', missed: 'Ausgelassen', corrected: 'Korrigiert' })[kind])); + const safeFilters=sanitizeFilters('medications',filters); + const data = await request(`/api/v1/medications?${query(safeFilters)}`, current); + const form=element('form',undefined,'record-filter-form');const from=document.createElement('input');from.type='date';from.value=safeFilters.from||'';const to=document.createElement('input');to.type='date';to.value=safeFilters.to||'';const medication=document.createElement('select');[['','Alle Medikamente'],...(data.prescriptions||[]).map(item=>[item.id,item.name])].forEach(([value,label])=>{const option=element('option',label);option.value=value;option.selected=safeFilters.medication===value;medication.append(option);});const eventStatus=document.createElement('select');[['','Alle Status'],['planned','Geplant'],['administered','Verabreicht / eingenommen'],['missed','Ausgelassen'],['corrected','Korrigiert'],['unknown','Unbekannt']].forEach(([value,label])=>{const option=element('option',label);option.value=value;option.selected=safeFilters.status===value;eventStatus.append(option);});const source=document.createElement('select');[['','Alle Quellen'],...(data.sources||[]).map(value=>[value,sourceLabel(value)])].forEach(([value,label])=>{const option=element('option',label);option.value=value;option.selected=safeFilters.source===value;source.append(option);});form.append(formRow('Von',from),formRow('Bis',to),formRow('Medikament',medication),formRow('Status',eventStatus),formRow('Quelle',source),button('Filter anwenden',()=>form.requestSubmit()));form.addEventListener('submit',event=>{event.preventDefault();render('medications',{push:true,filters:{from:from.value,to:to.value,medication:medication.value,status:eventStatus.value,source:source.value}});});node.append(form); + const currentSection=element('section',undefined,'medication-current');currentSection.append(element('h4','Aktive Verordnungen'));(data.current_prescriptions||[]).forEach(item=>{const article=element('article',undefined,'medication-prescription-row');article.append(element('strong',item.name),element('span','Aktiv','status-chip'),element('p',item.documented_dose||'Dosis nicht strukturiert dokumentiert','v5-meta'));article.append(button('Jetzt als eingenommen / verabreicht dokumentieren',()=>medicationActionDialog(item)));currentSection.append(article);});if(!(data.current_prescriptions||[]).length)appendEmpty(currentSection);node.append(currentSection); + const otherSection=element('section',undefined,'medication-other-prescriptions');otherSection.append(element('h4','Pausierte, beendete oder unklare Verordnungen'));(data.other_prescriptions||[]).forEach(item=>{const article=element('article',undefined,'medication-prescription-row');const label=item.status==='paused'?'Pausiert':item.status==='ended'?'Beendet':'Status unbekannt';article.append(element('strong',item.name),element('span',label,'status-chip'),element('p','Keine Darstellung als aktuell aktive Verordnung.','v5-meta'));otherSection.append(article);});if(!(data.other_prescriptions||[]).length)appendEmpty(otherSection);node.append(otherSection,element('h4','Verlauf')); + const prescriptionsById=new Map((data.prescriptions||[]).map(item=>[item.id,item])); + ['planned', 'administered', 'missed', 'corrected', 'unknown'].forEach(kind => { + const section = element('section'); section.append(element('h5', ({ planned: 'Geplant', administered: 'Tatsächlich verabreicht / eingenommen', missed: 'Ausgelassen', corrected: 'Korrigiert',unknown:'Status unbekannt' })[kind])); const rows = data[kind] || []; - section.append(rows.length ? table(['Datum', 'Medikament', 'Dosis', 'Quelle'], rows.map(item => [item.date, item.name, item.dose, sourceLabel(item.source)])) : element('p', 'Keine dokumentierten Angaben.')); - node.append(section); + if(!rows.length){section.append(element('p','Keine dokumentierten Angaben.'));node.append(section);return;} + const list=element('div',undefined,'medication-history-list');rows.forEach(item=>{const article=element('article',undefined,'medication-history-row');article.append(element('div',`${item.date} · ${item.name} · ${medicationDose(item)} · ${sourceLabel(item.source)}`));if(item.superseded_by_correction)article.append(element('span','Durch Korrektur ersetzt','status-chip'));const details=document.createElement('details');details.append(element('summary','Details'));const facts=element('dl');[['Status',item.status],['Geplante Dosis',[item.planned_dose_value,item.planned_dose_unit].filter(Boolean).join(' ')||'Nicht strukturiert dokumentiert'],['Tatsächliche Dosis',[item.actual_dose_value,item.actual_dose_unit].filter(Boolean).join(' ')||item.legacy_dose||'Nicht dokumentiert'],['Applikationsweg (Original)',item.route_original||'Nicht angegeben'],['Applikationsweg (Anzeige)',item.route_normalized||'Unbekannt'],['Injektionsstelle',[item.injection_region,item.injection_side,item.injection_detail].filter(Boolean).join(' · ')||'Nicht angegeben'],['Charge',item.lot_number||'Nicht angegeben'],['Notiz',item.note||'Nicht angegeben'],['Korrekturbegründung',item.correction_reason||'Nicht angegeben'],['Quelle',sourceLabel(item.source)]].forEach(([label,value])=>facts.append(element('dt',label),element('dd',value)));details.append(facts);article.append(details);const prescription=prescriptionsById.get(item.prescription_id);if(prescription&&kind==='planned'&&!item.plan_consumed){article.append(button('Als eingenommen / verabreicht dokumentieren',()=>medicationActionDialog(prescription,item,'administered')),button('Auslassung dokumentieren',()=>medicationActionDialog(prescription,item,'missed')));}if(prescription&&!item.superseded_by_correction&&item.correction_preview_revision)article.append(button('Eintrag korrigieren',()=>medicationActionDialog(prescription,item,'corrected')));list.append(article);});section.append(list);node.append(section); }); - node.append(element('p', `Datenvollständigkeit: ${data.truncated ? `gekürzt (${data.truncated_sections.join(', ')})` : 'vollständige Seite'}`, 'v5-meta')); + node.append(element('p', `Datenvollständigkeit: ${data.truncated ? `gekürzt (${data.truncated_sections.join(', ')})` : 'vollständige Seite'} · Fehlende Legacy-Felder bleiben unbekannt.`, 'v5-meta')); return node; } @@ -793,7 +862,7 @@ const personalDraws=[]; if(data.selected_sections.includes('overview')){const part=section('Datenabdeckung und fehlende Bereiche');const rows=Object.entries(data.completeness||{}).map(([key,item])=>[sectionNames[key]||key,item.status==='documented'?'Daten dokumentiert':'Nicht dokumentiert',item.truncated?'Aus Sicherheitsgründen gekürzt':'Vollständige begrenzte Antwort']);part.append(table(['Bereich','Abdeckung','Umfang'],rows));} if(data.selected_sections.includes('symptoms')){const part=section('Beschwerden und Symptomereignisse');const rows=[...(data.additional_symptoms||[]).map(item=>[item.occurred_at||item.date,item.symptom,item.severity??'unbekannt',item.note||'']),...(data.symptoms||[]).map(item=>[item.date,'7-Dimensionen-Tageswert',item.symptoms?.total??'unvollständig',''])];rows.length?part.append(table(['Zeitpunkt','Beschwerde','Schweregrad','Notiz'],rows)):empty(part);} - if(data.selected_sections.includes('medications')){const part=section('Medikamentenverlauf');[['Tatsächlich verabreicht','administered'],['Ausgelassen','missed'],['Korrigiert','corrected'],['Geplant – separat','planned']].forEach(([label,key])=>{part.append(element('h4',label));const rows=(data.medications?.[key]||[]).map(item=>[item.date,item.name,item.dose||'Dosis nicht dokumentiert']);rows.length?part.append(table(['Datum','Medikament','Dosis'],rows)):empty(part);});} + if(data.selected_sections.includes('medications')){const part=section('Medikamentenverlauf');[['Tatsächlich verabreicht','administered'],['Ausgelassen','missed'],['Korrigiert','corrected'],['Geplant – separat','planned'],['Status unbekannt – nicht interpretiert','unknown']].forEach(([label,key])=>{part.append(element('h4',label));const rows=(data.medications?.[key]||[]).map(item=>[item.date,item.name,item.status==='corrected'?`Zielstatus: ${item.effective_status||'unbekannt'} · ${medicationDose(item)}`:medicationDose(item)]);rows.length?part.append(table(['Datum','Medikament','Dokumentierte Angabe'],rows)):empty(part);});} if(data.selected_sections.includes('supplements')){const part=section('Supplemente');[['Tatsächlich eingenommen','administered'],['Ausgelassen','missed'],['Korrigiert','corrected'],['Geplant – separat','planned']].forEach(([label,key])=>{part.append(element('h4',label));const rows=(data.supplements?.[key]||[]).map(item=>[item.date,item.product,`${item.amount} ${item.unit} ${item.nutrient}`,item.composition_source,item.assignment_reliability]);rows.length?part.append(table(['Datum','Präparat','Dokumentierte Menge','Zusammensetzungsquelle','Zuordnung'],rows)):empty(part);});part.append(element('p','Dokumentierte Einnahme; keine Dosierungsempfehlung oder Aussage über einen Bedarf.','doctor-summary-disclaimer'));} if(data.selected_sections.includes('labs')){const part=section('Relevante Laborverläufe');const rows=(data.labs||[]).map(item=>[item.date,item.parameter,`${text(item.display_value ?? `${item.operator||''}${item.value}`)} ${text(item.unit)}`]);rows.length?part.append(table(['Datum','Parameter','Wert'],rows)):empty(part);} if(data.selected_sections.includes('observations')){const part=section('Schlaf, Kreislauf und Aktivität');(data.observations||[]).forEach(metric=>{part.append(element('h4',metric.label||'Körperwert'));const rows=(metric.points||[]).filter(point=>point.value!==null&&point.value!==undefined).map(point=>[point.date,`${point.value} ${metric.unit||''}`.trim()]);rows.length?part.append(table(['Datum','Dokumentierter Wert'],rows)):empty(part);});if(!(data.observations||[]).length)empty(part);} diff --git a/tests/fixtures/dashboard_v5_fixture.py b/tests/fixtures/dashboard_v5_fixture.py index ec678a4..2383b42 100644 --- a/tests/fixtures/dashboard_v5_fixture.py +++ b/tests/fixtures/dashboard_v5_fixture.py @@ -227,6 +227,15 @@ def build_dashboard_v5_fixture( ) ], ) + connection.executemany( + "INSERT INTO medikamente(medikament_name,dosierung,anwendungsform,prescription_status,prescription_status_source,prescription_status_provenance,ermittlung_datum) VALUES(?,?,?,?,?,?,?)", + [ + ("SYNTHETIC_EVENT_ON_MEASUREMENT_GAP", "10 mg", "synthetic", "unknown", "fixture", "synthetic fixture", fixture_timestamp), + ("SYNTHETIC_ADMINISTERED_MEDICATION", "10 mg", "synthetic", "active", "fixture", "synthetic fixture", fixture_timestamp), + ("SYNTHETIC_PLANNED_MEDICATION_WITH_A_VERY_LONG_LABEL_FOR_RESPONSIVE_LAYOUT", "10 mg", "synthetic", "active", "fixture", "synthetic fixture", fixture_timestamp), + ("SYNTHETIC_CANCELLED_MEDICATION", "10 mg", "synthetic", "ended", "fixture", "synthetic fixture", fixture_timestamp), + ], + ) connection.executemany( """INSERT INTO medication_administrations (datum,medication_name,dose,route,event_type,scheduled_next_date,notes,source,created_at) @@ -345,6 +354,14 @@ def build_dashboard_v5_fixture( worker_module.apply_document_schema(connection) worker_module.apply_media_schema(connection) importlib.import_module("dashboard_v5.sprint6i_c_schema").apply_schema(connection) + importlib.import_module("dashboard_v5.medication_schema").apply_schema(connection) + connection.execute( + "UPDATE medication_public_identity_key SET key=? WHERE singleton=1", + (bytes.fromhex("7cf0" * 16),), + ) + connection.execute( + "UPDATE medication_schema_meta SET installed_at='2026-06-15 12:00:00'" + ) recomputed_days = [*exposure_days, current] for nutrition_day in recomputed_days: worker_module.recompute_nutrition_day(connection, _iso_day(nutrition_day)) __HERMES_CWD_8d46a20096ed__/home/agent/.hermes/repos/HealthManager__HERMES_CWD_8d46a20096ed__