Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions loopx/capabilities/native_chat/external_conversations.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,11 @@ def recover(self, *, request_ref: str | None = None) -> None:
try:
if row.get("delivery_verified") and not row.get("commission_adoption_pending"):
continue
# Completed commands have no Core execution left to recover.
# The transport still revalidates the binding and source before
# delivering their pending response; do not add an idle probe.
if row["status"] == "command_completed" and not row.get("commission_adoption_pending"):
continue
self.bindings.resolve(binding_id=row["binding_id"], **row["source"])
if row["status"] == "prepared":
self.admit(binding_id=row["binding_id"], source=row["source"], request_ref=row["request_ref"],
Expand Down
48 changes: 46 additions & 2 deletions tests/test_lark_private_conversations.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,50 @@ def finish_group_turn(runtime, transport, *, message):
return row


@pytest.mark.parametrize("command", ["/status", "/stop", "/help"])
def test_completed_command_recovery_leaves_provenance_to_delivery(ordinary, command): # noqa: F811
store, runtime, provider, transport = connect_group(ordinary)
root = provider.topic("command-root", "/help")
event = provider.topic("completed-command", command, root=root["message_id"])
try:
assert transport.admit("notes-app", event)["status"] == "command_recorded"
path = next(path for path in transport.root.glob("*.json")
if json.loads(path.read_text())["event"]["message_id"] == event["message_id"])
record = json.loads(path.read_text())
native_path = transport.core.root / f"{record['request_ref']}.json"
before = native_path.read_bytes()
assert json.loads(before)["status"] == "command_completed"

# There is no command execution to recover. Provider availability must
# not add an identity round-trip to this already committed Core state.
provider.calls.clear()
transport.core.recover(request_ref=record["request_ref"])
assert provider.calls == []
assert native_path.read_bytes() == before

pending = json.loads(before) | {"commission_adoption_pending": True}
native_path.write_text(json.dumps(pending))
transport.core.recover(request_ref=record["request_ref"])
assert any("auth" in call for call in provider.calls)
assert json.loads(native_path.read_text()) == pending
native_path.write_bytes(before)

# Skipping idle recovery does not skip the delivery owner's fresh check.
provider.bot_ready = False
assert transport.reconcile_request(path) == 0
assert provider.writes == []
assert json.loads(path.read_text())["status"] != "delivered"

provider.bot_ready = True
assert transport.reconcile_request(path) == 1
assert json.loads(path.read_text())["status"] == "delivered"
assert json.loads(native_path.read_text())["delivery_verified"] is True
assert len(provider.writes) == 1
assert provider.topic_writes[0][:2] == (event["chat_id"], root["message_id"])
finally:
runtime.close()


def test_lark_transport_recovery_returns_on_original_admission_without_model_replay(ordinary, monkeypatch): # noqa: F811
from test_chat_turn_steering import install_transport_failure

Expand Down Expand Up @@ -1576,7 +1620,7 @@ def reconcile_request(self, path):



def test_scoped_recovery_does_not_probe_unrelated_app_and_revocation_blocks_reply(ordinary): # noqa: F811
def test_completed_command_recovery_defers_app_probe_and_revocation_blocks_reply(ordinary): # noqa: F811
store, runtime, provider, transport = connect(ordinary)
try:
for profile in ["notes-app", "steward-app"]:
Expand All @@ -1587,7 +1631,7 @@ def test_scoped_recovery_does_not_probe_unrelated_app_and_revocation_blocks_repl
original = transport.bindings.observe
transport.bindings.observe = lambda profile: (observed.append(profile), original(profile))[1]
transport.core.recover(request_ref=first["request_ref"])
assert observed == ["notes-app"]
assert observed == [] # A completed command has no Core work to recover.
binding = transport.bindings.read()
transport.bindings.disconnect(first["binding_id"], expected_revision=binding["revision"])
assert transport.reconcile_request(transport.root / f"{first['request_ref']}.json") == 0
Expand Down
Loading