]> git.kaiwu.me - haproxy.git/commitdiff
DEV: patchbot: don't pretend a save succeeded when the server ignored it
authorWilly Tarreau <w@1wt.eu>
Mon, 6 Jul 2026 17:17:48 +0000 (19:17 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 7 Jul 2026 12:45:32 +0000 (14:45 +0200)
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 <n> 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.

dev/patchbot/scripts/post-ai.sh

index c1b8ad7d2628b7541d28eef3cb405d0a80d6e2ce..8f9d8590cc0c0e8649fb5282bdbe19e7e7835100 100755 (executable)
@@ -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 <n> ..."):
+      // 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];