Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
24bd5bc
.gitignore up to date
yohannmarguier Jun 30, 2026
e7d8174
Fix : updates tests to add the datapath
yohannmarguier Jul 7, 2026
3ab1010
Add Task-2 contract test suite scaffold (GoogleTest + CTest)
yohannmarguier Jul 7, 2026
3b63677
Merge branch 'iterorganization:develop' into develop
yohannmarguier Jul 7, 2026
7fa83c3
Add Task-2 introspection + version-sentinel contract tests (issue #5)
yohannmarguier Jul 7, 2026
33fedc6
Merge branch 'develop' of github.com:yohannmarguier/IMAS-Core into de…
yohannmarguier Jul 7, 2026
edbdee0
Add synthetic write→read round-trip matrix (issue #3)
yohannmarguier Jul 8, 2026
fcc1e24
Add Task-2 capability-gated op tests (issue #6)
yohannmarguier Jul 8, 2026
1e43819
Update TRACEABILITY.md
yohannmarguier Jul 8, 2026
e48e222
Update test_capability_gated.cpp
yohannmarguier Jul 8, 2026
1e80dd6
fix : add current-behavior tripwires for all rot-prone xfails
yohannmarguier Jul 8, 2026
e5ce77c
split unit/integration CTest labels + add sanitizer CI leg
yohannmarguier Jul 8, 2026
306df1c
Assert getDDVersion() invariance (not the literal) in the version sen…
yohannmarguier Jul 8, 2026
1cbc103
Add plugin-lifecycle + crash-class defect tests (issue #7)
yohannmarguier Jul 8, 2026
9a015bb
Add structured-data contract tests: AOS, delete, occurrences, lifecyc…
yohannmarguier Jul 8, 2026
2658dda
Merge pull request #10 from yohannmarguier/test/issue-4-structured-data
yohannmarguier Jul 9, 2026
3ae109d
Update TRACEABILITY.md
yohannmarguier Jul 9, 2026
4b681bf
Merge branch 'develop' into test/issue-7-plugin-lifecycle
yohannmarguier Jul 9, 2026
4333a24
Merge pull request #11 from yohannmarguier/test/issue-7-plugin-lifecycle
yohannmarguier Jul 9, 2026
d115cd1
Update .gitignore
yohannmarguier Jul 9, 2026
10cdaf2
Close the ownership sweep + comprehensive-coverage exit criterion (is…
yohannmarguier Jul 9, 2026
dcd80a3
Merge pull request #19 from yohannmarguier/test/issue-8-ownership-sweep
yohannmarguier Jul 9, 2026
8ffae4e
Update .gitignore
yohannmarguier Jul 9, 2026
165c317
Merge branch 'develop' of github.com:yohannmarguier/IMAS-Core into de…
yohannmarguier Jul 9, 2026
c2c21db
final review updates
yohannmarguier Jul 10, 2026
86e7f38
update : D2 is now consistent, doc-to-code
yohannmarguier Jul 10, 2026
353e4ca
Add MDSplus tracer-bullet contract test (issue #13)
yohannmarguier Jul 10, 2026
ce74eba
Join MDSplus to the parametrized contract fixtures (issue #14)
yohannmarguier Jul 10, 2026
2c206a8
Address code review: join MDSplus to EquilibriumSeedMatrix, dedupe sk…
yohannmarguier Jul 10, 2026
09a4d61
Add MDSplus real-DD-path datatype x rank breadth matrix (issue #15)
yohannmarguier Jul 10, 2026
43d6849
Pin the MDSplus version-drift check as its own test (issue #16)
yohannmarguier Jul 10, 2026
f903fbf
Fix AOS-descent lifecycle safety in MdsplusRealPathMatrix (issue #15 …
yohannmarguier Jul 10, 2026
d4c5e89
Add MDSplus-unique surface test file (issue #17)
yohannmarguier Jul 10, 2026
21bc634
Close TRACEABILITY.md Part 4 and add non-blocking mdsplus-contract CI…
yohannmarguier Jul 10, 2026
6a2ad48
Merge branch 'develop' into test/mdsplus
yohannmarguier Jul 15, 2026
09992fc
Merge pull request #22 from yohannmarguier/test/mdsplus
yohannmarguier Jul 15, 2026
82e03aa
Add UDA reference-stack Docker spike + C-ABI smoke round trip (issue …
yohannmarguier Jul 15, 2026
7e0ee7c
Add ./test dispatcher + make targets for the backend contract tiers
yohannmarguier Jul 15, 2026
edb1938
Add UDA read-only parity fixture over the equilibrium seed (issue #24)
yohannmarguier Jul 15, 2026
2314b2a
Add UDA parity breadth: real-path matrix, AOS/occurrences/list_filled…
yohannmarguier Jul 15, 2026
b4282ff
Fix cell count in TRACEABILITY.md Part 5 (32, not 34)
yohannmarguier Jul 15, 2026
ef1e973
Add UDA unique-surface: cache modes, DD loading, datapath, capability…
yohannmarguier Jul 15, 2026
623cf17
Add UDA unique-surface: fetch mode, local_cache, write-divergence pin…
yohannmarguier Jul 15, 2026
c00552d
Close TRACEABILITY Part 5: cross-reference notes + closure summary (i…
yohannmarguier Jul 16, 2026
d73f134
Add non-blocking uda-contract CI leg (issue #29)
yohannmarguier Jul 16, 2026
2612c1d
Characterize UDA pulse lifecycle modes
yohannmarguier Jul 16, 2026
e4911ec
Pin the UDA-Plugins source commit
yohannmarguier Jul 16, 2026
5165a13
Pin exact UDA complex AOS defects
yohannmarguier Jul 16, 2026
8d8a284
Correct UDA traceability closure counts
yohannmarguier Jul 16, 2026
7f5e5f9
Update AGENTS.md
yohannmarguier Jul 16, 2026
6a9b8e4
Skip UDA contracts when the server is unreachable
yohannmarguier Jul 16, 2026
09bb450
Read every reported UDA occurrence
yohannmarguier Jul 16, 2026
cf123d6
Pin UDA characterization defects accurately
yohannmarguier Jul 16, 2026
f6bc181
Centralize UDA test addressing and assert cleanup
yohannmarguier Jul 16, 2026
eace872
Merge pull request #30 from yohannmarguier/test/uda
yohannmarguier Jul 16, 2026
b19bd27
Fix backend Note steps truncated by YAML comments and add workflow lint
yohannmarguier Jul 16, 2026
54db010
Build the MDSplus DD model before running contract_tests
yohannmarguier Jul 16, 2026
297a946
Fail the dedicated UDA tier when the reference server does not start
yohannmarguier Jul 16, 2026
7ba5c54
Prevent cold-matrix vcpkg download stampedes on Windows wheels
yohannmarguier Jul 16, 2026
7274728
Replace iterator argvalues before pytest 10
yohannmarguier Jul 16, 2026
c6c4d38
Restore unit/integration CTest labels on supported CMake versions
yohannmarguier Jul 16, 2026
21c5570
Cover unknown backend IDs at the C-ABI factory boundary
yohannmarguier Jul 16, 2026
240330d
Make the dlopen-failure pin safe in assert-enabled builds
yohannmarguier Jul 16, 2026
29e5136
Back off and retry the Windows dependency-prep install on upstream 429s
yohannmarguier Jul 16, 2026
8322cfe
Parse CTest's real JUnit shape in the dedicated UDA check
yohannmarguier Jul 16, 2026
5dbc566
Add a stored-backend-version drift fixture for HDF5
yohannmarguier Jul 16, 2026
b26d7e0
Make the UDA version-drift tripwire use a mismatched stored fixture
yohannmarguier Jul 16, 2026
26c8f9a
Accept the legitimately empty ids_model.datafile in the model verify …
yohannmarguier Jul 16, 2026
c90b8e3
Keep the MDSplus version-drift contract test on the public C ABI
yohannmarguier Jul 16, 2026
8506879
Share the MDSplus/UDA real-DD path catalog (#46)
yohannmarguier Jul 16, 2026
cd20a87
Make UDA AOS traversal detect cursor no-ops
yohannmarguier Jul 16, 2026
a39e680
Document UDA cache invalidation terminal gap
yohannmarguier Jul 16, 2026
92f8466
Strengthen UDA timerange capability assertion
yohannmarguier Jul 16, 2026
cfa8896
Characterize MDSplus real-path delete semantics (#34)
yohannmarguier Jul 17, 2026
23204bc
Make the equilibrium seed DD-valid and hash structural metadata (#33)
yohannmarguier Jul 17, 2026
73c71f3
Merge pull request #49 from yohannmarguier/test/uda
yohannmarguier Jul 17, 2026
624d7e3
Ignore IDE cmake-build-* directories
yohannmarguier Jul 17, 2026
aade3e7
Add CMake presets as the canonical test entry points; drive CI with them
yohannmarguier Jul 17, 2026
10bda17
Document how to run the test suites (tests/README.md + routing stubs)
yohannmarguier Jul 17, 2026
b105206
Make ./test delegate to the CMake presets instead of duplicating flags
yohannmarguier Jul 17, 2026
690f539
Make contract fixtures linkable outside the test tree (issue #51)
yohannmarguier Jul 18, 2026
f24b119
Add benchmark harness skeleton: benchmarks/ + Google Benchmark + CTes…
yohannmarguier Jul 18, 2026
e2f2d19
Validate benchmark JSON with CMake parser
yohannmarguier Jul 20, 2026
144206e
Add whole-IDS equilibrium read benchmark on HDF5 (issue #53)
yohannmarguier Jul 20, 2026
7246824
Share legacy pulse storage between tests and benchmarks
yohannmarguier Jul 20, 2026
af0fb25
Add Memory backend as zero-I/O control for whole-IDS read (issue #54)
yohannmarguier Jul 20, 2026
4a20b81
Add baseline capture tooling: metadata + committed-artifact conventio…
yohannmarguier Jul 20, 2026
c0ee66c
Fix benchmark baseline capture metadata
yohannmarguier Jul 20, 2026
2b9df07
Validate benchmark JSON with CMake parser
yohannmarguier Jul 20, 2026
9554df2
Extract shared per-backend benchmark boilerplate into bench_common.h
yohannmarguier Jul 21, 2026
f15d86a
Add single time-slice-element read benchmark (HDF5 + Memory) (issue #60)
yohannmarguier Jul 21, 2026
353a66d
Fix HDF5 dataset re-creation on repeated whole-IDS writes to an open …
yohannmarguier Jul 21, 2026
e7cfb7a
Add whole-IDS write benchmark (HDF5 + Memory) (issue #59)
yohannmarguier Jul 21, 2026
2d7e07c
Add AOS-heavy traversal benchmark (HDF5 + Memory) (issue #61)
yohannmarguier Jul 21, 2026
8ab1815
Cover repeated HDF5 dataset writes
yohannmarguier Jul 21, 2026
36f4cdc
Skip ASCII in AOS traversal regression
yohannmarguier Jul 21, 2026
e41a944
Address issue 57 review findings
yohannmarguier Jul 21, 2026
5748ec5
Pin HDF5 al_delete_data's occurrence-wide widening (issue #63)
yohannmarguier Sep 10, 2026
c8e49ca
Make HDF5 al_delete_data honor its `path` argument (issue #63)
yohannmarguier Sep 10, 2026
1c00c85
Match delete paths per segment, so a path may cross an AOS (issue #63)
yohannmarguier Sep 10, 2026
0250431
Address the code review on the al_delete_data change (issue #63)
yohannmarguier Sep 10, 2026
dae4abd
Merge pull request #64 from yohannmarguier/fix/63-hdf5-delete-data-path
yohannmarguier Sep 10, 2026
858a7a2
Make HDF5 reads honor absolute field paths (issue #65)
yohannmarguier Sep 20, 2026
3e5871a
Merge pull request #66 from yohannmarguier/fix/65-hdf5-absolute-field…
yohannmarguier Sep 20, 2026
5148f1f
Merge branch 'develop' of github.com:yohannmarguier/IMAS-Core into de…
yohannmarguier Sep 22, 2026
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
58 changes: 58 additions & 0 deletions .github/workflows/contract-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Contract suite — functional (blocking)

# PRD user story 23 (issue #1): the whole suite runs in CI on every PR so a
# change breaking any pinned capability fails fast. This is the BLOCKING
# functional leg — a plain (non-sanitized) build that runs everything ctest
# knows about, including the Death tests and the CurrentlyCorrupts tripwires
# that the informational sanitizer leg (sanitizers.yml) excludes. An xfail
# flipping to pass (a DISABLED_ test's tripwire going red) or a green test
# going red both fail this check.

on:
push:
branches: [develop]
pull_request:

jobs:
contract-functional:
name: Contract tests (Linux, ${{ matrix.preset }}, blocking)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Both build modes (issue #32): the dlopen-failure plugin pin is
# build-mode dependent — assert-abort death test in Debug, swallowed
# assert tripwire under NDEBUG (RelWithDebInfo) — so each branch needs
# its own leg or one of them never runs anywhere. The presets
# (CMakePresets.json) are the single source of truth for flags and
# binary dirs; builddir here only feeds the label-partition check.
include:
- preset: tests # RelWithDebInfo
builddir: build
- preset: tests-debug
builddir: build-debug

steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0 # git describe needs full history for the version macro

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y ninja-build libhdf5-dev libboost-filesystem-dev

- name: Configure (tests on, no Python bindings)
run: cmake --preset ${{ matrix.preset }}

- name: Build
run: cmake --build --preset ${{ matrix.preset }}

# Issue #31: an empty `ctest -L unit` exits 0, so a broken label
# partition is invisible to the test run below — check it explicitly.
- name: Verify unit/integration label partition
run: bash tests/contract/check_label_partition.sh ${{ matrix.builddir }}/tests/contract

- name: Run the whole test suite
run: ctest --preset ${{ matrix.preset }}
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
else
VERSION=dev
fi
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"

- name: Build documentation
env:
Expand Down
124 changes: 124 additions & 0 deletions .github/workflows/mdsplus-contract.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: MDSplus contract suite (non-blocking)

# Task 2 issue #18 (parent #12): a dedicated, informational CI leg for the
# MDSplus tier (tests/contract/test_mdsplus*.cpp, TRACEABILITY.md Part 4),
# mirroring the D7 sanitizer leg (sanitizers.yml). continue-on-error: true —
# informational, not a merge gate, until the characterization baseline
# (issues #13-17) is triaged. Promotion to a blocking gate is deferred to
# Task 3.
#
# Runs on a GitHub-hosted arm64 runner: MDSplus publishes no arm64 packages
# for Ubuntu 22, only 24.04+ (docker/mdsplus/README.md's deviation note), and
# the characterization image itself is aarch64.
#
# Two-layer cache, so an ordinary push doesn't pay the full toolchain-install
# + DD-download cost every time:
# 1. the toolchain image (docker/mdsplus/Dockerfile) — keyed on its hash.
# A miss means re-running the MDSplus/Java/DD-toolchain package install.
# 2. the baked DD model tree (build-mdsplus/) — keyed on the DD version
# plus the model-build inputs (ALBuildDataDictionary.cmake,
# models/mdsplus/CMakeLists.txt). A hit restores the whole configured
# build directory (including the generated ids.xml and the model-tree
# files under build-mdsplus/models/mdsplus), so the configure step is
# skipped entirely on a hit — CMake's own dependency tracking then only
# rebuilds C++ sources that actually changed.

on:
push:
pull_request:

env:
DD_VERSION: "4.1.1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we see this version being updated following future DD releases? Or do we want DD_LATEST ?

IMAGE_TAG: imas-core-mdsplus:ci

jobs:
mdsplus-contract:
name: MDSplus contract suite (aarch64, non-blocking)
runs-on: ubuntu-24.04-arm
continue-on-error: true # informational leg, not a gate — for now

steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0 # git describe needs full history for the version macro

- name: Cache toolchain image (layer 1 — keyed on Dockerfile)
id: cache-image
uses: actions/cache@v4
with:
path: /tmp/mdsplus-image.tar
key: mdsplus-image-${{ hashFiles('docker/mdsplus/Dockerfile') }}

- name: Build toolchain image
if: steps.cache-image.outputs.cache-hit != 'true'
run: |
docker build -f docker/mdsplus/Dockerfile -t "${IMAGE_TAG}" docker/mdsplus
docker save "${IMAGE_TAG}" -o /tmp/mdsplus-image.tar

- name: Load cached toolchain image
if: steps.cache-image.outputs.cache-hit == 'true'
run: docker load -i /tmp/mdsplus-image.tar

- name: Cache baked DD model tree (layer 2 — keyed on DD version + model-build inputs)
id: cache-model
uses: actions/cache@v4
with:
path: build-mdsplus
key: mdsplus-model-${{ env.DD_VERSION }}-${{ hashFiles('common/cmake/ALBuildDataDictionary.cmake', 'models/mdsplus/CMakeLists.txt') }}

- name: Configure (bakes the DD model tree on a cache miss)
# The `mdsplus` preset (CMakePresets.json) carries the backend/model/
# test flags and the build-mdsplus binary dir; only the DD pin stays
# here, next to the cache key it feeds.
if: steps.cache-model.outputs.cache-hit != 'true'
run: >
docker run --rm --platform linux/arm64
-v "$PWD":/workspace -w /workspace
"${IMAGE_TAG}" bash -c "
cmake --preset mdsplus -DDD_VERSION=${DD_VERSION}
"

- name: Build contract suite
run: >
docker run --rm --platform linux/arm64
-v "$PWD":/workspace -w /workspace
"${IMAGE_TAG}" bash -c "
cmake --build --preset mdsplus
"

- name: Verify baked DD model tree is present (cache-hit and cache-miss paths)
run: |
set -euo pipefail
# ids_model.datafile is legitimately 0 bytes for a model tree (all
# structure lives in .tree/.characteristics; a model carries no
# data), so it is checked for existence only.
for f in ids_model.tree ids_model.characteristics; do
if [ ! -s "build-mdsplus/models/mdsplus/${f}" ]; then
echo "FATAL: missing/empty model file build-mdsplus/models/mdsplus/${f} — the MDSplus tier would fail with %TREE-E-FOPENR (issue #42)"
exit 1
fi
done
if [ ! -e "build-mdsplus/models/mdsplus/ids_model.datafile" ]; then
echo "FATAL: missing model file build-mdsplus/models/mdsplus/ids_model.datafile (issue #42)"
exit 1
fi
echo "Baked DD model tree complete under build-mdsplus/models/mdsplus."

- name: Run MDSplus contract suite
# The `mdsplus` test preset selects the tier (-L mdsplus) and points
# MDSPLUS_MODELS_PATH at the baked model tree under build-mdsplus/.
run: >
docker run --rm --platform linux/arm64
-v "$PWD":/workspace -w /workspace
"${IMAGE_TAG}" bash -c "
ctest --preset mdsplus
"

- name: Note
if: always()
# Block scalar, not a plain scalar: in a plain scalar ` #` starts a YAML
# comment even inside shell-looking quotes, truncating the command into
# an unterminated string (issue #43).
run: |
echo "MDSplus leg is informational (issue #12/#18). Red-by-design until the characterization baseline is triaged; promotion to a blocking gate is Task 3."
61 changes: 61 additions & 0 deletions .github/workflows/sanitizers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Contract suite — sanitizers (non-blocking)

# Decision D7 (TEST_STRATEGY.md): build the contract suite with
# AddressSanitizer + UndefinedBehaviorSanitizer + LeakSanitizer and run it, so a
# leak / use-after-free / overrun in the hot path is caught for free — no
# per-test assertions. This leg is INFORMATIONAL, not a merge gate
# (continue-on-error: true), until the baseline is triaged. LSan leak detection
# is Linux-only, which is why this leg runs on ubuntu.

# push is limited to develop so a PR from an in-repo branch runs the leg once,
# not twice (push + pull_request).
on:
push:
branches: [develop]
pull_request:

jobs:
asan-ubsan-lsan:
name: ASan/UBSan/LSan (Linux, non-blocking)
runs-on: ubuntu-latest
continue-on-error: true # informational leg (D7), not a gate — for now

steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0 # git describe needs full history for the version macro

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y ninja-build libhdf5-dev libboost-filesystem-dev

- name: Configure (sanitized, tests on, no Python bindings)
# The `sanitize` preset (CMakePresets.json) sets AL_CONTRACT_SANITIZE,
# which instruments both libal and the test binary. Python bindings are
# off: a sanitized libal must not be linked into a wheel whose bindings
# lack the ASan runtime (see tests/contract/CMakeLists.txt).
run: cmake --preset sanitize

- name: Build contract suite
run: cmake --build --preset sanitize

- name: Run contract suite under sanitizers
# The `sanitize` test preset carries the ASAN/LSAN/UBSAN_OPTIONS
# (halt/abort_on_error=0 so the whole suite runs and reports everything
# at once — informational leg) and two exclusions:
# * `Death` tests deliberately crash child processes (asserting today's
# crash-class defects) — not a memory-safety target, and ASan would
# report the intentional crash as an error.
# * `CurrentlyCorrupts` tripwires pin the ASCII rank-7 DOUBLE/COMPLEX
# corruption, which is UB whose manifestation ASan's memory layout
# masks (the data round-trips intact under ASan), so they legitimately
# fail here. They guard against rot in the blocking functional leg
# (contract-tests.yml). Real leaks/UAF in the ordinary paths still
# surface.
run: ctest --preset sanitize

- name: Note
if: always()
run: echo "Sanitizer leg is informational (D7). Triage findings before promoting it to a required check."
96 changes: 96 additions & 0 deletions .github/workflows/uda-contract.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: UDA contract suite (non-blocking)

# Issue #29 (parent #21): a dedicated, informational CI leg for the UDA tier
# (tests/contract/test_uda*.cpp, TRACEABILITY.md Part 5), mirroring the
# mdsplus-contract leg (mdsplus-contract.yml) and its rationale: UDA is one of
# the two DD-coupled backends (CLAUDE.md), and lands as a non-blocking leg only
# now that issue #28 has triaged the whole baseline to terminal statuses, so
# this leg is green (modulo pinned defects) from its first run and there is
# never a red informational leg to maintain.
#
# Runs on a GitHub-hosted arm64 runner: docker/uda/Dockerfile is aarch64 (the
# pinned reference stack docker/uda/README.md documents), matching the
# mdsplus-contract leg's own runner choice.
#
# One cache layer, unlike the mdsplus leg's two: the UDA image
# (docker/uda/Dockerfile) is the pinned, source-independent reference stack
# (UDA server + IMAS plugin source + IDSDef.xml); it does not COPY the repo, so
# it is cached across ordinary pushes and only Dockerfile/run.sh edits bust the
# cache. IMAS-Core itself and the IMAS server plugin are always built fresh
# from the mounted workspace by docker/uda/run.sh, by design (README.md
# "Design: toolchain image + build-workspace-at-runtime") — never baked into
# the image — so there is no second, workspace-keyed cache: CMake's own
# dependency tracking is the only reuse mdsplus's layer 2 gets from a restored
# build-mdsplus/ directory, and the UDA leg has no equivalent artifact to
# restore, only source it must always rebuild against.

on:
push:
pull_request:

env:
IMAGE_TAG: imas-core-uda:ci

jobs:
uda-contract:
name: UDA contract suite (aarch64, non-blocking)
runs-on: ubuntu-24.04-arm
continue-on-error: true # informational leg, not a gate

steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0 # git describe needs full history for the version macro

- name: Cache reference-stack image (keyed on Dockerfile + run.sh)
id: cache-image
uses: actions/cache@v4
with:
path: /tmp/uda-image.tar
key: uda-image-${{ hashFiles('docker/uda/Dockerfile', 'docker/uda/run.sh') }}

- name: Build reference-stack image
if: steps.cache-image.outputs.cache-hit != 'true'
run: |
docker build --platform linux/arm64 -f docker/uda/Dockerfile -t "${IMAGE_TAG}" docker/uda
docker save "${IMAGE_TAG}" -o /tmp/uda-image.tar

- name: Load cached reference-stack image
if: steps.cache-image.outputs.cache-hit == 'true'
run: docker load -i /tmp/uda-image.tar

- name: Verify pinned stack identifiers match TRACEABILITY Part 5 header
run: |
set -euo pipefail
uda_server=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.uda-server-version" }}' "${IMAGE_TAG}")
uda_plugins=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.uda-plugins-version" }}' "${IMAGE_TAG}")
uda_plugins_commit=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.uda-plugins-commit" }}' "${IMAGE_TAG}")
dd_version=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.dd-version" }}' "${IMAGE_TAG}")
echo "Image labels: uda-server=${uda_server} uda-plugins=${uda_plugins}@${uda_plugins_commit} dd=${dd_version}"
header=tests/contract/TRACEABILITY.md
grep -q "tag \*\*${uda_server}\*\*" "${header}"
grep -q "tag \*\*${uda_plugins}\*\*" "${header}"
grep -q "commit \*\*\`${uda_plugins_commit}\`\*\*" "${header}"
grep -q "\*\*${dd_version}\*\*" "${header}"
echo "Image stack identifiers match ${header}'s Part 5 pinned-reference-stack table."

# AL_UDA_DEDICATED_CI=1: inside the dedicated reference-stack job a
# server bootstrap failure must fail the job, not skip every test —
# uda-run.sh makes the listener wait and the uda_cli ping fatal, and
# fails unless a nonzero number of UDA tests actually executed
# (issue #41). Developer builds without the flag keep skip semantics.
- name: Run the UDA contract tier
run: >
docker run --rm --platform linux/arm64
-v "$PWD":/workspace -w /workspace
-e AL_UDA_DEDICATED_CI=1
"${IMAGE_TAG}" uda-run.sh

- name: Note
if: always()
# Block scalar, not a plain scalar: in a plain scalar ` #` starts a YAML
# comment even inside shell-looking quotes, truncating the command into
# an unterminated string (issue #43).
run: |
echo "UDA leg is informational (issue #21/#29). Red-by-design only for un-pinned defects; TRACEABILITY.md Part 5 (issue #28) records the pinned baseline this leg should stay green against."
Loading