Duplicate-conducto guard is the dominant practica-form rejection (29/32 in 30d)
practicas/nueva/actions.ts:474 rejects two conductos with the same conductoLabelOptionId on one pieza. Correct rule, bad surfacing. Three defects: (1) practica-form.tsx:609 validates conductos with no Tipo client-side but does NOT check for duplicates, so the rejection only lands after submit; (2) the message does not name which conducto is duplicated; (3) users read 'No se puede repetir un conducto en la pieza 47' as a restriction on the pieza - SOP-MARS-70 was filed with the subject 'no se puede repetir la pieza 47'. Measured 2026-09-25: 29 of 32 create-rejected events in 30 days are this one guard, ~8 distinct users, mostly molars (47, 46, 36, 37, 16, 26); one student blocked 2h25m before filing. To confirm with the clinical lane: conductoLabel has no second mesiovestibular (MV2) option, only '4to conducto' and 'Otro', which may be pushing students to pick MV twice. Fix: client-side duplicate check naming the conducto index, plus reworded copy.
Activity
-
coder-mars-cc
-
Assigned coder-mars-cc 2026-09-28 under Elazar's standing instruction (CLI, nqla 6): which agent takes a bug is immaterial and routing is never to be raised with him. The loop is now mine to drive - assign, verify it actually got done, reassign to the next agent if not, and do it myself if nobody does. Raising priority is warranted on the evidence already in this row: the duplicate-conducto guard is 29 of 32 práctica-form rejections in 30 days, which is a user-facing break, not a papercut.
-
1
-
FIXED AND PUSHED by me, mars v2.84.0, commit 5542a5e. coder-mars-cc had the assignment and said it would not touch the practica form, so under Elazar's standing instruction (assign, verify, reassign, then do it myself) I did it. All three surfacing defects plus one functional defect neither of us had listed. 1. The form now rejects a duplicate Tipo inline, before submit. practica-form.tsx validated a MISSING Tipo and never a repeated one, so every hit cost a round trip. 2. The message names the Tipo and BOTH conducto positions: 'En la pieza 47, los conductos 1 y 3 tienen el mismo Tipo (Mesiovestibular (MV))'. 3. It states outright 'La pieza no es el problema y podes cargar todos los conductos que tenga', because SOP-MARS-70 was filed as 'no se puede repetir la pieza 47'. 4. FUNCTIONAL, not surfacing: the guard keyed on conductoLabelOptionId alone, so two 'Otro' conductos with DIFFERENT free text were rejected as a duplicate though they are two real conductos. Now 'Otro' is keyed by its trimmed, case-folded text. This matters because the option list has no MV2/MB2 (measured: 8 options, vestibular/palatina/mesiovestibular/distovestibular/mesiolingual/distolingual/cuarto/otro), so an extra canal is recorded as '4to conducto' or 'Otro'. Rule and message live in src/lib/conducto-duplicates.ts, used by BOTH the client pre-check and the server backstop, so they cannot drift - a client guard that rejects a different set than the server is worse than none. 14 new unit tests, suite 900 pass (was 886). Own error code DUPLICATE_CONDUCTO, added to USER_INPUT_REJECTION_CODES, so the next count is a group-by instead of a message LIKE. Updated measurement, 35d to 2026-09-28: 32 rejections, 9 distinct piezas, 47 worst at 11 over 3 users. Latest was 2026-09-27 23:39, two 52s apart from one user, so it was still biting the day before the fix. Includes piezas 25, 24 and 14 - upper premolars, which argues the cause is form confusion rather than missing molar anatomy. TWO FOLLOW-UPS, neither blocking, both verified by grep not guessed. (a) The EDIT path has no duplicate-conducto guard at all - no match for the rule outside nueva/actions.ts - so an edit can persist a pair the create path forbids. (b) appEvents.detail is empty on every one of these rejections and errorName is not set, which is why the duplicated Tipo could not be read from the logs and had to be inferred. Worth capturing the Tipo pair in detail.
-
DEPLOY VERIFIED LIVE: /api/health reports version 2.84.0, deployment dpl_Ga7LuvZVXKArfg1ePSVCYJGnquxu, 09:35Z. Previous was 2.83.0/dpl_GL6S7yC84EGc7o1JBygfsPQAkPpH, so the swap is observed, not assumed.
-
completed