docs(metodo): puntero de enrutado en CLAUDE.md + gate que lo vigila
El Método ya viajaba completo a este repo desde el cutover del 2026-08-19, pero se midió que en 9 de 18 repos NADA lo enrutaba: la copia llegaba y no la abría nadie. Es el raíl §8 aplicado al propio Método — un fallo benigno solo protege si alguien LEE la línea; una constitución solo gobierna si alguien la ABRE. El puntero va a CLAUDE.md porque es el único fichero que el harness carga solo en toda sesión sobre el repo; cualquier otro destino reproduce la enfermedad. Bloque GESTIONADO entre marcadores (<!-- metodo:puntero -->): `metodo update` sustituye sólo su interior y no toca un byte fuera — probado con diff contra git en los dos CLAUDE.md ricos, e idempotente (3 updates, mismo md5). Y su gate: `metodo check` gana `check_pointer` — el bloque existe y su destino resuelve. Probado EN ROJO en los tres estados (sin CLAUDE.md, sin bloque, destino inexistente) y con el código de salida moviéndose, que es lo que separa un gate de un aviso que nadie lee. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e7225bc758
commit
db9d69d119
@ -1,2 +1,2 @@
|
||||
37cd8e9792f5cad5e57827068fe6cb00ca5602eca7692ef2ca943a48806bc8a8 metodo.md
|
||||
653e618441c519689753e709df9c8e886db78d84faab4d55167883c5026872a9 bin/metodo
|
||||
22f810404cd02141177066918e66e98ba208c8529fe5ad92cdd66ccb98873ee5 bin/metodo
|
||||
|
||||
@ -152,6 +152,31 @@ check_commits() {
|
||||
[ "$bad_c" -eq 0 ] && ok "los ${n} commit(s) desde la adopción siguen Conventional"
|
||||
}
|
||||
|
||||
# ── Check 6 · el puntero de enrutado existe y RESUELVE (raíl 8) ──────────────
|
||||
# Un puntero sin gate se pudre: es la línea que nadie lee de mañana. Y no basta con que el bloque
|
||||
# esté — su DESTINO tiene que resolver, porque un puntero a la nada enruta a la nada (y encima con
|
||||
# la conciencia tranquila de haberlo puesto). Sabe ponerse rojo de tres formas distintas:
|
||||
# sin CLAUDE.md · con CLAUDE.md pero sin bloque · con bloque cuyo destino no existe.
|
||||
check_pointer() {
|
||||
hdr "puntero de enrutado en CLAUDE.md (raíl 8)"
|
||||
[ -d "$ROOT/.metodo" ] || { skip "no hay .metodo/ — repo sin el Método vendorizado"; return; }
|
||||
local cm="$ROOT/CLAUDE.md"
|
||||
[ -f "$cm" ] || { bad "no hay CLAUDE.md — el Método VIAJA pero nada lo enruta (raíl 8); 'metodo update' desde la matriz"; return; }
|
||||
if ! grep -qxF '<!-- metodo:puntero -->' "$cm" || ! grep -qxF '<!-- /metodo:puntero -->' "$cm"; then
|
||||
bad "CLAUDE.md sin el bloque 'metodo:puntero' — el Método viaja y nada lo abre; 'metodo update'"; return
|
||||
fi
|
||||
ok "CLAUDE.md lleva el bloque del puntero"
|
||||
local tgt found=0 broken=0 l
|
||||
while IFS= read -r l; do
|
||||
tgt="${l%%#*}"; [ -z "$tgt" ] && continue
|
||||
found=$((found+1))
|
||||
[ -e "$ROOT/$tgt" ] || { bad "el puntero apunta a algo que NO EXISTE: $tgt"; broken=$((broken+1)); }
|
||||
done < <(awk '/^<!-- metodo:puntero -->$/{f=1;next} /^<!-- \/metodo:puntero -->$/{f=0} f' "$cm" \
|
||||
| grep -oE '\]\([^)]+\)' | sed -E 's/^\]\(//; s/\)$//')
|
||||
[ "$found" -eq 0 ] && { bad "el bloque del puntero no lleva NINGÚN enlace — no enruta a nada"; return; }
|
||||
[ "$broken" -eq 0 ] && ok "el destino del puntero resuelve ($found enlace(s) comprobado(s))"
|
||||
}
|
||||
|
||||
# ── plantillas de doc/ (sólo se crean si faltan — brownfield: no pisar) ───────
|
||||
_scaffold_docs() { # $1 = repo destino
|
||||
# La casa de docs es UNA y se llama doc/ (el linter ancla ahí el corpus de estado).
|
||||
@ -192,6 +217,67 @@ EOF
|
||||
EOF
|
||||
}
|
||||
|
||||
# ── el PUNTERO de enrutado (bloque gestionado en CLAUDE.md) ──────────────────
|
||||
# Por qué en CLAUDE.md y sólo ahí: es el ÚNICO fichero que el harness carga solo en toda sesión
|
||||
# sobre el repo. Un puntero en cualquier otro sitio reproduce la enfermedad que viene a curar
|
||||
# ("protege si alguien lo abre") — medido el 2026-08-19: la copia viajaba a 9 de 18 repos sin que
|
||||
# nada la abriera. El bloque va entre marcadores y `update` sustituye SÓLO su interior: los
|
||||
# CLAUDE.md ricos son del repo, no nuestros, y no se toca un byte fuera.
|
||||
_PTR_OPEN='<!-- metodo:puntero -->'
|
||||
_PTR_CLOSE='<!-- /metodo:puntero -->'
|
||||
|
||||
_ptr_block() { # escribe el bloque COMPLETO (marcadores incluidos) por stdout
|
||||
cat <<'PTREOF'
|
||||
<!-- metodo:puntero -->
|
||||
⛔ **Antes de tocar nada, lee el Método: [`.metodo/metodo.md`](.metodo/metodo.md)** — los raíles
|
||||
transversales, completos y con sus cicatrices. **Viaja con este repo y aquí NO se edita**: su fuente
|
||||
es el repo `metodo` (la matriz), que lo re-estampa con `metodo update` — este bloque incluido.
|
||||
⇒ Del corpus de este repo, **`doc/AVISOS.md` se lee ANTES que el backlog**. El gate de todo esto es
|
||||
**`metodo check .`** — y si sale rojo, no lo apagues: arréglalo o dilo.
|
||||
⇒ *Existe porque el 2026-08-19 se midió que el Método viajaba a 9 de 18 repos **sin que nada lo
|
||||
abriera**. Una constitución solo gobierna si alguien la lee: es su propio raíl `§8`.*
|
||||
<!-- /metodo:puntero -->
|
||||
PTREOF
|
||||
}
|
||||
|
||||
_stamp_pointer() { # $1 = repo destino
|
||||
local tgt="$1" cm="$1/CLAUDE.md" blk tmp
|
||||
blk=$(mktemp); _ptr_block > "$blk"
|
||||
tmp=$(mktemp)
|
||||
if [ ! -f "$cm" ]; then
|
||||
# No hay CLAUDE.md: se crea MÍNIMO (título + bloque y nada más). Lo que la matriz no puede
|
||||
# mantener no se siembra: se pudriría (raíl 7).
|
||||
{ printf '# %s\n\n' "$(basename "$(cd "$tgt" && pwd)")"; cat "$blk"; } > "$cm"
|
||||
rm -f "$blk" "$tmp"; echo " CLAUDE.md creado (mínimo) con el puntero"; return
|
||||
fi
|
||||
if grep -qxF "$_PTR_OPEN" "$cm" && grep -qxF "$_PTR_CLOSE" "$cm"; then
|
||||
# Ya está: se sustituye SÓLO el interior de los marcadores (idempotente).
|
||||
awk -v blk="$blk" -v o="$_PTR_OPEN" -v c="$_PTR_CLOSE" '
|
||||
$0 == o { inb=1; while ((getline l < blk) > 0) print l; close(blk); next }
|
||||
$0 == c { inb=0; next }
|
||||
inb { next }
|
||||
{ print }' "$cm" > "$tmp" && mv "$tmp" "$cm"
|
||||
rm -f "$blk"; echo " CLAUDE.md: puntero re-estampado (sólo el interior de los marcadores)"; return
|
||||
fi
|
||||
# Existe pero sin bloque: se inserta ANTES del primer `## `; si no hay, tras el H1; si no, arriba.
|
||||
awk -v blk="$blk" '
|
||||
function put( l){ while ((getline l < blk) > 0) print l; close(blk); print ""; done=1 }
|
||||
!done && /^## / { put() }
|
||||
{ print }
|
||||
NR==1 && $0 ~ /^# / { h1=1 }
|
||||
END { if (!done) exit 9 }' "$cm" > "$tmp"
|
||||
if [ $? -eq 9 ]; then
|
||||
# sin ningún `## `: tras el H1 (o al principio si no hay H1)
|
||||
awk -v blk="$blk" '
|
||||
function put( l){ print ""; while ((getline l < blk) > 0) print l; done=1 }
|
||||
NR==1 { print; if ($0 ~ /^# /) put(); else { print ""; } ; next }
|
||||
NR==2 && !done { put(); print; next }
|
||||
{ print }' "$cm" > "$tmp"
|
||||
fi
|
||||
mv "$tmp" "$cm"; rm -f "$blk"
|
||||
echo " CLAUDE.md: puntero insertado antes del primer encabezado"
|
||||
}
|
||||
|
||||
# ── metodo init <repo> — vendoriza el Método a un repo por primera vez ────────
|
||||
cmd_init() {
|
||||
local tgt="${1:-.}"
|
||||
@ -219,6 +305,7 @@ Etiquetas: [NUEVA-REGLA] · [REFINA Cn] · [Cn-NO-ENCAJA] · [FALSA]. Se cosecha
|
||||
---
|
||||
EOF
|
||||
_scaffold_docs "$tgt"
|
||||
_stamp_pointer "$tgt"
|
||||
echo "metodo init: $tgt inicializado — .metodo/ (máster $mver) + doc/ de tres capas."
|
||||
echo " siguiente: siembra doc/backlog.md con el trabajo abierto de hoy y corre 'metodo check .'"
|
||||
}
|
||||
@ -239,6 +326,7 @@ cmd_update() {
|
||||
[ -n "$adopt" ] && echo "adopted_commit: $adopt"; } > "$md/VERSION"
|
||||
_write_checksums "$md" || echo " (aviso: sin sha256 → CHECKSUMS no escrito)"
|
||||
printf '* text eol=lf\n' > "$md/.gitattributes"
|
||||
_stamp_pointer "$tgt"
|
||||
echo "metodo update: $tgt actualizado al máster $mver (metodo.md + linter, byte a byte); realimentacion.md y adopted_commit preservados."
|
||||
}
|
||||
|
||||
@ -249,6 +337,7 @@ cmd_check() {
|
||||
check_headings
|
||||
check_links
|
||||
check_commits
|
||||
check_pointer
|
||||
hdr "resultado"
|
||||
if [ "$FAILS" -eq 0 ]; then
|
||||
printf ' \033[32mPASA el Método\033[0m (0 avisos)\n'; exit 0
|
||||
|
||||
11
CLAUDE.md
Normal file
11
CLAUDE.md
Normal file
@ -0,0 +1,11 @@
|
||||
# smtp-relay
|
||||
|
||||
<!-- metodo:puntero -->
|
||||
⛔ **Antes de tocar nada, lee el Método: [`.metodo/metodo.md`](.metodo/metodo.md)** — los raíles
|
||||
transversales, completos y con sus cicatrices. **Viaja con este repo y aquí NO se edita**: su fuente
|
||||
es el repo `metodo` (la matriz), que lo re-estampa con `metodo update` — este bloque incluido.
|
||||
⇒ Del corpus de este repo, **`doc/AVISOS.md` se lee ANTES que el backlog**. El gate de todo esto es
|
||||
**`metodo check .`** — y si sale rojo, no lo apagues: arréglalo o dilo.
|
||||
⇒ *Existe porque el 2026-08-19 se midió que el Método viajaba a 9 de 18 repos **sin que nada lo
|
||||
abriera**. Una constitución solo gobierna si alguien la lee: es su propio raíl `§8`.*
|
||||
<!-- /metodo:puntero -->
|
||||
Loading…
Reference in New Issue
Block a user