[ci] and [ci-es] name the same NodeNorm deployment:
[ci]
NodeNormURL = https://nodenorm-es.ci.transltr.io/
NameResURL = https://name-lookup.ci.transltr.io/
[ci-es]
NodeNormURL = https://nodenorm-es.ci.transltr.io/
NameResURL = https://namelookup-es.ci.transltr.io/
That is deliberate and correct — the two targets differ in their NameRes backend, and pairing each against the same NodeNorm is the point. But it means generate_report.fetch_status() fetches that one NodeNorm /status twice per run, and StatusMatrix.statusCellClass() then counts one deployment's answer twice when it decides which value is the odd one out:
const values = this.targetNames.map((t) => this.statusValue(statusRow, t));
...
const ranked = [...tally.entries()].sort((a, b) => b[1] - a[1]);
if (ranked.length > 1 && ranked[0][1] === ranked[1][1]) return '';
const majority = ranked[0][0];
What goes wrong
On any NodeNorm-sourced row — babel_version, biolink_version, the eq_id_to_id_db record count — the ci deployment gets two votes out of seven rather than one out of six.
A genuine 3–3 split is exactly what mid-promotion looks like, and the tie guard exists to leave it unshaded rather than pick a winner by insertion order. But if the ci deployment is on the winning side of that split, the tally reads 4–2, the tie guard does not fire, and the three environments on the other version get shaded amber as the odd ones out. The row then asserts a majority that does not exist.
It is not hypothetical arithmetic: a Babel version rolling out to exp/dev/ci and not yet to test/prod is a 3–3 on babel_version with ci on the new side, which is a routine day.
Why it needs a decision, not just a fix
Deduplicating by URL before tallying is the obvious fix, and probably the right one, but it raises a question the code currently does not answer: what is the unit of agreement? Today it is the target. If it becomes the deployment, then:
- the NodeNorm rows and the NameRes rows have different denominators (5 NodeNorm deployments, 6 NameRes), which the shared
STATUS_ROWS table does not currently express;
unreachable in generate_report.py is per-target, and would keep double-counting even if the shading stopped;
- a reader looking at a six-column table and being told "the majority is 3" has to know that two of the columns are one machine, which nothing on the page says.
Simply hiding the duplicate column is not an option — [ci] and [ci-es] are genuinely different test targets, and their results differ.
Where it is
website/src/components/StatusMatrix.vue, statusCellClass()
src/babel_validation/tools/generate_report.py, fetch_status() — the duplicate fetch, which is also a wasted request every run
tests/targets.ini — the shared URL, which is correct and should not change
Noticed while reviewing #120; not caused by it.
[ci]and[ci-es]name the same NodeNorm deployment:That is deliberate and correct — the two targets differ in their NameRes backend, and pairing each against the same NodeNorm is the point. But it means
generate_report.fetch_status()fetches that one NodeNorm/statustwice per run, andStatusMatrix.statusCellClass()then counts one deployment's answer twice when it decides which value is the odd one out:What goes wrong
On any NodeNorm-sourced row —
babel_version,biolink_version, theeq_id_to_id_dbrecord count — the ci deployment gets two votes out of seven rather than one out of six.A genuine 3–3 split is exactly what mid-promotion looks like, and the tie guard exists to leave it unshaded rather than pick a winner by insertion order. But if the ci deployment is on the winning side of that split, the tally reads 4–2, the tie guard does not fire, and the three environments on the other version get shaded amber as the odd ones out. The row then asserts a majority that does not exist.
It is not hypothetical arithmetic: a Babel version rolling out to exp/dev/ci and not yet to test/prod is a 3–3 on
babel_versionwith ci on the new side, which is a routine day.Why it needs a decision, not just a fix
Deduplicating by URL before tallying is the obvious fix, and probably the right one, but it raises a question the code currently does not answer: what is the unit of agreement? Today it is the target. If it becomes the deployment, then:
STATUS_ROWStable does not currently express;unreachableingenerate_report.pyis per-target, and would keep double-counting even if the shading stopped;Simply hiding the duplicate column is not an option —
[ci]and[ci-es]are genuinely different test targets, and their results differ.Where it is
website/src/components/StatusMatrix.vue,statusCellClass()src/babel_validation/tools/generate_report.py,fetch_status()— the duplicate fetch, which is also a wasted request every runtests/targets.ini— the shared URL, which is correct and should not changeNoticed while reviewing #120; not caused by it.