Entré a un dominio regulado y complejo sin ser del sector ni saber programar, y en ~6 semanas levanté un producto real y desplegado. Lo que lo hace distinto no es que funcione: es que el rigor y la honestidad están escritos en el propio sistema: el producto renuncia a llamar "seguridad" a lo que la ley no lo es, el motor legal se prohíbe dictaminar cumplimiento y cita el BOE o calla, y cada bug que cazo se convierte en una regla. Es un MVP (Stripe en modo test, licencia en trámite): esa disciplina es el producto.
I walked into a regulated, complex domain without being from the industry or knowing how to code, and in ~6 weeks I stood up a real, deployed product. What makes it different isn't that it works: it's that rigor and honesty are written into the system itself: the product refuses to call "security" what the law doesn't, the legal engine forbids itself from ruling on compliance and cites the BOE or stays silent, and every bug I catch becomes a rule. It's an MVP (Stripe in test mode, license pending): that discipline is the product.
La misma UI vende cinco sectores, pero por debajo el código distingue con precisión cuáles son legalmente "seguridad privada" y cuáles no. Dos de los cinco no lo son, y la copy de cara al cliente lo admite, porque venderlos como "seguridad" sería intrusismo. La ley encajada en el catálogo, no en un disclaimer.
The same UI sells five sectors, but underneath the code precisely tells which are legally "private security" and which are not. Two of the five are not, and the client-facing copy admits it, because selling them as "security" would be an offense. The law embedded in the catalog, not in a disclaimer.
| SectorSector | Régimen legalLegal regime | Cómo se contrataHow it's engaged | ¿Seguridad privada?Private security? |
|---|---|---|---|
| EscoltaBodyguardProtección de personas · flota + nivelesPersonal protection · fleet + tiers | Ley 5/2014 · seguridad privadaLaw 5/2014 · private security | autorización estatal · por contrataciónstate authorization · per engagement | SÍYES |
| VigilanteSecurity guardVigilancia estática / presencialStatic / on-site guarding | Ley 5/2014 · seguridad privadaLaw 5/2014 · private security | self-service · sin autorización individualself-service · no individual authorization | SÍYES |
| Controlador de accesoAccess controllerAdmisión y aforo en espectáculosAdmission & capacity at events | Régimen autonómico de espectáculosRegional entertainment-venue regime | self-service · acreditación autonómicaself-service · regional accreditation | NONO |
| Personal auxiliarAuxiliary staffRecepción · conserjería · control administrativoReception · concierge · administrative control | Art. 6.2 · "personal auxiliar análogo"Art. 6.2 · "analogous auxiliary staff" | self-service · fuera del ámbito de la leyself-service · outside the law's scope | NONO |
| Cuerpos del EstadoState forcesEn preparaciónIn preparation | : | : | ProntoSoon |
El controlador de acceso (régimen autonómico de espectáculos) y el personal auxiliar (art. 6.2) no son seguridad privada, y el motor lo sabe: cada sector lleva su régimen, y el gate legal exime a los que la ley no obliga (sin autorización estatal, sin contrato del art. 20.1). Cada servicio compone además una calculadora distinta y una tabla de asignación propia; un cliente puede pedir varios a la vez para un evento, y cada uno conserva intacta su maquinaria legal.
Access control (regional entertainment regime) and auxiliary staff (art. 6.2) are not private security, and the engine knows it: each sector carries its regime, and the legal gate exempts those the law doesn't bind (no state authorization, no art. 20.1 contract). Each service also composes a distinct calculator and its own assignment table; a client can request several at once for one event, and each keeps its legal machinery intact.
La protección de personas exige autorización específica para cada contratación, con la identidad de los profesionales concretos. Eso obliga a separar el dato legal del permiso de datos: nombrar a alguien en el expediente no le da acceso; darle acceso exige reserva pagada y que conste en ese expediente. Tocar el equipo caduca el expediente y bloquea cobro y prestación.
Personal protection requires a specific authorization for each engagement, naming the concrete professionals. That forces a split between the legal fact and the data permission: naming someone in the file does not grant access; granting access requires a paid booking and that they're on that file. Touching the team expires the file and blocks charging and provision.
Pellizca para acercar y leer el detalle ↔Pinch to zoom in and read the detail ↔
Etiquetas conceptuales, no el esquema real. El invariante rector: quien consta autorizado ante la Administración == quien presta el servicio. Los sectores self-service (vigilancia, controlador, auxiliar) saltan el trámite de autorización; la protección de personas no.
Conceptual labels, not the real schema. The governing invariant: whoever is on record as authorized == whoever provides the service. The self-service sectors (guarding, access control, auxiliary) skip the authorization step; personal protection doesn't.
No es un panel de admin: son ocho departamentos, cada uno un área de negocio con su propia lógica, girando alrededor del ciclo de vida de la reserva. Un solo dev construyó el back-office entero de una empresa de seguridad.
It's not an admin panel: it's eight departments, each a business area with its own logic, spinning around the booking lifecycle. One dev built the whole back-office of a security company.
Máquina de estados, verificar, asignar, arrancar el servicio.State machine, verify, assign, start the service.
Documento en bucket privado; el admin lo ve por URL firmada efímera.Document in a private bucket; admin views it via a short-lived signed URL.
Altas del back-office y su matriz de permisos por departamento.Back-office members and their per-department permission matrix.
Solo cuenta lo cobrado real (no el sembrado); costes, márgenes, proyección.Only real charges count (not seeded); costs, margins, projection.
Watchlist de normas, registro de riesgos, contratos y autorizaciones.Rules watchlist, risk registry, contracts and authorizations.
Tickets y conversaciones de doble cara, aisladas del profesional.Two-sided tickets and threads, isolated from the professional.
Contratos laborales + el candado: nadie presta sin contrato vigente.Employment contracts + the lock: no one provides without a live contract.
Checks evaluados contra el estado real del sistema, no hardcodeados.Checks evaluated against the system's real state, not hardcoded.
Recorrido por los 8 departamentos operando: se avanza una reserva y se cambia un permiso en vivo · datos de ejemplo, sin PII real.Tour of the 8 departments in operation: a booking is advanced and a permission toggled live · sample data, no real PII.
El acceso se resuelve con doble gate fail-closed (¿es del back-office? · ¿tiene ese departamento?), reusando las mismas queries en la página, la acción y la UI para que no puedan contradecirse. Y una honestidad que está en los propios comentarios del código: es RBAC de capa-app (el panel lee con una clave de servicio que salta la RLS), así que jamás lo vendo como "permisos aislados en la base de datos". Un noveno tab, Roadmap, es un mapa de solo lectura del pipe entero que dice, por reserva real, qué la bloquea, reusando los mismos predicados del servidor, nunca reimplementándolos.
Access is resolved with a fail-closed double gate (in the back-office? · has that department?), reusing the same queries in the page, the action and the UI so they can't contradict each other. And an honesty written in the code's own comments: it's app-layer RBAC (the panel reads with a service key that bypasses RLS), so I never sell it as "permissions isolated in the database". A ninth tab, Roadmap, is a read-only map of the whole pipe that says, per real booking, what blocks it, reusing the server's own predicates, never reimplementing them.
Es un servicio de protección: la identidad, la ubicación y la agenda del cliente son PII cuya fuga es catastrófica. Por eso "no filtrar" es un requisito de diseño, no un extra, y en ningún punto se confía en el navegador.
It's a protection service: the client's identity, location and schedule are PII whose leak is catastrophic. So "don't leak" is a design requirement, not an extra, and at no point is the browser trusted.
Pellizca para acercar y leer el detalle ↔Pinch to zoom in and read the detail ↔
El detalle que lo hace serio: se descubrió que un permiso de tabla completa dejaba a un profesional asignado leer PII del cliente por el API directo aunque ninguna pantalla la mostrara; el fix estrechó el permiso a la unión exacta de columnas que la app usa. Dos costuras independientes (precio y pago) y la firma del gate se cambió a propósito para romper el build en sus tres call-sites, para que nadie se olvide de uno.
The detail that makes it serious: a full-table grant was found to let an assigned professional read client PII via the direct API even though no screen showed it; the fix narrowed the grant to the exact union of columns the app uses. Two independent seams (price and payment), and the gate's signature was changed on purpose to break the build across its three call-sites, so nobody forgets one.
Un escolta asignado a un servicio no puede ver la identidad del cliente ni la de otros profesionales, y no es una promesa: es una suite de tests por rol que corre contra una base de datos real y distingue "cero filas por RLS" de "permiso denegado por columna", dos modos de fallo que un test perezoso confundiría. La postura de seguridad se lee en vivo (¿RLS activa en toda tabla? ¿buckets privados? ¿unicidad del cobro?), nunca se afirma.
A bodyguard assigned to a service cannot see the client's identity or other professionals', and it's not a promise: it's a per-role test suite that runs against a real database and distinguishes "zero rows by RLS" from "permission denied by column", two failure modes a lazy test would conflate. The security posture is read live (RLS on every table? private buckets? charge uniqueness?), never asserted.
El cumplimiento es una opinión jurídica; no se verifica por ejecución. El motor legal solo detecta hechos con fuente: que una norma cambió, o que el código trata un dato que la Política de Privacidad no declara. Cada hallazgo lleva su artículo del BOE y su cita, y un registro de riesgos donde "mitigado" nunca es "resuelto".
Compliance is a legal opinion; it isn't verified by execution. The legal engine only detects sourced facts: that a rule changed, or that the code handles data the Privacy Policy doesn't declare. Every finding carries its BOE article and citation, and a risk registry where "mitigated" is never "resolved".
| Hallazgo (registro de riesgos)Finding (risk registry) | FuenteSource | Estado honestoHonest status |
|---|---|---|
| Empresa de seguridad, no "marketplace"Security company, not a "marketplace"Estos servicios solo puede prestarlos una empresa autorizada → pivote de modelo.Only an authorized company may provide these services → model pivot. | Ley 5/2014 art. 5.2 · BOELaw 5/2014 art. 5.2 · BOE | verificado en el BOEverified in the BOE |
| Autorización por contrataciónPer-engagement authorizationLa protección de personas exige autorización estatal nominal antes de prestar.Personal protection requires a named state authorization before providing. | RD 2364/1994 art. 27 · BOERD 2364/1994 art. 27 · BOE | encajado en el flujoencoded in the flow |
| Sectores que no son "seguridad"Sectors that aren't "security"Controlador y auxiliar → riesgo de objeto social exclusivo.Access control & auxiliary → exclusive-corporate-purpose risk. | art. 6.2 / 19.1.a · BOEart. 6.2 / 19.1.a · BOE | abierto · para el abogadoopen · for the lawyer |
| PII declarada en PrivacidadPII declared in the Privacy PolicyCada tratamiento nuevo se declara; la versión legal la fija el servidor.Every new processing is declared; the legal version is server-pinned. | RGPD 6.1 · AEPDGDPR 6.1 · AEPD | verificable en códigoverifiable in code |
| Licencia · RC · aval · Nº de RegistroLicense · liability · bond · registry no.Requisitos de empresa de seguridad (trámite societario), no suscritos aún.Security-company requirements (corporate steps), not yet in place. | Ley 5/2014 art. 19-20 · BOELaw 5/2014 art. 19-20 · BOE | pendiente · placeholder honestopending · honest placeholder |
Ningún agente afirma que SEKURA "cumple": el dictamen lo firma un abogado. Cada norma vigilada y cada hallazgo llevan URL oficial (BOE / EUR-Lex / AEPD) y cita literal, fetcheada en la corrida; sin fuente verificada, no se reporta. La regla nació de un fallo real: un agente de este equipo se inventó un hecho legal y casi entra en material de inversor. La watchlist que barre la rutina mensual es la misma que ve el inversor, no pueden divergir. Y sobre el estatus, sin adornos: MVP · Stripe test · licencia y Nº de Registro en trámite (placeholder honesto, no inventado).
No agent claims SEKURA "complies": the ruling is a lawyer's. Every watched rule and every finding carries an official URL (BOE / EUR-Lex / AEPD) and a literal citation, fetched during the run; without a verified source, it isn't reported. The rule was born from a real failure: an agent on this team invented a legal fact and nearly reached investor material. The watchlist the monthly routine sweeps is the same the investor sees: they can't diverge. And on status, unadorned: MVP · Stripe test · license and registry number pending (an honest placeholder, not invented).
No presumo de no tener bugs. Presumo de un sistema que los caza: un registro append-only donde cada incidente se convierte en una regla que la próxima sesión aplica sola. Estos son reales, del propio proyecto (23 en total), contados a nivel de patrón, sin exponer el esquema.
I don't brag about having no bugs. I brag about a system that catches them: an append-only ledger where each incident becomes a rule the next session applies on its own. These are real, from the project (23 total), told at the pattern level: no schema exposed.
| IncidenteIncident | Qué eraWhat it was | EvidenciaEvidence | VeredictoVerdict |
|---|---|---|---|
| El gate que reabría su propio agujeroThe gate that reopened its own holeUn gate nuevo debía impedir prestar sin equipo.A new gate was meant to block provision without a team. | Con nadie designado, comparaba 0 == 0 y daba luz verde → se podía cobrar y prestar un servicio con cero profesionales. Más un fail-open por un dato ausente que el compilador no ve.With nobody designated, it compared 0 == 0 and went green → you could charge and provide a service with zero professionals. Plus a fail-open on a missing value the compiler can't see. | reproducido ejecutando el predicado real + 2.º pasereproduced by running the real predicate + 2nd pass | cazado pre-pushcaught pre-push |
| Recursión en las reglas de accesoRecursion in the access rulesDos tablas que se referenciaban en círculo.Two tables referencing each other in a loop. | La primera auditoría de seguridad no la vio. Apareció en el segundo pase independiente; se rompió con funciones de definición segura.The first security audit missed it. It surfaced on the independent second pass; broken with security-definer functions. | cubierto luego por la suite RLS reallater covered by the real RLS suite | doble pasedouble pass |
| Fuga de datos por una función expuestaData leak via an exposed functionUna función consultable por API saltaba el cero-grant.An API-callable function bypassed the zero-grant. | Al crearse, concedía permiso al público por defecto: cualquier usuario autenticado podía sondear estatus de personal (PII) por una vía lateral, saltándose el blindaje de la tabla.On creation it granted the public by default: any authenticated user could probe staff status (PII) through a side channel, bypassing the table's lockdown. | test que asierta permiso denegado por esa víatest asserting permission denied by that path | cazado + testcaught + test |
| La red de seguridad estaba apagadaThe safety net was offLa CI llevaba 12 corridas en rojo desde la primera.CI had been red for 12 runs since the first. | En local siempre pasaba (hay secretos) y el despliegue va por su cuenta → nadie lo notó. El check automático no protegía nada. Se descubrió al mirar el panel de verdad.Locally it always passed (secrets present) and deploy is independent → nobody noticed. The automatic check protected nothing. Found by actually looking at the panel. | registro de la corrida fallida → verde en la #13/#14failed-run log → green on #13/#14 | reactivada + reglare-armed + rule |
| El invariante sobre la tabla que documentaThe invariant on the documenting tableSe blindó el registro, no lo que concede el acceso.The record was locked, not what grants access. | Se podía autorizar a una persona y prestar con otra: el gate miraba la tabla que documenta la decisión, no la que de verdad la ejecuta.You could authorize one person and provide with another: the gate watched the table that documents the decision, not the one that actually executes it. | gate movido a donde ocurre (+ trigger en BD)gate moved to where it happens (+ DB trigger) | → regla→ rule |
| La etapa que no se parece a las demásThe stage unlike the othersDos etapas "sellaban una versión"; la tercera era una fecha.Two stages "sealed a version"; the third was a date. | El invariante se puso en las etapas que se parecen y se olvidó en la que no (comunicar), que quedó como un booleano rancio → se prestaba con la versión que la Administración nunca vio.The invariant went on the stages that look alike and was forgotten on the one that doesn't (notify), left as a stale boolean → provision with a version the Administration never saw. | enumerar las etapas por EFECTO, no por formaenumerate stages by EFFECT, not by shape | → regla→ rule |
| Verde en local, denegado en runtimeGreen locally, denied at runtimeUn permiso por columnas no cubría la columna del filtro.A column grant missed the column in the filter. | Compilador, tests y build en verde; la base de datos exige permiso sobre toda columna referenciada, incluidas las del WHERE. Un fallback honesto casi ocultó el fallo en una página pública.Compiler, tests and build all green; the database requires permission on every referenced column, including those in the WHERE. An honest fallback nearly hid the failure on a public page. | solo lo vio la corrida contra la BD realonly the run against the real DB saw it | verde local ≠ runtimegreen local ≠ runtime |
| Un "admin" que abría PII a todosAn "admin" that opened PII to allUna regla de cinturón exponía texto libre del cliente.A belt-and-suspenders rule exposed the client's free text. | Como todo el back-office comparte el mismo rol técnico, una regla basada en "es admin" abría la PII más sensible a cualquier miembro por su propio token, saltándose el permiso fino por departamento.Since the whole back-office shares one technical role, a rule based on "is admin" opened the most sensitive PII to any member via their own token, bypassing the fine-grained departmental permission. | cero-grant-a-admin; nunca desplegadozero-grant-to-admin; never shipped | cazado pre-pushcaught pre-push |
Probar los valores degenerados de tu propio gate (el conjunto vacío, el dato ausente) justo cuando todos los tests están en verde. Esa es la señal que un escéptico cree imposible en un perfil construido con IA.
Testing the degenerate values of your own gate (the empty set, the missing value) right when every test is green. That's the signal a skeptic assumes is impossible in an AI-built profile.
Sospeché del caso feliz. Los 14 tests del gate estaban en verde, pero todos fijaban el mismo caso cómodo, así que ninguno tocaba el conjunto vacío ni el dato ausente. Un fixture que solo genera el caso bueno es un punto ciego, no cobertura.
Lo reproduje ejecutando el predicado real (no leído de un informe) y un segundo pase de auditoría lo confirmó. Cerré las tres puertas y añadí tests de los casos degenerados.
Probar los valores degenerados de tu propio gate, no el caso feliz, es lo que se transfiere a un equipo.
I got suspicious of the happy path. The gate's 14 tests were green, but all pinned the same comfortable case, so none touched the empty set or the missing value. A fixture that only builds the good case is a blind spot, not coverage.
I reproduced it by running the real predicate (not read from a report) and a second audit pass confirmed it. I closed all three doors and added tests for the degenerate cases.
Testing your own gate's degenerate values, not the happy path, is what transfers to a team.
La verificación automática es inútil si nadie mira si de verdad corre. La mía llevaba 12 corridas en rojo desde la primera, tapada por dos coincidencias.
Automatic verification is useless if nobody checks it actually runs. Mine had been red for 12 runs since the first, hidden by two coincidences.
Doce corridas en rojo y nadie lo notó: en local hay secretos, así que siempre pasaba; y el despliegue va por su cuenta, así que la demo seguía subiendo y tapaba el síntoma. La causa: un secreto que se leía al importar un módulo, y en la CI no hay secreto a propósito.
No apareció hasta que miré el panel de verdad en lugar de asumir que estaba verde. Se convirtió en regla: verifica en el modo plano (como corre la CI), y vigila el estado REAL, no el que supones.
Vigilar el estado real, no asumirlo: eso se transfiere.
Twelve red runs and nobody noticed: locally there are secrets, so it always passed; and deploy runs on its own, so the demo kept shipping and hid the symptom. The cause: a secret read at import time, and CI has no secret on purpose.
It didn't show until I looked at the real panel instead of assuming green. It became a rule: verify in the bare mode (as CI runs), and watch the REAL state, not the one you assume.
Watching the real state, not assuming it: that transfers.
No le pido a la IA una respuesta. Orquesto flotas de agentes que se auditan entre sí: uno propone un cambio, otros intentan refutarlo por lentes distintas, y un asiento de síntesis re-deriva cada veredicto del código. Un cambio sensible solo pasa si resiste el ataque, y cada fallo que se cuela se convierte en un anticuerpo.
I don't ask the AI for an answer. I orchestrate fleets of agents that audit each other: one proposes a change, others try to refute it through distinct lenses, and a synthesis seat re-derives every verdict from the code. A sensitive change ships only if it withstands the attack, and every failure that slips through becomes an antibody.
Pellizca para acercar y leer el detalle ↔Pinch to zoom in and read the detail ↔
Un cambio sensible pasa solo si resiste el ataque. El juicio es de la síntesis que re-deriva del código, no de un agente que "reporta OK".
A sensitive change ships only if it withstands the attack. Judgment belongs to the synthesis that re-derives from code, not to an agent that "reports OK".
Cambios, Seguridad y Legal: atacan tres verdades distintas. Todo cambio se descompone con un agente que lee el código real; se verifica por ejecución, no por informe. Ningún "reportó que está OK" cierra nada.Changes, Security and Legal: they attack three distinct truths. Every change is decomposed by an agent that reads the real code; verified by execution, not report. No "it reported OK" closes anything.
Un hecho sin fuente es una mentira plausible. El pivote legal se verificó literalmente en el BOE, no de memoria: una vez un agente se inventó un hecho legal, y por eso todo dato lleva su fuente o no entra.A fact without a source is a plausible lie. The legal pivot was verified literally in the BOE, not from memory, once an agent invented a legal fact, so now every claim carries its source or it doesn't ship.
La flota no es teoría: corre en cada handoff. Un agente ciego reconstruye el objetivo desde la fuente más upstream; varios críticos atacan con el mandato de refutar. Lo que cae, se corrige antes de tocar nada. Esta misma página pasó por ese filtro.
The fleet isn't theory: it runs on every handoff. A blind agent rebuilds the goal from the most upstream source; several critics attack, mandated to refute. What falls gets fixed before touching anything. This very page went through that filter.
Las lentes agénticas comparten los mismos priors: cazan falsos positivos, pero no el falso negativo de una medición mala o un requisito omitido: eso ninguna cantidad de agentes lo ve. Lo estrecho así: el gate humano (yo pruebo en el navegador cada fase) y convirtiendo cada punto ciego en una lente reutilizable. Por eso existe el registro de incidentes: cada fallo se promueve a una regla dura que la próxima sesión aplica sola, con un único escritor y un conjunto inmutable que ningún auto-proceso toca. Irreducible: la primera vez que aparece un sesgo nuevo, sigue haciendo falta un humano.
The agentic lenses share the same priors: they kill false positives, but not the false negative of a bad measurement or a missing requirement, no number of agents sees that. I narrow it like this: the human gate (I test every phase in the browser) and turning each blind spot into a reusable lens. That's why the incident ledger exists: every failure is promoted to a hard rule the next session applies on its own, with a single writer and an immutable set no auto-process touches. Irreducible: the first time a new bias appears, it still takes a human.
El resto del método —la refutación en lentes disjuntas, el invariante que vive en un solo sitio— es el mismo en los cinco sistemas y está contado una vez: en el índice.The rest of the method —refutation through disjoint lenses, the invariant that lives in one single place— is the same across all five systems and is told once: on the index.
Si buscas a alguien para applied-AI, automatización o forward-deployed engineering, que no se engaña con sus propios resultados, hablemos.
If you're looking for someone in applied-AI, automation or forward-deployed engineering who doesn't fool themselves with their own results, let's talk.