Identifier.system nella conversione v2→FHIR: chi decide l’URI dell’anagrafe
Da PID-3 a Identifier.system: cosa dicono davvero le ConceptMap del v2-to-FHIR IG, perché il registro degli identificativi non può rispondere, e come si decide in un progetto.
Un messaggio ADT arriva da un anagrafico ospedaliero e va convertito in FHIR. Il segmento che porta gli identificativi del paziente, ridotto all’osso e sintetico, è questo:
PID|1||441122^^^RIVERLAND^MR~3950000000^^^AUSHIC&2.16.840.1.113883.3.879&ISO^MC||ROSSI^MARIO||19800101|M
Due numeri. Il primo è un numero di cartella locale, e l’unica indicazione di provenienza è la stringa RIVERLAND. Il secondo porta anche un OID e la sigla ISO che dice cos’è quell’OID. La domanda da cui dipende tutto il resto della conversione è una sola: quale URI finisce in Identifier.system?
In FHIR system è il namespace del valore: dice quale anagrafe ha emesso quel numero. Due record vengono riconosciuti come lo stesso identificativo solo se coincidono valore e system. Sbagliare quel campo produce uno di due danni, entrambi silenziosi. Se il system viene derivato dal testo, la stessa anagrafe finisce spezzata in più namespace il giorno in cui un mittente cambia maiuscole o abbreviazione, e lo stesso paziente diventa due persone. Se il system manca, numeri di anagrafi diverse finiscono nello stesso secchio, e due pazienti diventano uno.
L’errore: urn:oid: al posto dell’autorità assegnante
La settimana scorsa abbiamo passato in rassegna l’output di un convertitore v2→FHIR di un collega, in una discussione pubblica su chat.fhir.org. Fra le altre cose gli abbiamo detto che il secondo identificativo del messaggio sopra doveva diventare system: "urn:oid:2.16.840.1.113883.3.879", perché l’OID è lì e la sigla dice che è un OID ISO. Lui l’ha implementato. Noi avevamo torto, e la correzione è più interessante dell’errore.
Le ConceptMap HD→uri e CX→Identifier
Le regole di mappatura del v2-to-FHIR Implementation Guide sono pubblicate come ConceptMap scaricabili, ed è più affidabile leggere il JSON che la pagina. Qui ne entrano in gioco due.
La prima mappa il tipo di dato HD verso un URI. HD ha tre componenti: un nome locale, un identificativo globale, e un codice che dice di che tipo è quell’identificativo globale (la tabella HL7 0301: ISO per un OID, UUID, DNS, URI, L per locale, e altri). La mappa dice che HD.1 — il nome locale — diventa l’URI così com’è, senza condizioni. E dice che HD.2 diventa urn:oid: più il valore solo se HD.1 non è valorizzato e HD.3 è ISO; urn:uuid: alla stessa condizione se HD.3 è UUID; il valore nudo negli altri casi.
La seconda mappa CX — il tipo di dato dell’identificativo — verso Identifier. CX.4, l’autorità assegnante, va in system solo se CX.4 è nel registro degli identificativi di FHIR. Altrimenti va in assigner, che è un riferimento a una Organization, accompagnato dall’istruzione di decidere caso per caso se si tratta di un’organizzazione o di un sistema.
Applicate alla lettera al nostro messaggio: HD.1 è valorizzato (AUSHIC), quindi le righe che producono l’urn:oid: non scattano. E AUSHIC non è nel registro, quindi non finisce nemmeno in system. Alla lettera, quel numero non ha un system: ha un assigner. Il nostro urn:oid: era un output migliore di quello previsto dalla regola, ma era una deviazione. E una deviazione non dichiarata, in un convertitore, è il problema — non la deviazione.
Il registro degli identificativi R4: 57 voci, quasi tutte statunitensi
La condizione che decide tutto è “se l’autorità assegnante è nel registro”. Vale la pena aprirlo. Nella R4 il registro degli identificativi ha 57 righe: l’UID DICOM, il GTIN, e per il resto identificativi statunitensi — Social Security Number, Medicare, MBI, National Provider Identifier e una cinquantina di patenti di guida per singolo stato. Nessuna voce australiana. Nessuna voce italiana. Per qualunque mittente fuori dagli Stati Uniti quella condizione può solo risultare falsa. La regola non è sbagliata: non ha niente da indicare.
Ed è in via di pensionamento. Nella build continua della specifica quella pagina non contiene più alcun elenco: il contenuto è stato spostato in HL7 Terminology, curato da HL7 International, con l’indicazione di seguire la procedura del Terminology Services Management Group quando un URI non è registrato. La ConceptMap, però, punta ancora alla pagina vecchia.
Le guide di base nazionali: AU Base e HL7 Italia
Il posto giusto per questa decisione è la guida di base del paese del mittente, e qui si vede quanto cambia il paese.
L’Australia ce l’ha. AU Base fissa, nel profilo dedicato al numero Medicare, Identifier.system a un URI preciso e vincola il tipo al codice MC della tabella 0203. Per quell’identificativo la risposta esiste, scritta, in un documento pubblicato: non nella IG di mappatura e non nel registro.
L’Italia è più scoperta. Il profilo Patient di HL7 Italia divide Patient.identifier in slice per tipo di identificativo. Il codice fiscale ha il system fissato a http://hl7.it/sid/codiceFiscale, con anche un’invariante che ne controlla i sedici caratteri; l’identificativo ANPR è fissato allo stesso modo. Ma la slice che riceve il numero che un ospedale italiano mette davvero in PID-3 è quella dell’identificativo regionale, e lì il system è obbligatorio con un binding required a un value set di URI. Quel value set contiene cinque voci: Lazio, Piemonte, Valle d’Aosta, Veneto, Friuli-Venezia Giulia — tre espresse come urn:oid: e due come URL sotto hl7.it. Un mittente di qualunque altra regione non ha un valore conforme da mettere in un elemento obbligatorio.
Non è una colpa di nessuno: quel profilo è dichiarato in stato draft e risale a una ballot di commento pubblico del 2020. È però il dato di fatto con cui si apre un progetto oggi: per la maggior parte dei mittenti italiani la risposta non c’è.

L’assegnazione del system è una decisione di progetto
Quando non c’è una regola da applicare, la scelta la fa qualcuno. Meglio che la faccia in modo esplicito e scritto. Nella nostra esperienza funziona così:
- una tabella, in configurazione e non nel codice, che va dall’autorità assegnante all’URI del system, definita per mittente e versionata insieme all’interfaccia;
- dove esiste un URI nazionale o regionale pubblicato, si usa quello, anche se è più scomodo di uno inventato;
- dove non esiste, se ne definisce uno sotto un dominio che controlliamo noi, e si scrive nero su bianco che è locale;
- il system non si deriva mai dal testo dell’HD: la stessa autorità scritta in due modi diventa due anagrafi;
- un identificativo senza system non si emette: meglio un URI locale dichiarato che nessuno.
E il report della conversione deve dire, per ogni identificativo, quale regola ha applicato. Perché questo è uno dei pochi casi in cui la validazione non aiuta: un system sbagliato è un URI perfettamente valido. Nessun validatore — nemmeno BridgeLab, il workbench con cui ispezioniamo questi messaggi — può sapere se l’anagrafe che hai nominato è quella che ha emesso il numero.
Da cui la domanda da fare a chi vi porta un convertitore, prima di guardare quanti tipi di messaggio supporta: quale URI mettete in Identifier.system per le nostre autorità assegnanti, quell’elenco è configurabile, e il report dice quale regola avete applicato a ciascun identificativo?