Practica detail page shows raw camelCase codes instead of labels: roturaInstrumento, anteroSuperior - and the comment saying that is fine has been false since the catedra lists were seeded
MEASURED LIVE 2026-08-22. /practicas/[id] renders the STORED CODE for every lookup-backed value, not the human label. practica-detail.ts selects vc.value for campos, ci.value / cp.value for complicaciones intra and post, and r.regionAnatomicaValue for regiones - none of them joins lookupOptions for a label. So a student who recorded Rotura de instrumento reads roturaInstrumento, and Antero superior reads anteroSuperior. Confirmed value<>label on all 6 regionesAnatomicas and all 12 terraComplicacionesIntra rows. THE COMMENT IN THE PAGE IS THE INTERESTING PART: it says a lookup value shows its stored code when the catedra list is still empty - which is the state today for all four fields. That was TRUE when written and SHIPPING FALSIFIED IT - terra_35/38/39 and the venus import filled those lists (marca 19, injerto 4, zonaDadora 6, barrera 4 and 7), so the stated CONDITION expired while the sentence stayed. Same class as the /panel and TERRA-95 corrections. THE READ MUST BE UNSCOPED AND INACTIVE-INCLUSIVE, per db-terra-cc note in 06-lessons-applied: do NOT use resolveScopedVocabulary or vLookupOptions here. Those are active-only and picker-facing, so the moment an option is retired the practica that recorded it would render a blank or fall back to the code again - a historical record must resolve the label the value had, not the label the picker offers today. That means a straight lookupOptions join with no isActive/deletedAt filter, and it is a NEW read rather than a flag on the existing resolvers. FALLBACK STAYS: if no row matches at all, render the raw code rather than nothing - an unresolvable code is still evidence, and blank is not. Piezas already do this correctly (LEFT JOIN piezasDentarias) which is the pattern to copy. Not urgent for data integrity - the stored values are correct - but it is the first thing Puia sees when he opens a saved practica.
Activity
-
CORRECTION TO MY OWN FILING, made before writing any code. I said the page renders raw codes for campos, complicaciones, regiones and anestesia. WRONG on three of the four: page.tsx has a labelOf() helper and already resolves anestesiaType, regiones, complicacionesIntra and rolEnPractica against picker lists fetched in a Promise.all. I read practica-detail.ts (which does select raw values) and stopped there - the SQL is not the render. WHAT IS ACTUALLY BROKEN: campos ONLY. They are rendered as {c.value} with no labelOf call at all, so tipoInjerto shows the stored code. That is the real, visible defect and it is narrower than filed. WHAT IS LATENT AND STILL WORTH FIXING IN THE SAME PASS: the three that DO resolve use ACTIVE, SCOPED picker lists (getAnestesiaOptions, getRegionesAnatomicas, getComplicaciones, getScopedVocabulary). labelOf falls back to the raw code when no option matches - so the day an option is RETIRED, every past practica that recorded it silently reverts to showing camelCase. Same bug, deferred, and it fires exactly when the catedra tidies a vocabulary. Fixing only campos would leave four fields one retirement away from the bug I just filed. PLAN: resolve all five in the detail SQL with an unscoped, inactive-inclusive lookupOptions read (scalar subqueries, not joins - a join could multiply rows if two owners ever hold the same category+value), keep the raw code as the fallback, and drop the four picker fetches from the page. Fewer round trips and the historical record stops depending on what the picker offers today.
-
Live v0.24.45 dpl_2iC3KgKPvEyZT19ryNfF6Bexkjtx. Verified against real data before pushing: the newest practica returns "Terminal" and "Rotura de instrumento" where it returned terminal and roturaInstrumento. Only CAMPOS were actually rendering raw codes (I corrected the over-filed description before writing code); the other four resolved via active picker lists, which is the same bug one vocabulary retirement away, so all five moved to an unfiltered lookupOptions read in SQL. complicacionesPost deliberately NOT resolved - it is the post-op form initial state and labelling it would render nothing selected, then soft-delete every recorded complication on the next save. 8 arms, 325/325 green.