PLUTO-91 db half: practicas_live_natural_key_idx must key on the CANONICAL pieza set, not the raw typed string (permuted-order duplicates still win the concurrent race)
App-side half shipped v2.23.58 (coder lane): the tier-1 pre-check now compares canonicalPiezaKey(piezaDentaria) - split on [\s,]+, dedupe, sort, join with ',' - so '12, 11' and '11, 12' are recognised as the same practica. The unique index still keys on the raw string, so the pre-check is now deliberately STRICTER than its own backstop. Safe in that direction, but it leaves one hole: two CONCURRENT submissions with permuted pieza order clear the pre-check window AND do not collide in the index, so the race backstop never fires and a permuted duplicate is still creatable. Wanted: the index on a canonical expression - a functional UNIQUE index over an IMMUTABLE canonicalisation of piezaDentaria, or a stored normalised key column maintained alongside it. HARD CONSTRAINT: storage and display order stay AS ENTERED (clinicians read the first pieza as primary); only the key is canonical. Must stay byte-compatible with canonicalPiezaKey in src/lib/dental-utils.ts. Note practica-actions.ts:540's 23505 recovery lookup keys on the raw string ON PURPOSE (it runs only after the raw-keyed index raised, so the colliding row is a byte-for-byte match) and will need revisiting if the index changes. NOT MEASURED - coder cannot read prod: whether permuted-order duplicate pairs already exist live in practicas. Count that BEFORE creating the index, since a UNIQUE index over the canonical form will fail to build if any such pair exists. That is a prerequisite, not a curiosity.
Activity
-
Already shipped: migration 117 (bf66fa9) replaced practicas_live_natural_key_idx's raw-string key with f_canonicalPiezaKey() to match the PLUTO-91 app-side pre-check. App-side 23505 recovery lookup (practica-actions.ts:641) already updated too - no surviving gap. bwi row was never closed at ship time.