fix(mattermost): harden delivery hygiene
PROBLEM: Mattermost threads can become invalid or enormous, exposing two failure modes: internal scratch/reasoning/commentary displays could leak into persistent Mattermost threads via global display toggles, while rejected threaded user-visible replies could disappear unless every failed send fell back flat. A broad flat fallback would pollute channels with tool/status/progress noise. SOLUTION: Require explicit Mattermost platform opt-in for scratch displays, keep using the existing notify=True metadata marker for user-visible final text/media/file replies, and allow the Mattermost plugin adapter to flat-fallback only notify-worthy sends whose threaded POST failure looks like a broken root/thread. Keep tool/status/progress and other non-notify sends thread-strict. Add regression tests for display opt-in, notify-only broken-thread fallback, generic API failure suppression, and stream notify metadata. Verification: tests/gateway/test_mattermost.py tests/gateway/test_stream_consumer.py tests/gateway/test_stream_consumer_thread_routing.py tests/gateway/test_stream_consumer_fresh_final.py tests/gateway/test_stream_consumer_draft.py; tests/gateway/test_session_api.py tests/gateway/test_status_command.py tests/gateway/test_resume_command.py tests/hermes_cli/test_commands.py; py_compile touched gateway files; git diff --check. Session: Mattermost thread 6qg8e9dd1pd9pkhi74xyaa1mry, 2026-06-01.
This commit is contained in:
committed by
Teknium
parent
925b0d1ab5
commit
16fc717091
@@ -106,6 +106,42 @@ class TestInitialReplyToId:
|
||||
assert call_kwargs["metadata"] == {**metadata, "expect_edits": True}
|
||||
assert metadata == {"thread_id": "omt_topic789"}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_final_first_send_marks_metadata_notify_true(self):
|
||||
"""Final streaming sends should use the existing notify=True marker."""
|
||||
adapter = _make_adapter()
|
||||
consumer = GatewayStreamConsumer(
|
||||
adapter,
|
||||
"chat_123",
|
||||
metadata={"thread_id": "root_post_123"},
|
||||
initial_reply_to_id="reply_post_456",
|
||||
)
|
||||
|
||||
await consumer._send_or_edit("Final answer", finalize=True)
|
||||
|
||||
call_kwargs = adapter.send.call_args[1]
|
||||
metadata = call_kwargs["metadata"]
|
||||
assert metadata["thread_id"] == "root_post_123"
|
||||
assert metadata["notify"] is True
|
||||
assert "delivery_kind" not in metadata
|
||||
assert "allow_flat_fallback" not in metadata
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_nonfinal_first_send_does_not_mark_notify(self):
|
||||
"""Preview/interim streaming sends must not be notify-worthy."""
|
||||
adapter = _make_adapter()
|
||||
consumer = GatewayStreamConsumer(
|
||||
adapter,
|
||||
"chat_123",
|
||||
metadata={"thread_id": "root_post_123"},
|
||||
initial_reply_to_id="reply_post_456",
|
||||
)
|
||||
|
||||
await consumer._send_or_edit("Preview", finalize=False)
|
||||
|
||||
metadata = adapter.send.call_args[1]["metadata"]
|
||||
assert metadata == {"thread_id": "root_post_123", "expect_edits": True}
|
||||
|
||||
|
||||
class TestOverflowFirstMessage:
|
||||
"""Verify thread routing is preserved when the first message overflows."""
|
||||
|
||||
Reference in New Issue
Block a user