Repository navigation
Hooks y gates fiables en los cuatro backends, revisión acotada y prosa sin capacidades ausentes - #106
Merged
Merged
Conversation
Las descriptions de asesor, implementar, planificar, spec, tareas y estado empezaban por «Se activa…», usaban frases del usuario y no nombraban la skill vecina; planificar y spec competían por «crear una spec». Ahora siguen la guía de CONTRIBUTING: condición observable, qué hace y a qué skill van los casos que no son suyos. El comentario de cabecera de asesor se alinea con esa guía. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Estos comandos reciben $ARGUMENTS pero no indicaban qué argumento esperan. El campo solo lo usa Claude Code: command-to-backend lee solo description, así que ningún derivado cambia. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Los cuatro comandos reciben $ARGUMENTS pero no declaraban argument-hint, así que Claude Code no mostraba qué argumento esperan al autocompletar. El campo solo lo usa Claude Code: command-to-backend lee solo description y command-to-skill toma el frontmatter del fragmento, de modo que ningún derivado cambia. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La guía de contribución seguía diciendo que el repositorio no tenía integración continua, aunque .github/workflows/test.yml ya ejecuta npm test y el gate de deriva en cada PR y en push a main, y exigía Node >= 20.11 para los hooks, cuando los hooks funcionan con >= 20 y 20.11 es el mínimo de engines para la suite. La entrada de [Unreleased] que afirmaba que no había CI se reescribe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Los prompts de revisión por task y de auditoría exigían seguir todos los pasos de la plantilla sin saltar ninguno, mientras los agentes aplican los pasos pertinentes al riesgo y declaran los omitidos. Ahora los prompts dicen lo mismo. Se retira «si la evidencia es ambigua, reporta el hallazgo como problema», que contradecía la regla del propio prompt de auditoría: las dudas sin evidencia van en avisos y no bloquean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Los agentes no declaraban Grep ni Glob, y el planificador tenía que reescribir ficheros enteros para corregir una spec. La política de Gemini traduce ahora Grep -> grep_search y Glob -> glob en map, y ambas salen de always, que las concatenaba sin deduplicar; retirarlas es seguro porque los cuatro agentes las declaran. El fixture del test de traducción declara también Grep/Glob, como el asesor real. Codex y Antigravity no cambian. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La plantilla de PR no decía cómo revertir el cambio, no tenía vínculo a issue ni una frase para quien no conoce el código; ahora incluye las tres, con la orden de revert para merge commit, squash y rebase. /revision revisaba sin comprobar si la rama ya estaba fusionada: un Paso 0 lo confirma primero con la PR y, sin PR, con git (avisando de que un squash o un rebase merge no se detectan así) y, si ya lo está, revisa como post-merge. El comando gana argument-hint. La skill de Codex y Antigravity cambia su description a condición, acción y frontera, y su postura aplica el criterio de bloqueo de revision_adversarial. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El bloqueo de escrituras solo engancha las herramientas de edición (Write, Edit, NotebookEdit); lo escrito por shell no pasa por él y lo detecta la revisión del diff. CLAUDE.md y README lo declaran ahora. El motivo de denegación invitaba a añadir la ruta a la task, y como ai_docs/ está exento del guard un implementador podía ampliar su propio alcance. Ahora separa los remedios: quien implementa se detiene y reporta la desviación; quien planifica declara la ruta en la task. README añade una guía por herramienta: Copilot, Windsurf y Devin leen AGENTS.md, pero ahí no corren hooks ni workflows, y dice qué copiar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La skill pr tiene efecto externo: declara disable-model-invocation y una description que deja claro, sin depender de la sintaxis de un backend, que solo se usa cuando el usuario pide explícitamente crear o revisar una PR. El transform de skills retira los campos de Claude Code según el backend: Antigravity/Codex pierden argument-hint y el flag; Gemini solo el flag. Una skill sin esos campos sigue saliendo idéntica. La deriva de derivados se comprobaba varias veces por run de CI con la misma severidad. Los dos casos que lanzaban compile.js --check como subproceso se fusionan en uno, y el paso duplicado sale del workflow: npm test ya falla con cualquier deriva. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El caso de rutas fallidas usaba chmod 0555, que no impide escribir a root, y se saltaba en silencio en Windows. Ahora .claude es un fichero normal: crear .claude/workflows falla con cualquier uid y plataforma. F3 afirmaba que siempre aborta exactamente una de las dos instalaciones concurrentes, lo que dependía de la velocidad de copia. Ahora comprueba invariantes lógicas (0 o 1, al menos un éxito, abortos solo por el lock, sin EEXIST, destino completo y sin lockfile); el lock lo sigue acreditando el test determinista del lockfile preexistente. ejecutarAsync usa process.execPath. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
…esgo Las skills bugfix, cleanup, commit, diff y testing empezaban por «Se activa», citaban frases literales del usuario y no marcaban la frontera con la skill vecina. Ahora siguen la fórmula condición + qué hace + frontera; bugfix y commit declaran que comparten plantilla con el comando homónimo sin depender del backend. testing baja al cuerpo la redirección al setup de tests. El cuerpo de bugfix, cleanup, commit, testing y pr deja de exigir todos los pasos de la plantilla: aplica los pertinentes al riesgo y declara los omitidos, como ya hacen los agentes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
revision-adversarial y revisar-tarea se anunciaban en el mismo punto que implementar-spec y planificar, que ya revisan cada task: su description acota ahora el uso al trabajo hecho a mano fuera de esos workflows. auditar recuerda que planificar ya audita e inicio pierde el «Se activa». Ambas skills de revisión aplican los pasos pertinentes al riesgo y declaran los omitidos. revisar_tarea.md fija cuándo emitir cada veredicto: NECESITA_AJUSTES solo con un hallazgo material con evidencia; la duda sin evidencia va a avisos y no impide LISTO_PARA_IMPLEMENTAR. «NUNCA aceptes un plan sin cuestionar» convertía cualquier duda en ajuste. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El contador era único por sesión y solo lo reiniciaba un git commit visto como tool call; el workflow commitea por child_process, así que sumaba todas las tasks. Cada subagente cuenta ahora en su registro (<sesión>-a-<agent_id>, con hash si el id es muy largo, o <sesión>-sub sin agent_id) y el commit del hilo principal reinicia también el común. Los avisos de subagente ya no piden commitear, y en advisory el hard_stop propone un checkpoint en vez de ordenar interrumpir; en enforce se sigue denegando. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El gate de tests no volvía a correr tras la pasada de corrección, una revisión APROBADA con problemas críticos se commiteaba y un PARCIAL pasaba a gate y commit sin bloquear a sus dependientes. Ahora el gate se repite tras corregir, normalizarRevision convierte el veredicto contradictorio en NECESITA_CORRECCIONES y solo COMPLETADA satisface una dependencia; PARCIAL se aparta en stash. Preparación, revisión y commit comparten pathspecDeTask: en secuencial, el proyecto salvo ai_docs/tasks y ai_docs/audits, para que el registro de sesiones no impida arrancar y un cambio en ai_docs/core entre en el commit de su propia task; en concurrente, solo las rutas del ámbito que cambiaron, sin add cuando no hay ninguna, de modo que un fichero declarado y no creado o un borrado ya preparado no rompen la preparación. El gate deja de preparar fuera del proyecto y corre la suite en su raíz con la salida acotada. Los prompts dejan de contradecir a las plantillas. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Las instrucciones raíz de los tres backends no decían nada sobre cuándo compensa una verificación, cómo informar, cómo pasar texto largo a una orden ni cómo esperar procesos largos. Se añaden al bloque compartido de límites del núcleo, sin herramientas propias de un solo backend, junto con una tabla breve de dónde vive cada tipo de información. Los temporales siguen fuera del árbol de trabajo, con ruta absoluta literal, como ya pide la plantilla de commit. La regla clave 7 aclara que el revisor bloquea solo lo material, y la fila de asesor deja de anunciarse como read-only: tiene Bash y su restricción vive en su propio cuerpo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Los hooks trataban enabled ausente como encendido y gates_on del registro de sesiones exigía enabled === true: una sección sin enabled dejaba el hook corriendo mientras el registro lo declaraba apagado. hookEnabled en sdd-hook-utils.js aplica un booleano explícito o el valor por defecto de una única tabla (review-gate apagado, el resto encendido); los cuatro hooks y gatesOn la consumen, y gates_on cuenta también los hooks encendidos por defecto sin sección. Tests de coherencia ejecutan cada hook y comparan con gates_on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
REVIEW_SCHEMA no tenía avisos y reviewSummary solo reenviaba veredicto, problemas y ajustes: la duda sin evidencia que revisar_tarea.md manda a «Avisos (no bloquean)» se perdía o acababa en problemas y abría la segunda pasada. REVIEW_SCHEMA gana avisos opcional, el prompt por task pide no mezclarlos con problemas, el resumen sale de la función pura resumenDeRevisiones (lib/auditoria.js), que los reenvía como avisos_no_bloqueantes, y el prompt del auditor los manda a sus avisos, no a huecos ni incoherencias. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
En codex-cli 0.162.1 apply_patch entrega el parche en tool_input.command y el guard de pipeline solo leía input/patch/content: respondía con el aviso de ruta ilegible y nunca denegaba. Ahora lee command y, si no trae cabeceras, el resto; y reconoce «*** Move to:», de modo que renombrar hacia una ruta no declarada también se deniega. El guard de commits acepta exec_command como alias defensivo (no observado como tool_name; el shell llega como Bash). Tests con la forma medida. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
codex-cli 0.162.1 rechaza el parámetro reason en prefix_rule y no arranca; con justification las reglas cargan y bloquean git commit --no-verify. o4-mini no figura en el catálogo de esa versión (aviso de metadatos): config.toml pasa a gpt-5.5. install y update con codex o all avisan del modelo del config.toml instalado y de `codex debug models`. El README deja de presentar las reglas como experimentales. Tests de contrato de las reglas y del modelo frente al catálogo medido. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Antes cualquier veredicto distinto de APROBADA abría la corrección, el corrector recibía también los menores, la segunda revisión empezaba de cero sin los hallazgos previos y, tras una sola corrección, la task se descartaba. Ahora solo un crítico, un RECHAZADA o una revisión sin veredicto abren ronda; los menores viajan, aplanados, en el cuerpo del commit. Cada ronda corrige los críticos, vuelve a pasar el gate y re-revisa con los hallazgos previos (resuelto, persistente o refutado) y el delta, calculado sobre el último diff con revisión utilizable y acotado al pathspec de la task, sin leer el índice compartido. Tras tres rondas la task queda BLOQUEADA_REVISION: su trabajo se aparta con nombre, sin destruir nada, y los hallazgos abiertos pasan al usuario. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
codex-cli 0.162.1 ignoraba .codex/hooks.json entero por las claves _comment: ahora solo lleva claves del esquema, con un test que rechaza claves fuera del esquema. El shell llega como tool_name Bash, así que el matcher del guard de commits pasa a Bash. Cada orden sube desde el cwd hasta la raíz del proyecto (primer directorio con .git, .codex/hooks.json o hooks/hooks.json; hasta 10 niveles) y lanza desde ahí el hook -codex correspondiente; dentro de un subdirectorio los hooks ya no fallan por ruta relativa. Si no encuentra el hook, falla en abierto con aviso por stderr. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El estado efímero de turn-budget y del rastreador de lecturas vivía suelto en la raíz del temporal del sistema. Ahora va a una subcarpeta propia: sdd-hooks-<uid> en POSIX y sdd-hooks en Windows. Tras crearla se valida con lstat que sea un directorio real, no un enlace, del uid propio, y se deja en 0700; si la validación falla, se avisa una vez por stderr y se vuelve a la raíz del temporal, como antes. La purga no sigue enlaces, ignora ficheros de otro usuario y no cuenta los que no puede borrar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La verificación de cierre de spec ya no escribe: devuelve brechas con criterio, hallazgo, evidencia y severidad. Con alguna BLOQUEANTE, un paso con escritura, inyectado en resolverConvergencia, las convierte en tasks numeradas con next-task-number.sh y devuelve sus rutas; con solo WARNING la spec converge y los avisos quedan para el usuario. Si la creación no devuelve rutas, las brechas siguen en el resultado. El log distingue lo reportado de lo creado. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El gate calculaba el hash con git diff --cached en la raíz de partida, aunque el commit apuntara a otro repositorio. Ahora localiza la raíz del commit observado: git -C (también con ~), --git-dir/--work-tree y las asignaciones GIT_DIR=/GIT_WORK_TREE=, o el cwd del payload; si la ruta no se puede resolver (variables, comillas invertidas), usa la raíz de partida como antes. El diff corre con core.fsmonitor desactivado y con el mismo comando que el emisor de la señal, de modo que un diff.external global da el mismo hash en los dos lados. sdd-git-command exporta segmentar para que el gate no duplique la segmentación. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Ninguna llamada agent() de planificar.js ni de implementar-spec.js declaraba agentType: todos los pasos corrían con el modelo de la sesión y sin las herramientas de su rol, y la documentación prometía un implementador en otro modelo que el workflow no aplicaba. Cada llamada declara ahora su rol (asesor, planificador, implementador o revisor); el modelo y las herramientas salen del frontmatter del agente, única fuente. Un test exige agentType existente en cada llamada, con fixture negativo. «Modelo por defecto» deja de nombrar ids y describe lo que hace el código. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Gemini CLI 0.63.0 llama replace y run_shell_command a la edición y al shell: los matchers con edit_file y run_command no cubrían ninguna de las dos, y los cuatro agentes de .gemini/agents no cargaban (Invalid tool name). Los matchers y el mapa de herramientas pasan a los nombres medidos, y los comandos de hooks/hooks.json a la plantilla del lanzador, que ejecuta cada hook desde la raíz aunque Gemini arranque en un subdirectorio; antes fallaban con Cannot find module y la escritura no declarada pasaba. GEMINI.md documenta además el aviso inocuo de skills duplicadas con --backend all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Hasta ahora el campo Estado solo se escribía al crear la task y el workflow calculaba el resultado en memoria: el documento seguía PENDIENTE para siempre y /estado no podía contar el progreso. ejecutarTask escribe EN_PROGRESO justo antes de implementar y, al retornar, el estado final (COMPLETADA, PARCIAL, FALLIDA o BLOQUEADA_REVISION), solo en las tasks intentadas: las bloqueadas, las que encuentran residuo al empezar y las no ejecutadas tras una parada siguen PENDIENTE. El escritor marcarEstado reescribe solo el valor de la última línea Estado:, resuelve la ruta ascendiendo desde el directorio en curso, se limita a las tasks de ai_docs/tasks/ (nunca una spec; ruta fuera de todo commit) y ante cualquier fallo avisa sin cambiar el resultado de la task. La plantilla de tasks documenta quién escribe cada estado, /implementar aplica las mismas transiciones y /estado cuenta por estado vigente. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Gemini CLI llama replace a su edición parcial y run_shell_command a su shell. Los conjuntos de nombres de pipeline-guard, read-before-edit, commit-guard y turn-budget no los incluían, así que una edición o un commit por esas herramientas salían del hook sin evaluarse aunque el matcher los enrutara. replace se trata como escritura parcial. Se retira edit_file, que ninguna versión medida expone ni ningún matcher enruta; run_command se mantiene porque es la shell de Antigravity. Un test nuevo cubre los casos positivos y negativos con la forma de payload de Gemini. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El aviso buscaba /Estado:\s*PENDIENTE/ en las 10 primeras líneas, y la plantilla de task escribe **Estado:** PENDIENTE, que no casaba: el aviso no saltaba nunca con tasks reales. estaPendiente pasa a usar estadoVigente (exportado desde sdd-plan-state) sobre el texto completo: la misma última línea Estado: que reescribe el escritor del motor de workflows, así que lector y escritor coinciden. Tests con fixture leído de la plantilla y composición con marcarEstado donde el motor está instalado. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La skill de Codex/Antigravity prometía emitir la señal de revisión, que solo existe en el motor de workflows de Claude Code. Ahora el revisor revisa el diff y solo con APROBADA se commitea, con tope de 3 rondas y BLOQUEADA_REVISION. Las dos variantes procedurales comprueban el árbol limpio al empezar, escriben el Estado según tareas.md y apartan el trabajo no aprobado con un stash con nombre acotado a los ficheros con cambios, sin borrar nada; sin script de numeración informan del error. Gemini declara su revisión no independiente. AGENTS.md documenta la delegación de Codex con los nombres verificados en 0.162.1 y el modelo gpt-5.5, deja de anunciar revision-adversarial como paso 5 y de decir que el implementador commitea. El Paso 4bis usa los 4 campos del schema del workflow. Un test escanea las salidas no Claude en busca de capacidades exclusivas de Claude Code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
…etida El revisor recibe del flujo el resultado del gate de tests (comando y código de salida) y las desviaciones que declaran implementador y corrector: el gate es la única suite completa por task, y los demás agentes ejecutan pruebas dirigidas. La postura del revisor vive en su agente y en la plantilla, así que los prompts dejan de repetirla, y cada agente lee de ai_docs/core/ solo las secciones citadas (el intake conserva la lectura completa). Cada workflow declara su tamaño. El emisor de la señal de revisión y sdd-review-gate leen el diff con --no-ext-diff --no-textconv: el hook ya no ejecuta herramientas de diff configuradas en el repositorio antes de decidir, y el hash sigue atando en los dos lados. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Los tests de cada hook fabrican el payload con los campos que el hook lee, así que pasan aunque el runtime envíe otros. Se añade un fixture capturado de Claude Code 2.1.296 (anonimizado) y un banco en proceso que comprueba, para cada hook cableado en .claude/settings.json, que los campos que lee existen en el payload real de su evento, que los de subagente solo llegan en llamadas de subagente y que toda lectura del payload en la fuente del hook está declarada. CONVENTIONS.md fija el criterio de aceptación de un cambio de hook: fixture real con la versión del CLI, mutante que pone el test en rojo y productor de cada dato verificado. measure-hook-overhead.js reutiliza hookEnabled de sdd-hook-utils: su copia local daba por encendido sdd-review-gate sin clave enabled, y el hook real lo da por apagado. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Los árboles de los fragmentos y del núcleo citaban a mano cuántos comandos, skills, hooks y plantillas hay, sin nada que los atara al disco: ahora se comprueban contra los mismos contadores que la tabla del README. La pila que carga cada rol (CLAUDE.md + agente + las plantillas que cita su despacho en los workflows) tiene límite propio: la medida ×1,15, redondeada al KB. CONVENTIONS.md documenta ese presupuesto y que subir un límite exige volver a medir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
--parallel lanzaba el nivel entero a la vez, sin tope ni detección de colisiones, y dos suites o dos operaciones de git podían pisarse en el índice compartido. Ahora --parallel[=N] limita las tasks en vuelo (MAX_CONCURRENCIA = 4 por defecto), las que comparten ficheros declarados o no tienen ámbito legible van en serie, y el gate de tests, la preparación del diff, el commit y el apartado pasan por un mutex; la implementación sigue en paralelo. El revisor recibe además los ficheros cambiados que no declara ninguna task en vuelo. Cada sitio del mutex tiene un test con promesas diferidas que cae si se quita el wrapper de ese sitio. El README declara el residuo: el gate sigue viendo en el árbol compartido el trabajo a medias de las hermanas. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El caso de contrato de entrada de exit-code-contract ejecutaba sdd-session-start sin SDD_PROVENANCE_FILE, y cada corrida de la suite en un proyecto instalado añadía dos líneas a su ai_docs/audits/provenance.jsonl. Ahora el caso inyecta el registro y una config vacía en un temporal propio, y comprueba que el registro llegó a ese destino. La corrección va en el llamador y no en el helper, porque otro test necesita que falte la variable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El SessionStart capturado de Claude Code (claude -p) no trae model ni versión. session_model ya escribía null en ese caso, pero la prosa prometía el modelo y los tests usaban un payload con un campo que el runtime no envía. Ahora la prosa lo condiciona a que el CLI lo envíe, y el payload de los tests copia las claves del fixture capturado. cc_version deja de leer variables de entorno heredadas: medían la versión del proceso padre, no la del CLI que lanza el hook, y un valor falso es peor que null. El campo conserva nombre y posición y vale null mientras el CLI no fije una fuente propia. cohort_id mantiene su fórmula; sin modelo agrupa por configuración, y la cabecera lo documenta. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
tokenizar cortaba la palabra en la comilla: git -c user.name='a b' commit --no-verify dejaba 'a b' como programa y el commit pasaba sin detectarse, igual que GIT_DIR="/a b" git commit. Ahora une las piezas adyacentes como el shell, y entrecomillado solo vale true si todas iban entre comillas, así "--no-"verify llega como flag. El script de bash -c en una sola palabra con blanco también se re-analiza. Un alias en línea (git -c alias.x='commit -n' x) añade la invocación expandida y conserva la original: nombre sin distinguir mayúsculas, en cadena con detección de bucles, nunca sobre un builtin de git (lista de git 2.43.0, 140 nombres) y con ! como script anidado. Cada invocación lleva además entorno, globales (solo las anteriores al subcomando), separadorAntes/separadorDespues, grupos (paréntesis, llaves, if…fi y bucles…done; null si no cuadran) y script, para que el gate de revisión resuelva la raíz del commit. Son campos aditivos: programa, palabras y flags conservan su forma. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Una función que se llamaba a sí misma, como el wrapper
git() { command git "$@"; }, agotaba la pila. La excepción hacía
fallar abiertos a commit-guard y al gate de revisión, y con ello
pasaban --no-verify y el commit sin revisar.
Ahora una llamada a función conserva la invocación original y añade
la de su cuerpo. Cada cuerpo se expande como mucho una vez por orden,
lo que cubre la recursión directa y la mutua y deja el coste lineal en
las cascadas. Pasadas 32 expansiones anidadas, el cuerpo no se analiza:
cuenta como un git commit con --no-verify, marcado como incompleta,
que hereda el contexto del punto de llamada. El análisis añade las
invocaciones de un segmento una a una, sin pasarlas como argumentos,
para no agotar la pila con un cuerpo muy largo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Añade a [Unreleased] el Estado que escribe el flujo, las rondas de revisión con tope, el agente por rol, el tope y la partición de --parallel, el contrato de hooks con payloads reales, la carga de Codex y Gemini y el refuerzo del review-gate y del analizador de órdenes git. Marca como incompatibles los cambios del registro de sesiones y de la configuración de Codex, y corrige las entradas que estos cambios dejaban desfasadas. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Que cambia
39 commits, uno por cambio, que corrigen prosa, hooks y gates para que hagan lo que dicen en los cuatro backends:
justificationy un modelo de su catálogo.replace,run_shell_command,tool_input.command).-C,--git-dir,GIT_DIR) con el mismo diff que el emisor (--no-ext-diff --no-textconv).enableddecide qué hooks están activos.--parallel[=N]tiene tope, serializa colisiones y pone el gate y el git del índice en exclusión mutua.Por que
Varios mecanismos parecían enforzar y no lo hacían: Codex ignoraba su
hooks.jsonentero, los guards de Gemini no reconocían sus herramientas reales y una función recursiva hacía fallar abiertos los hooks. La prosa también afirmaba cosas que el código no hacía, como el modelo del implementador o la señal de revisión en backends sin motor. Cada cambio se midió contra el runtime real cuando era posible (codex-cli 0.162.1, Gemini CLI 0.63.0, Claude Code 2.1.296).Como probarlo
npm test: 1118 tests, 1117 pass, 0 fail. El único skip es la instalación real con el gestor de extensiones de Gemini, que necesita red y CLI.node scripts/compile.js --check: sin deriva.node bin/cli.js install --backend claudey--backend geminien un directorio temporal,node --test "hooks/tests/*.test.js"da 0 fallos y no añade líneas aai_docs/audits/provenance.jsonl.Checklist
README.md,CLAUDE.md,GEMINI.md) si el comportamiento cambiaCHANGELOG.mdbajo## [Unreleased]hooks/*.js) se ejecutan sin error con Node >= 20.gitattributes)<tipo>: <descripcion>, asunto de 72 caracteres o menos: dos asuntos tienen 73 y 74 caracteres (update: descriptions de skills…yupdate: revisión con evidencia del gate…). El resto cumpleCompatibilidad
Este cambio rompe la compatibilidad con proyectos que ya usan el framework
Registro de sesiones:
cc_versionvale siemprenullysession_modelsolo se rellena si el CLI lo envía en el arranque. Un consumidor que esperaba esos valores debe tratarlos como opcionales.Codex:
.codex/config.tomlpasa agpt-5.5y las reglas usanjustification.updatesustituye los ficheros gestionados; si los editaste a mano, revisa el aviso deupdate.🤖 Generated with Claude Code
https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Generated by Claude Code