From 3a796b5013cbae99db9805629277696426740d10 Mon Sep 17 00:00:00 2001 From: DeeJanuz <45082401+DeeJanuz@users.noreply.github.com> Date: Mon, 5 Oct 2026 14:28:15 -0600 Subject: [PATCH] Gaze: the first calibration no longer runs twice Turning gaze mode on wakes our tracker, so its eyes come back just as the first calibration opens. DON_DELAY later, "the headset went on" re-armed the automatic calibration while it was still open, and when it ended, ft-eyes' status was still a moment old (not calibrated), so a second one opened at once. Seen live on 2026-10-05: 26 of 27 dots, then 27 more. The headset going on re-arms it only when no check is open. first-calibration-test.py now has the headset go on mid-calibration and checks that only one opens. Co-Authored-By: Claude Opus 5.5 --- gaze/gazecheck.py | 6 +++++- gaze/test/first-calibration-test.py | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/gaze/gazecheck.py b/gaze/gazecheck.py index 932b2a9..23f32c5 100644 --- a/gaze/gazecheck.py +++ b/gaze/gazecheck.py @@ -894,7 +894,11 @@ class Checks: self.back_since = None # gone again before DON_DELAY elif self.back_since is not None and now - self.back_since >= DON_DELAY: self.away, self.back_since = False, None - self.full_armed = True # a calibration that closed unfinished opens again + if not self.check: + # A calibration that closed unfinished opens again. Not one still open: gaze mode + # coming on wakes our tracker, so its eyes come back just as the calibration + # opens, and re-arming then opened a second one when the first ended. + self.full_armed = True self.auto_quick("the headset went on") if svc.kind == "own" and now - svc.own_at < 5: reseat = any(e.get("reseat") for e in (svc.own.get("eyes") or {}).values()) diff --git a/gaze/test/first-calibration-test.py b/gaze/test/first-calibration-test.py index cb0d4f9..f22a7ec 100755 --- a/gaze/test/first-calibration-test.py +++ b/gaze/test/first-calibration-test.py @@ -201,8 +201,14 @@ helper_state["reply"] = "ok on worn" check("gaze mode on: the calibration opens by itself", wait(lambda: check_state().get("kind") == "full", 6), True) check("it runs blind (no gaze from ours yet)", check_state().get("blind"), True) check("nothing says it can't open", any("can't open" in m for m in logs), False) +# Live 2026-10-05: turning gaze mode on woke our tracker, and the calibration opened before +# DON_DELAY of eyes had passed, so "the headset went on" came while it was open. That re-armed +# it, and a second calibration opened as soon as the first ended. +svc.checks.away, svc.checks.back_since = True, None check("dot 1: a click takes it", take_dot(0), True) +check("the headset went on while it was open", + wait(lambda: not svc.checks.away, gazecheck.DON_DELAY + 2) and bool(svc.checks.check), True) t0, t1, yaw, pitch = eyes_state["points"][0] dot = gazecheck.check_dots("full", True)[0] check("its window is the look up to the click (about CHECK_WINDOW)", @@ -222,6 +228,8 @@ check("all dots: ours fits its calibration (calib-fit)", wait(lambda: eyes_state["cal"] is not None and not svc.checks.check, 4), True) check("the service sees it calibrated", wait(lambda: svc.checks.calibrated() is True, 4), True) check("and gaze mode stays on", "gaze off" in helper_state["heard"], False) +check("and no second calibration opens", wait(lambda: svc.checks.check is not None, 3), False) +check("one calibration in the log", sum(m.startswith("full check:") for m in logs), 1) print("FAILED: " + ", ".join(failures) if failures else "all passed", flush=True) svc.running = False