fix(bot-screen): no-op lease transitions do not bump the epoch

release() on an agent-held lease and a same-viewer re-acquire rewrote the record and bumped the
epoch, so an admitted in-flight agent action looked overtaken and was voided by a double-clicked
Hand back or a stray CLI stop; the re-acquire also reset `since` and wiped the on-screen reason.
This commit is contained in:
teknium1
2026-09-14 17:35:21 -07:00
parent e4a9e7f21e
commit 4ffa767127
2 changed files with 19 additions and 0 deletions

View File

@@ -193,3 +193,16 @@ def test_lease_files_are_private_even_when_the_lease_is_written_before_the_scree
for path in (sd, sd / "lease.json", sd / "lease.lock"):
assert path.exists(), path
assert stat.S_IMODE(path.stat().st_mode) & 0o077 == 0, f"{path.name} is {oct(path.stat().st_mode)}"
def test_no_op_transitions_do_not_bump_the_epoch():
"""Callers void an admitted in-flight action when the epoch moved. A release on an agent-held lease
(double-clicked Hand back, a stray CLI stop) or the same viewer re-acquiring changes nothing real, so
it must not make a legitimate agent action look overtaken."""
e0 = lease.get().epoch
assert lease.release().epoch == e0
got = lease.acquire("v1", reason="log in please")
assert got.epoch == e0 + 1
again = lease.acquire("v1")
assert again.epoch == got.epoch and again.reason == "log in please" and again.since == got.since
assert lease.acquire("v2").epoch == got.epoch + 1 # a different viewer IS a transition

View File

@@ -170,6 +170,8 @@ def acquire(viewer_id: str, *, profile_key: Optional[str] = None, reason: str =
"""Human ``viewer_id`` takes control. Last writer wins: a second viewer evicts the first, and the
RFB bridge closes the evicted socket so its UI drops to view-only."""
def _m(lease: Lease) -> bool:
if lease.holder == HUMAN and lease.viewer_id == viewer_id:
return False # already theirs: no epoch bump, `since` and the reason on screen stay put
# The agent's ask ("please log in to X") stays as the takeover reason: the human needs it
# on screen WHILE they act, not only before they clicked Take over.
lease.holder, lease.viewer_id, lease.since = HUMAN, viewer_id, time.time()
@@ -194,6 +196,10 @@ def release(viewer_id: Optional[str] = None, *, profile_key: Optional[str] = Non
# caller that never inspects the return value leaves a trace.
logger.info("bot-desktop lease: release by %r ignored, another viewer holds", viewer_id)
return False
if lease.holder == AGENT:
# Already the agent's. Bumping the epoch here would make a legitimately admitted in-flight
# agent action (a double-clicked Hand back, a stray CLI stop) look overtaken and get voided.
return False
lease.holder, lease.viewer_id, lease.since, lease.reason = AGENT, None, time.time(), ""
return True
return _transition(profile_key, _m)