fix(learning): never broadcast agent learnings to human roles (#250)

Every recorded learning was sent as a knowledge-share notification to all agents,
and the recipient query included the human / human-driven roles (CEO, prompter,
secretary) — so the CEO's inbox filled with agent learnings. Exclude those roles
from the recipient query. The human-role set is resolved from the foundation enum
at import (a module constant) so a test that patches the models.base AgentRole
alias can't break it.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
Renzo F
2026-06-24 03:35:02 +02:00
committed by GitHub
co-authored by Renn F
parent 40d685bd9f
commit d8254300cd
3 changed files with 52 additions and 4 deletions
@@ -120,6 +120,41 @@ async def test_team_scope_role_uppercase_via_agent_role_enum(
assert other_role.id in notified_ids
@pytest.mark.asyncio
async def test_org_scope_excludes_human_roles(
shared_session: AsyncSession,
) -> None:
"""Human / human-driven roles are never learning recipients, even at ORG
scope: knowledge-share is a signal for agents, not noise in the human's inbox.
"""
author = _make_agent(AgentRole.DEVELOPER)
peer = _make_agent(AgentRole.QA)
ceo = _make_agent(AgentRole.CEO)
secretary = _make_agent(AgentRole.SECRETARY)
shared_session.add_all([author, peer, ceo, secretary])
await shared_session.flush()
svc = LearningPropagationService()
await svc.initialize(_StubOptimal())
learning = await svc.record_learning(
RecordLearningParams(
agent_id=cast("uuid.UUID", author.id),
agent_role="developer",
content="A useful pattern worth sharing org-wide",
learning_type=LearningType.PATTERN,
scope=LearningScope.ORG,
)
)
notified_ids = {
n.target_agent_id
for n in svc._notification_queue
if n.learning_id == learning.learning_id
}
assert peer.id in notified_ids
assert ceo.id not in notified_ids
assert secretary.id not in notified_ids
@pytest.mark.asyncio
async def test_team_scope_invalid_role_skips_filter(
shared_session: AsyncSession,