From 9650366d34bfcc0b5b78c7c66b9a48600f9e02dd Mon Sep 17 00:00:00 2001 From: anti Date: Sun, 26 Apr 2026 21:40:06 -0400 Subject: [PATCH] fix(orchestrator): drop topology_deckies FK on event src/dst columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once the orchestrator started seeing fleet + SWARM shard sources via list_running_deckies (a844148), every event row landing on a fleet decky broke the FK to topology_deckies — the column now carries opaque ids ("local:omega-decky" for fleet, "host_uuid:decky_name" for shards) that will never match topology_deckies.uuid. Symptom on the operator's mothership: IntegrityError 1452 — orchestrator_events_ibfk_2 FK violated on every tick once the reconciler populated fleet_deckies. Index on dst_decky_uuid is preserved (the dashboard reads "events for this decky" frequently); only the FK is removed. Keeps data integrity loose by design — events are append-only history that should outlive the deckies they reference. Existing MySQL deployments need the FK dropped manually: ALTER TABLE orchestrator_events DROP FOREIGN KEY orchestrator_events_ibfk_2, DROP FOREIGN KEY orchestrator_events_ibfk_1; SQLite users are unaffected — SQLite doesn't enforce FKs by default. --- decnet/web/db/models/orchestrator.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/decnet/web/db/models/orchestrator.py b/decnet/web/db/models/orchestrator.py index ac71b7ba..5d217eab 100644 --- a/decnet/web/db/models/orchestrator.py +++ b/decnet/web/db/models/orchestrator.py @@ -41,12 +41,14 @@ class OrchestratorEvent(SQLModel, table=True): kind: str = Field(index=True, max_length=16) # traffic|file protocol: str = Field(index=True, max_length=16) # ssh for MVP action: str = Field(max_length=64) # exec:uptime|file:create|... - src_decky_uuid: Optional[str] = Field( - default=None, foreign_key="topology_deckies.uuid", index=True - ) - dst_decky_uuid: str = Field( - foreign_key="topology_deckies.uuid", index=True - ) + # No FK to topology_deckies: dst/src may be a TopologyDecky.uuid + # (MazeNET source), a "host_uuid:name" composite (fleet / SWARM shard + # sources), or — for retired deckies — a row that's already gone. The + # column is an opaque identifier matching whatever + # ``BaseRepository.list_running_deckies`` emits in its ``uuid`` field. + # Index is kept; the FK was misleading and broke fleet-source events. + src_decky_uuid: Optional[str] = Field(default=None, index=True) + dst_decky_uuid: str = Field(index=True) success: bool = Field(default=False, index=True) payload: str = Field( sa_column=Column("payload", Text, nullable=False, default="{}")