truth-pass: Annex III process genus, regulatory-basis provenance, pin… #145
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ROBOT Validation | |
| # Independent DL validation using ROBOT (v1.9.10) and HermiT. | |
| # Runs alongside the production owlrl pipeline as a cross-check, not a replacement. | |
| # | |
| # Two-job structure: | |
| # | |
| # Job 1: ontology-validate (single, ~5-10 min) | |
| # Phase 0: confirm ROBOT installs and runs in CI. | |
| # Phase 1: merge ARCO ontology files and run robot validate-profile --profile DL. | |
| # Confirms the ontology is OWL 2 DL conformant. | |
| # Gates CI: profile violations fail the build. | |
| # Phase 2: run robot reason --reasoner HermiT for consistency check. | |
| # Gates CI: HermiT crash or DL inconsistency fails the build. | |
| # | |
| # Job 2: hermit-cross-check (matrix, runs in parallel; needs: ontology-validate) | |
| # Phase 3: per-fixture HermiT vs OWL-RL classification agreement. | |
| # Each certificate-grade fixture runs as its own parallel matrix job. | |
| # Gates CI: any classification mismatch on any fixture fails the build. | |
| # | |
| # Why two jobs with `needs:` instead of one big serial job: | |
| # - Phase 3 only makes sense if the ontology is already DL-conformant + consistent | |
| # (Phases 1+2). Sequential dependency preserves that ordering. | |
| # - Within Phase 3, the six fixtures are independent. Running them in parallel | |
| # (matrix) drops Phase 3 wall time from ~35-45 min sequential to ~7-10 min. | |
| # - Total wall time: ~10 min (Phases 1+2) + ~10 min (matrix) = ~20 min, | |
| # instead of the prior ~50 min serial-with-timeout-bump design. | |
| # | |
| # GhostSystem (ARCO_instances_adversarial_blanknode.ttl) is excluded from the | |
| # cross-check matrix. Its disposition is an anonymous individual; HermiT does | |
| # not emit ClassAssertion axioms for blank-node individuals (DL profile | |
| # behavior, not a defect). The audit-side detect_latent_risk traversal returns | |
| # False under HermiT and True under OWL-RL on GhostSystem only. GhostSystem is | |
| # a reasoner-property probe, not production modeling guidance. | |
| # Documented in LIMITATIONS.md §7.4. | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| env: | |
| ROBOT_VERSION: v1.9.10 | |
| ROBOT_JAR_URL: https://github.com/ontodev/robot/releases/download/v1.9.10/robot.jar | |
| jobs: | |
| ontology-validate: | |
| name: DL profile + HermiT consistency | |
| runs-on: ubuntu-latest | |
| # 30 min: realistic per-job is ~10-15 min (ROBOT setup + Java + merge + | |
| # validate-profile + HermiT consistency on the merged ontology). 30 gives | |
| # comfortable headroom for slow runners without masking a hung job. | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Cache ROBOT JAR | |
| id: cache-robot | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.local/share/robot/robot.jar | |
| key: robot-${{ env.ROBOT_VERSION }} | |
| - name: Download ROBOT | |
| if: steps.cache-robot.outputs.cache-hit != 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p ~/.local/share/robot | |
| curl -L -o ~/.local/share/robot/robot.jar "$ROBOT_JAR_URL" | |
| - name: Verify ROBOT version | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| java -jar ~/.local/share/robot/robot.jar --version | |
| echo "ROBOT smoke test PASSED." | |
| # Phase 1: OWL 2 DL profile validation. | |
| # Merges the same files the Python pipeline loads, then runs validate-profile. | |
| # Uses Sentinel as the instance fixture for this validation; per-fixture | |
| # cross-checking moves to Job 2 (matrix). | |
| - name: Merge ARCO ontology files | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ROBOT="java -jar $HOME/.local/share/robot/robot.jar" | |
| $ROBOT merge \ | |
| --input "03_TECHNICAL_CORE/ontology/imports/bfo-2020.owl" \ | |
| --input "03_TECHNICAL_CORE/ontology/imports/iao_bot.owl" \ | |
| --input "03_TECHNICAL_CORE/ontology/imports/ro_bot.owl" \ | |
| --input "03_TECHNICAL_CORE/ontology/imports/cco_bot.owl" \ | |
| --input "03_TECHNICAL_CORE/ontology/ARCO_core.ttl" \ | |
| --input "03_TECHNICAL_CORE/ontology/ARCO_governance_extension.ttl" \ | |
| --input "03_TECHNICAL_CORE/ontology/ARCO_instances_sentinel.ttl" \ | |
| --output /tmp/arco_merged.owl | |
| echo "Merge complete: /tmp/arco_merged.owl" | |
| - name: Validate OWL 2 DL profile | |
| shell: bash | |
| run: | | |
| ROBOT="java -jar $HOME/.local/share/robot/robot.jar" | |
| mkdir -p /tmp/robot-reports | |
| set +e | |
| $ROBOT validate-profile \ | |
| --profile DL \ | |
| --input /tmp/arco_merged.owl \ | |
| --output /tmp/robot-reports/dl_profile_report.txt \ | |
| 2>&1 | |
| PROFILE_EXIT=$? | |
| set -e | |
| echo "=== OWL 2 DL Profile Report ===" | |
| cat /tmp/robot-reports/dl_profile_report.txt || echo "(no report file generated)" | |
| echo "=== Profile validation exit code: ${PROFILE_EXIT} ===" | |
| if [ "${PROFILE_EXIT}" -eq 0 ]; then | |
| echo "RESULT: ARCO is OWL 2 DL conformant." | |
| else | |
| echo "FAIL: ARCO has OWL 2 DL profile violations. See report above." | |
| exit 1 | |
| fi | |
| - name: Upload profile report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: owl2-dl-profile-report | |
| path: /tmp/robot-reports/ | |
| if-no-files-found: warn | |
| # Phase 2: HermiT consistency check. | |
| # Confirms ontology is DL-consistent and HermiT terminates without error. | |
| # Reasoned graph uploaded as artifact. | |
| - name: Reason with HermiT (consistency) | |
| shell: bash | |
| run: | | |
| ROBOT="java -jar $HOME/.local/share/robot/robot.jar" | |
| mkdir -p /tmp/robot-reports | |
| set +e | |
| $ROBOT reason \ | |
| --reasoner hermit \ | |
| --axiom-generators "ClassAssertion SubClass" \ | |
| --include-indirect true \ | |
| --input /tmp/arco_merged.owl \ | |
| --output /tmp/robot-reports/arco_reasoned.owl \ | |
| 2>&1 | tee /tmp/robot-reports/hermit_log.txt | |
| REASON_EXIT=${PIPESTATUS[0]} | |
| set -e | |
| echo "=== HermiT reasoning exit code: ${REASON_EXIT} ===" | |
| if [ "${REASON_EXIT}" -eq 0 ]; then | |
| echo "RESULT: ARCO is consistent under HermiT. Reasoned graph produced." | |
| ls -la /tmp/robot-reports/arco_reasoned.owl | |
| else | |
| echo "FAIL: HermiT reported a problem. See log above." | |
| exit 1 | |
| fi | |
| - name: Upload HermiT reasoned graph | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: hermit-reasoned-graph | |
| path: | | |
| /tmp/robot-reports/arco_reasoned.owl | |
| /tmp/robot-reports/hermit_log.txt | |
| if-no-files-found: warn | |
| hermit-cross-check: | |
| name: HermiT vs OWL-RL (${{ matrix.fixture }}) | |
| runs-on: ubuntu-latest | |
| # 45 min: realistic per-job is ~10-15 min (one fixture's HermiT pass plus | |
| # setup). 45 gives 3x headroom on a slow runner so we are not chasing | |
| # timeouts on what is supposed to be the fast parallel design. Real fix | |
| # if a single matrix job ever hits 45 min is profiling that fixture, not | |
| # bumping further. | |
| timeout-minutes: 45 | |
| needs: ontology-validate | |
| strategy: | |
| # All fixtures still report even if one fails: better diagnostic signal | |
| # than fail-fast, since a real DL/RL disagreement on any fixture is its | |
| # own information. | |
| fail-fast: false | |
| matrix: | |
| fixture: | |
| - ARCO_instances_sentinel.ttl | |
| - ARCO_instances_creditscoring.ttl | |
| - ARCO_instances_verification.ttl | |
| - ARCO_instances_adversarial_decoy.ttl | |
| - ARCO_instances_adversarial_decoy_5b.ttl | |
| - ARCO_instances_flag_tests.ttl | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Cache ROBOT JAR | |
| id: cache-robot | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.local/share/robot/robot.jar | |
| key: robot-${{ env.ROBOT_VERSION }} | |
| - name: Download ROBOT | |
| if: steps.cache-robot.outputs.cache-hit != 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p ~/.local/share/robot | |
| curl -L -o ~/.local/share/robot/robot.jar "$ROBOT_JAR_URL" | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install Python deps | |
| shell: bash | |
| run: | | |
| python -m pip install --quiet rdflib owlrl==7.1.4 | |
| # Phase 3: HermiT vs OWL-RL agreement on ONE fixture (this matrix slot). | |
| # Uses --fixture argument to select; sequential six-fixture sweep stays | |
| # available (no --fixture argument) for local CLI use. | |
| - name: HermiT vs OWL-RL agreement (${{ matrix.fixture }}) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| export ROBOT_JAR="$HOME/.local/share/robot/robot.jar" | |
| python 03_TECHNICAL_CORE/scripts/hermit_cross_check.py \ | |
| --fixture "${{ matrix.fixture }}" |