← Commit history

bridge stepShot = authoritative per-step evidence; page snaps honest fallback

John Lauer ·9eeba61295 ·2mo ago ·parent 3598e3c
1 file changed +17−2
web-control-demo.html+17−2
@@ -419,6 +419,7 @@ for (const w of mine) {     if (target === "all") { setRes(c.res, "err", "pick ONE machine", "a demo streams per-machine progress - fan-out is not supported here"); return; }
     var who = machineLabel(target);
     c._who = who;
+    c._bridgeShots = false;
     c.btn.disabled = true;
     cardLog(c.card).textContent = "";
     var sb = c.card.querySelector("div.shots"); if (sb) sb.innerHTML = "";
@@ -456,7 +457,10 @@ for (const w of mine) {         if (!cfg.snap || snapBusy) return;
         snapBusy = true;
         var done = function () { snapBusy = false; };
-        var pin = function (img, title) { addShot(c.card, img, "live: " + label); clog(c, "  [proof] captured \"" + (title || label) + "\""); };
+        // HONEST label: this is the page's own capture taken DURING the step,
+        // not the bridge's evidence OF the step - the window shown may lag the
+        // label. Bridge-supplied stepShot (above) supersedes these entirely.
+        var pin = function (img, title) { addShot(c.card, img, "during “" + label + "”: " + (title || "app window")); clog(c, "  [page capture during \"" + label + "\": " + (title || "app window") + "]"); };
         if (cfg.snap.viaHwnd) {
           // fusion_state's own screenshot exceeds the 4MB inline cap (it comes
           // back as a PATH on the far machine), so snap via the hwnd instead:
@@ -494,12 +498,23 @@ for (const w of mine) {             return finishDemo(c, cfg, est, target);
           }
           setProgress(c.card, d.percent, d.stepLabel || d.step, d.beatIndex, d.beatCount, d.elapsedSec, d.estimatedSec || est);
+          // BRIDGE-SUPPLIED step evidence is authoritative: the bridge knows
+          // the exact moment a step completed and which window is that step's
+          // surface, so a `stepShot {step, title, image}` on a progress frame
+          // is pinned verbatim and disables the page's own guess-snaps (which
+          // race the tour and can label the wrong window - John's catch).
+          var ss = d.stepShot || (d.result && d.result.stepShot);
+          if (ss && (ss.image || ss.base64)) {
+            c._bridgeShots = true;
+            addShot(c.card, ss.image || ss.base64, "step: " + (ss.step || ss.title || d.stepLabel || "step"));
+            clog(c, "  [proof] bridge evidence for \"" + (ss.step || ss.title || d.stepLabel) + "\"");
+          }
           // Log + snap only on CHANGE - a 2.5s poll of a 30s step used to spam
           // the same line eight times.
           if (d.stepLabel && d.stepLabel !== lastStep) {
             lastStep = d.stepLabel;
             clog(c, "  " + (d.percent != null ? d.percent + "% " : "") + d.stepLabel + (d.beatCount ? " (step " + ((d.beatIndex || 0) + 1) + "/" + d.beatCount + ")" : ""));
-            maybeSnap(d.stepLabel);
+            if (!c._bridgeShots) maybeSnap(d.stepLabel);
           }
           if (d.done === true || d.active === false) {
             setProgress(c.card, 100, "done", d.beatCount, d.beatCount, d.elapsedSec, d.estimatedSec || est);