docs(metodo): re-estampar el linter — D100 (vocabulario de ids + límite por la derecha)
_IDPFX gana B y M (medusa numera Mn, hermes-sitad Bn: el linter era ciego a los dos corpus enteros) y la extracción de ids gana límite por la derecha: P9b no es P9, E8.a no es E8, R5-bis no es R5, E2E no es un id. El reconocedor pasa a awk, porque el límite no se puede expresar en un grep -oE sin lookahead. Y el censo dice ahora lo que TIRA (sub-ids) y lo que NO ADMITE, en vez de callarlo. Copia vendorizada: aquí NO se edita. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d2df969153
commit
ecee0e1d7b
@ -1,2 +1,2 @@
|
||||
140cf44bc4d8e9eff08cd4f6466df22c897efa2c6c6f83662a747e3348a4f2bd metodo.md
|
||||
d469ed0f661c56e3137953f880f5a7dfc51e0b74e49ae7616ac5d88bf6d91b99 bin/metodo
|
||||
252f0e98ca4f8e015fceff57493a132f665514e4fd590ef2172dc6e4dfa021ab bin/metodo
|
||||
|
||||
@ -93,22 +93,53 @@ check_drift() {
|
||||
# fichero —«vistos: 0» fue indistinguible de «no hay» durante dos semanas— y si un fichero
|
||||
# tiene líneas con FORMA de id y 0 parseados, saca nota de posible ceguera. Es el
|
||||
# gate-sin-sujeto aplicado al propio linter.
|
||||
_IDPFX='(D|A|G|H|C|R|F|E|P)'
|
||||
# id DEFINIDO = al principio de una fila de tabla (|) o item de lista (-*), con el adorno que
|
||||
# sea. Así una MENCIÓN inline ("ver D5") no cuenta como definición (evita falsos positivos).
|
||||
_RE_ID_DEF="^[[:space:]]*[|*_-]+[[:space:]]*[*~\`]*${_IDPFX}[0-9]+"
|
||||
# LAXO: la MISMA posición de definición, pero con CUALQUIER adorno (hasta 12 caracteres no
|
||||
# alfanuméricos: casillas `- [ ]`, emoji, comillas…) y —esto es lo que importa— con CUALQUIER
|
||||
# PREFIJO de letra, no los de `_IDPFX`. Un detector de ceguera construido sobre el vocabulario
|
||||
# que audita sólo sabe cazar la ceguera de ADORNO, jamás la de PREFIJO: sería el gate-sin-sujeto
|
||||
# un piso más arriba. Medido el 2026-08-22: con `_IDPFX` no veía los nueve `B` de hermes-sitad.
|
||||
# Es a propósito más ancho que el estricto y mucho más estrecho que «el id en cualquier sitio de
|
||||
# la línea» — una mención en mitad de una frase no tiene forma de definición. Sólo se usa cuando
|
||||
# el estricto ha visto 0: es el detector de «el sujeto está y no lo veo», no un criterio de id.
|
||||
# La casilla de markdown (`- [ ]` / `- [x]` / `- [~]`) se salta APARTE: lleva un alfanumérico
|
||||
# dentro y un item CERRADO define tanto como uno abierto.
|
||||
_RE_ID_LOOSE="^[[:space:]]*[|*_-][[:space:]]*(\[.\])?[^[:alnum:]]{0,12}[A-Z]{1,2}[0-9]+"
|
||||
_ids_def() { grep -oE "$_RE_ID_DEF" "$1" | grep -oE "${_IDPFX}[0-9]+"; }
|
||||
# Prefijos de id que reconoce el linter. ⚠️ **`B` y `M` entraron el 2026-08-22 (`D100`)**: medusa
|
||||
# numera su backlog `M0`…`Mn` y hermes-sitad sus avisos `B1`…`B9`, y el linter era CIEGO a los dos
|
||||
# corpus ENTEROS — 49 y 9 líneas, 0 vistas, aprobando sobre la nada desde el día uno. Lo cazó la
|
||||
# nota anti-ceguera de aquí abajo en su primera ejecución sobre corpus reales.
|
||||
_IDPFX='D|A|B|G|H|C|M|R|F|E|P'
|
||||
|
||||
# ── el reconocedor de ids ────────────────────────────────────────────────────
|
||||
# ⚠️ Está en **awk y no en un `grep -oE` encadenado**, y el motivo es el LÍMITE POR LA DERECHA
|
||||
# (`D100`): no se puede expresar sin lookahead. Se intentó con un segundo `grep -vE` y el filtro
|
||||
# casaba `D1` + `7` dentro de `D17` ⇒ **declaraba sub-id a todo id de dos cifras**. Aquí el id y su
|
||||
# cola se miran POR SEPARADO, que es la única forma de que la pregunta sea la que parece.
|
||||
#
|
||||
# modo `def` → **id DEFINIDO**: posición de definición (fila de tabla `|` o item de lista `-*`,
|
||||
# con su adorno: negrita, tachado y comilla invertida) + prefijo de `_IDPFX`. Así
|
||||
# una MENCIÓN inline («ver D5») no define nada y no da falsos positivos.
|
||||
# modo `forma` → **¿tiene esta línea FORMA de definición?**, con CUALQUIER prefijo de letra y
|
||||
# CUALQUIER adorno (casilla `- [ ]`/`- [x]` incluida — un item cerrado define tanto
|
||||
# como uno abierto). Es a propósito agnóstico de `_IDPFX`: un detector de ceguera
|
||||
# construido sobre el vocabulario que audita sólo caza la ceguera de ADORNO, jamás
|
||||
# la de PREFIJO, que es el gate-sin-sujeto un piso más arriba. Sólo se usa cuando
|
||||
# el estricto ha visto 0.
|
||||
#
|
||||
# El LÍMITE POR LA DERECHA vale para los dos: `P9b`/`P9c` NO son `P9`, `E8.a` NO es `E8` y
|
||||
# `R5-bis` NO es `R5` —son **sub-ids**, no colisiones, y contarlos como el padre fabricaba
|
||||
# duplicados que no existen—; y `E2E` («end-to-end») no es un id en absoluto. Ninguno de los dos
|
||||
# casos se puede distinguir del otro por su forma, así que ninguno cuenta como definición.
|
||||
_id_scan() { # $1 = fichero · $2 = def|forma
|
||||
awk -v pfx="$_IDPFX" -v modo="$2" '
|
||||
{ if (modo != "forma") { if (match($0, "^[[:space:]]*[|*_-]+[[:space:]]*[*~`]*") == 0) next }
|
||||
else { if (match($0, "^[[:space:]]*[|*_-][[:space:]]*([[].[]])?[^[:alnum:]]*") == 0) next }
|
||||
rest = substr($0, RLENGTH + 1)
|
||||
re = (modo == "forma") ? "^[A-Z][A-Z]?[0-9]+" : "^(" pfx ")[0-9]+"
|
||||
if (match(rest, re) == 0) next
|
||||
id = substr(rest, 1, RLENGTH); cola = substr(rest, RLENGTH + 1)
|
||||
# ⚠️ El LÍMITE POR LA DERECHA (`D100`) NO se aplica al modo `forma`: ese es el detector de
|
||||
# «el sujeto está y no lo veo», y un detector que descarta lo mismo que el criterio deja de
|
||||
# detectar nada. Se midió: con el límite puesto, medusa decía 12 líneas con forma de id
|
||||
# donde hay 49. Es la MISMA lección que ya obligó a hacerlo agnóstico de prefijo.
|
||||
if (modo != "forma") {
|
||||
if (cola ~ /^[[:alnum:]]/ ) { if (modo == "subid") print "1"; next } # P9b / E2E
|
||||
if (cola ~ /^[.-][[:alnum:]]/ ) { if (modo == "subid") print "1"; next } # E8.a / R5-bis
|
||||
}
|
||||
if (modo == "def") print id; else if (modo == "forma") print "1" }' "$1"
|
||||
}
|
||||
_ids_def() { _id_scan "$1" def; }
|
||||
_lineas_forma_id() { _id_scan "$1" forma | grep -c "^1$"; }
|
||||
_subids() { _id_scan "$1" subid | grep -c "^1$"; } # lo que el LÍMITE tira: se dice, no se calla
|
||||
|
||||
check_ids() {
|
||||
hdr "colisión de ids en los ficheros de estado (C17)"
|
||||
@ -116,14 +147,14 @@ check_ids() {
|
||||
# número sea < 100 (un legacy MIGRADO ya tiene dueño que puede cerrarlo).
|
||||
local dec="$ROOT/doc/decisiones.md" nuevos_dec=""
|
||||
[ -f "$dec" ] && nuevos_dec=$(awk '/^### /{ s=$0; gsub(/[*`]/,"",s); split(s,a,"[ \t]+"); if (a[2]!="") print a[2] }' "$dec")
|
||||
local any=0 f base ids vistos sueltos dups id num rojos legacy
|
||||
local any=0 f base ids vistos sueltos sub fuera detalle dups id num rojos legacy
|
||||
for f in "$ROOT/doc/AVISOS.md" "$ROOT/doc/backlog.md"; do
|
||||
[ -f "$f" ] || continue
|
||||
any=1; base=$(basename "$f")
|
||||
ids=$(_ids_def "$f")
|
||||
vistos=$(printf '%s\n' "$ids" | grep -c '[^[:space:]]')
|
||||
if [ "$vistos" -eq 0 ]; then
|
||||
sueltos=$(grep -cE "$_RE_ID_LOOSE" "$f")
|
||||
sueltos=$(_lineas_forma_id "$f")
|
||||
if [ "${sueltos:-0}" -gt 0 ]; then
|
||||
warn "$base: 0 ids DEFINIDOS parseados pero ${sueltos} línea(s) con forma de id — posible CEGUERA del regex (A6): el verde de este fichero no prueba nada, compruébalo a mano"
|
||||
else
|
||||
@ -131,7 +162,18 @@ check_ids() {
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
info "$base: ${vistos} id(s) DEFINIDOS vistos"
|
||||
# ── el CENSO, y es censo COMPLETO a propósito ────────────────────────────────────────────
|
||||
# Dice lo que VE, lo que TIRA (`D100` descarta sub-ids: `P9b` no es `P9`) y lo que NO ADMITE
|
||||
# (casillas `- [ ]`, prefijos fuera de `_IDPFX`). Un descarte callado es un cap silencioso:
|
||||
# medusa tiene 7 ids y **49** líneas con forma de id, y sin esta línea el censo diría «7» a
|
||||
# secas. La nota de ceguera de arriba sólo salta con `vistos == 0` ⇒ la ceguera PARCIAL se
|
||||
# escaparía entera.
|
||||
sub=$(_subids "$f"); sueltos=$(_lineas_forma_id "$f")
|
||||
fuera=$(( sueltos - vistos - sub )); [ "$fuera" -lt 0 ] && fuera=0
|
||||
detalle=""
|
||||
[ "${sub:-0}" -gt 0 ] && detalle="$detalle · ${sub} sub-id(s) descartados (D100)"
|
||||
[ "$fuera" -gt 0 ] && detalle="$detalle · ${fuera} línea(s) con forma de id que el censo estricto NO admite"
|
||||
info "$base: ${vistos} id(s) DEFINIDOS vistos${detalle}"
|
||||
rojos=0; legacy=0
|
||||
dups=$(printf '%s\n' "$ids" | sort | uniq -d)
|
||||
if [ -n "$dups" ]; then
|
||||
|
||||
Loading…
Reference in New Issue
Block a user