Skip to content

feat: implement data contract 1.6 — project-scoped programme and hone… #18

feat: implement data contract 1.6 — project-scoped programme and hone…

feat: implement data contract 1.6 — project-scoped programme and hone… #18

Workflow file for this run

name: CI
on:
# Feature branches too, not only main. The branch prefixes are the ones
# AGENTS.md already prescribes. Running the pipeline solely on main would
# mean a cross-platform determinism failure is discovered at merge time, by
# which point the work is finished and the diagnosis is expensive — which is
# the same shape of mistake as never running the pipeline in CI at all.
push:
branches:
- main
- "feat/**"
- "fix/**"
- "docs/**"
- "chore/**"
pull_request:
branches: [main]
permissions:
contents: read
jobs:
validate:
# Both platforms, because the determinism this project claims is a
# cross-platform claim and has never been tested as one. `dc351c9` fixed CSV
# line endings that differed by platform and was never regressed on Windows;
# the published run_id turned out to be reproducible only under a CRLF
# checkout. A single-OS pipeline found neither.
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"
cache: pip
cache-dependency-path: |
requirements.txt
requirements-dev.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt -r requirements-dev.txt
# An IDS document is currently read only by the library that wrote it,
# which proves the two agree and nothing else. `ids-tool` is a separate
# buildingSMART implementation, in another language, and it reads the
# document against the schema and the standard's content rules. The
# conformance corpus showed what that catches: three of the five cases
# where this project disagrees with the standard are documents whose value
# literal contradicts its declared data type, and IfcTester executes them
# and reports a pass. `ids-tool` rejects all three.
#
# Called as an external process at a pinned version. No code is copied.
# The tool targets net8.0, so the SDK is pinned to match rather than
# relying on roll-forward.
- name: Set up .NET for the IDS audit tool
uses: actions/setup-dotnet@v6
with:
dotnet-version: "8.0.x"
- name: Install the IDS audit tool
run: dotnet tool install --global ids-tool.CommandLine --version 1.0.124
# Checked before anything runs, because every comparison below depends on
# it. Under data contract 0.1 the published run_id is a SHA-256 over the
# IDS document's raw bytes; without this pin the file checks out with
# platform line endings, so a Linux runner computes a different run_id and
# silently re-keys all forty-seven findings.
- name: Verify the IDS byte pin survives checkout
run: |
if ! grep -qF 'ids/*.ids -text' .gitattributes; then
echo "::error::.gitattributes has lost 'ids/*.ids -text'."
echo "The published run_id is not reproducible across platforms without it."
exit 1
fi
- name: Lint
run: python -m ruff check .
# EPC_REQUIRE_IDS_AUDIT turns the IDS audit from a test that skips when
# its tool is absent into one that fails. Locally, skipping is right —
# not every contributor has a .NET SDK. Here the tool was just installed,
# so a skip would mean the install silently failed and the gate had
# quietly stopped running, which is the failure mode a gate must not have.
- name: Run regression suite
env:
EPC_REQUIRE_IDS_AUDIT: "1"
run: python -m pytest -p no:cacheprovider tests -q
# The pipeline had never been run by continuous integration at all. Every
# artifact in this repository was produced by hand on one machine, which is
# how a wall-clock timestamp and a set iteration order stayed inside
# published reports for an entire release without anybody noticing.
- name: Regenerate every published artifact
run: python -m epc_control_tower.cli run
- name: Fail if anything the pipeline produces has changed
run: git diff --exit-code
- name: Fail if the pipeline produced anything untracked
run: |
untracked="$(git status --porcelain --untracked-files=all)"
if [ -n "$untracked" ]; then
echo "::error::The pipeline left the working tree dirty."
echo "$untracked"
exit 1
fi
# Byte equality against the recorded contract snapshot. Moving it requires
# a CHANGELOG entry and an explicit acknowledgement; see
# `epc-ct snapshot --help`.
- name: Check the published contract against its snapshot
run: python -m epc_control_tower.cli snapshot
- name: Validate dashboard core contract
run: python src/validate_dashboard.py --mode core
- name: Validate tracked Power BI project
run: python src/validate_pbip.py
- name: Check dependency consistency
run: python -m pip check