Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions .github/scripts/filter_core_ids_by_standard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""Filter Published CORE rule IDs by Authorities.Standards.Name."""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

import yaml


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Return space-separated CORE IDs for Published rules matching standards."
)
parser.add_argument(
"--rules-root",
required=True,
help="Repository root containing Published/",
)
parser.add_argument(
"--standards",
nargs="+",
required=True,
help="Standards to match from Authorities[].Standards[].Name",
)
parser.add_argument(
"--core-ids",
default="",
help="Optional space-separated CORE IDs to intersect with the standard filter.",
)
return parser.parse_args()


def iter_published_rule_files(rules_root: Path) -> list[Path]:
published_dir = rules_root / "Published"
files: list[Path] = []
for pattern in ("**/rule.yml", "**/rule.yaml"):
files.extend(published_dir.glob(pattern))
return sorted(set(files))


def rule_matches_standard(rule: dict, target_standards: set[str]) -> bool:
for authority in rule.get("Authorities") or []:
if not isinstance(authority, dict):
continue
for standard in authority.get("Standards") or []:
if not isinstance(standard, dict):
continue
standard_name = str(standard.get("Name") or "").strip().upper()
if standard_name in target_standards:
return True
return False


def collect_filtered_core_ids(rules_root: Path, standards: list[str]) -> list[str]:
target_standards = {name.strip().upper() for name in standards if name.strip()}
core_ids: list[str] = []

for rule_file in iter_published_rule_files(rules_root):
with rule_file.open("r", encoding="utf-8") as handle:
rule = yaml.safe_load(handle) or {}
if not isinstance(rule, dict):
continue
if not rule_matches_standard(rule, target_standards):
continue

core = rule.get("Core") or {}
if not isinstance(core, dict):
continue
core_id = str(core.get("Id") or "").strip()
if core_id:
core_ids.append(core_id)
return core_ids


def intersect_with_requested(core_ids: list[str], requested_core_ids: str) -> list[str]:
requested = requested_core_ids.split()
if not requested:
return core_ids

allowed = set(core_ids)
return [core_id for core_id in requested if core_id in allowed]


def main() -> int:
args = parse_args()
rules_root = Path(args.rules_root)
if not rules_root.is_dir():
print(f"rules-root does not exist: {rules_root}", file=sys.stderr)
return 1

filtered_core_ids = collect_filtered_core_ids(rules_root, args.standards)
output_core_ids = intersect_with_requested(filtered_core_ids, args.core_ids)
print(" ".join(filtered_core_ids))
print(" ".join(output_core_ids))
return 0


if __name__ == "__main__":
raise SystemExit(main())
28 changes: 23 additions & 5 deletions .github/workflows/update-published-results.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,38 @@ jobs:
run: venv/bin/pip install tabulate jmespath pyyaml ruamel.yaml

# -----------------------------------------------------------------------
# 4. Run the engine for every Published rule, writing actual results.csv
# directly into each case's results/ directory (overwriting the old baseline)
# 4. Run the engine for Published rules filtered by Authorities.Standards.Name,
# writing actual results.csv directly into each case's results/ directory
# (overwriting the old baseline)
# -----------------------------------------------------------------------
- name: Run engine and write results
id: run_engine
continue-on-error: true
run: |
chmod +x .github/scripts/run_validation.sh
FILTER_STANDARDS=("USDM" "TIG")
mapfile -t FILTER_RESULT < <(venv/bin/python .github/scripts/filter_core_ids_by_standard.py \
--rules-root "$(pwd)" \
--standards "${FILTER_STANDARDS[@]}" \
--core-ids "${{ inputs.core_ids }}")
FILTERED_CORE_IDS="${FILTER_RESULT[0]}"
CORE_IDS_TO_RUN="${FILTER_RESULT[1]}"

if [ -z "$FILTERED_CORE_IDS" ]; then
echo "No Published rules found for standards: ${FILTER_STANDARDS[*]}"
exit 0
fi

CORE_IDS_ARG=""
if [ -n "${{ inputs.core_ids }}" ]; then
CORE_IDS_ARG="--core-ids ${{ inputs.core_ids }}"
if [ -z "$CORE_IDS_TO_RUN" ]; then
echo "No requested core_ids matched Published rules for standards: ${FILTER_STANDARDS[*]}"
exit 0
fi

echo "Running validation for standards: ${FILTER_STANDARDS[*]}"
echo "Rule count: $(echo "$CORE_IDS_TO_RUN" | wc -w | tr -d ' ')"

CORE_IDS_ARG="--core-ids $CORE_IDS_TO_RUN"

ENGINE_DIR_OVERRIDE="$(pwd)/engine" \
venv/bin/python engine/scripts/validate_published_rules.py \
--rules-root "$(pwd)" \
Expand Down
4 changes: 4 additions & 0 deletions Published/CORE-000206/negative/02/results/results.csv
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ RELREC,2,IDVAR,NONSENSE
RELREC,2,IDVARVAL,299
RELREC,2,RDOMAIN,LB
RELREC,2,USUBJID,S001
SUPPLB,1,IDVAR,LBSEQ
SUPPLB,1,IDVARVAL,320
SUPPLB,1,RDOMAIN,LB
SUPPLB,1,USUBJID,S001