Unify domain_events + ap_activities into AP-shaped event bus

All cross-service events now flow through ap_activities with a unified
EventProcessor. Internal events use visibility="internal"; federation
activities use visibility="public" and get delivered by a wildcard handler.

- Add processing columns to APActivity (process_state, actor_uri, etc.)
- New emit_activity() / register_activity_handler() API
- EventProcessor polls ap_activities instead of domain_events
- Rewrite all handlers to accept APActivity
- Migrate all 7 emit_event call sites to emit_activity
- publish_activity() sets process_state=pending directly (no emit_event bridge)
- Migration to drop domain_events table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-22 16:19:29 +00:00
parent d697709f60
commit 2e9db11925
15 changed files with 389 additions and 168 deletions

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from shared.events import emit_event
from shared.events import emit_activity
from shared.models.container_relation import ContainerRelation
@@ -40,17 +40,19 @@ async def attach_child(
if label is not None:
existing.label = label
await session.flush()
await emit_event(
await emit_activity(
session,
event_type="container.child_attached",
aggregate_type="container_relation",
aggregate_id=existing.id,
payload={
activity_type="Add",
actor_uri="internal:system",
object_type="rose:ContainerRelation",
object_data={
"parent_type": parent_type,
"parent_id": parent_id,
"child_type": child_type,
"child_id": child_id,
},
source_type="container_relation",
source_id=existing.id,
)
return existing
# Already attached and active — no-op
@@ -77,17 +79,19 @@ async def attach_child(
session.add(rel)
await session.flush()
await emit_event(
await emit_activity(
session,
event_type="container.child_attached",
aggregate_type="container_relation",
aggregate_id=rel.id,
payload={
activity_type="Add",
actor_uri="internal:system",
object_type="rose:ContainerRelation",
object_data={
"parent_type": parent_type,
"parent_id": parent_id,
"child_type": child_type,
"child_id": child_id,
},
source_type="container_relation",
source_id=rel.id,
)
return rel
@@ -139,17 +143,19 @@ async def detach_child(
rel.deleted_at = func.now()
await session.flush()
await emit_event(
await emit_activity(
session,
event_type="container.child_detached",
aggregate_type="container_relation",
aggregate_id=rel.id,
payload={
activity_type="Remove",
actor_uri="internal:system",
object_type="rose:ContainerRelation",
object_data={
"parent_type": parent_type,
"parent_id": parent_id,
"child_type": child_type,
"child_id": child_id,
},
source_type="container_relation",
source_id=rel.id,
)
return True