forked from molecule-ai/molecule-core
Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1) with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo. Brand: Starfire → Molecule AI. Slug: starfire / agent-molecule → molecule. Env vars: STARFIRE_* → MOLECULE_*. Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform. Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent. DB: agentmolecule → molecule. History truncated; see public repo for prior commits and contributor attribution. Verified green: go test -race ./... (platform), pytest (workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
87 lines
4.3 KiB
Markdown
87 lines
4.3 KiB
Markdown
# Event Log
|
|
|
|
Every structural change appends an immutable row to `structure_events`. The table is **append-only** — rows are never updated or deleted. This is the event sourcing pattern.
|
|
|
|
## How It Works
|
|
|
|
The `workspaces` table is a **projection** of these events — it represents current state. If you replay all events from the beginning, you get the same `workspaces` table.
|
|
|
|
## Event Types
|
|
|
|
**The rule: structural changes are persisted, presentational changes are ephemeral.**
|
|
|
|
The test: "If I replayed all `structure_events` from scratch, would I reconstruct a fully working system?" If yes, the event log is complete. Canvas positions don't affect system behavior — they belong in `canvas_layouts`, not `structure_events`.
|
|
|
|
### Persisted to structure_events (AND broadcast via WebSocket)
|
|
|
|
```
|
|
WORKSPACE_PROVISIONING workspace being created
|
|
WORKSPACE_PROVISION_FAILED launch error — needs audit trail
|
|
WORKSPACE_ONLINE availability change
|
|
WORKSPACE_OFFLINE availability change
|
|
WORKSPACE_DEGRADED health change
|
|
WORKSPACE_REMOVED permanent change
|
|
WORKSPACE_MOVED hierarchy change (different parent, NOT canvas drag)
|
|
WORKSPACE_EXPANDED hierarchy change
|
|
WORKSPACE_COLLAPSED hierarchy change
|
|
AGENT_ASSIGNED agent change
|
|
AGENT_REMOVED agent change
|
|
AGENT_REPLACED agent change
|
|
AGENT_MOVED agent moved between workspaces
|
|
AGENT_CARD_UPDATED capabilities changed
|
|
```
|
|
|
|
### WebSocket only, NOT persisted to structure_events
|
|
|
|
```
|
|
TASK_UPDATED current task changed — saved to workspaces.current_task
|
|
ACTIVITY_LOGGED activity log created — saved to activity_logs table
|
|
Canvas node dragged presentational — saved to canvas_layouts
|
|
Canvas viewport changed presentational — saved to canvas_viewport
|
|
Node collapsed/expanded presentational UI toggle — saved to canvas_layouts
|
|
(different from WORKSPACE_EXPANDED which is a structural team expansion)
|
|
```
|
|
|
|
`TASK_UPDATED` and `ACTIVITY_LOGGED` use `BroadcastOnly()` — they are sent over WebSocket but not recorded in `structure_events`. They have their own storage: `workspaces.current_task` column and `activity_logs` table respectively. This separation keeps `structure_events` focused on structural changes that define the org chart, while operational activity (A2A communications, task updates, agent logs) lives in `activity_logs` with its own retention policy.
|
|
|
|
`WORKSPACE_MOVED` is the nuanced case: a workspace moved to a different parent (hierarchy change) is structural and persisted. A node dragged to a new canvas position is presentational and saved to `canvas_layouts` only.
|
|
|
|
See [WebSocket Events](../api-protocol/websocket-events.md) for the full JSON payload of each event type.
|
|
|
|
## Why This Matters
|
|
|
|
1. **Complete audit trail** — you always know exactly what happened and when
|
|
2. **Meaningful responses for removed workspaces** — other workspaces can get context when querying a workspace that no longer exists
|
|
3. **Canvas timeline** — the canvas can show a timeline of changes for any workspace
|
|
4. **Easier debugging** — debugging distributed agent systems becomes much easier with a full history
|
|
5. **Future: time travel** — replay to any point in time ("what did our org chart look like last Tuesday?")
|
|
|
|
## Schema
|
|
|
|
```sql
|
|
CREATE TABLE structure_events (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
event_type TEXT NOT NULL,
|
|
workspace_id UUID,
|
|
agent_id UUID,
|
|
target_id UUID,
|
|
payload JSONB,
|
|
created_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
```
|
|
|
|
The `payload` JSONB field contains event-specific data (e.g. the old and new URL for a workspace move, the reason for a deletion).
|
|
|
|
## Rules
|
|
|
|
- **Never UPDATE or DELETE rows** in `structure_events`. It is append-only.
|
|
- The `workspaces` table is the mutable projection — update that instead.
|
|
- Every state change must produce an event before updating the projection.
|
|
|
|
## Related Docs
|
|
|
|
- [Database Schema](./database-schema.md) — Full table definitions
|
|
- [Registry & Heartbeat](../api-protocol/registry-and-heartbeat.md) — Events generated by registration
|
|
- [Platform API](../api-protocol/platform-api.md) — Event query endpoints
|
|
- [WebSocket Events](../api-protocol/websocket-events.md) — Full event payload reference
|