$populate: an item with both an answer and child items skips answer filtering entirely
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 61
- Forks
- 29
- Avg merge
- 2d 22h
- Merged PRs (30d)
- 19
Description
Describe the bug
filterValueSetAnswersRecursive (packages/sdc-populate/src/SDCPopulateQuestionnaireOperation/utils/processValueSets.ts) returns as soon as it recurses into an item's children, without ever checking that item's own answer:
const items = qrItem.item;
if (items && items.length > 0) {
// iterate through items of item recursively
const qrItems: QuestionnaireResponseItem[] = items
.map((item) => filterValueSetAnswersRecursive(item, ...))
.filter((item): item is QuestionnaireResponseItem => item !== null);
return { ...qrItem, item: qrItems };
}
// unreachable when qrItem.item is non-empty:
const answerOptionCodings = answerOptions[linkId]?.map((option) => option.valueCoding);
if (qrItem.answer && answerOptionCodings) { ... }
An item can legally carry both answer and nested item — normal FHIR Questionnaire nesting for a question with sub-questions. For such an item, the early return on the child-recursion branch means its own answer array never reaches filterAndNormaliseAnswers. An out-of-answerOption valueCoding survives unfiltered even on a plain choice item, and a matching coding is never normalised to the option's coding. No later pass compensates — addDisplayToQuestionnaireResponseCodings and removeEmptyAnswersFromResponse don't filter against answerOption/valueSet options.
To Reproduce
import { filterValueSetAnswersRecursive } from './utils/processValueSets';
const qrItem = {
linkId: 'parent-with-subquestions',
answer: [
{ valueCoding: { system: 'http://example.com', code: 'NOT-AN-OPTION', display: 'Bogus' } }
],
item: [{ linkId: 'child', answer: [{ valueString: 'irrelevant' }] }]
};
const answerOptions = {
'parent-with-subquestions': [
{ valueCoding: { system: 'http://example.com', code: 'REAL-OPTION', display: 'Real' } }
]
};
filterValueSetAnswersRecursive(qrItem, {}, answerOptions, {}, new Set());
Expected behavior
The item is choice-typed (not open-choice), so NOT-AN-OPTION — which isn't one of its answerOptions — should be filtered out, same as it would be if the item had no child items.
Actual behavior
{ "valueCoding": { "system": "http://example.com", "code": "NOT-AN-OPTION", "display": "Bogus" } }
survives unfiltered.
Additional context
- Found while reviewing #2096 (which fixes #2095) — pre-existing, older than the defects #2096 addresses, and not touched by that PR.
- A fix needs to filter the item's own
answerbefore (or in addition to) recursing intoitem, rather than the two being mutually exclusive branches. - Originally noted by @not-in-stock in a comment on #2095.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/sdc-populate/src/SDCPopulateQuestionnaireOperation/utils/processValueSets.ts at filterValueSetAnswersRecursive, using the supplied reproduction to trace items that contain both answer and child items. Ensure the item's own answers are checked against answerOptions while child items are recursively processed; done means the invalid coding is removed and a valid coding is normalised without losing the child item.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100