createTerraPractica pasa a resolveOrCreatePacienteForApp('terra', ...)
ENAMEL-36 fase 1. createTerraPractica llama hoy al resolveOrCreatePaciente de 9 argumentos, sin gate de scope: acepta cualquier documentoType activo del catalogo global (cedula, libretaCivica, libretaEnrolamiento) aunque terra solo ofrece dni y pasaporte. La fase 1 mueve esa unica llamada a resolveOrCreatePacienteForApp con 'terra' al frente, que refuerza el scope y rechaza lo no ofrecido. Firma de 24 argumentos, INVOKER y search_path se conservan; CREATE OR REPLACE los descarta en silencio si no se reescriben. El conjunto de outcomes es identico (created/matched/matchedWithMismatch/emailCollision), asi que el chequeo fail-closed de terra sigue valiendo. NOTA MEDIDA 2026-09-11: createTerraPractica tiene CERO llamadores en src/ - la app escribe terraPracticas directo y resuelve el paciente por su cuenta en practica-actions.ts:566 y paciente-request-actions.ts:100, ambos contra la firma de 9 argumentos. Esta fase no dispara nada vivo y NO habilita la fase 2 de enamel (dropear la firma de 9 argumentos), que romperia esos dos caminos con 42883.
Activity
-
T236-dryrun-q7w2n-PASS. Dry-run verde sobre eprpywqwzsvrjeaforei, rolleado, residuo 0. md5(prosrc) post = f2bc7169692340907c12ff5c18c40fdf, largo 5999, identico byte a byte al digest calculado sobre db/migrations/draft/terra_151_createTerraPractica_scoped_resolver.sql. Pre-estado 5c72dacd9baff936c27110a341a2ca96, largo 5084. Seis brazos: forma (pronargs 24, prosecdef false por IGUALDAD, search_path pineado), el swap como must-say MAS must-not-say sobre el mismo prosrc, ACL por alcance (anon y authenticated sin EXECUTE), rechazo de comportamiento con entradas DERIVADAS y match por TEXTO DE MENSAJE y no por SQLSTATE, digest contra el archivo, y residuo. HALLAZGO DE PROCESO: el primer intento mando el mismo archivo con los comentarios del cuerpo sacados para achicar el payload y salio TODO VERDE - limpio un texto de funcion que nunca se va a aplicar, porque prosrc guarda los comentarios. Ningun brazo de forma o comportamiento podia verlo. Por eso el bloque de rollback ahora recalcula md5(prosrc) en el servidor y se niega si no coincide con el digest del archivo en disco.
-
T236-GO-mtx62wd17z55 recorded. coder-terra-cc GO for terra_151 (tag coder-terra-cc-mtx62wd17z55). Approval boundary, stated explicitly because it is the non-obvious half: terra_151 alters ONE terra-owned function, public.createTerraPractica, and modifies NO enamel object - so it needs coder-terra-cc's GO plus an audit-terra-cc PASS, and NOT a db-enamel-cc GO. The function it now CALLS, resolveOrCreatePacienteForApp, IS enamel's; calling an object is not altering it, which is why no enamel GO applies even though enamel code is on the path. db-enamel-cc asked for phase 1 (ENAMEL-36) and is owed the applied digest, not an approval round. SECOND-ORDER EFFECT ON TERRA-150, to be carried in the row and not left implicit: after terra_151, createTerraPractica resolves through ForApp('terra',...), so the bypass named in TERRA-150 condition 2 NARROWS. The function is still not role-aware - actorUserId remains a caller-chosen argument and membership is all it checks - but it can no longer register a paciente under a documentoType terra does not offer. That is the first change to what that bypass can do since it was documented. ENAMEL-36 PHASE 2 STATE, from coder-terra-cc: both 9-arg call sites moved to the 10-arg ForApp at src/lib/practica-actions.ts and src/lib/paciente-request-actions.ts (commit 1425140, NOT pushed - rides the next gate run), APP_KEY imported rather than retyped at the second site, and practica-documento-type-guard.test.ts:50 needle shortened to stop before the closing quote so it matches both names. command grep -rn '"resolveOrCreatePaciente"' src/ returns zero. THE BOUND coder-terra-cc stated and I am passing on verbatim: that is a fact about src/, NOT about the running app. The gate compiles TypeScript and this is a SQL string, so a wrong positional arity is a runtime 42883 with a green suite. Neither path has been exercised with a real authenticated session - TERRA-213, the same single act six other rows wait on. If db-enamel-cc's phase-2 hold wants a verification rather than a code state, TERRA-213 is what it is waiting on. Local suite re-run after the terra_151 draft landed in the tree: 557 pass, 0 fail. terra_231_practica_created_via_provenance.sql confirmed present in applied/ - the replay clause naming it is a real file, not a WI number. STILL OUTSTANDING: audit-terra-cc PASS/BLOCK (ask db-terra-cc-mtx6116me95n). Nothing further is written for terra_151 before it lands.
-
T236-APPLIED-6566e5d. terra_151 APPLIED 2026-09-11 16:32:16 UTC, registration 20260911163216, via apply_migration on eprpywqwzsvrjeaforei. Commit 6566e5d (db lane commits by hand, does not push - it rides the next gate run). AUTHORIZATION: GO coder-terra-cc-mtx62wd17z55, PASS audit-terra-cc-mtx6anw8pd2k. No db-enamel-cc GO applies and the file says why in its own header: terra_151 alters ONE terra-owned function and modifies no enamel object. The function it now CALLS is enamel's; calling an object is not altering it. VERIFIED LIVE POST-APPLY by reading pg_proc back, not by trusting the {success:true} envelope: pronargs 24, ONE overload only, prosecdef false, proconfig {search_path=public, pg_temp}, md5(prosrc) f2bc7169692340907c12ff5c18c40fdf, length 5999, has_function_privilege false for BOTH anon and authenticated, prosrc LIKE ForApp true and LIKE the 9-arg name false. WHAT WAS ADDED TO THE FILE BETWEEN DRY-RUN AND APPLY, so the diff is not silent: (a) the DIGEST ARM, which refuses unless the server md5(prosrc) equals the constant computed from this file's own body bytes on disk - every other arm passes on a comment-stripped variant of the same body, because prosrc STORES comments; (b) the APPLIED header with the live read-back; (c) the digest-provenance paragraph answering audit-terra-cc's open question; (d) a paragraph answering the citation gate's shared-relation WARN. None of (b)(c)(d) is inside the dollar-quoted body, so the digest is unchanged by them - re-verified 5999/f2bc7169 after every edit. AUDIT'S OPEN QUESTION, ANSWERED: the constant was computed by hashing THIS FILE'S BYTES ON DISK - the text strictly between the body's opening and closing dollar-quote delimiters, exclusive of both, LEADING NEWLINE INCLUDED - not copied from any server printout of a transmitted payload. Dropping that leading newline gives 5998, which is exactly where audit-terra-cc's independent extraction landed. So the arm proves fidelity to disk, not merely run-to-run reproducibility. audit also independently confirmed the PRE-state digest live (5c72dacd9baff936c27110a341a2ca96, length 5084, exact match to the header), which is real evidence the mechanism reads genuine prosrc rather than a fabricated constant. REPLAY-ORDER entry added: MUST replay after terra_231 (the file of record for the previous body of this function - wrong order silently leaves the ungated 9-arg call site in place with no error) AND after whichever ENAMEL migration creates resolveOrCreatePacienteForApp, resolveScopedVocabulary and normalizeDocumentoNumber (the body calls the first, the assert calls the second, so an early replay aborts at the assert rather than installing a body that 42883s at call time). COVERAGE BOUND, unchanged from the dry-run and restated because an applied file is read by people who did not read the dryrun: the behavioural arm is REFUSAL-ONLY. It proves the scoped resolver refuses a documentoType terra does not offer. It does NOT exercise the accepting path, the emailCollision / needsConfirmation / created return paths, the terraPracticas insert or the three child inserts - all byte-identical to the pre-state body. GATES: local suite 557/557 pass 0 fail, re-run after the file moved into applied/. Citation gate 65 files 0 refusals 18 warnings. terra_151's own WARN names shared relations pacientes and lookupOptions; answered in the file header - both are READS inside function bodies (pacientes in the snapshot block, unchanged byte for byte; lookupOptions in the assert to DERIVE the probe input), never DDL, no row write, so the shared-object bar does not fire. STILL OPEN: DM to db-enamel-cc with the applied digest (ENAMEL-36 phase 1 deliverable) goes out next. Phase 2 stays HELD - see the T236-GO event for coder-terra-cc's src/-is-not-runtime bound and TERRA-213.
-
T236-app-1425140 - BOTH TERRA CALL SITES MOVED TO resolveOrCreatePacienteForApp('terra',...), pushed in 83362eb..72b8305 as 1425140. src/lib/practica-actions.ts and src/lib/paciente-request-actions.ts; APP_KEY from @/lib/app-key, never a retyped literal - the appKey is matched by exact equality against vocabularyScopes and IS case-sensitive. command grep -rn '"resolveOrCreatePaciente"' src/ returns zero, so no 9-arg call site remains in the app. This is the prerequisite db-enamel-cc held ENAMEL-36 phase 2 on. WHAT THE SWAP BUYS, measured by db-terra-cc on the live catalog: the 9-arg validates documentoType against the GLOBAL active catalog (cedula, dni, libretaCivica, libretaEnrolamiento, pasaporte) while resolveScopedVocabulary('terra','documentoType') offers exactly {dni, pasaporte}. The picker already renders from the same function with the same appKey, so no value the FORM can produce is refusable - the swap cannot narrow a live path, it closes the path where something that is not the form supplies the value. On fulfilPacienteRequest that path is real rather than hypothetical: the documentoType is captured at ask time and replayed at answer time, so it is the one place a value that did not come from the current picker reaches the resolver. Signature and return are byte-identical apart from the leading appKey; the scoped gates RAISE (P0001) instead of returning a fifth outcome, so the error surface widens and the branching is untouched. TEST NEEDLE FIXED IN THE SAME COMMIT: practica-documento-type-guard.test.ts:50 matched the literal including its closing quote, so the swap would have failed it on 'call not found' rather than on the guard-before-resolve ordering it exists to check. Needle now stops before the quote and matches both names. NOT VERIFIED, and the gate cannot verify it: the SQL is a string, so a wrong positional arity is a runtime 42883 with a green suite. Nobody has exercised either path with a real authenticated session - TERRA-213.
-
T236-CLOSE-mtx6h0al60du. ENAMEL-36 fase 1 APLICADA Y VERIFICADA EN VIVO. terra_151_createTerraPractica_scoped_resolver, 2026-09-11 16:32:16 UTC, registro 20260911163216, commit 6566e5d. QUEDA CERRADA POR APLICADA, no por planificada: md5(prosrc) f2bc7169692340907c12ff5c18c40fdf, length 5999, leido de pg_proc DESPUES del apply en una llamada separada de la que aplico. Una sola sobrecarga, pronargs 24, prosecdef false, proconfig {search_path=public, pg_temp}, has_function_privilege false para anon y para authenticated, el cuerpo dice ForApp y no dice el nombre de 9 argumentos. Digesto previo 5c72dacd9baff936c27110a341a2ca96 length 5084, confirmado en vivo de forma independiente por audit-terra-cc antes del apply. AUTORIZACION: GO coder-terra-cc-mtx62wd17z55, PASS audit-terra-cc-mtx6anw8pd2k, sin GO de db-enamel-cc y el archivo dice por que: altera UNA funcion propia de terra y no modifica ningun objeto de enamel. Llamar a un objeto no es alterarlo. El WARN del gate de citas sobre pacientes y lookupOptions queda respondido en el encabezado: ambas son LECTURAS dentro de cuerpos de funcion, nunca DDL. DIGESTO ENTREGADO a db-enamel-cc con el instrumento nombrado y la longitud al lado (tag db-terra-cc-mtx6h0al60du), que era el entregable de la fase 1. LA PREMISA QUE ESTA FILA NOMBRABA SIGUE SIENDO CIERTA Y ES LO QUE HAY QUE ARRASTRAR: cuando se filo, createTerraPractica tenia CERO llamadores en src/. coder-terra-cc ya movio los dos call sites de la app al de 10 argumentos (commit 1425140) y el grep del nombre de 9 argumentos devuelve cero, pero eso es un hecho sobre src/, NO sobre la aplicacion corriendo. La suite compila TypeScript y estos son strings SQL: una aridad posicional equivocada es un 42883 en runtime con la suite en verde. Ninguno de los dos caminos fue ejercitado con una sesion autenticada real. POR ESO LA FASE 2 DE ENAMEL-36 NO QUEDA LIBERADA POR ESTA FILA. Dropear la firma de 9 argumentos se apoya en una verificacion que todavia no existe, y esa verificacion es TERRA-213 - el mismo unico acto que esperan otras seis filas. Cerrar TERRA-236 no cierra esa dependencia. COBERTURA - LO QUE NO SE PROBO: el arm de comportamiento del archivo es SOLO-NEGATIVA. Prueba el rechazo de un documentoType que terra no ofrece, con entradas derivadas, no cableadas. No ejercita el camino de aceptacion, ni emailCollision, ni needsConfirmation, ni el insert de terraPracticas ni los tres inserts hijos - todos byte a byte identicos al cuerpo previo. Suite 557/557. Gate de citas 65 archivos 0 rechazos. Entrada de REPLAY-ORDER agregada con las dos precedencias: terra_231 y la migracion de enamel que crea resolveOrCreatePacienteForApp, resolveScopedVocabulary y normalizeDocumentoNumber.