diff --git a/internal/inventory/migrations/0048-the-artifact-store-seat-is-named-for-its-scope.sql b/internal/inventory/migrations/0048-the-artifact-store-seat-is-named-for-its-scope.sql index 26f8a72..2ac3538 100644 --- a/internal/inventory/migrations/0048-the-artifact-store-seat-is-named-for-its-scope.sql +++ b/internal/inventory/migrations/0048-the-artifact-store-seat-is-named-for-its-scope.sql @@ -5,7 +5,20 @@ -- than for the mesh; ADR 0121 decided the rename and deferred it because a delivering seat that stops -- resolving mid-flight takes a provision away from every consumer. ADR 0122 removed that risk: a seat's -- former name is an alias that resolves to it forever, a held record follows the rename by cascade, and --- a claim written with the old name still holds. So the rename is one update and one alias. +-- a claim written with the old name still holds. +-- +-- **Both rows may exist when this runs.** A controller whose compiled defaults already carry the new +-- name seeds it as a new seat the moment it can, and on the mesh this was written for that happened +-- before the rename: the first form of this migration renamed into a duplicate key and the control +-- node's prepare failed on every attempt (2026-09-30). So: if the new row is already there, the old +-- row's holding moves to it and the old row goes; otherwise the old row is renamed. Either way the old +-- name becomes an alias. +update seat_holding set seat = 'mesh-artifact-store' + where seat = 'the-artifact-store' + and exists (select 1 from seat where name = 'mesh-artifact-store'); +delete from seat + where name = 'the-artifact-store' + and exists (select 1 from seat where name = 'mesh-artifact-store'); update seat set name = 'mesh-artifact-store' where name = 'the-artifact-store'; insert into seat_alias (alias, seat) values ('the-artifact-store', 'mesh-artifact-store') on conflict (alias) do update set seat = excluded.seat;