Skip to content

fix(ci): un-poison the Maven cache so the Tycho baseline gate actually runs - #1497

Merged
joaodinissf merged 3 commits into
dsldevkit:masterfrom
joaodinissf:fix/ci-baseline-cache-poisoning
Aug 24, 2026
Merged

fix(ci): un-poison the Maven cache so the Tycho baseline gate actually runs#1497
joaodinissf merged 3 commits into
dsldevkit:masterfrom
joaodinissf:fix/ci-baseline-cache-poisoning

Conversation

@joaodinissf

@joaodinissf joaodinissf commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

The Tycho baseline gate (compare-version-with-baselines) has never actually compared against the live baseline repository in CI. This PR fixes three stacked problems — a poisoned metadata cache that made the gate pass vacuously, a shallow-clone qualifier bug (masked by the first) that would have made it fail on everything, and missing version bumps for bundles whose compiled output changed with the Tycho 5.0.4 toolchain bump (masked by both) — and proves the revived gate with a canary run (see Proof below).

Context: #1474 changed bundle content without a version bump and still passed maven-verify (comment).

Root cause

  1. The Actions dependency cache persists Tycho's HTTP/metadata cache. Both snapshot.yml (save) and verify.yml (restore) cache ~/.m2/repository, which contains ~/.m2/repository/.cache/tycho — Tycho's transport cache for p2 metadata.
  2. Tycho's transport is cache first and does not reliably revalidate. Cached 404/301 entries are served forever without revalidation; a 60-minute minimum-cache floor covers back-to-back master builds; and 304 revalidations refresh the staleness clock. The p2/releases/latest and p2/snapshots/latest composites are moving pointers, so serving them from a restored cache means the build sees a stale (or effectively empty) baseline.
  3. The mojo passes silently when it finds nothing. CompareWithBaselineMojo iterates the resolution result; if the baseline IU isn't found, the loop body never executes — no warning, no failure.

Observable evidence (run 32737809045, the run behind #1474's green check):

  • Every compare-version-with-baselines execution completed in 1–22 ms with zero output — no time for any network access, no content comparisons, no version errors. Bundles changed since v19.0.0 with unchanged 17.3.1 versions must fail this check when the real baseline is visible.
  • The transport banner: Update mode: cache first, Cache location: /home/runner/.m2/repository/.cache/tycho.
  • The sibling snapshot-baseline validator logged No baseline version <GAV> for all 64 modules in every run since May — including modules whose exact qualifiers were guaranteed to be published in snapshots/latest minutes earlier. The baseline repos have been effectively invisible to CI the whole time.

Meanwhile the same mojo, same Tycho 5.0.4, same URL, run locally with a fresh cache, correctly fails (Version has moved backwards… / Only qualifier changed…), and the published repo itself is complete and correct (all 87 IUs resolvable; verified via tycho-p2-extras:mirror).

Why nobody noticed: before v19.0.0 (Aug 19) the baseline held 17.3.0 bundles while the reactor was 17.3.1-SNAPSHOT — a working check would also have passed silently. The gate only grew teeth when v19.0.0 put 17.3.1 in the baseline, and #1474 was the first qualifier-only change to cross it.

Second root cause, exposed by the first fix

The first run with a clean cache (32746448963) immediately failed with Only qualifier changed for (com.avaloq.tools.ddk/17.3.1.v20260824-1542) — on a bundle untouched since June. The qualifier is the run's own timestamp: verify.yml checked out the PR merge ref with the default shallow clone (fetch-depth: 1), leaving Tycho's jgit build-qualifier no history, so every bundle's qualifier falls back to the HEAD timestamp. Even with a clean cache, every PR build would have false-positived on all bundles. (snapshot.yml already uses fetch-depth: 0, so master builds were unaffected.) That run doubles as proof the gate is alive.

Fix

  1. Drop the DDK-site entries from the restored Tycho cache before every Maven build, in both verify.yml and snapshot.yml:
rm -rf ~/.m2/repository/.cache/tycho/https/dsldevkit.github.io \
       ~/.m2/repository/.cache/tycho/https/ddk.tools.avaloq.com

Surgical on purpose: the only moving pointers in the build are the two latest composites on these hosts. Versioned eclipse.org repo metadata and all downloaded artifacts (including baseline jars, cached by exact version under ~/.m2/repository/p2/…) stay cached. Cost: a few KB of metadata re-fetched per run. release.yml needs no change (it promotes snapshots on gh-pages without a Maven build).

  1. fetch-depth: 0 on the maven-verify checkout so jgit computes real per-bundle qualifiers: unchanged bundles then match the baseline version exactly and pass via content comparison.

Third finding: the Tycho 5.0.4 bump changed compiled output without version bumps

With correct qualifiers (run 32747012141) the gate reported same fully qualified version, but different content on com.avaloq.tools.ddk.xtext and com.avaloq.tools.ddk.test.uicorrectly. Diffing the published jars (release v19.0.0 build vs snapshot 0d9deaf6 build of identical sources) shows the divergence: the tycho.version 5.0.3→5.0.4 bump (#1496) changed generic-signature emission in compiled classes (Class<? extends Object> vs Class<?>) without touching any bundle source, so jgit qualifiers — and versions — stayed at baseline values while content changed. The gate exists precisely to catch this.

A full reactor run with -DonIllegalVersion=warn against the live baseline enumerated the complete set: 18 bundles (the Xtend-heavy ones) + both features (their built feature.xml embeds the bumped plugin versions). This PR bumps those bundles to 17.3.2, the features to 19.0.1, and category.xml accordingly.

Proof

Run Branch state Result
32746448963 cache fix only red on an unchanged bundle — exposed the shallow-clone qualifier bug, and proved the gate runs
32747012141 + fetch-depth: 0 red, correctly: real content divergence from the Tycho 5.0.4 bump (see above)
32751642146 + version bumps green — gate active and passing
32752976699 + canary: comment-only change in com.avaloq.tools.ddk, no version bump red: Only qualifier changed for (com.avaloq.tools.ddk/17.3.1.v20260824-1635). Expected to have bigger x.y.z than what is available in baseline (17.3.1.v20260601-1241) — exactly the failure #1474 should have produced
32753327776 canary dropped via force-push back to the green tip (current head) green — final state

The canary is removed by force-push rather than revert: a revert commit would itself move the bundle's jgit qualifier past the baseline again and keep the gate red — same-version bundles must stay untouched until the next release.

Notes / follow-ups

  • This also revives the snapshot-side tycho-p2-plugin baseline (baselineRepositoriessnapshots/latest). No baselineMode/baselineReplace is configured, so Tycho defaults apply (warn + all): identical rebuilt artifacts get replaced by their published baseline versions and content mismatches warn — builds won't start failing from that mechanism.
  • Once this merges, fix(format): guard against null members in FormatJvmModelInferrer.inferConstants #1474 will correctly fail the gate on rebase and needs its format bundle bumped (to 17.3.2, or 17.3.3 if preferred after this PR's bumps — com.avaloq.tools.ddk.xtext.format is not among the 18 bumped here, so 17.3.2 is free for it).
  • Working-practice implication of a live gate: any change to a released bundle's content — including toolchain bumps — now requires a micro bump in the same PR.
  • Possible upstream reports to Tycho: the mojo's silent pass on missing baseline IUs, and the never-revalidated cached 404/301 entries.

🤖 Generated with Claude Code

joaodinissf and others added 3 commits August 24, 2026 16:41
The Actions dependency cache persists Tycho's HTTP cache
(~/.m2/repository/.cache/tycho) inside ~/.m2/repository. Tycho's
cache-first transport never revalidates cached 404/301 entries and
p2/releases/latest + p2/snapshots/latest are moving pointers, so
restored blobs served a stale baseline and the
compare-version-with-baselines gate passed vacuously (the mojo has no
'baseline not found' branch) - every compare execution completed in
1-22 ms with no network access and no comparisons, and the snapshot
baseline validator logged 'No baseline version' for all 64 modules in
every run since May. This is how dsldevkit#1474 changed bundle content without
a version bump and still passed maven-verify.

Delete only the DDK hosts' cached metadata after each cache restore,
in verify.yml and snapshot.yml: the baseline is fetched fresh (a few
KB) while versioned eclipse.org metadata and all downloaded artifacts
stay cached. release.yml runs no Maven build and needs no change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Run https://github.com/dsldevkit/dsl-devkit/actions/runs/32746448963
(first run with the revived baseline gate) failed with 'Only qualifier
changed for (com.avaloq.tools.ddk/17.3.1.v20260824-1542)' on an
UNCHANGED bundle: the shallow clone (default fetch-depth 1) of the PR
merge ref leaves Tycho's jgit build-qualifier no history, so every
bundle's qualifier falls back to the HEAD timestamp. With correct
per-bundle qualifiers, unchanged bundles match the baseline version
exactly and pass via content comparison.

A second latent bug masked by the cache poisoning: even with a clean
cache, every PR build would have false-positived on all bundles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The revived baseline gate correctly rejects same-version artifacts
whose content differs from the v19.0.0 baseline. The tycho.version
5.0.3 -> 5.0.4 bump (0d9deaf) changed the compiled output of the
Xtend-heavy bundles (e.g. generic-signature emission: Class<? extends
Object> vs Class<?>) without touching their sources, so their jgit
qualifiers - and versions - stayed at the baseline values. Bump the 18
affected bundles to 17.3.2 and, since their bumped versions change the
built feature content, both features to 19.0.1 (with category.xml
following).

Enumerated with a full local reactor run using -DonIllegalVersion=warn
against the live v19.0.0 baseline.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@joaodinissf
joaodinissf force-pushed the fix/ci-baseline-cache-poisoning branch from c8c91fd to 4e79db7 Compare August 24, 2026 16:52
@joaodinissf
joaodinissf marked this pull request as ready for review August 24, 2026 18:24
@joaodinissf
joaodinissf merged commit 4772c85 into dsldevkit:master Aug 24, 2026
8 checks passed
@joaodinissf
joaodinissf deleted the fix/ci-baseline-cache-poisoning branch August 24, 2026 18:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants