pieza/region rule diverges client-vs-server - three ways - and every one is dormant until content-seed lands categorias
DORMANT TODAY, ARMS ITSELF WITH NO CODE CHANGE. Measured 2026-09-11 against prod: cirugiasCategorias = 0 rows, cirugiasSubcategorias = 0 rows, cirugias = 171 rows with 171 subcategoriaId NULL. Because of that the client and server currently agree - both collapse to "at least one of pieza OR region" - and the divergence below is invisible. It becomes live the moment content-seed lands categorias and backfills cirugias.subcategoriaId. THREE SEPARATE DIVERGENCES, not one. (1) CONJUNCTION: src/lib/practica-actions.ts:460 and :467 enforce requierePieza and requiereRegion INDEPENDENTLY - a categoria needing both rejects a practica that has only one - while the client rule (src/lib/practica-checks.ts, pieza-o-region) enforces OR and accepts it. Server wins, so the user is blocked by a server toast the inline validation said nothing about. (2) DERIVATION SOURCE: the client derives requierePieza/requiereRegion from the user-selected CATEGORIA DROPDOWN (practica-form.tsx categoriaOpts -> categoriaRow); the server derives them from the chosen CIRUGIA via cirugias.subcategoriaId -> cirugiasSubcategorias -> cirugiasCategorias. A cirugia reached without touching the dropdown (edit rehydration, a filtered list, a cirugia whose subcategoria belongs to a different categoria than the one selected) gets the !isATM fallback client-side and the real flags server-side. (3) NULL FALLBACK: a cirugia with subcategoriaId still NULL takes the server legacy OR branch while the client uses whatever categoria happens to be selected - opposite defaults. Duplicated at practica-actions.ts:1054-1077 for editarPractica, so any fix must land in both. ACCEPTANCE: one rule, one derivation source, asserted by a differential test that runs the client predicate and the server predicate over the same fixture set and fails on ANY disagreement - including the cases that cannot occur today, since those are precisely the ones that arrive with the seed. Do NOT close this by observing that the tables are empty; that is the reason it is filable, not the reason it is not.
Activity
-
Nothing had shipped; all divergences live in code, dormant (0 categorías, 0/171 cirugías chained). FOUR divergences, not three: (1) predicate - server per-flag independent, client OR; (2) source - server reads the cirugía's chain, client the categoría DROPDOWN; (3) server chain ignores isActive, client lookups are active-only; (4) no-chain fallback - client exempted ATM by name literal, server required >=1 for ATM too while its message said '(excepto ATM)'. WHICH WAS RIGHT: authority is client Minuta 16-5/17-5 + CU-04 ('>=1 pieza O >=1 region, NO y'; ATM/ortognatica satisfy it with region Ninguna) plus pm/01-product.md:60 (per-categoria flags, Cancer requires region). (1) neither: flags default TRUE,TRUE, so the server's per-flag rule would demand BOTH for every seeded categoria - contradicts the Minuta; the client's OR ignores a single-flag categoria - contradicts Cancer=region. Rule: TT=either, TF=pieza, FT=region, FF=optional. (2) server right. (3) server right - deactivating a categoria hides it, does not relax its cirugias. (4) server right on behaviour - prod: 15/16 ATM practicas carry region Ninguna (id 25). FIX: one pure module src/lib/pieza-region-rule.ts used by practica-checks, practica-form and both crear/editar; lookups carry each cirugia's own flags via the same base-table joins; ATM literal removed. Class-S (no schema/auth/email).
-
Pushed 907d11b, 1.17.36. PTD: Vercel status success; live /api/health deploymentId dpl_Aw1oqTkT3KLM4QzzjrHSJkM1tpTB = target_url id; remote package.json 1.17.36 (non-discriminating, unchanged version). appEvents warn/error since the deploy: 0. Build logs unreadable from this seat (EVO-104). Review asked: audit-general-ca coder-venus-cc-muwb32zan9b2; browser check asked: proxy-general-cc coder-venus-cc-muwb35agqj2e.
-
DONE 907d11b / 1.17.36 / dpl_Aw1oqTkT3KLM4QzzjrHSJkM1tpTB. WHICH WAS RIGHT: predicate - neither (server per-flag would demand BOTH for default TT categorias, contradicting Minuta 17-5 'O, no y'; client OR ignored single-flag categorias, contradicting Cancer=region) -> TT either / TF pieza / FT region / FF optional. Flag source, inactive-categoria handling, ATM fallback - server right; the form's ATM name exemption is removed (prod: 15/16 ATM practicas carry region Ninguna). One module src/lib/pieza-region-rule.ts drives the form and both actions. audit-general-ca PASS:907d11b. proxy-general-cc browser PASS on 2 items: ATM shows the required mark + hint; empty submit blocked inline; Ninguna clears it. TESTS: 20-case client-vs-server differential + harness control; forced red: old server logic red 3 TT cases, old client OR red 4 single-flag cases. NOT EXERCISED: category-specific arms live (0 cirugias chained on prod), crearPractica through the harness (same helper), a live create/edit. Vercel build logs unreadable from this seat (EVO-104).