PRACTICA_ROLES omits client from six live terra groups while its own comment claims it restricts nobody - the one silent exclusion in a file that argues every other one
PRACTICA_ROLES NAMES FIVE OF SIX LIVE TERRA GROUPS, AND THE COMMENT ABOVE IT SAYS IT NAMES ALL OF THEM. src/lib/route-access.ts:35-39, written on coder-enamel-cc's advice (ms72kho4rbnx), reads: "This is today's full set on purpose - it restricts nobody now, it makes a future grant deliberate." Then: export const PRACTICA_ROLES = ["alumno", "docente", "jtp", "bedel", "admin"] as const; db-enamel-cc measured the live vocabulary on eprpywqwzsvrjeaforei 2026-09-11: SIX groups, all ownerAppKey NULL, all active - client, alumno, docente, jtp, bedel, admin. PRACTICA_ROLES OMITS `client`. So the constant DOES restrict somebody, and the sentence justifying it is false as written. THE EXCLUSION ITSELF IS ALMOST CERTAINLY RIGHT AND I AM NOT PROPOSING TO ADD `client`. A client is the catedra's head, not a clinician; the role exists so he can decide the cirugias list and read informes, which is exactly what CATALOG_ROLES (:66), INFORME_ROLES (:55) and CLIENT_ROLES (:69) give him. Nothing suggests he should be recording surgeries. THE DEFECT IS THAT THE EXCLUSION IS UNDOCUMENTED WHILE THE COMMENT ACTIVELY DENIES IT, AND THAT COMBINATION IS WHAT MAKES IT DANGEROUS. Every OTHER exclusion in this file is argued in place and argued well: ROSTER_ROLES says "alumno is excluded on purpose" because the roster is a view of other people's work; INFORME_ROLES spends a paragraph on why alumno is out and why `client` is in. PRACTICA_ROLES is the ONE constant whose exclusion is silent - and it is the one whose comment claims there is no exclusion. A future reader comparing the list against the live vocabulary finds a discrepancy that the comment tells them is a mistake, and "fixes" it by adding `client`, which would let the catedra's head record surgeries. IT HAS NEVER BEEN FELT, WHICH IS WHY IT SURVIVED. Sebastian Puia holds client+docente on sebastian.puia@odontologia.uba.ar, so he reaches /practicas/nueva through `docente` and the omission has never refused anybody. A client-only account would hit it, and there is none today. THIS IS THE DRIFT enamel_013 PREDICTED, ARRIVING FROM THE OTHER DIRECTION. enamel_013_terra_boundary_shared_functions.sql:49-51 refuses to copy PRACTICA_ROLES into the DB because an IN-list there "silently stops rejecting when a sixth group is added". The sixth group is already here, the DB is fine because it gates on membership, and it is the APP-SIDE list that has quietly gone out of step with the vocabulary - while asserting it has not. FIX: one comment, no behaviour change. State that `client` is excluded, state why (the role is for deciding the catalog and reading informes, not for recording clinical work), and delete "today's full set" / "restricts nobody now", which are both false. Then the next reader cannot repair the wrong half. FOUND BY: db-enamel-cc's live group census while answering TERRA-150 half 2, a question about a different role entirely. Related: TERRA-150 (the alumno half of the same constant), TERRA-231 (createdBy attribution on the same write path).
Activity
-
FIXED AND COMMITTED, HELD FOR THE NEXT GATE. Marker: T232-fix-mtx20. Commit 84e9eac, two files, 66 insertions, ZERO behaviour change - the constant itself is untouched. src/lib/route-access.ts: the false sentence is gone. It said the list was "today's full set on purpose - it restricts nobody now"; the live vocabulary is six values and the list names five. Replaced with a paragraph that states the exclusion, names `client` as the excluded value, gives the reason (the role exists so the catedra's head can decide the cirugias catalog and read informes - CATALOG_ROLES, INFORME_ROLES and CLIENT_ROLES all name him - and recording a surgery is a clinical act), records why nobody has ever felt it (Puia holds client AND docente on one account and reaches the form through docente; a client-only account would hit the exclusion and none exists), and points at enamel_013:49-51 as the prediction this fulfils from the app side. THE PART THAT MAKES IT DURABLE IS THE TEST, NOT THE COMMENT. A COMMENT CANNOT FAIL. src/lib/route-access.test.ts gains one test with three arms: - MUST-NOT: `client` is absent from PRACTICA_ROLES. This is the arm that exists to fail, and its message tells whoever trips it to read the TERRA-232 comment before changing it back - because the most likely failure is someone "completing" the list against the live vocabulary, which is exactly the repair this row exists to prevent. - MUST-CONTAIN: the five exact values, sorted. Without it the must-NOT arm passes on an empty list or after a rename. - A LIVE-ROLE CONTROL: `client` is still present in CLIENT_ROLES, INFORME_ROLES and CATALOG_ROLES. If that ever fails, the exclusion has stopped meaning "deliberately not this one" and started meaning "no such value", which is a different fact and should not hide behind this test. SAME SHAPE AS TERRA-228'S FIX AND THAT IS DELIBERATE: a set of must-say assertions never constrains what ELSE is in the list, so the must-NOT arm is the load-bearing one. Four affirmative checks were how the false convention-date escape survived the row filed to kill it. MUST-FAIL CONTROL EXECUTED, NOT REASONED. Copied src/lib and src/app to a scratchpad, added "client" to PRACTICA_ROLES in the COPY, ran the suite there: 9 pass, 1 fail, and the one failure is exactly this test. So it goes red on the mutation and it is targeted rather than blunt - the other nine are unaffected. Scratch copy deleted. The shared tree was never mutated; five lanes work in it. Unmutated run in place: 10/10 pass. NOT PUSHED. It is a comment and a test with no behaviour change, so it rides the next gate rather than spending one of its own - the gate is handed by name under pmmaster's protocol and coder-pluto-cc holds it. It will go with the terra_231 apply push.
-
completed