Legacy partner customization branches ran a single CI job. The first devel → customization/<partner> merge after devel’s workflow change swaps in devel’s six-job pipeline, so four jobs run on that branch for the very first time — surfacing years of latent breakage in one PR. This is systemic and will recur on every partner branch that has not yet taken a devel merge.
Budget for this before starting a partner devel-update
The red CI on a first-devel-merge PR is mostly pre-existing partner breakage newly enforced, not breakage your merge introduced. Triage each failure by origin (git log the offending line) before assuming the merge caused it.
Both live at .github/workflows/pull-request.yaml. The merge brings devel’s version onto the partner branch, so test, audit, depcheck and sonar execute against partner code for the first time ever.
Blob ec0a1244 is one shared frozen artefact, not a per-partner variant
The legacy workflow on customization/cib is byte-identical to the pre-merge Cofidis branch (FKITDEV-9197 vs FKITDEV-9059). So “is this branch still on the legacy pipeline?” is answerable with a single blob-hash comparison — no need to read the YAML:
git rev-parse <branch>:.github/workflows/pull-request.yaml # ec0a1244… ⇒ legacy, expect the expansion
And a branch can be below even that floor: portal_css’s customization/cib had no pull-request.yaml at all — zero CI on the branch until the merge.
Yes, all three — and on portal_css it was a win. Cost: 3 fixes; final CI 7/7, 6/6, and vuer_oss’s two standing override cases
Evidence — Cofidis, 2026-07-20
The FKITDEV-9059 merge (vuer_css #3100, vuer_oss #8040) produced 5 distinct failure clusters. Only 2 were merge-introduced; the rest dated back to 2017–2024. Full per-failure inventory with root causes and fix sides is in FKITDEV-9059.
Counter-evidence — Generali, 2026-08-08 (the trap did NOT fire)
Not every partner branch is still on the legacy workflow. In FKITDEV-9194both Generali branches (customization/generali-atvilagitas in vuer_oss and vuer_css) already carried devel’s full 6-job pipeline, so there was no expansion and no wave of newly-enforced breakage: vuer_css came out fully green (lint / 120 suites / build / depcheck / audit), vuer_oss red only on the pre-existing FKITDEV-8279 sequelize advisory.
Two things to carry forward from that round:
Check, don’t assume — git show <branch>:.github/workflows/pull-request.yaml and compare the blob against devel’s before budgeting for the expansion.
Also check scheduled workflows, not just PR checks — vuer_oss gained a scheduled long-lived-branches.yaml, but its branch matrix lists only devel / mbh / raiffeisen / kh / unicredit. The file being present on the branch does not mean the branch is in the matrix.
Evidence — CIB, 2026-08-11: the expansion as a SECURITY WIN
FKITDEV-9197 fired the trap on all three repos. The vuer_oss / vuer_css halves behaved as the Cofidis model predicts. portal_css did not — and it is the most interesting data point this note has.
customization/cib in portal_css had no pull-request.yaml whatsoever, so it had never been linted or audited by CI on that branch. Measured against a base worktree at the pre-merge tip bf6dfbf8:
Gate
Base (pre-merge)
Merged
eslint
exit 1 — 15 problems
exit 0
improved-yarn-audit --min-severity critical
25 CRITICAL
0
CIB’s portal had been shipping 25 critical advisories, unmeasured — tar via semantic-release > npm, handlebars, twig > locutus (×2), browserify > shell-quote — precisely because the branch carried no audit gate. The devel merge both turned the gate on and cleared everything it would have caught.
Reframe the expectation: the expansion is not automatically a tax
The Cofidis framing — “budget for a wave of newly-enforced pre-existing breakage” — is the common case, not the only one. When the partner branch is far enough behind that devel has already remediated the vulnerabilities it inherited, the same merge that switches the gate on also satisfies it.
Either way the honest statement in the PR body is the same, and it needs a measured base worktree to make: “these N gates are new on this branch; here is what they said before the merge and after.” Do not report a newly-green gate as your achievement, and do not report a newly-red one as your damage.
The actual CI outcome, 2026-08-12
The first round where the post-merge PR runs are recorded, not just the predicted expansion. All three PRs target customization/cib.
Unit Tests / Lint / Depcheck / SonarQube green after one fix. Audit red, SonarCloud red, Build skipped.
So the newly-enforced breakage cost three fixes across three repos — an order of magnitude less than Cofidis’s five clusters, because CIB had zero partner commits since its last release (a pure core-update round).
The vuer_css fixes are the archetype of what the test job switches on:
sso-login-endpoint.test.js had been red since 2024-12-03 — 20 months — asserting 400 against a middleware that returns 401. The commit that changed the behaviour also renamed the file and updated only the test’s require line. Nobody knew, because the branch had no test job.
portal-client.test.js failed at import: CIB’s PortalClient.js has a module-scope require('../../../config') that devel’s copy does not, and config/ has no test.json.
A 20-month-old red test on a branch with zero commits since the last release is the clean demonstration: the failures the expansion surfaces are a function of how long the branch has been unmeasured, not of what the merge did or of how much partner work happened.
"Skipped" is not "passed" — a red gate hides everything downstream of it
On the first vuer_css run, Build and SonarQube were skipped, not failed, because both needs: the red test job. Reporting that run as “4 green, 1 red” overstates what is known by two entire jobs.
Same shape on vuer_oss: build has needs: audit, and audit is permanently red on the FKITDEV-8279 sequelize advisory (npm 1114318, “Sequelize: SQL Injection (Oracle DB)”), so Build never runs on any vuer_oss partner PR. Re-read the needs: graph before drawing conclusions from a run.
The two vuer_oss reds need a human override, not a fix
Audit — the @techteamer/sequelize fork (FKITDEV-8279). Pre-existing on every branch.
SonarCloud quality gate — an eleven-month devel merge is graded as “New Code”; 334 commits of core arrive as if freshly authored. Note the split: the workflow’s own SonarQube job passed; it is the SonarCloud status check that is red.
Neither is fixable on a partner branch, and attempting it there is how partner branches acquire divergence they then pay for on every future merge.
The rest of the CIB round (the dependency-removal trap, the eslint-9 dead-directive wave, per-repo gate numbers) is in FKITDEV-9197.
Two structural amplifiers
These are architectural constraints of the repos, not cofidis quirks — they apply to every partner branch.
1. Partners fork core source files in place
There is no override layer for server-side service classes. A partner that needs different behaviour edits the core file directly — e.g. cofidis edits server/service/FlowLiveUpdateService.js in place. The forked file then violates the core unit test, which still asserts the upstream behaviour. See breakage-risks for the per-file fork census.
2. No customization-aware unit-test layer
jest.config-unit.js matches only test/tests/unit/**. There is no per-partner test directory. Consequences:
A partner-specific test failure can only be fixed by diverging a shared core test file.
That divergence then conflicts on every subsequent devel merge.
This is a recurring tax, not a one-off cost — each partner branch accumulates its own set of divergent core tests that must be re-reconciled on every sync.
For Agents
When picking up the next Devel update ticket for a partner:
Check whether the partner branch still carries the legacy single-job workflow (lint-and-build) — blob ec0a1244 — or no workflow at all. If either, expect the expansion, and stand up a base worktree so you can state what each new gate said before the merge.
Expect the same 5 clusters to be candidates: dead-code require() after a core .js→.ts rename, stale eslint-disable directives, forked-core-file vs core-unit-test mismatches, partner-only .trans.js keys returning undefined, and the request/form-data audit CVE (cve-2025-7783-form-data-via-request).
Classify every failure as merge-introduced vs pre-existing before proposing a fix — the fix side (partner vs core test) depends on it. Use git log --follow -S or git log -L <a>,<b>:<file> for this: plain git log -S <string> -- <path>stops at renames and will tell you a behaviour never existed (FKITDEV-9197 §15).
Read the workflow’s needs: graph before reporting a run. A red gate skips its dependents rather than failing them, so a run can look mostly-green while two jobs are simply unknown.
Separate the failures that need a code fix from the ones that need a human override — on vuer_oss the audit (FKITDEV-8279) and the SonarCloud “New Code” gate are always the latter. Do not fix them on a partner branch.
Related
FKITDEV-9059 — Cofidis devel update; where this pattern was first characterised, with the full failure inventory.
FKITDEV-9194 — Generali devel update; the counter-example where the branch was already on the 6-job pipeline.
FKITDEV-9197 — CIB devel update; fired on all three repos, and the round where the inherited audit gate was a security win rather than a tax.
vuer-oss-unit-tests-green-is-weak-evidence — and why the same job carries less signal than it looks in vuer_oss: one suite registers zero tests, two others flake. Relevant the moment the expansion turns that job on for a partner branch.