f3c4ba72b5a0ada0cb55cb9410bf2725771a3f76
Adds IiosInteractionAnnotation — an actor attaches an OPAQUE (annotationType, value)
label to an interaction. The kernel stores + aggregates them but never interprets the
strings (the chat app writes type "reaction" / value = emoji); the same primitive backs
pins/saves/flags/tags later. No chat vocabulary in kernel code — verified by grep.
- MessageService.toggleAnnotation(): governed (participant-only via new OPA rule
iios.interaction.annotate), idempotent toggle keyed on
(scope, interaction, actor, type, value); history DTO carries aggregated
{ type, value, users[] } groups.
- Gateway: `annotate` event → broadcasts `annotation` (refreshed user list) to the room.
- DevOpaPort: annotate allowed only for thread members (real OPA can tighten later).
- Migration add_interaction_annotations (additive; dev data untouched).
Tests: 178 pass (+3: toggle/aggregate, coexisting values, non-member denied).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Description
No description provided
Languages
TypeScript
88.8%
JavaScript
10.4%
Dockerfile
0.4%
HTML
0.3%
Shell
0.1%