USDM rules CORE-001055, CORE-000961 and CORE-001048 treat an omitted previousId/nextId differently from null
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- Half a day
- Newbie friendliness
- 65/100
Research direction
The bug lives in the JSONata conditions of the three rule definitions CORE-001055, CORE-000961 and CORE-001048, which treat an omitted previousId/nextId as different from null. Start by running the validate command on the omitted-null and explicit-null sample files and comparing the reports. Done means both files give the same results and the omitted-key file reports no issues from these three rules. The issue's suggested $exists check is a good starting point.
Written by the indexing model from the issue text.
Description
Standard
CDISC USDM
Reference Rule ID(s)
DDF00204, DDF00087, DDF00088
Conformance Rule ID(s) (if published in CORE)
CORE-001055, CORE-000961, CORE-001048
JIRA Ticket
https://jira.cdisc.org/projects/CORERULES/issues/CORERULES-
CLI Command Used (if applicable)
python core.py validate -s usdm -v 4-0 -dp issue12_data/shaun_h_usdm_nulls_omitted.json -r CORE-001055 -r CORE-000961 -r CORE-001048 -of JSON
Rule YAML
core_id: CORE-001055
description: Narrative content must only reference narrative content that is specified within the same study definition document version.
rule_type: JSONata
sensitivity: Record
entities:
Include:
- NarrativeContent
conditions: |
$.study.documentedBy@$sdd.
$sdd.versions@$sddv.
$filter(($sddv.contents),function($v)
{
$not(
$type($v.previousId) = "null" or
$v.previousId in $sddv.contents.id
) or
$not(
$type($v.nextId) = "null" or
$v.nextId in $sddv.contents.id
) or
$v.childIds[$not($ in $sddv.contents.id)]
}
)@$c.
{
"instanceType": $c.instanceType,
"id": $c.id,
"path": $c._path,
"StudyDefinitionDocument.id": $sdd.id,
"StudyDefinitionDocument.name": $sdd.name,
"StudyDefinitionDocumentVersion.id": $sddv.id,
"StudyDefinitionDocumentVersion.version": $sddv.version,
"name": $c.name,
"sectionNumber": $c.sectionNumber,
"Invalid previousId": $not(
$type($c.previousId) = "null" or
$c.previousId in $sddv.contents.id
)
? $c.previousId,
"Invalid nextId": $not(
$type($c.nextId) = "null" or
$c.nextId in $sddv.contents.id
)
? $c.nextId,
"Invalid childIds": $c.childIds[$not($ in $sddv.contents.id)] ~> $join("; ")
}
actions:
- name: generate_dataset_error_objects
params:
message: The narrative content references a previous, next or child id value that does not match the id of any narrative content defined within the same study definition document version.
---
core_id: CORE-000961
description: Encounter ordering using previous and next attributes is expected to be consistent with the order of corresponding scheduled activity instances according to their specified default conditions.
rule_type: JSONata
sensitivity: Record
entities:
Include:
- StudyDesign
- InterventionalStudyDesign
- ObservationalStudyDesign
conditions: |
($.study.versions)@$sv.
($sv.studyDesigns)@$sd.
($sd.scheduleTimelines[mainTimeline = true])@$st.
(
$actord := $utils.parse_refs("nextId","next",$sd.encounters)
[previousId = null].$append(id,**.next.id);
$reford := $utils.parse_refs("defaultConditionId","defaultCondition",$st.instances)
[id = $st.entryId].**[instanceType="ScheduledActivityInstance" and encounterId in $sd.encounters.id].encounterId
~> $filter(function($v,$i,$a){$i = 0 or ($i > 0 and $v != $a[$i-1])});
$encounter := function($id){($e:=$sd.encounters[id=$id];$id & ": " & $e.name)};
{
"instanceType": $sd.instanceType,
"id": $sd.id,
"path": $sd._path,
"name": $sd.name,
"ScheduleTimeline.id": $st.id,
"ScheduleTimeline.name": $st.name,
"ScheduleTimeline.mainTimeline": $st.mainTimeline,
"Encounter order by previous/next": "[ "&($actord ~> $map($encounter) ~> $join(" > "))&" ]",
"Encounter order by timeline refs": "[ "&($reford ~> $map($encounter) ~> $join(" > "))&" ]"
}[`Encounter order by previous/next` != `Encounter order by timeline refs`]
)
actions:
- name: generate_dataset_error_objects
params:
message: The order of the encounters in the study design (as defined by the next attribute) does not match the order of encounters as referenced from scheduled activity instances in the main timeline that are ordered by default condition.
---
core_id: CORE-001048
description: Epoch ordering using previous and next attributes is expected to be consistent with the order of corresponding scheduled activity instances according to their specified default conditions.
rule_type: JSONata
sensitivity: Record
entities:
Include:
- StudyDesign
- InterventionalStudyDesign
- ObservationalStudyDesign
conditions: |
($.study.versions)@$sv.
($sv.studyDesigns)@$sd.
($sd.scheduleTimelines[mainTimeline = true])@$st.
(
$actord := $utils.parse_refs("nextId","next",$sd.epochs)
[previousId = null].$append(id,**.next.id);
$reford := $utils.parse_refs("defaultConditionId","defaultCondition",$st.instances)
[id = $st.entryId].**[instanceType="ScheduledActivityInstance" and epochId in $sd.epochs.id].epochId
~> $filter(function($v,$i,$a){$i = 0 or ($i > 0 and $v != $a[$i-1])});
$epoch := function($id){($e:=$sd.epochs[id=$id];$id & ": " & $e.name)};
{
"instanceType": $sd.instanceType,
"id": $sd.id,
"path": $sd._path,
"name": $sd.name,
"ScheduleTimeline.id": $st.id,
"ScheduleTimeline.name": $st.name,
"ScheduleTimeline.mainTimeline": $st.mainTimeline,
"Epoch order by previous/next": "[ "&($actord ~> $map($epoch) ~> $join(" > "))&" ]",
"Epoch order by timeline refs": "[ "&($reford ~> $map($epoch) ~> $join(" > "))&" ]"
}[`Epoch order by previous/next` != `Epoch order by timeline refs`]
)
actions:
- name: generate_dataset_error_objects
params:
message: The order of the epochs in the study design (as defined by the next attribute) does not match the order of epochs as referenced from scheduled activity instances in the main timeline that are ordered by default condition.
Attach any sample test data file(s)
issue12_data.zip: two USDM 4.0 JSON files for the same fictional study. The only difference is that shaun_h_usdm_nulls_omitted.json leaves out previousId/nextId where they are null (on epochs, encounters and narrative content), and shaun_h_usdm_nulls_explicit.json writes them as null. Both pass the USDM 4.0 schema with no errors.
Second command, for the explicit-null file:
python core.py validate -s usdm -v 4-0 -dp issue12_data/shaun_h_usdm_nulls_explicit.json -r CORE-001055 -r CORE-000961 -r CORE-001048 -of JSON
Attach any output report and/or log file(s)
With previousId/nextId omitted, all three rules report issues (CORE-001055 on the first and last NarrativeContent; CORE-000961 and CORE-001048 on the study design, with an empty order from previous/next). With explicit null, all three pass.
Expected output
The same result for both files: no issues from CORE-001055, CORE-000961 or CORE-001048, since omitting an optional previousId/nextId means the same as null.
Any Additional Information
The USDM 4.0 API schema does not require previousId or nextId, so they can be omitted. CORE-001055 tests $type($v.previousId) = "null"; an omitted key is undefined, not null, so the ends of the list are reported as pointing to content that does not exist. CORE-000961 and CORE-001048 build the encounter and epoch order from the item where previousId = null; with the key omitted nothing matches and the order comes out empty.
Suggested fix: treat a missing key as null, e.g. $not($exists($v.previousId)) or $type($v.previousId) = "null" in CORE-001055, and [$not($exists(previousId)) or previousId = null] when finding the first item in CORE-000961 and CORE-001048.
Environment: CORE 0.17.1 (GitHub main, commit 22ce7a7, 29 October 2026), Python 3.12, Linux.
- Dominant language
- Python
- Stars
- 125
- Forks
- 50
- Avg merge
- 7h 40m
- Merged PRs (30d)
- 14
Getting set up
- Ships a Dockerfile or Docker Compose file
- No pull request template
- Read the contributing 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.
More from cdisc-org/cdisc-rules-engine
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
cdisc-org/cdisc-rules-engine#1891 ·
Maintainers usually reply within 1 day
-
CORE-000305 crashes ("argument of type 'float' is not iterable") when --DUR is empty on some recordsOpenquestion
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
cdisc-org/cdisc-rules-engine#1885 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
cdisc-org/cdisc-rules-engine#1848 · 1 comment ·
Maintainers usually reply within 1 day
-
SKIPPED rules have no reason in the XLSX or JSON report, though the FAQ says they doPossibly taken @SFJohnson24 claimed this 2 days ago. Openreporting
Difficulty 3/5 1-2 days Newbie friendliness 65/100
cdisc-org/cdisc-rules-engine#1897 · 1 assignee ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 45/100
cdisc-org/cdisc-rules-engine#1893 ·
Maintainers usually reply within 1 day
All issues in cdisc-org/cdisc-rules-engine
Similar issues
-
needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
gke-labs/kube-agents#5671 ·
Maintainers usually reply within 1 day
-
docs(auth): Method B step 4 should tell users to tick "Use this client for an AI-powered agent"Opendocumentation next-release v0.9.6
Difficulty 1/5 Under an hour Newbie friendliness 88/100
khuisman/mcp-gee-sweet#1446 ·
Maintainers usually reply within 1 day
-
model:sonnet runtime:claude security size:S
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
FootprintAI/Containarium#3671 ·
Maintainers usually reply within 1 day
-
HolidayBase: reassigning `language` does not re-initialize translations or re-populate holidaysPossibly taken @shikhabhadoria claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
vacanza/holidays#4116 · 1 comment ·
Maintainers usually reply within 1 day
-
bug CLI exec
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day