From d7c5e9f77558422ee0ecbb9fe3a602afb2a97046 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 10 Jun 2026 12:07:32 -0400 Subject: [PATCH 01/10] merge main --- Published/CORE-000084/negative/02/results/results.csv | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Published/CORE-000084/negative/02/results/results.csv b/Published/CORE-000084/negative/02/results/results.csv index ac0a344f7..daf1aa5b6 100644 --- a/Published/CORE-000084/negative/02/results/results.csv +++ b/Published/CORE-000084/negative/02/results/results.csv @@ -1,14 +1,6 @@ Dataset,Record,Variable,Value -<<<<<<< HEAD -AE,0,AEENTPT,2013-05-20 -AE,1,AEENTPT,2013-05-20 -AE,2,AEENTPT,2013-01-14 -AE,3,AEENTPT,2013-01-14 -AE,4,AEENTPT, -======= AE.csv,1,AEENTPT,2013-05-20 AE.csv,2,AEENTPT,2013-05-20 AE.csv,3,AEENTPT,2013-01-14 AE.csv,4,AEENTPT,2013-01-14 AE.csv,5,AEENTPT, ->>>>>>> main From 8a219b0f0d20a3cf4b8159b438f8d3a93a56cd8f Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 2 Sep 2026 16:58:13 -0400 Subject: [PATCH 02/10] changes --- audit_extra_folders.txt | 451 ---------------------------------------- test.py | 97 ++++----- 2 files changed, 49 insertions(+), 499 deletions(-) delete mode 100644 audit_extra_folders.txt diff --git a/audit_extra_folders.txt b/audit_extra_folders.txt deleted file mode 100644 index 30653d541..000000000 --- a/audit_extra_folders.txt +++ /dev/null @@ -1,451 +0,0 @@ -RULE FOLDERS WITH NO TEST DATA -============================================================ - -4 rule(s) with no negative/ or positive/: - - CORE-000110 - CG0549, TIG0637 - CORE-000645 - FB8601 - CORE-000765 - FB2401 - CORE-000887 - FB2301 - - -RULES WITH NO RESULTS DIRECTORY -============================================================ -280 test case(s) with no results/ directory: - CORE-000002 - CORE-000002\negative\01 - CORE-000002\positive\01 - CORE-000005 - CORE-000005\negative\01 - CORE-000005\positive\01 - CORE-000016 - CORE-000016\negative\03 - CORE-000023 - CORE-000023\negative\01 - CORE-000023\positive\01 - CORE-000024 - CORE-000024\negative\01 - CORE-000024\positive\01 - CORE-000026 - CORE-000026\negative\01 - CORE-000026\positive\01 - CORE-000027 - CORE-000027\positive\03 - CORE-000031 - CORE-000031\negative\01 - CORE-000031\negative\02 - CORE-000031\positive\01 - CORE-000032 - CORE-000032\negative\01 - CORE-000032\negative\02 - CORE-000032\negative\03 - CORE-000032\positive\01 - CORE-000074 - CORE-000074\negative\01 - CORE-000074\positive\01 - CORE-000075 - CORE-000075\negative\01 - CORE-000075\positive\01 - CORE-000081 - CORE-000081\negative\02 - CORE-000081\positive\02 - CORE-000097 - CORE-000097\negative\01 - CORE-000097\positive\01 - CORE-000107 - CORE-000107\negative\01 - CORE-000107\negative\02 - CORE-000107\negative\03 - CORE-000107\negative\04 - CORE-000107\negative\05 - CORE-000107\positive\01 - CORE-000107\positive\02 - CORE-000107\positive\03 - CORE-000107\positive\04 - CORE-000108 - CORE-000108\negative\01 - CORE-000108\positive\01 - CORE-000133 - CORE-000133\negative\01 - CORE-000133\positive\01 - CORE-000134 - CORE-000134\negative\02 - CORE-000134\positive\02 - CORE-000142 - CORE-000142\positive\03 - CORE-000157 - CORE-000157\negative\01 - CORE-000157\positive\01 - CORE-000178 - CORE-000178\negative\01 - CORE-000178\positive\01 - CORE-000181 - CORE-000181\positive\02 - CORE-000203 - CORE-000203\negative\01 - CORE-000203\positive\01 - CORE-000207 - CORE-000207\negative\01 - CORE-000207\positive\01 - CORE-000208 - CORE-000208\negative\01 - CORE-000208\positive\01 - CORE-000209 - CORE-000209\negative\01 - CORE-000209\positive\01 - CORE-000210 - CORE-000210\negative\01 - CORE-000210\positive\01 - CORE-000211 - CORE-000211\negative\01 - CORE-000211\positive\01 - CORE-000212 - CORE-000212\negative\01 - CORE-000212\positive\01 - CORE-000213 - CORE-000213\negative\01 - CORE-000213\negative\02 - CORE-000213\negative\03 - CORE-000213\positive\01 - CORE-000213\positive\02 - CORE-000216 - CORE-000216\negative\01 - CORE-000216\positive\01 - CORE-000225 - CORE-000225\TIG0359\negative\01 - CORE-000225\TIG0359\positive\01 - CORE-000236 - CORE-000236\negative\01 - CORE-000236\positive\01 - CORE-000239 - CORE-000239\negative\03 - CORE-000243 - CORE-000243\negative\01 - CORE-000243\positive\01 - CORE-000244 - CORE-000244\negative\01 - CORE-000244\positive\01 - CORE-000248 - CORE-000248\SENDIG063\negative\02 - CORE-000248\SENDIG063\positive\02 - CORE-000250 - CORE-000250\negative\01 - CORE-000250\positive\01 - CORE-000252 - CORE-000252\negative\01 - CORE-000252\positive\01 - CORE-000253 - CORE-000253\negative\01 - CORE-000253\positive\01 - CORE-000254 - CORE-000254\negative\01 - CORE-000254\positive\01 - CORE-000256 - CORE-000256\positive\02 - CORE-000264 - CORE-000264\negative\01 - CORE-000264\negative\02 - CORE-000264\positive\01 - CORE-000264\positive\02 - CORE-000264\positive\03 - CORE-000266 - CORE-000266\negative\02 - CORE-000266\positive\02 - CORE-000291 - CORE-000291\negative\01 - CORE-000291\positive\01 - CORE-000292 - CORE-000292\negative\01 - CORE-000292\positive\01 - CORE-000293 - CORE-000293\negative\01 - CORE-000293\negative\02 - CORE-000293\positive\01 - CORE-000293\positive\02 - CORE-000295 - CORE-000295\negative\01 - CORE-000295\positive\01 - CORE-000296 - CORE-000296\negative\01 - CORE-000296\positive\01 - CORE-000297 - CORE-000297\negative\02 - CORE-000297\negative\03 - CORE-000297\negative\04 - CORE-000297\negative\05 - CORE-000297\positive\01 - CORE-000297\positive\02 - CORE-000297\positive\03 - CORE-000297\positive\04 - CORE-000297\positive\05 - CORE-000302 - CORE-000302\negative\01 - CORE-000302\positive\01 - CORE-000354 - CORE-000354\negative\02 - CORE-000354\negative\03 - CORE-000354\positive\02 - CORE-000354\positive\03 - CORE-000358 - CORE-000358\negative\02 - CORE-000358\positive\02 - CORE-000361 - CORE-000361\positive\02 - CORE-000362 - CORE-000362\negative\01 - CORE-000362\positive\01 - CORE-000362\positive\02 - CORE-000362\positive\03 - CORE-000363 - CORE-000363\negative\01 - CORE-000363\positive\01 - CORE-000371 - CORE-000371\negative\01 - CORE-000371\positive\01 - CORE-000372 - CORE-000372\positive\01 - CORE-000373 - CORE-000373\negative\01 - CORE-000373\positive\01 - CORE-000376 - CORE-000376\TIG0514\negative\01 - CORE-000376\TIG0514\positive\01 - CORE-000377 - CORE-000377\negative\01 - CORE-000377\positive\01 - CORE-000457 - CORE-000457\negative\01 - CORE-000457\positive\01 - CORE-000458 - CORE-000458\positive\02 - CORE-000470 - CORE-000470\negative\02 - CORE-000487 - CORE-000487\positive\01 - CORE-000501 - CORE-000501\negative\01 - CORE-000501\positive\01 - CORE-000529 - CORE-000529\negative\02 - CORE-000529\negative\03 - CORE-000529\positive\02 - CORE-000529\positive\03 - CORE-000563 - CORE-000563\negative\01 - CORE-000563\positive\01 - CORE-000564 - CORE-000564\negative\01 - CORE-000564\negative\02 - CORE-000564\negative\03 - CORE-000564\positive\01 - CORE-000571 - CORE-000571\negative\02 - CORE-000579 - CORE-000571\negative\01 - CORE-000581 - CORE-000581\negative\01 - CORE-000581\positive\01 - CORE-000581\TRC1736a\negative\01 - CORE-000581\TRC1736a\positive\01 - CORE-000582 - CORE-000582\negative\01 - CORE-000582\positive\01 - CORE-000590 - CORE-000590\negative\01 - CORE-000590\positive\01 - CORE-000592 - CORE-000592\negative\01 - CORE-000592\positive\01 - CORE-000593 - CORE-000593\negative\01 - CORE-000593\positive\01 - CORE-000595 - CORE-000595\negative\01 - CORE-000595\negative\02 - CORE-000595\negative\03 - CORE-000595\negative\04 - CORE-000595\positive\01 - CORE-000595\positive\02 - CORE-000595\positive\03 - CORE-000596 - CORE-000596\negative\01 - CORE-000596\negative\02 - CORE-000596\positive\01 - CORE-000596\positive\02 - CORE-000600 - CORE-000600\negative\01 - CORE-000600\positive\01 - CORE-000601 - CORE-000601\negative\01 - CORE-000601\positive\01 - CORE-000602 - CORE-000602\negative\01 - CORE-000602\positive\01 - CORE-000603 - CORE-000603\negative\01 - CORE-000603\positive\01 - CORE-000603\positive\02 - CORE-000604 - CORE-000604\negative\01 - CORE-000604\positive\01 - CORE-000604\positive\02 - CORE-000605 - CORE-000605\negative\01 - CORE-000605\positive\01 - CORE-000605\positive\02 - CORE-000606 - CORE-000606\negative\01 - CORE-000606\positive\01 - CORE-000606\positive\02 - CORE-000606\positive\03 - CORE-000607 - CORE-000607\negative\01 - CORE-000607\positive\01 - CORE-000607\positive\02 - CORE-000609 - CORE-000609\negative\01 - CORE-000609\positive\01 - CORE-000609\positive\02 - CORE-000609\positive\03 - CORE-000610 - CORE-000610\negative\01 - CORE-000610\positive\01 - CORE-000610\positive\02 - CORE-000610\positive\03 - CORE-000611 - CORE-000611\negative\01 - CORE-000611\positive\01 - CORE-000611\positive\02 - CORE-000611\positive\03 - CORE-000660 - CORE-000660\negative\01 - CORE-000660\positive\01 - CORE-000660\positive\02 - CORE-000660\positive\03 - CORE-000673 - CORE-000673\negative\01 - CORE-000673\positive\01 - CORE-000673\positive\02 - CORE-000673\positive\03 - CORE-000675 - CORE-000675\negative\01 - CORE-000675\positive\01 - CORE-000685 - CORE-000685\negative\01 - CORE-000685\negative\02 - CORE-000685\positive\01 - CORE-000685\positive\02 - CORE-000686 - CORE-000686\negative\01 - CORE-000686\positive\01 - CORE-000689 - CORE-000689\negative\01 - CORE-000689\positive\01 - CORE-000698 - CORE-000698\negative\01 - CORE-000698\negative\02 - CORE-000698\positive\01 - CORE-000698\positive\02 - CORE-000698\positive\03 - CORE-000722 - CORE-000722\negative\01 - CORE-000722\positive\01 - CORE-000726 - CORE-000726\negative\01 - CORE-000726\positive\01 - CORE-000727 - CORE-000727\negative\01 - CORE-000727\negative\02 - CORE-000727\positive\01 - CORE-000727\positive\02 - CORE-000736 - CORE-000736\negative\01 - CORE-000736\positive\01 - CORE-000746 - CORE-000746\negative\01 - CORE-000746\positive\01 - CORE-000747 - CORE-000747\negative\01 - CORE-000747\positive\01 - CORE-000750 - CORE-000750\negative\01 - CORE-000750\negative\02 - CORE-000750\positive\01 - CORE-000750\positive\02 - CORE-000755 - CORE-000755\negative\01 - CORE-000755\positive\01 - CORE-000774 - CORE-000774\negative\01 - CORE-000774\positive\01 - CORE-000776 - CORE-000776\negative\01 - CORE-000776\positive\01 - CORE-000777 - CORE-000777\negative\01 - CORE-000777\negative\02 - CORE-000777\negative\03 - CORE-000777\negative\04 - CORE-000777\negative\05 - CORE-000777\positive\01 - CORE-000777\positive\02 - CORE-000777\positive\03 - CORE-000777\positive\04 - CORE-000777\positive\05 - CORE-000778 - CORE-000778\negative\01 - CORE-000778\positive\01 - CORE-000779 - CORE-000779\CG0378\negative\01 - CORE-000779\CG0378\positive\01 - CORE-000791 - CORE-000791\negative\01 - CORE-000791\positive\01 - CORE-000901 - CORE-000901\negative\01 - CORE-000901\positive\01 - CORE-001044 - CORE-001044\negative\01 - CORE-001078 - CORE-001078\negative\01 - CORE-001078\positive\01 - - - -RULES with no .env: - CORE-000386 - CORE-000386\negative\01 - CORE-000386\positive\01 - CORE-000429 - CORE-000429\negative\01 - CORE-000429\positive\01 - CORE-000444 - CORE-000444\negative\01 - CORE-000444\positive\01 - CORE-000477 - CORE-000477\negative\01 - CORE-000477\positive\01 - CORE-000554 - CORE-000554\negative\01 - CORE-000554\positive\01 - CORE-000577 - CORE-000577\negative\01 - CORE-000577\positive\01 - CORE-000578 - CORE-000578\negative\01 - CORE-000578\positive\01 - CORE-000652 - CORE-000652\negative\01 - CORE-000652\positive\01 - CORE-000898 - CORE-000898\negative\01 - CORE-000898\positive\01 - CORE-000899 - CORE-000899\negative\01 - CORE-000899\positive\01 - CORE-000926 - CORE-000926\negative\01 - CORE-000926\positive\01 - CORE-000946 - CORE-000946\negative\01 - CORE-000946\positive\01 diff --git a/test.py b/test.py index c00c589b2..404c4fa3b 100644 --- a/test.py +++ b/test.py @@ -2,7 +2,7 @@ """ Local test runner for CDISC Open Rules. Prompts for a rule folder path, runs the CORE engine against each test case, -and writes results.csv into each case's results/ directory. +and writes results.json into each case's results/ directory. """ import os @@ -12,6 +12,7 @@ from typing import Optional, Dict, List ENGINE_DIR = Path("engine") +CONVERT_SCRIPT = Path(".github/scripts/convert_results.py") LOG_LEVELS = ["info", "debug", "error", "critical", "disabled", "warn"] @@ -50,13 +51,11 @@ def get_test_cases(rule_path: Path) -> Dict[str, List[dict]]: continue for case_dir in sorted(type_dir.iterdir()): if case_dir.is_dir() and (case_dir / "data").is_dir(): - cases[test_type].append( - { - "case_id": case_dir.name, - "data_dir": case_dir / "data", - "results_dir": case_dir / "results", - } - ) + cases[test_type].append({ + "case_id": case_dir.name, + "data_dir": case_dir / "data", + "results_dir": case_dir / "results", + }) return cases @@ -70,15 +69,15 @@ def find_env_file(data_dir: Path) -> Optional[Path]: def next_results_path(results_dir: Path) -> Path: """ Creates results/ if needed. Returns the next available -o path for the engine - (without extension — engine appends .csv automatically). - - No results.csv yet -> results_dir/results - - results.csv exists -> results_dir/results(1), results_dir/results(2), ... + (without extension — engine appends .json automatically). + - No results.json yet -> results_dir/results + - results.json exists -> results_dir/results(1), results_dir/results(2), ... """ results_dir.mkdir(parents=True, exist_ok=True) - if not (results_dir / "results.csv").exists(): + if not (results_dir / "results.json").exists(): return results_dir / "results" n = 1 - while (results_dir / f"results({n}).csv").exists(): + while (results_dir / f"results({n}).json").exists(): n += 1 return results_dir / f"results({n})" @@ -87,7 +86,6 @@ def next_results_path(results_dir: Path) -> Path: # Engine invocation # --------------------------------------------------------------------------- - def run_engine( rule_yml: Path, data_dir: Path, @@ -100,23 +98,14 @@ def run_engine( return False, f"No .env file found in {data_dir}" cmd = [ - sys.executable, - "core.py", - "validate", - "-lr", - str(rule_yml.resolve()), - "-d", - str(data_dir.resolve()), - "-dep", - str(env_file.resolve()), - "-of", - "CSV", - "-o", - str(output_path.resolve()), - "-p", - "disabled", - "-l", - log_level, + sys.executable, "core.py", "validate", + "-lr", str(rule_yml.resolve()), + "-d", str(data_dir.resolve()), + "-dep", str(env_file.resolve()), + "-of", "JSON", + "-o", str(output_path.resolve()), + "-p", "disabled", + "-l", log_level, ] try: @@ -162,7 +151,7 @@ def run_rule( log_level: str, capture_logs: bool, ): - rule_yml = find_rule_yml(rule_path) + rule_yml = find_rule_yml(rule_path) all_cases = get_test_cases(rule_path) if specific_case: @@ -179,18 +168,28 @@ def run_rule( for test_type in ("positive", "negative"): for case in all_cases[test_type]: any_ran = True - case_id = case["case_id"] - data_dir = case["data_dir"] + case_id = case["case_id"] + data_dir = case["data_dir"] output_path = next_results_path(case["results_dir"]) print(f"\n Running {test_type}/{case_id}...") - ok, output = run_engine( - rule_yml, data_dir, output_path, log_level, capture_logs - ) - - csv_path = Path(str(output_path) + ".csv") - if ok and csv_path.exists(): - print(f" Done — results written to {csv_path}") + ok, output = run_engine(rule_yml, data_dir, output_path, log_level, capture_logs) + + json_path = Path(str(output_path) + ".json") + if ok and json_path.exists(): + print(f" Done — results written to {json_path}") + csv_path = output_path.with_suffix(".csv") + try: + proc = subprocess.run( + [sys.executable, str(CONVERT_SCRIPT), str(json_path), str(csv_path)], + capture_output=True, text=True + ) + if proc.returncode == 0: + print(f" Done — CSV written to {csv_path}") + else: + print(f" [WARN] CSV conversion failed: {proc.stderr.strip()}") + except Exception as e: + print(f" [WARN] CSV conversion error: {e}") else: print(f" [ERROR] Engine failed for {test_type}/{case_id}") for line in output.splitlines(): @@ -206,7 +205,6 @@ def run_rule( # Prompts # --------------------------------------------------------------------------- - def prompt_rule_path() -> Path: print("\nEnter the path to your rule folder (e.g. Unpublished/CORE-000001).") print("Expected structure:") @@ -230,7 +228,11 @@ def prompt_rule_path() -> Path: def prompt_case(cases: Dict[str, List[dict]]) -> Optional[str]: - flat = [f"{t}/{c['case_id']}" for t in ("positive", "negative") for c in cases[t]] + flat = [ + f"{t}/{c['case_id']}" + for t in ("positive", "negative") + for c in cases[t] + ] if not flat: return None @@ -273,12 +275,11 @@ def prompt_capture_logs() -> bool: # Entry point # --------------------------------------------------------------------------- - def main(): - rule_path = prompt_rule_path() - cases = get_test_cases(rule_path) - specific = prompt_case(cases) - log_level = prompt_log_level() + rule_path = prompt_rule_path() + cases = get_test_cases(rule_path) + specific = prompt_case(cases) + log_level = prompt_log_level() capture_logs = prompt_capture_logs() run_rule(rule_path, specific, log_level, capture_logs) From 49bf0414fce6c01e3a4ef584ab0f9064c3f3f9b5 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 2 Sep 2026 16:58:25 -0400 Subject: [PATCH 03/10] changes --- test.py | 95 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/test.py b/test.py index 404c4fa3b..0b999be13 100644 --- a/test.py +++ b/test.py @@ -12,7 +12,6 @@ from typing import Optional, Dict, List ENGINE_DIR = Path("engine") -CONVERT_SCRIPT = Path(".github/scripts/convert_results.py") LOG_LEVELS = ["info", "debug", "error", "critical", "disabled", "warn"] @@ -51,11 +50,13 @@ def get_test_cases(rule_path: Path) -> Dict[str, List[dict]]: continue for case_dir in sorted(type_dir.iterdir()): if case_dir.is_dir() and (case_dir / "data").is_dir(): - cases[test_type].append({ - "case_id": case_dir.name, - "data_dir": case_dir / "data", - "results_dir": case_dir / "results", - }) + cases[test_type].append( + { + "case_id": case_dir.name, + "data_dir": case_dir / "data", + "results_dir": case_dir / "results", + } + ) return cases @@ -69,15 +70,15 @@ def find_env_file(data_dir: Path) -> Optional[Path]: def next_results_path(results_dir: Path) -> Path: """ Creates results/ if needed. Returns the next available -o path for the engine - (without extension — engine appends .json automatically). - - No results.json yet -> results_dir/results - - results.json exists -> results_dir/results(1), results_dir/results(2), ... + (without extension — engine appends .csv automatically). + - No results.csv yet -> results_dir/results + - results.csv exists -> results_dir/results(1), results_dir/results(2), ... """ results_dir.mkdir(parents=True, exist_ok=True) - if not (results_dir / "results.json").exists(): + if not (results_dir / "results.csv").exists(): return results_dir / "results" n = 1 - while (results_dir / f"results({n}).json").exists(): + while (results_dir / f"results({n}).csv").exists(): n += 1 return results_dir / f"results({n})" @@ -86,6 +87,7 @@ def next_results_path(results_dir: Path) -> Path: # Engine invocation # --------------------------------------------------------------------------- + def run_engine( rule_yml: Path, data_dir: Path, @@ -98,14 +100,23 @@ def run_engine( return False, f"No .env file found in {data_dir}" cmd = [ - sys.executable, "core.py", "validate", - "-lr", str(rule_yml.resolve()), - "-d", str(data_dir.resolve()), - "-dep", str(env_file.resolve()), - "-of", "JSON", - "-o", str(output_path.resolve()), - "-p", "disabled", - "-l", log_level, + sys.executable, + "core.py", + "validate", + "-lr", + str(rule_yml.resolve()), + "-d", + str(data_dir.resolve()), + "-dep", + str(env_file.resolve()), + "-of", + "CSV", + "-o", + str(output_path.resolve()), + "-p", + "disabled", + "-l", + log_level, ] try: @@ -151,7 +162,7 @@ def run_rule( log_level: str, capture_logs: bool, ): - rule_yml = find_rule_yml(rule_path) + rule_yml = find_rule_yml(rule_path) all_cases = get_test_cases(rule_path) if specific_case: @@ -168,28 +179,18 @@ def run_rule( for test_type in ("positive", "negative"): for case in all_cases[test_type]: any_ran = True - case_id = case["case_id"] - data_dir = case["data_dir"] + case_id = case["case_id"] + data_dir = case["data_dir"] output_path = next_results_path(case["results_dir"]) print(f"\n Running {test_type}/{case_id}...") - ok, output = run_engine(rule_yml, data_dir, output_path, log_level, capture_logs) - - json_path = Path(str(output_path) + ".json") - if ok and json_path.exists(): - print(f" Done — results written to {json_path}") - csv_path = output_path.with_suffix(".csv") - try: - proc = subprocess.run( - [sys.executable, str(CONVERT_SCRIPT), str(json_path), str(csv_path)], - capture_output=True, text=True - ) - if proc.returncode == 0: - print(f" Done — CSV written to {csv_path}") - else: - print(f" [WARN] CSV conversion failed: {proc.stderr.strip()}") - except Exception as e: - print(f" [WARN] CSV conversion error: {e}") + ok, output = run_engine( + rule_yml, data_dir, output_path, log_level, capture_logs + ) + + csv_path = Path(str(output_path) + ".csv") + if ok and csv_path.exists(): + print(f" Done — results written to {csv_path}") else: print(f" [ERROR] Engine failed for {test_type}/{case_id}") for line in output.splitlines(): @@ -205,6 +206,7 @@ def run_rule( # Prompts # --------------------------------------------------------------------------- + def prompt_rule_path() -> Path: print("\nEnter the path to your rule folder (e.g. Unpublished/CORE-000001).") print("Expected structure:") @@ -228,11 +230,7 @@ def prompt_rule_path() -> Path: def prompt_case(cases: Dict[str, List[dict]]) -> Optional[str]: - flat = [ - f"{t}/{c['case_id']}" - for t in ("positive", "negative") - for c in cases[t] - ] + flat = [f"{t}/{c['case_id']}" for t in ("positive", "negative") for c in cases[t]] if not flat: return None @@ -275,11 +273,12 @@ def prompt_capture_logs() -> bool: # Entry point # --------------------------------------------------------------------------- + def main(): - rule_path = prompt_rule_path() - cases = get_test_cases(rule_path) - specific = prompt_case(cases) - log_level = prompt_log_level() + rule_path = prompt_rule_path() + cases = get_test_cases(rule_path) + specific = prompt_case(cases) + log_level = prompt_log_level() capture_logs = prompt_capture_logs() run_rule(rule_path, specific, log_level, capture_logs) From 9ce0223f1bb4c965c8c2870cc3c28afa59262545 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 2 Sep 2026 17:05:30 -0400 Subject: [PATCH 04/10] change --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 0b999be13..c00c589b2 100644 --- a/test.py +++ b/test.py @@ -2,7 +2,7 @@ """ Local test runner for CDISC Open Rules. Prompts for a rule folder path, runs the CORE engine against each test case, -and writes results.json into each case's results/ directory. +and writes results.csv into each case's results/ directory. """ import os From 6fabb816f2451bdb24b4c579bcac96dbffffaafc Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Tue, 15 Sep 2026 15:29:25 -0400 Subject: [PATCH 05/10] update scope --- Deprecated/CORE-000778/rule.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Deprecated/CORE-000778/rule.yml b/Deprecated/CORE-000778/rule.yml index f7e4f88eb..0f123c56f 100644 --- a/Deprecated/CORE-000778/rule.yml +++ b/Deprecated/CORE-000778/rule.yml @@ -13,8 +13,7 @@ Authorities: Version: "1" Version: "2.0" Citations: - - Cited Guidance: - Supplemental Qualifier datasets for split domains would also be + - Cited Guidance: Supplemental Qualifier datasets for split domains would also be split. The nomenclature would include the additional one-to-two characters used to identify the split dataset. Document: IG v3.4 @@ -29,8 +28,7 @@ Authorities: Version: "1" Version: "2.0" Citations: - - Cited Guidance: - AP Guide v1.0[2][Associated Persons datasets are given a prefix + - Cited Guidance: AP Guide v1.0[2][Associated Persons datasets are given a prefix of AP-- to identify the data as AP data to and distinguish them from study subject data.]|IG v3.2[4.1.1.7][Item 6][For example, if splitting by --CAT, then dataset names would be @@ -48,8 +46,7 @@ Authorities: Version: "1" Version: "2.0" Citations: - - Cited Guidance: - AP Guide v1.0[2][Associated Persons datasets are given a prefix + - Cited Guidance: AP Guide v1.0[2][Associated Persons datasets are given a prefix of AP-- to identify the data as AP data to and distinguish them from study subject data.]|IG v3.3[4.1.7][Item 6][For example, if splitting by --CAT, then dataset names would be @@ -75,8 +72,7 @@ Description: When an Associated Persons non-supplemental qualifier dataset is 4 and less than, or equal to, 6. Executability: Fully Executable Outcome: - Message: - Associated Persons non-supplemental qualifier dataset associated with a + Message: Associated Persons non-supplemental qualifier dataset associated with a split dataset does not have a dataset name with a length greater than 4 and less than, or equal to, 6. Rule Type: Dataset Metadata Check @@ -87,5 +83,9 @@ Scope: Domains: Include: - AP-- + Exclude: + - SQ-- + - APRELSUB + - APRELSPEC include_split_datasets: true Sensitivity: Dataset From d756ff10af929392c396a428c1954a773836ff1a Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 16 Sep 2026 18:01:03 -0400 Subject: [PATCH 06/10] new scope logic --- Deprecated/CORE-000510/rule.yml | 2 ++ Deprecated/CORE-000778/rule.yml | 4 ++-- Published/CORE-000357/rule.yml | 2 +- Published/CORE-000551/rule.yml | 2 +- docs/README.md | 42 +++++++++++++++++---------------- docs/scope.md | 2 +- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/Deprecated/CORE-000510/rule.yml b/Deprecated/CORE-000510/rule.yml index 70d4b45d5..2ddff12df 100644 --- a/Deprecated/CORE-000510/rule.yml +++ b/Deprecated/CORE-000510/rule.yml @@ -90,6 +90,8 @@ Scope: Include: - ALL Domains: + Include: + - SPLIT DATASETS Exclude: - SUPP-- - AP-- diff --git a/Deprecated/CORE-000778/rule.yml b/Deprecated/CORE-000778/rule.yml index 0f123c56f..dbeec1baa 100644 --- a/Deprecated/CORE-000778/rule.yml +++ b/Deprecated/CORE-000778/rule.yml @@ -82,9 +82,9 @@ Scope: - ALL Domains: Include: - - AP-- + - AP SPLIT DATASETS Exclude: - - SQ-- + - SUPPQUAL - APRELSUB - APRELSPEC include_split_datasets: true diff --git a/Published/CORE-000357/rule.yml b/Published/CORE-000357/rule.yml index 7d08e6764..019ec84c5 100644 --- a/Published/CORE-000357/rule.yml +++ b/Published/CORE-000357/rule.yml @@ -91,7 +91,7 @@ Scope: - ALL Domains: Include: - - SUPP-- + - SUPPQUAL include_split_datasets: true Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000551/rule.yml b/Published/CORE-000551/rule.yml index 6dac6f880..4decfff57 100644 --- a/Published/CORE-000551/rule.yml +++ b/Published/CORE-000551/rule.yml @@ -161,6 +161,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: NONCLIN Sensitivity: Record diff --git a/docs/README.md b/docs/README.md index 46d25a3d1..862d2e6c9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -125,26 +125,28 @@ Most of the metadata attributes below are derived automatically from the dataset - **`unsplit_name`** and **`is_split`** are derived from the above — split datasets have a naming convention defined in the IG and whose name differs from their base domain (e.g., `QSX` is a split of `QS`). Determined by comparing name and domain with some logic to exclude supplemental domains. Neither property is available for use in rule check logic. - **`domain_is_custom`**, **`related_domain`**, and **`related_domain_is_custom`** are computed by operations applied at rule evaluation time. Note that `domain_is_custom` applies only to the domain itself — supplemental and AP datasets built on top of a custom domain (e.g., `SUPPXX`, `APXX`, `SQAPXX`) are not themselves custom but their **`related_domain_is_custom`**. -| name | unsplit_name | is_supp | domain | rdomain | is_ap | ap_suffix | domain_is_custom | related_domain | related_domain_is_custom | -| ------ | ------------ | ------- | ------ | ------- | ----- | --------- |------------------| -------------- | ------------------------ | -| QS | QS | False | QS | None | False | | False | | | -| QSX | QS | False | QS | None | False | | False | | | -| QSXX | QS | False | QS | None | False | | False | | | -| SUPPQS | SUPPQS | True | None | QS | False | | False | QS | | -| SUPPQSX | SUPPQS | True | None | QS | False | | False | QS | | -| SUPPQSXX | SUPPQS | True | None | QS | False | | False | QS | | -| APQS | APQS | False | APQS | None | True | QS | False | QS | | -| APQSX | APQS | False | APQS | None | True | QS | False | QS | | -| APQSXX | APQS | False | APQS | None | True | QS | False | QS | | -| SQAPQS | SQAPQS | True | None | APQS | True | | False | QS | | -| SQAPQSX | SQAPQS | True | None | APQS | True | | False | QS | | -| SQAPQSXX | SQAPQS | True | None | APQS | True | | False | | | -| RELREC | RELREC | False | None | None | False | | False | | | -| XX | XX | False | XX | None | False | | True | | | -| SUPPXX | SUPPXX | True | None | XX | False | | False | XX | True | -| APXX | APXX | False | APXX | None | True | XX | False | XX | True | -| SQAPXX | SQAPXX | True | None | APXX | True | | False | XX | True | -| FA | FA | False | FA | None | False | | False | | | +| name | unsplit_name | is_supp | is_split | domain | wildcard_replacement | rdomain | is_ap | ap_suffix | domain_is_custom | related_domain | related_domain_is_custom | +| --------- | ------------ | ------- | -------- | ------ | --------------------- | ------- | ----- | --------- | ---------------- | --------------- | ------------------------- | +| QS | QS | False | False | QS | QS | None | False | | False | | | +| QSX | QS | False | True | QS | QS | None | False | | False | | | +| QSXX | QS | False | True | QS | QS | None | False | | False | | | +| SUPPQS | SUPPQS | True | False | | | QS | False | | False | QS | | +| SUPPQSX | SUPPQS | True | True | | | QS | False | | False | QS | | +| SUPPQSXX | SUPPQS | True | True | | | QS | False | | False | QS | | +| APQS | APQS | False | False | QS | QS | None | True | QS | False | QS | | +| APQSX | APQS | False | True | QS | QS | None | True | QS | False | QS | | +| APQSXX | APQS | False | True | QS | QS | None | True | QS | False | QS | | +| SQAPQS | SQAPQS | True | False | | | APQS | False | | False | QS | | +| SQAPQSX | SQAPQS | True | True | | | APQS | False | | False | QS | | +| SQAPQSXX | SQAPQS | True | True | | | APQS | False | | False | | | +| RELREC | RELREC | False | False | | | None | False | | False | | | +| XX | XX | False | False | XX | XX | None | False | | True | | | +| SUPPXX | SUPPXX | True | False | | | XX | False | | False | XX | True | +| APXX | APXX | False | False | XX | XX | None | True | XX | False | XX | True | +| SQAPXX | SQAPXX | True | False | | | APXX | False | | False | XX | True | +| FA | FA | False | False | FA | FA | None | False | | False | | | +| APRELSUB | APRELSUB | False | False | | RELSUB | None | True | RELSUB | False | | | +| APRELSPEC | APRELSPEC | False | False | | RELSPEC | None | True | RELSPEC | False | | | ## Business Rule Examples diff --git a/docs/scope.md b/docs/scope.md index 4ea9e9e97..6dc22b910 100644 --- a/docs/scope.md +++ b/docs/scope.md @@ -27,7 +27,7 @@ For example, if your Rule column references variables from the DM domain, your s ### 3. Split Dataset Handling -The `include_split_datasets` flag (when set to `true`) allows split datasets to be processed separately from their parent datasets. This is useful when you need to analyze split datasets independently. +The `include_split_datasets` flag (when set to `true`) allows split datasets to be processed separately from their parent datasets. This is useful when you need to analyze split datasets independently. `SPLIT DATASETS` can also be added to Domain inclusion/exclusion Scope criteria if the rule is applicable to unmerged split datasets. ### 4. Use Case Selection From 3aeaa0507d70557ac8e25482a9c73aeef9326848 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 16 Sep 2026 18:09:16 -0400 Subject: [PATCH 07/10] scope.md --- docs/scope.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/scope.md b/docs/scope.md index 6dc22b910..4102babe6 100644 --- a/docs/scope.md +++ b/docs/scope.md @@ -27,7 +27,7 @@ For example, if your Rule column references variables from the DM domain, your s ### 3. Split Dataset Handling -The `include_split_datasets` flag (when set to `true`) allows split datasets to be processed separately from their parent datasets. This is useful when you need to analyze split datasets independently. `SPLIT DATASETS` can also be added to Domain inclusion/exclusion Scope criteria if the rule is applicable to unmerged split datasets. +The `include_split_datasets` flag (when set to `true`) allows split datasets to be processed separately from their parent datasets. This is useful when you need to analyze split datasets independently. `SPLIT DATASETS` and `AP SPLIT DATASETS` can also be added in Rule Domain inclusion/exclusion scope criteria if the rule is applicable to unmerged split datasets. ### 4. Use Case Selection @@ -105,8 +105,19 @@ According to the schema, the following classes are available: ### Domains The following domain options are available: - Standard domains like `DM`, `AE`, `LB`, etc. -- Special values like `ALL`, `AP--`, `APRELSUB`, `POOLDEF`, etc. -- Supplementary datasets using patterns like `SUPP--`, `SUPP[domain]` +- Special values like `ALL`, `APRELSUB`, `POOLDEF`, etc. +- The fixed property keywords: `SUPPQUAL`, `AP--`, `SPLIT DATASETS`, `AP SPLIT DATASETS` + +## Fixed Property Keywords +Unlike literal domain names (`AE`, `LB`, `APRELSUB`, etc.), the following keywords match against **derived dataset properties** rather than the dataset name itself. See [README.md](./README.md#dataset-metadata-submission-guide) for how each property is derived: for the full definitions these properties are based on. + +| Keyword | Matches when | Derived from | +|---|---|---| +| `SUPPQUAL` | Dataset name starts with `SUPP` or `SQ` | `is_supp` | +| `AP--` | Dataset is an Associated Persons domain | `is_ap` | +| `SPLIT DATASETS` | Dataset name differs from its unsplit/parent domain name | `is_split` | +| `AP SPLIT DATASETS` | Dataset is an AP domain **and** split **and not** a SUPP/SQ dataset | `is_ap AND is_split AND NOT is_supp` | + ### Data Structures Alternative to Classes/Domains, you can specify data structures: From 4abde5a1a2e7a552a622becbc72ecdd4a11e6b5d Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 16 Sep 2026 18:31:03 -0400 Subject: [PATCH 08/10] update --- Deprecated/CORE-000211/rule.yml | 2 +- Deprecated/CORE-000375/rule.yml | 2 +- Deprecated/CORE-000510/rule.yml | 2 +- Published/CORE-000134/rule.yml | 2 +- Published/CORE-000203/rule.yml | 2 +- Published/CORE-000206/rule.yml | 2 +- Published/CORE-000218/rule.yml | 2 +- Published/CORE-000221/rule.yml | 2 +- Published/CORE-000293/rule.yml | 2 +- Published/CORE-000302/rule.yml | 2 +- Published/CORE-000438/rule.yml | 2 +- Published/CORE-000457/rule.yml | 2 +- Published/CORE-000485/rule.yml | 2 +- Published/CORE-000490/rule.yml | 2 +- Published/CORE-000491/rule.yml | 2 +- Published/CORE-000492/rule.yml | 2 +- Published/CORE-000502/rule.yml | 2 +- Published/CORE-000503/rule.yml | 2 +- Published/CORE-000538/rule.yml | 2 +- Published/CORE-000539/rule.yml | 2 +- Published/CORE-000598/rule.yml | 2 +- Published/CORE-000712/rule.yml | 2 +- Published/CORE-000783/rule.yml | 2 +- Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml | 2 +- Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml | 10 ++++++++-- 25 files changed, 32 insertions(+), 26 deletions(-) diff --git a/Deprecated/CORE-000211/rule.yml b/Deprecated/CORE-000211/rule.yml index ec677c744..a580ad2ea 100644 --- a/Deprecated/CORE-000211/rule.yml +++ b/Deprecated/CORE-000211/rule.yml @@ -71,5 +71,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Sensitivity: Record diff --git a/Deprecated/CORE-000375/rule.yml b/Deprecated/CORE-000375/rule.yml index 674f770f8..d3a17ca7c 100644 --- a/Deprecated/CORE-000375/rule.yml +++ b/Deprecated/CORE-000375/rule.yml @@ -62,5 +62,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Sensitivity: Record diff --git a/Deprecated/CORE-000510/rule.yml b/Deprecated/CORE-000510/rule.yml index 2ddff12df..031c4a0de 100644 --- a/Deprecated/CORE-000510/rule.yml +++ b/Deprecated/CORE-000510/rule.yml @@ -93,7 +93,7 @@ Scope: Include: - SPLIT DATASETS Exclude: - - SUPP-- + - SUPPQUAL - AP-- include_split_datasets: true Sensitivity: Record diff --git a/Published/CORE-000134/rule.yml b/Published/CORE-000134/rule.yml index fdcc6a1b5..51defb82d 100644 --- a/Published/CORE-000134/rule.yml +++ b/Published/CORE-000134/rule.yml @@ -100,6 +100,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000203/rule.yml b/Published/CORE-000203/rule.yml index 74bdcbd44..0536c2590 100644 --- a/Published/CORE-000203/rule.yml +++ b/Published/CORE-000203/rule.yml @@ -107,6 +107,6 @@ Scope: - ALL Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000206/rule.yml b/Published/CORE-000206/rule.yml index 34044d82d..75ff7f154 100644 --- a/Published/CORE-000206/rule.yml +++ b/Published/CORE-000206/rule.yml @@ -253,7 +253,7 @@ Scope: Domains: Include: - CO - - SUPP-- + - SUPPQUAL - RELREC Use Case: NONCLIN, INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000218/rule.yml b/Published/CORE-000218/rule.yml index a9134fbdb..d72b53338 100644 --- a/Published/CORE-000218/rule.yml +++ b/Published/CORE-000218/rule.yml @@ -195,6 +195,6 @@ Scope: Domains: Include: - CO - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD, NONCLIN Sensitivity: Record diff --git a/Published/CORE-000221/rule.yml b/Published/CORE-000221/rule.yml index 7d1d43931..a70f56ac1 100644 --- a/Published/CORE-000221/rule.yml +++ b/Published/CORE-000221/rule.yml @@ -110,6 +110,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000293/rule.yml b/Published/CORE-000293/rule.yml index b17ec7918..3c9dfd921 100644 --- a/Published/CORE-000293/rule.yml +++ b/Published/CORE-000293/rule.yml @@ -94,6 +94,6 @@ Scope: - ALL Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Dataset diff --git a/Published/CORE-000302/rule.yml b/Published/CORE-000302/rule.yml index ef7dbb2f2..55ade8a8f 100644 --- a/Published/CORE-000302/rule.yml +++ b/Published/CORE-000302/rule.yml @@ -174,5 +174,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Sensitivity: Record diff --git a/Published/CORE-000438/rule.yml b/Published/CORE-000438/rule.yml index a0353ec7f..042ea42e0 100644 --- a/Published/CORE-000438/rule.yml +++ b/Published/CORE-000438/rule.yml @@ -117,6 +117,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000457/rule.yml b/Published/CORE-000457/rule.yml index d322007de..e91bb545c 100644 --- a/Published/CORE-000457/rule.yml +++ b/Published/CORE-000457/rule.yml @@ -98,6 +98,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Dataset diff --git a/Published/CORE-000485/rule.yml b/Published/CORE-000485/rule.yml index 35f3608bb..1d96dd0e7 100644 --- a/Published/CORE-000485/rule.yml +++ b/Published/CORE-000485/rule.yml @@ -131,6 +131,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000490/rule.yml b/Published/CORE-000490/rule.yml index ffc277d1f..ad7aacf10 100644 --- a/Published/CORE-000490/rule.yml +++ b/Published/CORE-000490/rule.yml @@ -158,6 +158,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000491/rule.yml b/Published/CORE-000491/rule.yml index 2736254df..5f873dfa6 100644 --- a/Published/CORE-000491/rule.yml +++ b/Published/CORE-000491/rule.yml @@ -115,5 +115,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Sensitivity: Record diff --git a/Published/CORE-000492/rule.yml b/Published/CORE-000492/rule.yml index ebc55f44f..117c2bd33 100644 --- a/Published/CORE-000492/rule.yml +++ b/Published/CORE-000492/rule.yml @@ -132,6 +132,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000502/rule.yml b/Published/CORE-000502/rule.yml index 212266c80..e2219ba45 100644 --- a/Published/CORE-000502/rule.yml +++ b/Published/CORE-000502/rule.yml @@ -108,6 +108,6 @@ Scope: Include: - CO - RELREC - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Dataset diff --git a/Published/CORE-000503/rule.yml b/Published/CORE-000503/rule.yml index 273cbb848..5b0e9b1c0 100644 --- a/Published/CORE-000503/rule.yml +++ b/Published/CORE-000503/rule.yml @@ -153,6 +153,6 @@ Scope: - ALL Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000538/rule.yml b/Published/CORE-000538/rule.yml index b97aae66c..c99847e89 100644 --- a/Published/CORE-000538/rule.yml +++ b/Published/CORE-000538/rule.yml @@ -99,6 +99,6 @@ Scope: - ALL Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000539/rule.yml b/Published/CORE-000539/rule.yml index 6f7766e49..801abb6b7 100644 --- a/Published/CORE-000539/rule.yml +++ b/Published/CORE-000539/rule.yml @@ -115,6 +115,6 @@ Scope: Exclude: - RELREC - RELSUB - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000598/rule.yml b/Published/CORE-000598/rule.yml index a3d304e50..738affbd2 100644 --- a/Published/CORE-000598/rule.yml +++ b/Published/CORE-000598/rule.yml @@ -190,7 +190,7 @@ Scope: - ALL Domains: Exclude: - - SUPP-- + - SUPPQUAL - RELREC - RELREF - POOLDEF diff --git a/Published/CORE-000712/rule.yml b/Published/CORE-000712/rule.yml index 5c6ec3bc1..253177876 100644 --- a/Published/CORE-000712/rule.yml +++ b/Published/CORE-000712/rule.yml @@ -128,6 +128,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000783/rule.yml b/Published/CORE-000783/rule.yml index 08b3b881c..3a9bdfe08 100644 --- a/Published/CORE-000783/rule.yml +++ b/Published/CORE-000783/rule.yml @@ -172,5 +172,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Sensitivity: Record diff --git a/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml b/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml index 1405d589d..abe8efd2d 100644 --- a/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml +++ b/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml @@ -136,5 +136,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPP-- + - SUPPQUAL Sensitivity: Dataset diff --git a/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml b/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml index 5cbc3dfc6..6612bef06 100644 --- a/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml +++ b/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml @@ -758,20 +758,26 @@ Scope: - ALL - AP-- - APRELSUB + - APRELSPEC - POOLDEF - RELREC - RELSPEC - RELSUB - - SUPP-- + - SUPPQUAL + - SPLIT DATASETS + - AP SPLIT DATASETS Include: - ALL - AP-- - APRELSUB + - APRELSPEC - POOLDEF - RELREC - RELSPEC - RELSUB - - SUPP-- + - SUPPQUAL + - SPLIT DATASETS + - AP SPLIT DATASETS include_split_datasets: true | false Subclasses: Exclude: From c4ade8fe1a8e0047102f73e980a62a3ed96d009f Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Thu, 8 Oct 2026 11:56:17 -0400 Subject: [PATCH 09/10] removed suppqual --- Deprecated/CORE-000211/rule.yml | 2 +- Deprecated/CORE-000375/rule.yml | 2 +- Deprecated/CORE-000510/rule.yml | 2 +- Deprecated/CORE-000778/rule.yml | 3 +-- Published/CORE-000134/rule.yml | 2 +- Published/CORE-000203/rule.yml | 2 +- Published/CORE-000206/rule.yml | 2 +- Published/CORE-000218/rule.yml | 2 +- Published/CORE-000221/rule.yml | 2 +- Published/CORE-000293/rule.yml | 2 +- Published/CORE-000302/rule.yml | 2 +- Published/CORE-000357/rule.yml | 2 +- Published/CORE-000438/rule.yml | 2 +- Published/CORE-000457/rule.yml | 2 +- Published/CORE-000485/rule.yml | 2 +- Published/CORE-000490/rule.yml | 2 +- Published/CORE-000491/rule.yml | 2 +- Published/CORE-000492/rule.yml | 2 +- Published/CORE-000502/rule.yml | 2 +- Published/CORE-000503/rule.yml | 2 +- Published/CORE-000538/rule.yml | 2 +- Published/CORE-000539/rule.yml | 2 +- Published/CORE-000551/rule.yml | 2 +- Published/CORE-000598/rule.yml | 2 +- Published/CORE-000712/rule.yml | 2 +- Published/CORE-000783/rule.yml | 2 +- Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml | 2 +- Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml | 6 ++++-- docs/scope.md | 4 ++-- 29 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Deprecated/CORE-000211/rule.yml b/Deprecated/CORE-000211/rule.yml index a580ad2ea..ec677c744 100644 --- a/Deprecated/CORE-000211/rule.yml +++ b/Deprecated/CORE-000211/rule.yml @@ -71,5 +71,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Sensitivity: Record diff --git a/Deprecated/CORE-000375/rule.yml b/Deprecated/CORE-000375/rule.yml index d3a17ca7c..674f770f8 100644 --- a/Deprecated/CORE-000375/rule.yml +++ b/Deprecated/CORE-000375/rule.yml @@ -62,5 +62,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Sensitivity: Record diff --git a/Deprecated/CORE-000510/rule.yml b/Deprecated/CORE-000510/rule.yml index 031c4a0de..2ddff12df 100644 --- a/Deprecated/CORE-000510/rule.yml +++ b/Deprecated/CORE-000510/rule.yml @@ -93,7 +93,7 @@ Scope: Include: - SPLIT DATASETS Exclude: - - SUPPQUAL + - SUPP-- - AP-- include_split_datasets: true Sensitivity: Record diff --git a/Deprecated/CORE-000778/rule.yml b/Deprecated/CORE-000778/rule.yml index dbeec1baa..8fb660d58 100644 --- a/Deprecated/CORE-000778/rule.yml +++ b/Deprecated/CORE-000778/rule.yml @@ -82,9 +82,8 @@ Scope: - ALL Domains: Include: - - AP SPLIT DATASETS + - SUPP-- Exclude: - - SUPPQUAL - APRELSUB - APRELSPEC include_split_datasets: true diff --git a/Published/CORE-000134/rule.yml b/Published/CORE-000134/rule.yml index 5bc8c635d..392df43fa 100644 --- a/Published/CORE-000134/rule.yml +++ b/Published/CORE-000134/rule.yml @@ -100,6 +100,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000203/rule.yml b/Published/CORE-000203/rule.yml index df61bed19..960fcc5d0 100644 --- a/Published/CORE-000203/rule.yml +++ b/Published/CORE-000203/rule.yml @@ -108,6 +108,6 @@ Scope: - ALL Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000206/rule.yml b/Published/CORE-000206/rule.yml index 076a501e1..26e08d733 100644 --- a/Published/CORE-000206/rule.yml +++ b/Published/CORE-000206/rule.yml @@ -247,7 +247,7 @@ Scope: Domains: Include: - CO - - SUPPQUAL + - SUPP-- - RELREC Use Case: NONCLIN, INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000218/rule.yml b/Published/CORE-000218/rule.yml index 62673caea..8e1d08d23 100644 --- a/Published/CORE-000218/rule.yml +++ b/Published/CORE-000218/rule.yml @@ -195,6 +195,6 @@ Scope: Domains: Include: - CO - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD, NONCLIN Sensitivity: Record diff --git a/Published/CORE-000221/rule.yml b/Published/CORE-000221/rule.yml index 4835a4518..0bb04fc00 100644 --- a/Published/CORE-000221/rule.yml +++ b/Published/CORE-000221/rule.yml @@ -110,6 +110,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000293/rule.yml b/Published/CORE-000293/rule.yml index 5b95269a3..db8ec2b64 100644 --- a/Published/CORE-000293/rule.yml +++ b/Published/CORE-000293/rule.yml @@ -94,6 +94,6 @@ Scope: - ALL Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Dataset diff --git a/Published/CORE-000302/rule.yml b/Published/CORE-000302/rule.yml index 02408a047..1a92a6aaf 100644 --- a/Published/CORE-000302/rule.yml +++ b/Published/CORE-000302/rule.yml @@ -174,5 +174,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Sensitivity: Record diff --git a/Published/CORE-000357/rule.yml b/Published/CORE-000357/rule.yml index 7d3a18270..0e637e91b 100644 --- a/Published/CORE-000357/rule.yml +++ b/Published/CORE-000357/rule.yml @@ -92,7 +92,7 @@ Scope: - ALL Domains: Include: - - SUPPQUAL + - SUPP-- include_split_datasets: true Use Case: INDH, PROD Sensitivity: Dataset diff --git a/Published/CORE-000438/rule.yml b/Published/CORE-000438/rule.yml index 042ea42e0..a0353ec7f 100644 --- a/Published/CORE-000438/rule.yml +++ b/Published/CORE-000438/rule.yml @@ -117,6 +117,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000457/rule.yml b/Published/CORE-000457/rule.yml index 19ab28f23..da2897fc9 100644 --- a/Published/CORE-000457/rule.yml +++ b/Published/CORE-000457/rule.yml @@ -102,6 +102,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Dataset diff --git a/Published/CORE-000485/rule.yml b/Published/CORE-000485/rule.yml index 1d96dd0e7..35f3608bb 100644 --- a/Published/CORE-000485/rule.yml +++ b/Published/CORE-000485/rule.yml @@ -131,6 +131,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000490/rule.yml b/Published/CORE-000490/rule.yml index ad7aacf10..ffc277d1f 100644 --- a/Published/CORE-000490/rule.yml +++ b/Published/CORE-000490/rule.yml @@ -158,6 +158,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000491/rule.yml b/Published/CORE-000491/rule.yml index 5f873dfa6..2736254df 100644 --- a/Published/CORE-000491/rule.yml +++ b/Published/CORE-000491/rule.yml @@ -115,5 +115,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Sensitivity: Record diff --git a/Published/CORE-000492/rule.yml b/Published/CORE-000492/rule.yml index 117c2bd33..ebc55f44f 100644 --- a/Published/CORE-000492/rule.yml +++ b/Published/CORE-000492/rule.yml @@ -132,6 +132,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000502/rule.yml b/Published/CORE-000502/rule.yml index fe0f4cd36..f9cacfdf0 100644 --- a/Published/CORE-000502/rule.yml +++ b/Published/CORE-000502/rule.yml @@ -108,6 +108,6 @@ Scope: Include: - CO - RELREC - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Dataset diff --git a/Published/CORE-000503/rule.yml b/Published/CORE-000503/rule.yml index 5b0e9b1c0..273cbb848 100644 --- a/Published/CORE-000503/rule.yml +++ b/Published/CORE-000503/rule.yml @@ -153,6 +153,6 @@ Scope: - ALL Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000538/rule.yml b/Published/CORE-000538/rule.yml index c99847e89..b97aae66c 100644 --- a/Published/CORE-000538/rule.yml +++ b/Published/CORE-000538/rule.yml @@ -99,6 +99,6 @@ Scope: - ALL Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000539/rule.yml b/Published/CORE-000539/rule.yml index 801abb6b7..6f7766e49 100644 --- a/Published/CORE-000539/rule.yml +++ b/Published/CORE-000539/rule.yml @@ -115,6 +115,6 @@ Scope: Exclude: - RELREC - RELSUB - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000551/rule.yml b/Published/CORE-000551/rule.yml index 4decfff57..6dac6f880 100644 --- a/Published/CORE-000551/rule.yml +++ b/Published/CORE-000551/rule.yml @@ -161,6 +161,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: NONCLIN Sensitivity: Record diff --git a/Published/CORE-000598/rule.yml b/Published/CORE-000598/rule.yml index 738affbd2..a3d304e50 100644 --- a/Published/CORE-000598/rule.yml +++ b/Published/CORE-000598/rule.yml @@ -190,7 +190,7 @@ Scope: - ALL Domains: Exclude: - - SUPPQUAL + - SUPP-- - RELREC - RELREF - POOLDEF diff --git a/Published/CORE-000712/rule.yml b/Published/CORE-000712/rule.yml index 253177876..5c6ec3bc1 100644 --- a/Published/CORE-000712/rule.yml +++ b/Published/CORE-000712/rule.yml @@ -128,6 +128,6 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Use Case: INDH, PROD Sensitivity: Record diff --git a/Published/CORE-000783/rule.yml b/Published/CORE-000783/rule.yml index 1fba94816..8e8603be6 100644 --- a/Published/CORE-000783/rule.yml +++ b/Published/CORE-000783/rule.yml @@ -173,5 +173,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Sensitivity: Record diff --git a/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml b/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml index abe8efd2d..1405d589d 100644 --- a/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml +++ b/Unpublished/SENDIG/CDISC.SENDIG.299B/rule.yml @@ -136,5 +136,5 @@ Scope: - RELATIONSHIP Domains: Include: - - SUPPQUAL + - SUPP-- Sensitivity: Dataset diff --git a/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml b/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml index 6612bef06..d80e1b9f9 100644 --- a/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml +++ b/Unpublished/SENDIG/SEND_AUTHORING_TEMPLATE/rule.yml @@ -763,7 +763,8 @@ Scope: - RELREC - RELSPEC - RELSUB - - SUPPQUAL + - SUPP-- + - SQ-- - SPLIT DATASETS - AP SPLIT DATASETS Include: @@ -775,7 +776,8 @@ Scope: - RELREC - RELSPEC - RELSUB - - SUPPQUAL + - SUPP-- + - SQ-- - SPLIT DATASETS - AP SPLIT DATASETS include_split_datasets: true | false diff --git a/docs/scope.md b/docs/scope.md index 4102babe6..ad2643de3 100644 --- a/docs/scope.md +++ b/docs/scope.md @@ -106,14 +106,14 @@ According to the schema, the following classes are available: The following domain options are available: - Standard domains like `DM`, `AE`, `LB`, etc. - Special values like `ALL`, `APRELSUB`, `POOLDEF`, etc. -- The fixed property keywords: `SUPPQUAL`, `AP--`, `SPLIT DATASETS`, `AP SPLIT DATASETS` +- The fixed property keywords: `SUPP--`, `SQ--`, `AP--`, `SPLIT DATASETS`, `AP SPLIT DATASETS` ## Fixed Property Keywords Unlike literal domain names (`AE`, `LB`, `APRELSUB`, etc.), the following keywords match against **derived dataset properties** rather than the dataset name itself. See [README.md](./README.md#dataset-metadata-submission-guide) for how each property is derived: for the full definitions these properties are based on. | Keyword | Matches when | Derived from | |---|---|---| -| `SUPPQUAL` | Dataset name starts with `SUPP` or `SQ` | `is_supp` | +| `SUPP--` or `SQ--` | Dataset name starts with `SUPP` or `SQ` (interchangeable) | `is_supp` | | `AP--` | Dataset is an Associated Persons domain | `is_ap` | | `SPLIT DATASETS` | Dataset name differs from its unsplit/parent domain name | `is_split` | | `AP SPLIT DATASETS` | Dataset is an AP domain **and** split **and not** a SUPP/SQ dataset | `is_ap AND is_split AND NOT is_supp` | From 25c6452874c39d256250be90e6a7db7de5655d00 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Thu, 8 Oct 2026 11:58:36 -0400 Subject: [PATCH 10/10] update --- Deprecated/CORE-000778/rule.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Deprecated/CORE-000778/rule.yml b/Deprecated/CORE-000778/rule.yml index 8fb660d58..ff6ed9420 100644 --- a/Deprecated/CORE-000778/rule.yml +++ b/Deprecated/CORE-000778/rule.yml @@ -82,8 +82,9 @@ Scope: - ALL Domains: Include: - - SUPP-- + - AP SPLIT DATASETS Exclude: + - SUPP-- - APRELSUB - APRELSPEC include_split_datasets: true