docs(metodo): re-estampado al máster 2026-08-22 — cuarta capa del corpus
metodo.md describe las CUATRO capas (backlog · decisiones · AVISOS · bitácora) y la regla de refinement de D7; el linter estampa doc/decisiones.md en los init nuevos y gana tres checks de la capa de decisiones. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
db9d69d119
commit
a901586bab
@ -1,2 +1,2 @@
|
||||
37cd8e9792f5cad5e57827068fe6cb00ca5602eca7692ef2ca943a48806bc8a8 metodo.md
|
||||
22f810404cd02141177066918e66e98ba208c8529fe5ad92cdd66ccb98873ee5 bin/metodo
|
||||
140cf44bc4d8e9eff08cd4f6466df22c897efa2c6c6f83662a747e3348a4f2bd metodo.md
|
||||
bf2144db0bb987bd32ce7eb8d99021ca0d29cb7b6a48d30a8ffd0fe723ca2a3f bin/metodo
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Copia vendorizada del Método (raíl C11). Gestionada por 'metodo init/update'.
|
||||
master: metodo
|
||||
version: 2026-08-19
|
||||
version: 2026-08-22
|
||||
estado: vendored
|
||||
adopted_commit: 6a10eab342a477846ab5f3e67f8ab17169f12807
|
||||
|
||||
@ -16,6 +16,7 @@ set -uo pipefail # -u: variable sin definir es error · pipefail: un pipe here
|
||||
|
||||
ROOT="."
|
||||
FAILS=0
|
||||
WARNS=0 # notas: se cuentan y se dicen, pero NO mueven el código de salida (ver check 8)
|
||||
SELF_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)" # raíz del repo del script
|
||||
|
||||
# sha256 portable (Git Bash trae sha256sum; si no, shasum -a 256; si ninguno, la deriva no se mide)
|
||||
@ -34,11 +35,12 @@ _write_checksums() { # $1 = dir .metodo del destino
|
||||
}
|
||||
_is_matriz() { [ -f "$SELF_ROOT/constitucion-de-facto.md" ]; } # marca inequívoca de la matriz
|
||||
|
||||
# --- veredictos (los cuatro colores del check) ---
|
||||
# --- veredictos (los cinco colores del check) ---
|
||||
hdr() { printf '\n\033[1m== %s ==\033[0m\n' "$*"; }
|
||||
ok() { printf ' \033[32mok \033[0m %s\n' "$*"; }
|
||||
bad() { printf ' \033[31mAVISO\033[0m %s\n' "$*"; FAILS=$((FAILS+1)); }
|
||||
skip() { printf ' \033[33mSKIP\033[0m %s\n' "$*"; }
|
||||
warn() { printf ' \033[33mnota\033[0m %s\n' "$*"; WARNS=$((WARNS+1)); }
|
||||
|
||||
# ── Check 1 · integridad de la copia vendorizada (C11) ───────────────────────
|
||||
# El máster vive en OTRO repo (la matriz), así que el testigo no es el máster sino el
|
||||
@ -177,6 +179,93 @@ check_pointer() {
|
||||
[ "$broken" -eq 0 ] && ok "el destino del puntero resuelve ($found enlace(s) comprobado(s))"
|
||||
}
|
||||
|
||||
# ── Check 7 · la capa de DECISIONES: ids únicos (rojo) y campos (nota) ───────
|
||||
# Cuarta capa del corpus (`D6`, 2026-08-22). Existe porque una decisión guardada en el backlog se
|
||||
# numera por FASE, y la numeración por fase colisiona: 18 decisiones distintas llamadas `D1` en un
|
||||
# solo backlog.md. Por eso el id duplicado va en ROJO y no en nota — es AMBIGÜEDAD DE CITA sobre lo
|
||||
# peligroso del repo: un nombre que apunta a dos decisiones distintas hace que citar una gobierne
|
||||
# con la otra. Los CAMPOS van en nota: un repo que acaba de estrenar la capa no se pone rojo por
|
||||
# terminar de rellenarla.
|
||||
# Una entrada se DEFINE con un encabezado `### <id> — <título>`, y el id es el primer token: así una
|
||||
# mención inline ("ver D107") no define nada y el testigo no puede dar falsos positivos.
|
||||
check_decisiones() {
|
||||
hdr "capa de decisiones · ids y campos (C17 · D6)"
|
||||
local f="$ROOT/doc/decisiones.md"
|
||||
[ -f "$f" ] || { skip "sin doc/decisiones.md — la cuarta capa se adopta cuando la orquestadora del repo migre sus 'D' (D6)"; return; }
|
||||
local ids n dups id
|
||||
ids=$(awk '/^### /{ s=$0; gsub(/\*/,"",s); split(s,a,"[ \t]+"); if (a[2]!="") print a[2] }' "$f")
|
||||
n=$(printf '%s\n' "$ids" | grep -c '[^[:space:]]')
|
||||
if [ "$n" -eq 0 ]; then
|
||||
warn "doc/decisiones.md no tiene NINGUNA entrada '### <id> — <título>' — un registro vacío no gatea nada (D6)"
|
||||
return
|
||||
fi
|
||||
dups=$(printf '%s\n' "$ids" | sort | uniq -d)
|
||||
if [ -n "$dups" ]; then
|
||||
while IFS= read -r id; do
|
||||
[ -n "$id" ] && bad "id duplicado en decisiones.md: $id — dos decisiones con el mismo nombre: citar una gobierna con la otra (C17); renumera la NUEVA desde el contador del repo"
|
||||
done <<< "$dups"
|
||||
else
|
||||
ok "decisiones.md: $n entrada(s), sin ids duplicados"
|
||||
fi
|
||||
# Campos obligatorios de cada entrada: dueño (Xavier / técnica — una técnica escalada como suya
|
||||
# ya coló) y estado (vigente / sustituida — sin él, una decisión muerta sigue mandando).
|
||||
local faltan miss
|
||||
faltan=$(awk '
|
||||
function flush( m){ if (id!="") { m=""; if(!hd) m=m" dueño"; if(!he) m=m" estado";
|
||||
if (m!="") print id "\t" m } id=""; hd=0; he=0 }
|
||||
/^### / { flush(); s=$0; gsub(/\*/,"",s); split(s,a,"[ \t]+"); id=a[2]; next }
|
||||
/^#{1,2} / { flush(); next }
|
||||
{ if ($0 ~ /\*\*due/) hd=1
|
||||
if ($0 ~ /\*\*estado/) he=1 }
|
||||
END { flush() }' "$f")
|
||||
if [ -n "$faltan" ]; then
|
||||
while IFS=$'\t' read -r id miss; do
|
||||
[ -n "$id" ] && warn "decisiones.md · «$id» sin:$miss — el dueño y el estado son el gate de la entrada (D6)"
|
||||
done <<< "$faltan"
|
||||
else
|
||||
ok "todas las entradas llevan dueño y estado"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Check 8 · textos de DECISIÓN dentro del backlog (nota) ───────────────────
|
||||
# Invierte el gradiente de comodidad: escribir la decisión en el sitio equivocado pasa a ser lo que
|
||||
# cuesta. Se mide el BLOQUE —la línea que define `Dn` más sus líneas de continuación indentadas—;
|
||||
# más de 3 líneas ya es un cuerpo de decisión, no una referencia.
|
||||
# ⚠️ CALIBRADO para no enrojecer a los backlogs legacy que aún no han migrado, y SÍ se pueden
|
||||
# distinguir: los ids nuevos nacen en `D100` (rango limpio — ningún legacy del árbol llega a 100).
|
||||
# ⇒ `Dn` con n>=100 y cuerpo = decisión escrita HOY en el sitio equivocado → nota nominal.
|
||||
# ⇒ `Dn` con n<100 = deuda de migración de la orquestadora de ese repo → se CUENTA y se dice, no se
|
||||
# juzga. Y ninguno de los dos mueve el código de salida a propósito: la capa se estrena hoy y
|
||||
# romper el gate de 21 repos por deuda ajena es cómo se aprende a apagar el gate.
|
||||
check_decisiones_en_backlog() {
|
||||
hdr "textos de decisión dentro del backlog (D6)"
|
||||
local f="$ROOT/doc/backlog.md"
|
||||
[ -f "$f" ] || { skip "sin doc/backlog.md (repo sin corpus de estado)"; return; }
|
||||
local out legacy=0 nuevos=0 id len num
|
||||
out=$(awk '
|
||||
function flush(){ if (id!="" && len>3) print id "\t" len; id=""; len=0 }
|
||||
/^[[:space:]]*[-*|_]+[[:space:]]*[*~`]*D[0-9]+/ {
|
||||
flush(); match($0, /D[0-9]+/); id=substr($0, RSTART, RLENGTH); len=1; next }
|
||||
/^[[:space:]]+[^[:space:]]/ { if (id!="") { len++; next } }
|
||||
{ flush() }
|
||||
END { flush() }' "$f")
|
||||
if [ -n "$out" ]; then
|
||||
while IFS=$'\t' read -r id len; do
|
||||
[ -n "$id" ] || continue
|
||||
num=${id#D}
|
||||
if [ "$num" -ge 100 ] 2>/dev/null; then
|
||||
nuevos=$((nuevos+1))
|
||||
warn "«$id» lleva $len líneas de texto de decisión dentro de backlog.md — las decisiones viven en doc/decisiones.md (D6)"
|
||||
else
|
||||
legacy=$((legacy+1))
|
||||
fi
|
||||
done <<< "$out"
|
||||
fi
|
||||
[ "$legacy" -gt 0 ] && ok "$legacy texto(s) de decisión con id legacy (<D100) en backlog.md: migran cuando su orquestadora migre (D6) — las NUEVAS ya no se escriben aquí"
|
||||
[ "$nuevos" -eq 0 ] && [ "$legacy" -eq 0 ] && ok "ninguna decisión con cuerpo dentro de backlog.md"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── 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).
|
||||
@ -190,15 +279,55 @@ _scaffold_docs() { # $1 = repo destino
|
||||
[ -f "$d/backlog.md" ] || cat > "$d/backlog.md" <<'EOF'
|
||||
# Backlog
|
||||
|
||||
> Tres capas: **este backlog** = estado (metas + decisiones cerradas `D` + items) ·
|
||||
> AVISOS.md = bandera (se lee primero) · bitacora.md = relato append-only.
|
||||
> Método vendorizado en ../.metodo/metodo.md. ⛔ Las `D` son inmutables. Un `##` no lleva marca de
|
||||
> Cuatro capas: **este backlog** = el eje del TROCEO (metas + items; un item ≈ una sesión) ·
|
||||
> decisiones.md = lo peligroso, todo junto · AVISOS.md = bandera (se lee primero) ·
|
||||
> bitacora.md = relato append-only. Método vendorizado en ../.metodo/metodo.md.
|
||||
> ⛔ Las decisiones son **inmutables**: contradecir = PARAR y reportar. Un `##` no lleva marca de
|
||||
> estado; abierto = tiene `[ ]`.
|
||||
|
||||
## Decisiones cerradas
|
||||
## Decisiones
|
||||
|
||||
Viven en **[decisiones.md](decisiones.md)** (cuarta capa, `D6`). Aquí se **citan por id**, no se
|
||||
copian: escribirlas en los dos sitios es crear la deriva que §7 existe para impedir.
|
||||
|
||||
## Abierto
|
||||
- [ ] (siembra aquí el trabajo ABIERTO de hoy — brownfield: el pasado no se reconstruye)
|
||||
EOF
|
||||
[ -f "$d/decisiones.md" ] || cat > "$d/decisiones.md" <<'EOF'
|
||||
# Decisiones
|
||||
|
||||
> **Cuarta capa del corpus** (`D6`, Xavier 2026-08-22): backlog = el eje del troceo ·
|
||||
> **este fichero = lo peligroso, TODO JUNTO** · AVISOS.md = bandera, se lee primero ·
|
||||
> bitacora.md = relato append-only. Los raíles, en ../.metodo/metodo.md (§7: el destino se decide
|
||||
> UNA vez).
|
||||
>
|
||||
> ⛔ **Una decisión `vigente` no se contradice**: o **PARAS y reportas**, o la **sustituyes**
|
||||
> explícitamente — y la sustitución **edita la entrada vieja** (⚰️ + puntero a la nueva), nunca
|
||||
> deja las dos vivas.
|
||||
> ⛔ **Antes de cerrar nada, recorre el ámbito y mira QUÉ CONTRADICES.** Ésa es la fuerza que
|
||||
> mantiene vivo este documento: no hay gate automático que la sustituya.
|
||||
>
|
||||
> **Orden: por ÁMBITO, no por fase** — numerar por fase es lo que fabricó **18 decisiones distintas
|
||||
> llamadas `D1`** en un solo backlog. **Ids nuevos: contador único del repo desde `D100`**,
|
||||
> monótono, jamás reiniciado por sección. Los legacy migran con su **id INTACTO**, citados
|
||||
> `fase·Dn` (p. ej. `I11·D18`): C17 prohíbe renumerar, y renumerar rompe las citas cruzadas.
|
||||
>
|
||||
> **Formato**: una entrada = un `### <id> — <título>`. El id es el primer token (es lo que lee
|
||||
> `metodo check`). Los campos **dueño** y **estado** son el gate de la entrada.
|
||||
|
||||
## Ámbito: (nombre del ámbito — p. ej. "transporte", "identidad", "panel")
|
||||
|
||||
### D100 — (título corto, sin punto final)
|
||||
|
||||
- **dueño**: Xavier · **fecha**: 2026-01-01 · **estado**: vigente
|
||||
- **sustituye**: — · **testigo**: — *(si la decisión AFIRMA algo medible, el testigo y su condición
|
||||
van AQUÍ, en esta misma línea: la clase de fallo del «VALIDADO» con su condición 116 líneas
|
||||
más abajo)*
|
||||
|
||||
(Texto **ÍNTEGRO** de la decisión, en las palabras en que se tomó. **Nunca un resumen**: un resumen
|
||||
adquiere invariantes que la decisión no tiene, y ya gobernó una sesión entera en lugar de la `D`.
|
||||
Sustituye este ejemplo por tu primera decisión real — si dejas el `D100` puesto, la primera de
|
||||
verdad colisiona con él y `metodo check` se pone rojo.)
|
||||
EOF
|
||||
[ -f "$d/AVISOS.md" ] || cat > "$d/AVISOS.md" <<'EOF'
|
||||
# ⚠️ AVISOS
|
||||
@ -306,7 +435,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 "metodo init: $tgt inicializado — .metodo/ (máster $mver) + doc/ de CUATRO capas (backlog · decisiones · AVISOS · bitácora)."
|
||||
echo " siguiente: siembra doc/backlog.md con el trabajo abierto de hoy y corre 'metodo check .'"
|
||||
}
|
||||
|
||||
@ -337,12 +466,16 @@ cmd_check() {
|
||||
check_headings
|
||||
check_links
|
||||
check_commits
|
||||
check_decisiones
|
||||
check_decisiones_en_backlog
|
||||
check_pointer
|
||||
hdr "resultado"
|
||||
local nota=""
|
||||
[ "$WARNS" -gt 0 ] && nota=$(printf ' · %d nota(s) — no mueven el código de salida, pero se cuentan' "$WARNS")
|
||||
if [ "$FAILS" -eq 0 ]; then
|
||||
printf ' \033[32mPASA el Método\033[0m (0 avisos)\n'; exit 0
|
||||
printf ' \033[32mPASA el Método\033[0m (0 avisos%s)\n' "$nota"; exit 0
|
||||
else
|
||||
printf ' \033[31m%d aviso(s) — el Método NO pasa\033[0m\n' "$FAILS"; exit 1
|
||||
printf ' \033[31m%d aviso(s) — el Método NO pasa\033[0m%s\n' "$FAILS" "$nota"; exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ Principios que valen para **cualquier** sesión (exploración, ejecución, despl
|
||||
incidente, orquestación) y para cualquier backlog. Los workflows concretos referencian este
|
||||
doc en vez de repetirlo. No son teoría: cada uno lleva el caso real que lo enseñó.
|
||||
|
||||
> **Versión 2026-08-19.** Documento **autocontenido**: es lo que se vendoriza, byte a byte, a cada
|
||||
> **Versión 2026-08-22.** Documento **autocontenido**: es lo que se vendoriza, byte a byte, a cada
|
||||
> repo (no lleva enlaces a rutas de un árbol concreto, para que funcione clonado en solitario).
|
||||
> Cada regla lleva su **cicatriz** (meta-principio: un raíl se escribe con el incidente que lo
|
||||
> enseñó, no a priori). Procedencia, fuerza (nº de repos) y partición linter/juicio: fichero
|
||||
@ -105,6 +105,15 @@ foco**, que es el recurso escaso. ⇒ Lo que convierte esto en método y no en e
|
||||
la mejora se **mide** y lo que queda fuera se **escribe** (un ⏸️ con su motivo, como el aplazamiento
|
||||
de la captura de hub), para que nadie lo confunda con un olvido.
|
||||
|
||||
⛔ **Y el refinement que lo hace ejecutable: una decisión que acarrea trabajo FUERA del alcance del
|
||||
producto o de la fase NO se queda como casilla.** Se convierte en **épica nueva** si es grande, o se
|
||||
va **a su fase** si tiene una — y se prioriza como todo lo demás: **por valor de producto**, no por
|
||||
lo bien argumentada que esté. *(Xavier, `D7`, 2026-08-22. Estrenada el mismo día: `I11.11` salió de
|
||||
su ficha a una épica propia **con su valor declarado — cero, porque no hay nadie esperándola**, que
|
||||
es justo el dato que una casilla escondida dentro de otra ficha no da.)*
|
||||
⇒ Es el mismo movimiento que el del ámbito de amenaza, una capa más arriba: **lo que no es de aquí
|
||||
no se descarta ni se cuela — se muda, con su valor escrito.**
|
||||
|
||||
## 1. Verifica el resultado, no la intención
|
||||
|
||||
Comprueba lo que el sistema **sirve/hace**, no lo que su fuente **dice** que hará. Una señal
|
||||
@ -920,11 +929,29 @@ copia pura.)*
|
||||
`sesion-ordenacion-docs.md` (capa `workflows/`)— pero vivía **en el workflow de la sesión
|
||||
que LIMPIA, no en el de las que ESCRIBEN**, así que se incumplía sistemáticamente y se pagaba
|
||||
después en una pasada. Por eso está aquí ahora.
|
||||
⇒ **Al escribir, decide el destino UNA vez**, con el test del workflow: *¿una sesión futura necesita
|
||||
esto para NO contradecir una decisión?* → **backlog**. *¿Es cómo nos enteramos —lo medido, las
|
||||
predicciones, los mutantes, las premisas falsas, el relato—?* → **bitácora**, y en el backlog **un
|
||||
puntero fechado**. ⭐ Escribirlo en los dos **no es prudencia: es crear la deriva** que §7 existe
|
||||
para impedir, porque el día que uno de los dos se corrija el otro seguirá ahí.
|
||||
⇒ **Al escribir, decide el destino UNA vez**, y los destinos son **CUATRO**: el corpus de un repo
|
||||
tiene **cuatro capas**, no tres. *¿Es una decisión cerrada, de las que otra sesión no puede
|
||||
contradecir sin PARAR?* → **`doc/decisiones.md`**, con su texto **íntegro**. *¿Es trabajo — un item
|
||||
que cabe en una sesión?* → **`doc/backlog.md`**, que es **el eje del troceo**. *¿Es lo que hay que
|
||||
saber el primer día?* → **`doc/AVISOS.md`**, que se lee antes que el backlog. *¿Es cómo nos
|
||||
enteramos —lo medido, las predicciones, los mutantes, las premisas falsas, el relato—?* →
|
||||
**`doc/bitacora.md`**, append-only, y en el backlog **un puntero fechado**. ⭐ Escribirlo en dos
|
||||
**no es prudencia: es crear la deriva** que §7 existe para impedir, porque el día que uno de los dos
|
||||
se corrija el otro seguirá ahí.
|
||||
⛔ **Y la cuarta capa existe porque una decisión guardada en el backlog se numera POR FASE, y la
|
||||
numeración por fase colisiona.** *(Cicatriz 2026-08-22, `D6` de Xavier: **18 decisiones distintas
|
||||
llamadas `D1`** en un solo `backlog.md` — y cuatro fallos de una semana que salen de ahí: un
|
||||
**resumen** que gobernó en lugar de la decisión, un «precio aceptado» que Xavier nunca pensó, dos
|
||||
ids que colisionaban, y una sustitución con las **dos versiones vivas** a 90 líneas de distancia.
|
||||
En sus palabras, para qué sirve la capa: «así tienes todo lo peligroso en un único documento».)*
|
||||
⇒ Por eso se ordena **por ámbito, no por fase**; cada entrada lleva **texto íntegro** (nunca un
|
||||
resumen — un resumen adquiere invariantes que la decisión no tiene), **dueño visible** (*Xavier* o
|
||||
*técnica*: una técnica escalada como suya ya coló), **estado**, y el **testigo en la misma línea**
|
||||
si afirma algo medible (§1). Una sustitución **edita la entrada vieja** —⚰️ y puntero—, jamás deja
|
||||
las dos vivas.
|
||||
⇒ Y «todo lo peligroso en un único documento» solo protege si **alguien lo recorre** (§8): toda
|
||||
sesión de diseño mira ahí **qué contradice** antes de cerrar nada, y si contradice una `vigente`,
|
||||
**PARA y reporta** (§6) o la sustituye explícitamente.
|
||||
⛔ **Un valor por DEFECTO declarado como dato en la capa base solo es fuente única si TODOS los
|
||||
consumidores pasan por el merge.** El que se lo salta no es un descuido: es una **segunda fuente**
|
||||
—con su propia verdad— y hay que buscarlo **explícitamente al introducir el default**, no el día que
|
||||
|
||||
Loading…
Reference in New Issue
Block a user