diff --git a/sage/gateway/hestia_dispatch.py b/sage/gateway/hestia_dispatch.py index fb82d0659..b9a404408 100644 --- a/sage/gateway/hestia_dispatch.py +++ b/sage/gateway/hestia_dispatch.py @@ -387,7 +387,7 @@ def _attach_named_scope_status(self, intent: BeingIntent, env: ResultEnvelope) - acted. Peers' answers were delivered as forum replies a beat later (mcnugget, 10-22: "a Sprout side fault"). This states what hestia holds for each named id, from the being's own scope queue, and nothing else: no advice, no verdict on the ask.""" - text = " ".join(str(intent.args.get(k, "")) for k in ("reason", "body", "why")) + text = " ".join(str(intent.args.get(k, "")) for k in ("reason", "body", "why", "text")) own = str((env.result or {}).get("request_id") or "") if isinstance(env.result, dict) else "" ids = [i for i in dict.fromkeys(_SCOPE_ID.findall(text)) if i != own][:3] if not ids: @@ -4732,8 +4732,11 @@ def publish(to: str, body: str) -> str: # Verbs whose free text may name a scope request; their receipts carry its status -# (HestiaF1aDispatcher._attach_named_scope_status). -_NAMES_SCOPE_IDS = ("request_scope", "peer_ask", "request_run") +# (HestiaF1aDispatcher._attach_named_scope_status). `say` joined after #518's 24 h on Sprout +# (2026-10-23..24): mentions of the expired id fell from ~65/day to 9, and the one that reached a +# person went by `say`, after a peer_ask redirected it there, so it met no fact. The fact goes +# on the being's receipt only; the turn it spoke is delivered as written. +_NAMES_SCOPE_IDS = ("request_scope", "peer_ask", "request_run", "say") def _scope_next(request_id, daemon_next) -> str: diff --git a/sage/gateway/tests/test_hestia_dispatch.py b/sage/gateway/tests/test_hestia_dispatch.py index c85ceb37e..9e4ac5de0 100644 --- a/sage/gateway/tests/test_hestia_dispatch.py +++ b/sage/gateway/tests/test_hestia_dispatch.py @@ -2590,6 +2590,21 @@ def test_a_scope_id_the_being_names_comes_back_with_its_status_in_the_same_recei assert "scope-0fefb5f67e46: pending" in env.to_tool_message() +def test_a_scope_id_named_in_say_gets_its_status_on_the_receipt_not_in_the_turn(): + """After #518, the expired id reached a person by `say` (a peer_ask had redirected it there).""" + from pathlib import Path + from sage.gateway import conversations as conv + d, root = _qdisp() + conv.create(Path(root), "dp", title="dp", participants=["dp", "sprout-being"], + writable_by=["dp", "sprout-being"]) + words = "scope-ef204d003703 has been pending for days; can you check?" + env = d(BeingIntent("say", {"to": "dp", "text": words}), _ALLOW) + assert env.ok, env.error + assert "scope-ef204d003703: expired" in env.to_tool_message() + assert conv.recent(Path(root), "dp", limit=1)[-1]["text"] == words # the turn is untouched + assert len(_mb_calls("hestia_scope_status")) == 1 + + def test_naming_no_scope_id_reads_nothing_and_adds_nothing(): d, _ = _qdisp() env = d(BeingIntent("request_scope", {"path": "/srv/elsewhere/x", "reason": "to read a peer's note"}), _ALLOW)