mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
[chore] logical-gaps: a2a service hierarchy gate (typed, unconditional) + persist skill on message row (3 gaps)
create_a2a_notification gated A2A hierarchy only when both ends resolved (`if from_agent and target_agent:`), so an unattributed (from_agent falsy) or unresolvable-target request slipped past the hierarchy matrix and dispatched with from_agent='unknown' / to_agent='' — and a denial came back as a bare ValueError indistinguishable from the missing-task_id ValueError. Require both ends present, then validate via the shared typed validate_a2a_access path (A2AAccessDeniedError + route_hint) so the legacy notification surface enforces the same who-may-talk-to-whom invariant as the conversation path. send() accepts skill= and the gateway callers (qa/doc/pr_gate) pass it expecting the receiver to learn which capability the message is about, but send_chat_message never read it from options — silently dropped. Persist a nullable skill column (migration 054) on a2a_messages, wire it through send_chat_message + _msg_to_model + the A2AChatMessage model, and fix the send() docstring (it claimed 'recorded in message metadata'). TDD: 4 red→green (skill recorded on message + surfaces in inbox; permission denied raises typed A2AAccessDeniedError with route_hint; self-A2A raises typed; missing from_agent raises instead of silent dispatch). 103 a2a integration tests green; ruff/mypy clean; migration 054 verified upgrade/downgrade on throwaway PG.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
"""Persist ``skill`` on a2a_messages.
|
||||
|
||||
Directed A2A ``send()`` accepts a ``skill=`` (the capability the sender is
|
||||
exercising/requests of the receiver, e.g. ``code_review``) and the gateway
|
||||
callers (qa / doc / pr_gate) pass it expecting the receiver to learn which
|
||||
capability the message is about. Until now ``send_chat_message`` never read it
|
||||
from options, so it was silently dropped — the receiver's inbox showed a bare
|
||||
message with no skill context. This adds a nullable ``skill`` column so the
|
||||
capability rides on the row and surfaces in the inbox model.
|
||||
|
||||
Revision ID: 054_a2a_message_skill
|
||||
Revises: 053_playbook_archived_attr
|
||||
Create Date: 2026-06-30
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision = "054_a2a_message_skill"
|
||||
down_revision = "053_playbook_archived_attr"
|
||||
branch_labels: dict[str, str] | None = None
|
||||
depends_on: dict[str, str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("a2a_messages", sa.Column("skill", sa.String(100), nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("a2a_messages", "skill")
|
||||
Reference in New Issue
Block a user