---
{
  "title": "Terminology is fun: CodeableConcept.coding[]",
  "description": "CodeableConcept a través del prisma productor/consumidor: por qué un campo contiene múltiples códigos, qué debe capturar el productor mientras aún puede, y cómo debe interpretar el array el consumidor —pertenencia, subsunción, proyección— sin que .first() le juegue una mala pasada.",
  "date": "2026-05-28",
  "author": "Nikolai Ryzhikov",
  "reading-time": "12 min read",
  "tags": ["FHIR Standard", "Terminology", "Analytics"],
  "tldr": "CodeableConcept es un protocolo que salva una brecha: el productor conoce la realidad pero no a los lectores; cada consumidor conoce su caso de uso pero no las decisiones del productor. Por eso un campo contiene muchos códigos, ninguno de ellos es «el principal» y el orden no significa nada. Reglas para el productor: capture todo aquello que solo usted sabe —el código más preciso, códigos en sistemas alternativos, texto, userSelected, meta.profile—. Reglas para el consumidor: la interpretación es su responsabilidad —clasifique su tipo de consumo (pertenencia, proyección, tránsito), compruebe la pertenencia mediante subsunción, nunca mediante .first()—.",
  "utm-campaign": "fhir_expert",
  "utm-content": "codeableconcept-codings"
}
---

> For the complete documentation index, see [llms.txt](https://www.health-samurai.io/llms.txt).
> Use it to discover all available pages before guessing URLs.

---

Elimine los elementos codificados de un recurso FHIR y lo que queda es fontanería: ids, referencias, fechas, estados. *Qué* es la condición, *qué* se observó, *qué* se prescribió —el significado de los datos sanitarios reside en la terminología—. La estructura le indica que existe una Condition y a quién pertenece; los códigos le dicen qué *es* en realidad.

Y casi en cualquier lugar donde aparece un significado en FHIR, aparece como un único tipo de dato: `CodeableConcept` — Condition.code, Observation.code, Procedure.code, MedicationRequest.medication, AllergyIntolerance.code. Aprenda a leer correctamente este único tipo y habrá aprendido a leer la semántica de FHIR; léalo mal y la estructura permanecerá perfectamente válida mientras el significado se escapa en silencio.

Entonces, ¿cómo leer e interpretar `CodeableConcept` correctamente? Por ejemplo, si estoy consultando un diagnóstico en SNOMED CT.

La primera idea es usar `code.coding.where(system='...snomed...').code.first()`.
Pero eso no es correcto. Eso es lo que aprendí en la reunión del grupo de trabajo HL7 FHIR-I de Lloyd McKenzie.

> Puede haber perfectamente dos o tres códigos SNOMED, y hay que contemplar esa posibilidad.

Para entender *por qué* —y qué hacer en su lugar— conviene dar un paso atrás y ver los datos codificados como una conversación entre dos partes que nunca se encuentran: quien escribe el código y quien lo lee.

## Qué significa codificar datos

**Codificar** es sustituir el significado por un puntero a un diccionario compartido: un concepto de algún sistema de códigos. Un código sin sistema carece de significado —el par (system, code) es la unidad de significado—. El objetivo es que dos sistemas que no saben nada el uno del otro interpreten los datos de la misma manera.

Tres cosas complican el panorama de inmediato:

**Los conceptos tienen granularidad.** Viven en jerarquías: «diabetes» ⊃ «diabetes de tipo 2» ⊃ «diabetes de tipo 2 bien controlada». Elegir un nivel es una decisión sobre cuánta información se captura —y cuánta se pierde—.

**Los sistemas de códigos se construyen sobre principios distintos.** ICD es una *clasificación*: su objetivo es asignar cada caso a categorías mutuamente excluyentes y exhaustivas (para estadísticas y facturación), de ahí los cajones de «otro» y «no especificado». Un caso → exactamente una categoría. SNOMED CT es una *ontología*: su objetivo es describir la realidad clínica —jerarquías con múltiples padres, definiciones formales, expresiones componibles—. Un caso → una descripción tan precisa como se necesite. Responden a preguntas distintas: ICD —«en qué categoría va para el informe»—, SNOMED —«qué es esto»—. La correspondencia entre ellos es intrínsecamente imperfecta y de tipo muchos a muchos.

**A veces el concepto no existe, pero se puede construir.** Eso es la postcoordinación: la gramática del sistema de códigos permite componer un concepto a partir de otros existentes. La expresión SNOMED CT `81745001:272741003=7771000` — «ojo : lateralidad = izquierdo»—. La expresión va, íntegra, en un único `Coding.code` —la especificación es explícita en que «cualquier expresión definida por el sistema de códigos sigue considerándose un "código" y se representa como tal»:

```json
{
  "system": "http://snomed.info/sct",
  "code": "128045006:{363698007=56459004}"
}
```

Nota: el resultado sigue siendo **un único código**. *No* son dos codings —«ojo» + «izquierdo»— en un array; más adelante veremos por qué eso está prohibido.

## Qué es realmente CodeableConcept

`CodeableConcept` porta **un** significado y almacena sus representaciones en un array `coding` más un campo `text` legible por humanos.

```json
{
  "coding": [
    { "system": "http://loinc.org",      "code": "8867-4",    "display": "Heart rate" },
    { "system": "http://snomed.info/sct", "code": "364075005", "display": "Heart Rate" }
  ],
  "text": "Heart rate"
}
```

La idea clave: *múltiples codings no son múltiples conceptos*. Un concepto, escrito en distintos «idiomas» para distintos destinatarios. Un código ICD-10 para el pagador, un código SNOMED CT para el sistema clínico, un código local para depuración —todo en un mismo campo—.

¿Por qué necesitaría un campo todo eso? Por quiénes están en cada extremo.

## La brecha: un escritor, muchos lectores

Aquí reside la asimetría central del intercambio de datos codificados: **el productor escribe una vez —los consumidores son muchos y quieren cosas diferentes—.** El regulador quiere categorías gruesas para un informe, el investigador quiere el máximo detalle, la facturación quiere ICD, el soporte a la decisión clínica quiere SNOMED. Lloyd McKenzie, en la sesión de FHIR-I:

> Puede haber perfectamente dos o tres códigos SNOMED, y hay que contemplar esa posibilidad. Porque habrá situaciones en las que alguien tiene una guía de implementación que dice que estoy capturando esto con códigos de alto nivel... necesito que me envíe ese código para poder elaborar ese informe gubernamental. Y luego tiene otro caso de uso en el que quiero saber exactamente qué tipo de cáncer era, quiero saber en qué estadio está, quiero saber si es una recurrencia o no. Y tiene dos sistemas distintos que quieren información ligeramente diferente, y la única manera de lograrlo es enviar ambos códigos.

Y el productor no puede elegir uno «para todos»:

> Cuando se crea una instancia, se crea para todos los receptores —emitimos lo mismo para todos—. Por tanto, tal prohibición no es razonable.

Esta asimetría explica todas las propiedades «extrañas» de `CodeableConcept`:

**No existe el código «principal»** —porque «principal» es una propiedad del par (dato, consumidor), no del dato—. El productor no tiene derecho a decidir por todos los lectores. Le pregunté directamente a Lloyd si existe algún indicador para el código más preciso:

> Tenemos un elemento central que permite indicar que este es el código que seleccionó el usuario. Pero en la situación en que se realiza una postcodificación, no existe ningún mecanismo para indicar cuál es el más específico. Y puede haber circunstancias en las que sean igualmente específicos, pero simplemente estén expresando cosas distintas.

Un único código «más específico» a menudo ni siquiera existe:

> Ambos tienen más detalle que el código base, pero no se puede marcar uno de ellos como «este es el más detallado», y no existe ningún código en SNOMED para «presión arterial sistólica de la arteria digital en posición sentada». Eso no existe.

**El orden no significa nada** —la [versión CI de la especificación](https://build.fhir.org/datatypes.html#CodeableConcept) lo establece de forma normativa: «El orden de los codings no está definido y NO DEBERÁ utilizarse para inferir significado». `CodeableConcept.coding` no tiene `orderMeaning` ([hilo en Zulip](https://chat.fhir.org/#narrow/stream/implementers/topic/Does%20array%20order%20ever%20matter%3F))—. Por tanto, `.first()` no obtiene el código principal, sino uno aleatorio.

**Los códigos adicionales no son sinónimos.** Elliot Silver, en la misma reunión, planteó exactamente esta trampa:

> Supongamos que tenemos ese CodeableConcept codificado con cáncer de pulmón, cáncer y enfermedades del pulmón. Mi sistema no reconoce «cáncer de pulmón». Sí reconoce «enfermedades del pulmón» y reconoce «cánceres»... Voy a encontrar una coincidencia con «enfermedades del pulmón», y ese es el que voy a conservar. Y voy a asumir que todo lo demás que hay ahí es un sinónimo...

La corrección de Lloyd resume todo el asunto:

> Está codificando un único concepto, pero no necesariamente expresa la misma información con cada uno... un código transmite un aspecto o un conjunto de información que el otro no transmite, y viceversa. Eso es lo que ocurre con los sistemas de códigos: tienen distintos niveles de precisión y distintas capacidades de expresividad.

Así que cuando el sistema de Elliot selecciona silenciosamente «enfermedad del pulmón» y descarta «cáncer de pulmón» como «sinónimo», en la base de datos de análisis acaba «enfermedad del pulmón» en lugar de «cáncer de pulmón», y nadie lo nota.

**La brecha se extiende en el tiempo.** El consumidor de hoy no conoce los códigos de mañana en el mismo campo. Lloyd:

> Los receptores que inicialmente solo tuvieron que gestionar uno o dos códigos pueden acabar enfrentándose a 7 u 8 códigos con el tiempo. Como consumidor, no puede dar por sentado que lo que ve hoy va a ser igual en el futuro.

¿Por qué eligió FHIR este modelo? Grahame Grieve:

> La expectativa y el deseo en FHIR es que la información sea robusta en múltiples entornos sin necesidad de un contexto específico con un acuerdo personalizado, porque así es como la gente utiliza la información en la práctica. Eso tiene un precio, y aquí estamos.

El precio recae de forma asimétrica: el productor paga poco (coloca todo en el array), el consumidor paga caro (una política de selección, un servidor de terminología, correspondencias). `CodeableConcept` es, en esencia, un protocolo para comunicarse a través de la brecha: el productor maximiza la posibilidad de ser comprendido; el consumidor está obligado a saber cómo elegir.

Así que escribamos las reglas para cada parte.

## La única regla estricta que vincula el array

Antes de las reglas, la única restricción que la especificación impone sobre los múltiples codings. Se elaboró en el hilo [Multiple codes in CodeableConcept](https://chat.fhir.org/#narrow/stream/terminology/topic/Multiple%20codes%20in%20CodeableConcept) (`#terminology`, 113 mensajes) y en la reunión de FHIR-I, dando lugar a dos tickets de JIRA —**FHIR-50188** y **FHIR-50189**— y a un fragmento de la especificación reescrito.

La especificación publicada (hasta R5) decía que los codings «pueden tener una granularidad **ligeramente** diferente», y esa palabra confundió a los implementadores durante años. **Rutt Lindström**:

> La mayoría de los debates en los que he participado (normalmente sobre Medication.code) se han desgastado en torno a la palabra «ligeramente». ¿Lo siguiente es una diferencia leve o una diferencia enorme?

**Grahame Grieve** respondió que la regla no trata del tamaño de la diferencia:

> Lo legal es cualquier diferencia de granularidad, siempre que la intersección no esté vacía; la buena práctica es no forzar los límites y variar la granularidad lo menos posible.

«Ligeramente» ha desaparecido: la [versión CI](https://build.fhir.org/datatypes.html#CodeableConcept) ahora reza «Cuando hay múltiples códigos presentes, la intersección de sus significados NO DEBERÁ estar vacía. (En rigor, según la ISO 704, la intersección de sus "extensiones" no está vacía)».

Válido: `LOINC 8867-4 (Heart rate)` + `SNOMED CT 364075005 (Heart Rate)`.

Inválido: `LOINC 9279-1 (Respiratory Rate)` + `SNOMED CT 364075005 (Heart Rate)`. **Michael Lawley**:

> No existe *ninguna cosa* que sea a la vez una frecuencia respiratoria y una frecuencia cardíaca —en sentido estricto, el fondo (⊥) es el concepto que constituye la intersección de todos los conceptos, pero por definición no tiene instancias—.

Nota: la regla **no es verificable automáticamente** —es orientación, no un validador—. Y no hubo votación formal en la reunión de FHIR-I —el quórum se redujo al final—. Hubo acuerdo sustantivo; el texto reescrito de FHIR-50188 ya está integrado en la versión CI, mientras que las versiones publicadas hasta R5 siguen con la redacción antigua.

## Reglas para el productor

La asimetría del productor: **usted es el último punto donde existe el conocimiento.** El clínico vio al paciente; el dispositivo realizó la medición. El momento de la codificación es el momento de contacto con la realidad —después de escribir el recurso, la ventana se cierra—. Todo lo que no capture ahora se pierde, porque:

- **Generalizar posteriormente es computable; especializar no lo es.** Cualquier consumidor con un servidor de terminología puede elevar «diabetes de tipo 2 bien controlada» hasta «diabetes» (`$subsumes`, la jerarquía). La dirección inversa es imposible en principio: la información no está en los datos.
- **La correspondencia entre sistemas a posteriori es una lotería.** Los ConceptMaps entre sistemas son de tipo muchos a muchos con coincidencias «más amplio / más estrecho / inexacto». El mapeador posterior solo ve el código; usted vio el caso. Usted resuelve la ambigüedad con *conocimiento*; `$translate` la resuelve con una suposición.

De ahí la regla principal:

**P0. Capture todo aquello que solo usted conoce, en el momento de la codificación:**

1. **El código más preciso que pueda justificar.** Nadie más adelante podrá añadir precisión.
2. **Códigos en sistemas alternativos que usted conozca** (categoría ICD *y* concepto SNOMED). Su elección de categoría es conocimiento; una correspondencia calculada después es una suposición.
3. **Siempre `text`** —el significado completo en palabras—. Es el canal de último recurso que comprende el 100 % de los receptores (incluidos los humanos), y el único lugar donde preservar detalles que no encajaron en ningún código: `"text": "Negative for Chlamydia Trachomatis rRNA"` junto a un coding que simplemente dice «Negative».
4. **Marque la procedencia: `userSelected = true`** en el código que un humano eligió realmente. En un array donde todos los códigos son iguales, existe una asimetría de origen oculta —un código lo eligió una persona que miraba al paciente, el resto se derivaron—. Esto es indecidible a partir de los datos en retrospectiva. (Pero recuerde: `userSelected` marca el *origen*, no la granularidad).
5. **Declare las reglas con las que jugó: `meta.profile`.** Tres códigos en un array —¿eso es «volcamos lo que teníamos» o «binding requerido de US Core + código heredado + traducción del regulador»?— Estructuralmente son indistinguibles. La declaración de perfil indica al lector qué contrato estaba ejecutando —y le permite validarlo—.

Y tres salvaguardas para no *distorsionar* el significado al empaquetarlo:

**P1. Cada coding expresa el concepto completo por sí mismo.** No partes, no modificadores. Lloyd, sobre el truco de «ojo» + «izquierdo» ([hilo](https://chat.fhir.org/#narrow/stream/implementers/topic/Multiple%20Coding%20in%20Codeable%20Concept)):

> No se interpretan combinándolos. Como estos códigos son SNOMED, puede combinar los conceptos mediante postcoordinación: `81745001:272741003=7771000` —«ojo:lateralidad=izquierdo»—. No existe ningún elemento «modificador» en Coding.

Por qué esta es la regla número uno: se garantiza que el consumidor tomará un código del array —ese es su algoritmo—. Si sus códigos son partes, la mala interpretación no es un riesgo, es una certeza.

Y si el sistema de códigos *no tiene* gramática de postcoordinación —por ejemplo, un código LOINC que necesita un calificador SNOMED— tampoco puede simularlo con dos codings, ni inventar un código combinado. Lloyd, respondiendo exactamente a esta pregunta en el hilo [Handling post-coordination in CodeableConcept](https://chat.fhir.org/#narrow/stream/implementers/topic/Handling%20post-coordination%20in%20CodeableConcept):

> Si desea enviar una expresión postcoordinada, el Coding.system debe ser un sistema de códigos que defina la sintaxis de postcoordinación y cómo interpretar la expresión... En su caso, no existe ninguna sintaxis publicada ni por LOINC ni por SNOMED para lo que está haciendo, por lo que no podría llamar al resultado un código LOINC o SNOMED... Es probable que enviar un código LOINC con una extensión (o usar el elemento «method» u otros elementos en Observation) para transmitir su calificación sea mejor comprendido.

Las vías de escape legales viven *fuera* de `coding[]`: una extensión para el calificador, elementos dedicados del recurso (`Observation.method`, `bodySite`), o un recurso vinculado separado (`Observation.hasMember`). La gramática pertenece al sistema de códigos, no a usted.

**P2. Los códigos no deben contradecirse entre sí** —la regla de la intersección no vacía mencionada más arriba—. Es lo que hace posible P1: «cualquier código es verdadero» solo funciona si todos los códigos tratan sobre lo mismo.

**P3. Permanezca dentro del ámbito del elemento y vigile la dirección de la granularidad, especialmente bajo negación.** No introduzca una raíz jerárquica como SNOMED `138875005 (SNOMED CT Concept)` en `Observation.code` (eso es FHIR-50189). Y el nuevo texto de la especificación incluye una advertencia que el anterior no tenía —la granularidad mixta no es solo inconveniente, puede ser insegura:

> Una prescripción de «APO Amoxicillin 250 mg cápsula» (necesaria para dispensar el pedido) podría tener de forma segura también una codificación adicional de «Penicilina de amplio espectro» (quizás necesaria para activar protocolos de monitorización de antibióticos). En cambio, si hubiera una orden que dijera «No administrar APO Amoxicillin 250 mg cápsula», añadir una traducción de «Penicilina de amplio espectro» podría interpretarse incorrectamente como una prohibición de todas las penicilinas de amplio espectro.

Los mismos dos códigos, la misma intersección no vacía —pero cambie la afirmación a una negación y el coding más amplio amplía silenciosamente la prohibición—. Cuando la afirmación es negativa, opte por el código más estrecho.

## Reglas para el consumidor

La asimetría del consumidor refleja la del productor: **el productor conocía la realidad pero no la aplicación; usted conoce la aplicación** —qué análisis, qué acción, qué cuesta un error—. Ese conocimiento no está en los datos, y solo usted puede aplicarlo.

**C0. La interpretación es su responsabilidad, y se ejecuta sobre una política explícita elegida de antemano.** El algoritmo de Lloyd, del mismo intercambio en FHIR-I:

> Lo primero que hace es descartar todos los que no comprende. Lo ideal es quedarse con todos, aunque no sepa qué son, porque alguien más adelante podría entenderlos. Si no puedo interpolar el significado a partir de múltiples conceptos, tengo que elegir cuál de estos es el más preferido para el tipo de análisis que estoy realizando. Y esa decisión la habría tomado de antemano en términos de cuál de estas terminologías es mi terminología más preferida.

La frase clave es *de antemano*. La política de preferencia (sistemas → value sets → granularidad → `userSelected` → `text`) vive en su configuración de correspondencia —versionada y revisada—, no en una expresión FHIRPath en el momento de la lectura. `.first()` es una política que nadie aprobó.

### Clasifique su tipo de consumo primero

Antes de seleccionar códigos, pregúntese qué operación está realizando realmente sobre el array. Solo existen unas pocas clases de consumo, y cada una tiene su propia semántica y su propio riesgo:

| Clase | Códigos necesarios | ¿Con pérdida? | Riesgo principal |
|---|---|---|---|
| **Prueba de pertenencia** — «¿cae bajo el concepto X?» (activación de CDS, inclusión en cohorte) | cualquiera (∃) | no | negación |
| **Proyección** — «dame exactamente un código en el vocabulario Y» (ETL, FHIR a OMOP, facturación) | exactamente uno | sí | elegir sin una política |
| **Agregación** — «¿en qué categoría?» (informes, estadísticas) | exactamente una categoría | sí | doble conteo |
| **Tránsito** — almacenar y reenviar, pasarela | todos, incluidos los no reconocidos | no | «limpiar» el array |
| **Visualización** — mostrar a un humano | ninguno (`text`) | no | texto vacío |
| **Inferencia** — razonamiento por subsunción, combinación de detalles | todos + servidor de terminología | no | coste |

Dos observaciones emergen de esta tabla.

Primera, **la pertenencia es la clase más segura** —sin selección de código, sin pérdida: un OR sobre el array, donde los codings adicionales solo *ayudan* (más representaciones → mayor probabilidad de coincidir con su value set)—. Todos los dolores de este artículo —«qué código es el principal, cuál es el más preciso»— son dolores de la clase **proyección**. La mitad del remedio consiste en darse cuenta de que su tarea es en realidad pertenencia, y puede dejar de elegir un código allí donde basta con comprobar la contención.

Segunda, **`.first()` es proyección realizada sin una política** —la peor clase ejecutada de la peor manera—.

### Pertenencia significa subsunción, no igualdad

Y aquí nuestra propia P0 da la vuelta: **le dijimos al productor que codificara con la máxima precisión posible —por lo que un consumidor que pruebe la igualdad no encontrará casi nada—.** Usted busca «diabetes» (73211009), pero los datos dicen «diabetes de tipo 2 bien controlada», porque el productor siguió honestamente P0. Igualdad → falso → el paciente cae fuera de la cohorte. Cuanto mejores sean los datos, peor funciona el consumidor ingenuo.

Por tanto, la prueba de pertenencia debe ser:

```
∃ coding : subsumes(X, coding)    — «el código es X o un descendiente de X»
```

Mecánica, a su elección: `$subsumes` para una comprobación puntual; un ValueSet con un filtro `is-a` o ECL de SNOMED `<< 73211009` más `$expand` / `$validate-code` para un conjunto materializado; en OMOP, `concept_ancestor` —el mismo cierre transitivo precalculado como tabla—.

Dónde falla:

- **La jerarquía vive dentro de un sistema.** No existe subsumes(SNOMED-X, código-ICD) directamente —primero hay que mapear, luego escalar, y las pérdidas de ambos pasos se multiplican—. Un argumento más para P0: un productor que incluyó un código SNOMED le dio acceso a una jerarquía *buena*.
- **Las jerarquías no son iguales.** El is-a de SNOMED es una ontología formal; la «jerarquía» de ICD es la organización por capítulos —adecuada para informes, no para lógica clínica—. Elegir un sistema para pertenencia = elegir una jerarquía en la que confíe.
- **La postcoordinación** nunca coincide por igualdad —pero la subsunción basada en ECL la capta, *si* su servidor de terminología gestiona expresiones—.
- **La negación amplifica de nuevo:** un criterio de exclusión mediante subsunción sobre un concepto amplio excluye todos sus descendientes —recuerde la amoxicilina—. Incluir por un ancla amplia es seguro; excluir por un ancla amplia es peligroso.

Una cosa más que `$translate` no hará por usted: la generalización. Michael Lawley, [respondiendo a Lloyd](https://chat.fhir.org/#narrow/stream/terminology/topic/Will%20%24translate%20do%20generalization%3F):

> Nada en la definición de $translate sugiere que haga algo «semántico»... ¿debería $translate de B devolver tanto X como Y? Es probable que eso conduzca a un comportamiento muy ruidoso e inmanejable.

Si necesita conceptos ancestros, eso es un value set con un filtro `generalizes` (o ECL) —no una llamada a `$translate`—.

### Lea a través del perfil —y la brecha de proyección

Si el productor declaró `meta.profile`, úselo: un perfil reduce «array desconocido» a «mínimo garantizado más posibles extras». Un binding requerido le indica que al menos un coding proviene de un value set conocido; el slicing le indica que el array tiene roles con nombre (el «código LOINC obligatorio» en Vital Signs) reconocibles por discriminadores.

Sin embargo, observe qué falta en las herramientas. El perfil *describe* una proyección —el slicing divide `coding[]` en partes con nombre—, pero no existe ninguna *operación* estándar para ejecutarla. Los validadores resuelven slices internamente (deben hacerlo, para comprobar cardinalidades) y descartan la asignación, devolviendo únicamente sí/no. No existe ningún `$project(profile)` que devuelva el recurso visto a través del perfil, con cada coding anotado con el nombre de su slice. Hoy se reimplementan los discriminadores a mano (`coding.where(memberOf('http://...vs'))`) o se codifica la política de selección en una ViewDefinition de SQL on FHIR. Un perfil es un contrato; la validación es la comprobación del contrato por parte del productor; la proyección sería la *ejecución* del mismo por parte del consumidor —los dos primeros existen en la especificación, el tercero aún no—.

### Las salvaguardas restantes

**C1. La estructura del array no porta ningún significado.** Orden, recuento, composición —nada de eso es una señal—. El array refleja el conjunto de consumidores *del productor*, no sus prioridades.

**C2. Elegir un código es una pérdida deliberada de los demás.** Cada coding puede contener detalles que sus vecinos no tienen (cáncer de pulmón ≠ enfermedad del pulmón). Tome uno —sepa qué descartó—. Y conserve los códigos que no comprende cuando transmita los datos: usted no es el último lector.

**C3. Conozca su dirección segura de error.** Para acciones positivas, interpretar por el código más amplio es conservador y seguro; para las negativas (prohibiciones, exclusiones, filtros «todos excepto»)—solo el código estrecho, o ampliará la prohibición.

**C4. La rama «no comprendí nada» debe existir y ser significativa.** Longitud de array desconocida, sistemas desconocidos, nuevos códigos mañana. Nada coincidió → `text` → humano → rechazo explícito. No es una excepción ni un salto silencioso —de lo contrario, `.first()` se cuela de nuevo como «bueno, al menos algo»—.

## En conclusión

`CodeableConcept` es un protocolo que salva la brecha productor/consumidor. El deber principal del productor —**capturar el conocimiento que existe solo en el momento de la codificación**: el código más preciso, los códigos en sistemas alternativos, el texto completo, la procedencia, el perfil—. Cada uno de ellos responde a una pregunta del consumidor que de otro modo sería irrespondible: «¿cuán preciso?», «¿en qué categoría?», «¿qué significa en palabras?», «¿qué código eligió el humano?», «¿qué reglas estaban en juego?».

El deber principal del consumidor —**aplicar el conocimiento que existe solo en su lado**: el caso de uso—. Clasifique el consumo, compruebe la pertenencia mediante subsunción en lugar de igualdad, proyecte a través de los perfiles donde existan, y elija los códigos mediante una política explícita —nunca por posición en el array—.

Terminology is fun, como le gusta decir a Lloyd McKenzie. Especialmente cuando la diversión llega en forma del séptimo código en un array para el que su parser no fue diseñado.

## Fuentes

Hilos en Chat.fhir.org (se requiere inicio de sesión en Zulip):

- [Multiple codes in CodeableConcept](https://chat.fhir.org/#narrow/stream/terminology/topic/Multiple%20codes%20in%20CodeableConcept) — `#terminology`, 113 mensajes. El debate principal y la reescritura de la especificación.
- [Will $translate do generalization?](https://chat.fhir.org/#narrow/stream/terminology/topic/Will%20%24translate%20do%20generalization%3F) — `#terminology`. Por qué `$translate` no realiza generalización.
- [Does array order ever matter?](https://chat.fhir.org/#narrow/stream/implementers/topic/Does%20array%20order%20ever%20matter%3F) — `#implementers`. `orderMeaning` y el orden en los arrays.
- [CodeableConcept.coding.userSelected](https://chat.fhir.org/#narrow/stream/terminology/topic/CodeableConcept.coding.userSelected) — `#terminology`. userSelected frente a coding-purpose.
- [Adding a tag to coding in CodeableConcept](https://chat.fhir.org/#narrow/stream/implementers/topic/Adding%20a%20tag%20to%20coding%20in%20CodeableConcept) — `#implementers`. Un caso de uso de coding-purpose.
- [Handling post-coordination in CodeableConcept](https://chat.fhir.org/#narrow/stream/implementers/topic/Handling%20post-coordination%20in%20CodeableConcept) — `#implementers`.
- [Multiple Coding in Codeable Concept](https://chat.fhir.org/#narrow/stream/implementers/topic/Multiple%20Coding%20in%20Codeable%20Concept) — `#implementers`. El caso de lateralidad «ojo + izquierdo».
- [codings with null](https://chat.fhir.org/#narrow/stream/terminology/topic/codings%20with%20null) — `#terminology`. US Core, VA VUID, «no enviar UNK».
- [CodeableConcept Validation](https://chat.fhir.org/#narrow/stream/terminology/topic/CodeableConcept%20Validation) — `#terminology`. «El 99 % válido sigue siendo inválido».

HL7 JIRA:

- **FHIR-50188** — nuevo texto para múltiples codings en `CodeableConcept`.
- **FHIR-50189** — ámbito/granularidad para `Observation.code`.

Especificación FHIR:

- [CodeableConcept, CI build](https://build.fhir.org/datatypes.html#CodeableConcept) — la sección «Multiple Codings» reescrita con la regla de intersección y la advertencia de negación.
- [CodeableConcept, R5](https://hl7.org/fhir/R5/datatypes.html#CodeableConcept) — la antigua redacción de «granularidad ligeramente diferente», para comparación.