Summary
While testing SNOMED ECL expansion against https://tx.fhir.org/r4 (FHIRsmith 0.9.6 from /metadata), I found several ECL behaviors that appear incorrect or incomplete.
Checklist
References:
Bug 1: memberOf returns fabricated sentinel code 4294967295
Bare memberOf expressions return a one-code expansion containing inactive code 4294967295. This happens both for apparent reference-set concepts and for concepts that are plainly not reference sets.
Reproducer:
for ECL in '^700043003' '^900000000000497000' '^404684003'; do
printf '%s\t' "$ECL"
jq -nc --arg ecl "$ECL" '{
resourceType:"ValueSet",
compose:{include:[{
system:"http://snomed.info/sct",
filter:[{property:"constraint",op:"=",value:$ecl}]
}]}
}' |
curl -sS -X POST 'https://tx.fhir.org/r4/ValueSet/$expand' \
-H 'Content-Type: application/fhir+json' \
--data-binary @- |
jq -r '[.expansion.total, (.expansion.contains[0].code // "no-code")] | @tsv'
done
Observed:
^700043003 1 4294967295
^900000000000497000 1 4294967295
^404684003 1 4294967295
Expected:
- For a valid concept-based reference set,
^refset should return the active referenced component concepts from that reference set.
- For
404684003 |Clinical finding|, which is not a reference set, the server should reject the expression or return no members.
- The expansion should never contain fabricated SCTID
4294967295.
Impact: clients using ECL memberOf expansion can receive a non-SNOMED sentinel as if it were a real inactive SNOMED concept.
Bug 2: wrapped memberOf operands are rejected as unsupported
Reproducer:
for ECL in '^(<<900000000000455006)' '^(404684003)' '^(<<404684003)'; do
printf '\n%s\n' "$ECL"
jq -nc --arg ecl "$ECL" '{
resourceType:"ValueSet",
compose:{include:[{
system:"http://snomed.info/sct",
filter:[{property:"constraint",op:"=",value:$ecl}]
}]}
}' |
curl -sS -X POST 'https://tx.fhir.org/r4/ValueSet/$expand' \
-H 'Content-Type: application/fhir+json' \
--data-binary @- |
jq -r '.issue[0].details.text'
done
Observed:
^(<<900000000000455006)
The ECL expression is not supported: '^(<<900000000000455006)': (ECL ^ (member-of) with a non-concept-reference refset is not yet supported)
^(404684003)
The ECL expression is not supported: '^(404684003)': (ECL ^ (member-of) with a non-concept-reference refset is not yet supported)
^(<<404684003)
The ECL expression is not supported: '^(<<404684003)': (ECL ^ (member-of) with a non-concept-reference refset is not yet supported)
Expected: ECL permits the memberOf operand to be a refset expression. For example, ^(<<900000000000455006) means members of all reference sets in the descendants-or-self closure of 900000000000455006 |Reference set|. The server should resolve the operand expression to reference-set concepts and return the union of their referenced component concepts.
Impact: clients cannot use standard ECL patterns that compute the set of reference sets dynamically.
Bug 3: cardinality appears to count raw relationship rows instead of non-redundant attributes
The witness concept is 903008 |Chorioretinal infarction|.
First, tx.fhir.org lookup reports one 116676008 |Associated morphology| value for the concept:
curl -sS 'https://tx.fhir.org/r4/CodeSystem/$lookup?system=http://snomed.info/sct&code=903008' |
jq -r '[.parameter[]
| select(.name=="property")
| select((.part[]? | select(.name=="code").valueCode) == "116676008")
| (.part[] | select(.name=="value").valueCode)] | @json'
Observed:
Now compare [1..1] and [2..*] cardinality for that same attribute/value constraint:
for ECL in \
'<<404684003:[1..1]116676008=<<55641003' \
'<<404684003:[2..*]116676008=<<55641003'
do
printf '%s\t' "$ECL"
jq -nc --arg ecl "$ECL" '{
resourceType:"ValueSet",
compose:{include:[{
system:"http://snomed.info/sct",
filter:[{property:"constraint",op:"=",value:$ecl}]
}]}
}' |
curl -sS -X POST 'https://tx.fhir.org/r4/ValueSet/$expand' \
-H 'Content-Type: application/fhir+json' \
--data-binary @- |
jq -r '[.expansion.total, ((.expansion.contains // []) | map(.code) | index("903008") != null)] | @tsv'
done
Observed:
<<404684003:[1..1]116676008=<<55641003 257 false
<<404684003:[2..*]116676008=<<55641003 11 true
Expected: if 903008 has one non-redundant associated morphology matching <<55641003 |Infarct|, it should satisfy [1..1] and should not satisfy [2..*].
Observed behavior is the opposite: 903008 is excluded from [1..1] and included in [2..*]. This is consistent with counting raw relationship instances instead of the non-redundant attribute values required by ECL.
Impact: cardinality-constrained ECL queries can include false positives and exclude true positives.
Sanity check
Ordinary attribute refinements are not simply ignored:
ECL='<<404684003:116676008=<<55641003'
jq -nc --arg ecl "$ECL" '{resourceType:"ValueSet",compose:{include:[{system:"http://snomed.info/sct",filter:[{property:"constraint",op:"=",value:$ecl}]}]}}' |
curl -sS -X POST 'https://tx.fhir.org/r4/ValueSet/$expand' -H 'Content-Type: application/fhir+json' --data-binary @- |
jq '{total: .expansion.total, first: [.expansion.contains[:5][] | {code, display}]}'
Observed total: 268, with infarction-related first results. The cardinality issue appears more specific than all refinements being ignored.
Summary
While testing SNOMED ECL expansion against
https://tx.fhir.org/r4(FHIRsmith 0.9.6from/metadata), I found several ECL behaviors that appear incorrect or incomplete.Checklist
memberOfexpressions such as^700043003return fabricated inactive code4294967295.memberOfover a non-reference-set concept such as^404684003also returns4294967295instead of rejecting or returning empty.memberOfoperands such as^(<<900000000000455006)are rejected as unsupported.References:
referencedComponentIdfor active reference set members, for reference sets whose referenced components are concepts: https://docs.snomed.org/snomed-ct-specifications/snomed-ct-expression-constraint-language/behaviour-specification-with-examples/6.1-simple-expression-constraintsBug 1:
memberOfreturns fabricated sentinel code4294967295Bare
memberOfexpressions return a one-code expansion containing inactive code4294967295. This happens both for apparent reference-set concepts and for concepts that are plainly not reference sets.Reproducer:
Observed:
Expected:
^refsetshould return the active referenced component concepts from that reference set.404684003 |Clinical finding|, which is not a reference set, the server should reject the expression or return no members.4294967295.Impact: clients using ECL memberOf expansion can receive a non-SNOMED sentinel as if it were a real inactive SNOMED concept.
Bug 2: wrapped
memberOfoperands are rejected as unsupportedReproducer:
Observed:
Expected: ECL permits the memberOf operand to be a refset expression. For example,
^(<<900000000000455006)means members of all reference sets in the descendants-or-self closure of900000000000455006 |Reference set|. The server should resolve the operand expression to reference-set concepts and return the union of their referenced component concepts.Impact: clients cannot use standard ECL patterns that compute the set of reference sets dynamically.
Bug 3: cardinality appears to count raw relationship rows instead of non-redundant attributes
The witness concept is
903008 |Chorioretinal infarction|.First, tx.fhir.org lookup reports one
116676008 |Associated morphology|value for the concept:Observed:
["55641003"]Now compare
[1..1]and[2..*]cardinality for that same attribute/value constraint:Observed:
Expected: if
903008has one non-redundant associated morphology matching<<55641003 |Infarct|, it should satisfy[1..1]and should not satisfy[2..*].Observed behavior is the opposite:
903008is excluded from[1..1]and included in[2..*]. This is consistent with counting raw relationship instances instead of the non-redundant attribute values required by ECL.Impact: cardinality-constrained ECL queries can include false positives and exclude true positives.
Sanity check
Ordinary attribute refinements are not simply ignored:
Observed total:
268, with infarction-related first results. The cardinality issue appears more specific than all refinements being ignored.