Skip to content

Garantías de revisión, seguridad de datos en /implementar-spec, update robusto y CI mínimo - #105

Merged
gmoncor merged 15 commits into
mainfrom
claude/metarepo-changes-audit-nco5e1
Oct 13, 2026
Merged

gmoncor merged 15 commits into
mainfrom
claude/metarepo-changes-audit-nco5e1

Conversation

@gmoncor

@gmoncor gmoncor commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Que cambia

Quince commits, uno por cambio, que corrigen los mecanismos (workflows, hooks, instalador) y la prosa del proceso (agentes y plantillas) para que funcionen sin contradicciones ni pérdida de datos:

  • /implementar-spec ya no borra trabajo. Antes descartaba con reset --hard + clean -fd sobre todo el árbol. Ahora exige el árbol limpio al arrancar y aparta lo no commiteado en git stash (sdd-apartado: <task>). En --parallel se acota a las rutas cambiadas del ámbito, y en secuencial add/diff/commit se limitan al proyecto (monorepo).
  • /planificar no aprueba planes con huecos de revisión. Una revisión ausente o un APROBADO incoherente dan al menos NECESITA_AJUSTES. La segunda pasada revisa solo lo pendiente, con sus hallazgos previos. El auditor tiene un campo avisos que no bloquea.
  • La revisión bloquea solo lo material. Hay una sola definición de BLOQUEANTE, y la seguridad siempre bloquea. El revisor reporta las tasks de convergencia en vez de crearlas. Los agentes aplican los pasos pertinentes al riesgo.
  • Destinos ESM: .claude/workflows/lib/ y scripts/ llevan "type": "commonjs".
  • update:
    • normaliza CRLF en el hash de ficheros de texto;
    • refresca los ficheros que ya convergieron con la versión nueva;
    • avisa de hooks y claves sin cablear, sin fusionar nada.
  • Hooks:
    • read-before-edit ya no avisa sobre lo que el propio agente escribió;
    • session-start avisa si no puede crear el directorio del registro de sesiones;
    • el lint de commits lee git commit -F.
  • session-analyzer:
    • deduplica por message.id, también entre transcripciones;
    • aplica las tarifas vigentes con caché y el tramo de Haiku 5.5;
    • incluye los subagentes.
  • Plantillas: premisas verificadas, control negativo, registro de decisiones con estado, coste de la verificación, tests sin reloj y commit con -F.
  • Calidad:
    • validador de frontmatter y guía de autoría en CONTRIBUTING.md;
    • CI mínimo (npm test + compile.js --check) y --test-timeout;
    • engines.node >=20.11.

Por que

Una auditoría encontró:

  • Riesgo de pérdida de datos: el descarte global de /implementar-spec.
  • Huecos en los gates:
    • un plan podía aprobarse con una task sin revisar;
    • un APROBADO podía ir con críticos;
    • la prosa empujaba a bloquear por duda.
  • Fallos en destinos reales:
    • proyectos ESM;
    • core.autocrlf;
    • avisos de hooks que eran falsos positivos.
  • Métricas de coste infladas: el conteo de cada respuesta salía unas 3 veces de más en entrada y caché y unas 7 en salida.

Como probarlo

  • npm test: sin root, 883 tests, 0 fallos y 1 omitido (la instalación real de Gemini, que necesita red y CLI). Como root falla además «install con un subdirectorio sin permisos…», que ya fallaba antes de esta rama.
  • node scripts/compile.js --check: sin deriva.
  • Cada cambio pasó una revisión independiente con controles negativos (mutantes que vuelven a poner el código anterior y ponen el test en rojo). Los cambios en git se probaron con repositorios reales en directorios temporales (subdirectorio, monorepo, borrados preparados, rutas unicode).
  • Este es el primer run del workflow .github/workflows/test.yml.

Checklist

  • El cambio tiene un unico proposito (no mezcla feature, refactor y formato)
  • Si toca un agente, comando o skill, el cambio equivalente esta aplicado en los cuatro backends (derivados regenerados con compile.js --write; --check sin deriva)
  • Documentacion actualizada (README.md, CLAUDE.md, GEMINI.md) si el comportamiento cambia
  • Entrada anadida en CHANGELOG.md bajo ## [Unreleased]
  • Los hooks (hooks/*.js) se ejecutan sin error con Node >= 20
  • Sin secretos, credenciales, rutas locales ni configuracion de mi IDE
  • Finales de linea LF (los normaliza .gitattributes)
  • Mensajes de commit en formato <tipo>: <descripcion>, asunto de 72 caracteres o menos

Compatibilidad

  • Este cambio rompe la compatibilidad con proyectos que ya usan el framework

Dos cambios visibles sin ruptura:

  • /implementar-spec se niega a arrancar con cambios sin commitear fuera de ai_docs/; el mensaje ofrece commit, stash o worktree.
  • npm test del propio repositorio exige Node 20.11 o superior. Los hooks instalados siguen funcionando con Node 20.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS


Generated by Claude Code

claude added 15 commits October 13, 2026 16:25
Una task cuya revisión individual falló se descartaba con un aviso y el
veredicto final salía solo de la auditoría, así que el plan podía
aprobarse sin que nadie la revisara. Ahora cada task sin revisión se
nombra en los huecos y fuerza al menos NECESITA_AJUSTES.

Un APROBADO con criterios sin cobertura, huecos o incoherencias se
contradice: se normaliza a NECESITA_AJUSTES y se conserva el veredicto
original y la causa. Las dudas sin evidencia del auditor van a un campo
avisos que no bloquea.

La segunda pasada volvía a revisar todas las tasks sin sus hallazgos
previos. Ahora solo revisa las no listas, las que no tuvieron revisión
y las que la corrección tocó, calculadas por hash del contenido de cada
task y de la spec antes y después de corregir, sobre las mismas rutas
resueltas una sola vez dentro del proyecto. Cada una recibe sus
hallazgos previos; las demás conservan su revisión y la auditoría
cruzada se repite completa.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
En un proyecto con "type": "module" en su package.json raíz, Node trata
como ESM los .js de .claude/workflows/lib y de scripts, que son
CommonJS, y los workflows fallan con "require is not defined" al
cargarlos con import(). Un package.json con "type": "commonjs" en cada
directorio fija su ámbito, como ya hacía hooks/. El banco de instalación
prueba ahora un destino ESM: carga cada módulo de lib con import(),
ejecuta cada hook cableado y comprueba que sin el marcador la carga
falla.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Con core.autocrlf=true todo lo instalado queda en CRLF y el hash crudo
hacía que update lo diera entero por editado y dejara de actualizarlo.
El hash de los ficheros de texto normaliza ahora CRLF a LF; un fichero
sin CRLF conserva su hash, así que los sidecars existentes siguen
valiendo, y un binario se sigue hasheando en crudo. Un fichero que el
usuario ya dejó igual a la versión nueva se informa como convergido y
refresca su hash en lugar de repetirse como cambio local en cada update
(con --dry-run solo se anuncia).

Si .claude/settings.json o hooks/config.json se saltan por edición
local, update avisa de los hooks (evento, matcher, comando) y de las
claves de la plantilla que faltan, con la entrada exacta a añadir o la
opción --reset-protected. Solo avisa: no fusiona el JSON del usuario.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La prosa empujaba a convertir la duda en bloqueo («mejor un falso
positivo») y un bloqueo dudoso cuesta la task entera. La plantilla de
revisión adversarial fija ahora una sola definición de BLOQUEANTE
(defecto material con evidencia, incluido todo fallo de seguridad sea
cual sea su severidad percibida); la duda sin evidencia va como WARNING
con lo que la resolvería y se intenta refutar antes de bloquear, sin
relajar la búsqueda. Distingue modo task e integración, define la
re-revisión, amplía la búsqueda (llamadas, coste, mecanismos de
verificación) y abre la salida con el veredicto. El Paso 4bis deja de
ordenar al revisor, que no tiene escritura, crear tasks de convergencia:
las reporta y las crea quien escribe. La auditoría de spec bloquea
también por contrato roto o dependencia circular y manda las dudas a
avisos. El agente revisor aplica los pasos pertinentes al riesgo y
justifica los omitidos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Solo se comprobaba el frontmatter de una skill y el compilador solo
exigía description. El test nuevo recorre en proceso skills, fragmentos
de docs-src, agentes y comandos, y comprueba name contra la carpeta o el
fichero, description en una línea de 240 caracteres como máximo y sin
duplicados, ausencia de model en skills, campos admitidos por tipo y que
ningún campo exclusivo de Claude Code llegue a .agents/skills/. Cada
regla lleva un fixture negativo en línea.

CONTRIBUTING.md añade la guía de autoría: fórmula de la description,
cuándo usar disable-model-invocation, campos por tipo y los tokens que
leen los hooks, que se escriben en ASCII.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
readPayload admite setTimeout/clearTimeout inyectables (por defecto los
globales) y sus tests afirman qué decidió la carrera y que el
temporizador se limpia, no cuánto tardó: con carga, la cota de reloj
daba rojos espurios. Se retira la forma numérica, que nadie usaba.

El registro de sesiones no escribible ya no se omite como root: el
fallo se provoca con un destino que es un directorio (EISDIR) o con un
padre que es un fichero (ENOTDIR), en vez de con permisos, que root
ignora. Este segundo caso destapó que ensureDir callaba el error y el
hook no avisaba; ahora lo avisa por stderr y sigue saliendo con 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Un Write que creaba un fichero salía por «no existe» sin registrar la
ruta, así que el Edit posterior del mismo agente disparaba el aviso: un
falso positivo que enseña a ignorar el hook. Ahora una escritura
completa (Write y sus equivalentes por backend) registra la ruta como
conocida en la sesión. Sobrescribir un fichero existente sin leerlo
sigue avisando. En backends que no entregan lecturas no se registra,
para no activar avisos sobre lecturas que el hook nunca ve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Las tasks no exigían evidencia de sus premisas ni el sentido contrario
de un criterio de ausencia, y las decisiones de la planificación técnica
se recogían sin estado, de modo que una decisión nueva podía contradecir
una vigente en silencio. tareas.md añade «Premisas verificadas», el
control positivo y negativo y criterios condicionales de coste de
verificación y de acceso a datos; revisar_tarea.md los comprueba y pone
el veredicto primero; 02_planificacion_tecnica.md numera las decisiones
como D<n> y las registra con estado VIGENTE / SUSTITUIDA / DESCARTADA.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La plantilla de implementación reporta los hallazgos fuera de alcance
en vez de anotarlos y solo admite tests dirigidos cuando quien lanza la
task declara que ejecuta la suite completa como gate antes de commitear;
si no lo declara, se ejecuta la suite completa. Pide parar los procesos
propios, releer antes de reintentar, declarar el coste de cada
verificación nueva y verificar la interfaz en el viewport real, amplía
el checklist de datos y lista las desviaciones en el informe.
testing_basico sustituye la cota de 50ms por tests independientes del
reloj y añade dos antipatrones; limpieza_de_codigo convierte los
umbrales de líneas en señal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Claude Code escribe varias líneas por message.id durante el streaming,
con el uso acumulándose hasta la última, y el analizador las sumaba
todas: en transcripciones reales inflaba la entrada y la caché unas 3
veces y la salida unas 7. Ahora cuenta cada message.id una vez con su
última línea, también entre transcripciones si se comparte un Set de
ids (una sesión reanudada repite mensajes), agrega
<sesión>/subagents/*.jsonl y aplica las tarifas de entrada, salida,
escritura en caché (5 min y 1 h) y lectura de caché de los modelos
vigentes, copiadas de la página oficial de precios con su URL y fecha,
incluido el precio por tramos de Haiku 5.5 calculado por petición. Un
modelo sin tarifa sigue en unpricedModels. La skill auditar-sesion
describe el nuevo alcance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Implementador, planificador y asesor dejan de exigir todos los pasos de
su plantilla: aplican los pertinentes al riesgo y justifican los que
omiten. El implementador escribe con Edit/Write, reporta los hallazgos
fuera de alcance y no commitea dentro del workflow, que crea el commit
tras la revisión; con /implementar manual el commit lo decide el
usuario. Nombra en su punto de decisión testing_basico,
correccion_de_bugs y limpieza_de_codigo. El asesor no ejecuta cambios:
usa la shell solo para leer y analizar. Cada agente tiene una única
descripción, con su condición de despacho, para los cuatro backends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
La plantilla de commit enseñaba git commit -m "[mensaje]", que se rompe
con un cuerpo multilínea o con comillas. Ahora enseña a escribir el
mensaje en un fichero temporal con ruta absoluta literal y pasarlo con
-F. Para que ese mensaje no quede sin revisar, extractCommitMessage lee
también -F, --file y --file=, resueltos contra el directorio en curso;
un fichero ilegible, -F -, una ruta con variables o un bash -c anidado
no generan aviso ni error. La plantilla deja de pedir una segunda
confirmación cuando el usuario ya pidió el commit de forma explícita.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
El README remite la frontera dura a CI y el repo no tenía workflows.
test.yml ejecuta npm test y compile.js --check en cada PR y en push a
main, con permisos de solo lectura, sin credenciales persistidas y con
la versión mínima de Node que declara engines.

--test-timeout=120000 evita que una prueba colgada bloquee la suite sin
nombrar su fichero; solo protege contra cuelgues (el caso más lento
tarda unos 5 s). La opción exige Node 20.11, así que engines y la
documentación suben a >= 20.11. Los globs van sin comillas porque Node
20 no los expande.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
/implementar-spec descartaba el trabajo de una task fallida con
reset --hard + clean -fd sobre todo el árbol: borraba cambios sin
commitear del usuario y, en --parallel, el trabajo de las tareas
hermanas en curso. Además, sin comprobar el árbol al arrancar, el
add -A de la primera task absorbía cambios ajenos en su commit.

Ahora el workflow no arranca con cambios fuera de ai_docs/ y en
secuencial lo comprueba antes de cada task. El trabajo que no se
commitea se aparta en un stash "sdd-apartado: <task>": en secuencial,
todo el proyecto salvo ai_docs/; en paralelo, solo las rutas cambiadas
de su ámbito, incluidos borrados ya preparados. Si el apartado falla o
deja residuo, no se destruye nada y el recorrido secuencial se detiene.
En secuencial, add, diff y commit se acotan al proyecto (-- .), así que
en un monorepo no arrastran cambios de fuera. El README explica cómo
recuperar lo apartado.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
Añade a [Unreleased] el apartado sin destruir de /implementar-spec, las
garantías nuevas de /planificar y de la revisión, el ámbito CommonJS en
destinos ESM, los arreglos de update, de los hooks y de session-analyzer,
el validador de frontmatter y el CI mínimo. Corrige la entrada de
--parallel, que aún decía que el descarte de una task fallida borraba
los cambios de sus hermanas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6TkghJV3bztMnLNXV4jTS
@gmoncor
gmoncor merged commit c7aa132 into main Oct 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants