@@ -437,17 +437,40 @@ defmodule Electric.ShapeCache.ShapeStatusTest do
437437 assert ShapeStatus . shape_handle_for_log ( stack_id , id ) == "unknown, id: #{ id } "
438438 end
439439
440- test "ids minted on the restore path are resolvable both ways " , % { stack_id: stack_id } do
441- { :ok , { handle , _id } } = ShapeStatus . add_shape ( stack_id , shape! ( ) )
440+ test "refresh preserves the id of an existing shape " , % { stack_id: stack_id } do
441+ { :ok , { handle , id } } = ShapeStatus . add_shape ( stack_id , shape! ( ) )
442442 ShapeStatus.ShapeDb . mark_snapshot_complete ( stack_id , handle )
443443
444444 # refresh/1 repopulates the meta table from SQLite via
445- # populate_shape_meta_table/2, which mints a fresh id per restored handle.
445+ # populate_shape_meta_table/2, reusing (not re-minting) the id for a handle
446+ # it already knows, so the id stays stable across a refresh.
447+ :ok = ShapeStatus . refresh ( stack_id )
448+
449+ assert { :ok , ^ id } = ShapeStatus . id_for_handle ( stack_id , handle )
450+ assert { :ok , ^ handle } = ShapeStatus . handle_for_id ( stack_id , id )
451+ end
452+
453+ test "refresh prunes the reverse id mapping for handles removed elsewhere" , % {
454+ stack_id: stack_id
455+ } do
456+ { :ok , { removed_handle , removed_id } } = ShapeStatus . add_shape ( stack_id , shape! ( ) )
457+ { :ok , { kept_handle , kept_id } } = ShapeStatus . add_shape ( stack_id , shape2! ( ) )
458+ ShapeStatus.ShapeDb . mark_snapshot_complete ( stack_id , removed_handle )
459+ ShapeStatus.ShapeDb . mark_snapshot_complete ( stack_id , kept_handle )
460+
461+ # Simulate another instance deleting the shape from the shared SQLite while
462+ # our in-memory meta/reverse tables still reference it.
463+ :ok = ShapeStatus.ShapeDb . remove_shape ( stack_id , removed_handle )
464+
446465 :ok = ShapeStatus . refresh ( stack_id )
447466
448- assert { :ok , restored_id } = ShapeStatus . id_for_handle ( stack_id , handle )
449- assert is_integer ( restored_id )
450- assert { :ok , ^ handle } = ShapeStatus . handle_for_id ( stack_id , restored_id )
467+ # the removed handle's pre-refresh id no longer resolves in either direction
468+ assert :error = ShapeStatus . id_for_handle ( stack_id , removed_handle )
469+ assert :error = ShapeStatus . handle_for_id ( stack_id , removed_id )
470+
471+ # the surviving shape keeps its id
472+ assert { :ok , ^ kept_id } = ShapeStatus . id_for_handle ( stack_id , kept_handle )
473+ assert { :ok , ^ kept_handle } = ShapeStatus . handle_for_id ( stack_id , kept_id )
451474 end
452475
453476 test "list_shapes_with_ids returns each shape's handle, id and shape" , % { stack_id: stack_id } do
0 commit comments