Skip to content

Item Delete Bug #782 -- PROPAGATE Fork Fix

Status: In Progress Ticket: Arda-cards/management#782 Repository: operations Branch: jmpicnic/management-782

A PUT /v1/item/item/{eId} with the default PROPAGATE qualifier creates a forked bitemporal version chain when the item has two or more supplies. The fork makes the item non-deterministic to read and permanently blocks deletion with the error:

400: Record[ITEM] cannot be deleted because it has a successor

ItemService.update() creates the updated item record once, then iterates over the item’s supplies. Each updateFixed() call ends with parentUniverse.touch(), which reads the item tip and inserts a new record pointing to it as previous. Within the same database transaction, all touch() calls read the same pre-loop tip (because recorded_as_of = NOW() is identical for all records in the transaction) and insert separate successors pointing to the same parent — creating a diamond fork.

For an item with two supplies, three INSERT INTO item statements are generated in a single request. Two of them point to the same previous record, producing the fork.

Add updateSupplyOnly() to ItemSupplyUniverse — identical to updateFixed() but omitting the final parentUniverse.touch(). Implement a private updateSupplyOnly() on ItemService.Impl that delegates to the universe method. Change the PROPAGATE supply loop in ItemService.update() to call updateSupplyOnly() instead of updateFixed().

The parent item record is already created correctly by updater() before the supply loop begins. The supply loop only needs to persist the individual item_supply child records.

#DescriptionStatus
1Set up worktree and branchPlanned
2Write regression tests (PROPAGATE fork detection + delete blocked)Planned
3Run regression tests, confirm expected failuresPlanned
4Implement production code fixPlanned
5Run regression tests, confirm they passPlanned
6Full buildPlanned
7API testsPlanned
8Commit, push, PRPlanned
9Monitor CIPlanned

In scope: updateSupplyOnly() method, ItemService.update() supply loop change, regression tests.

Out of scope: Changing recorded_as_of DEFAULT NOW() behavior in common-module; data cleanup of the existing forked item (handled by separate SQL scripts on the ticket); frontend changes.

The affected tenant and item are identified in the ticket. Cleanup SQL scripts were posted as a ticket comment and are separate from the code fix.