From: Willy Tarreau Date: Mon, 6 Jul 2026 17:17:48 +0000 (+0200) Subject: DEV: patchbot: don't pretend a save succeeded when the server ignored it X-Git-Url: http://git.kaiwu.me/%22data:,/static//%22%22?a=commitdiff_plain;h=351c7e6598e47933a005e625f38b16dcd2fb4ddc;p=haproxy.git DEV: patchbot: don't pretend a save succeeded when the server ignored it The save handler treated any HTTP 200 as a full success and advanced the local reference for everything it had sent, only special-casing the reported conflicts. But the server legitimately drops directives it cannot parse, and answers "OK directives applied" with what it really did. The typical case is an outdated update scripton the server which ignores the whole "setnotes" directive, applies nothing, and the client still displayed the edit as saved... until the next "Get updates" reverted it. Let's count the directives sent, and when the server's applied count plus the reported conflicts don't add up, believe the server, not ourselves: advance nothing, keep every edit local (boxes open, save button lit) and tell the user how many changes were ignored, suggesting a version mismatch. --- diff --git a/dev/patchbot/scripts/post-ai.sh b/dev/patchbot/scripts/post-ai.sh index c1b8ad7d2..8f9d8590c 100755 --- a/dev/patchbot/scripts/post-ai.sh +++ b/dev/patchbot/scripts/post-ai.sh @@ -495,7 +495,7 @@ function updt_save_btn() { // Note that a state moved back to the reference by hand is simply not sent. function save_ref() { var st = [], nt = [], rp = [], rp_on = []; - var body = "", i, s, el, txt; + var body = "", nsent = 0, i, s, el, txt; if (!branch) return; @@ -505,6 +505,7 @@ function save_ref() { if (s && s != ref_state[i]) { st[i] = s; body += cid[i] + " state " + s + "\n"; + nsent++; } el = document.getElementById("in_" + i); txt = el ? el.value.replace(/\r/g, "").replace(/[\x00-\x1f\x7f]/g, " ").trim() : ""; @@ -515,11 +516,13 @@ function save_ref() { rp[i] = txt; rp_on[i] = 1; body += cid[i] + " setnotes " + sdbm(note_base[i]) + " " + txt + "\n"; + nsent++; } } else if (txt) { nt[i] = txt; body += cid[i] + " notes " + txt + "\n"; + nsent++; } } @@ -534,7 +537,7 @@ function save_ref() { .then(function(t) { var confl = {}; var resp = t.split("\n"); - var i, j, nbc = 0; + var i, j, ok, nbc = 0; for (j = 0; j < resp.length; j++) { if (resp[j].indexOf("conflict ") == 0) { @@ -546,6 +549,22 @@ function save_ref() { } } + // The server states how many directives it applied ("OK ..."): + // anything neither applied nor reported as a conflict was silently + // ignored (e.g. an outdated update.bin not knowing a directive). In + // that case believe the server, not ourselves: advance nothing, keep + // every edit local for a retry, and say what happened. + ok = resp[0] ? resp[0].match(/^OK (\d+) /) : null; + if (!ok || parseInt(ok[1], 10) != nsent - nbc) { + for (i = 1; i < nb_patches; i++) { + if (confl[i]) + mark_conflict(i, 1); + } + sync_msg("server applied only " + (ok ? ok[1] : "?") + " of " + nsent + + " changes (outdated update.cgi/update.bin?), edits kept"); + return; + } + for (i = 1; i < nb_patches; i++) { if (st[i]) ref_state[i] = st[i];