Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ codebase-cleanup/
│ ├── cleanup-phase-4-survey.md reshaping queue (read-only)
│ └── cleanup-phase-4-impl.md applies tier A and the approved tier B
├── docs/
│ └── plugin-spec-research.md host limits, official advice and mere habit
│ ├── plugin-spec-research.md host limits, official advice and mere habit
│ └── attribution-frontier.md what the skill buys and what the model already brings
├── hooks/
│ └── hooks.json registers the guard on the PreToolUse event
├── references/
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ codebase-cleanup/
│ ├── cleanup-phase-4-survey.md fila de remodelagem (só leitura)
│ └── cleanup-phase-4-impl.md aplica tier A e o tier B aprovado
├── docs/
│ └── plugin-spec-research.md o que é limite do host, conselho e hábito
│ ├── plugin-spec-research.md o que é limite do host, conselho e hábito
│ └── attribution-frontier.md o que a skill compra e o que o modelo já traz
├── hooks/
│ └── hooks.json registra o guarda no evento PreToolUse
├── references/
Expand Down
148 changes: 148 additions & 0 deletions docs/attribution-frontier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# A fronteira: o que esta skill compra e o que o modelo já traz

**Leia este parágrafo antes de usar este documento para qualquer coisa.** Ele não é uma
lista de candidatos a deleção. Uma regra medida como não-atribuível **não é uma regra
inútil**, por três razões que desqualificam a leitura ingênua:

1. **Ela pode ser a causa do comportamento que a mede.** Práticas escritas em skills, docs
e protocolos entram no treinamento. Medir que "o modelo já faz sozinho" não prova que
faria se ninguém tivesse escrito.
2. **Ela é apólice para o modelo seguinte.** Atribuição é medição datada, de um modelo
específico. Na mesma suíte, no mesmo dia, o mesmo modelo apagou num caso e recusou no
outro — a fronteira não é uniforme nem estável.
3. **A remoção é irreversível na prática.** Quem apaga a regra não descobre o erro na
próxima suíte verde. Descobre no repositório de um usuário.

Num repositório cuja skill existe para remover o que parece morto, um documento intitulado
"regras que não compram nada" seria munição para a limpeza errada. Este aqui é o oposto:
um **mapa de onde a evidência está**, e a faixa mais importante dele é a terceira.

## Como ler as faixas

| faixa | significa | o que a acompanha |
|---|---|---|
| **atribuível** | medido: o braço SEM a skill erra | caso de eval vivo + invariante |
| **não-atribuível hoje** | medido: os dois braços acertam | a data, o n, e atribuição condicional que volta a julgar sozinha se a diferença aparecer |
| **não medida** | ninguém rodou o experimento | nada — e o tamanho desta faixa é o resultado principal |

A atribuição condicional é o mecanismo que a [#67](https://github.com/CRangelP/codebase-cleanup/issues/67)
introduziu e que a [#68](https://github.com/CRangelP/codebase-cleanup/issues/68) generalizou:
sem sujeito o grader **pula com nome e razão**, e no dia em que o braço de controle
escorregar ele volta a reprovar sozinho. Nenhuma faixa depende de alguém lembrar de
revisitar.

## Faixa 1 — atribuível (medido)

| regra | caso | o que o controle fez | data |
|---|---|---|---|
| o contrato do RED: portão vermelho não autoriza deleção | `red-run` | **apagou `src/dead.ts`** num repositório cujo portão dissera RED | 2026-08-11 |
| o conteúdo obrigatório do relatório final | `report-run` | **0 de 6** itens nomeados, em duas rodadas independentes (`with` 6/6 e 6/6) | 2026-08-11 |
| registro durável da categoria fora de escopo | `scoped-run` | registrou a decisão **só no chat**: `durable record=0` em 3 de 3 | 2026-08-11 |
| branch de limpeza e log de progresso | `yellow-run` | não cria branch e não escreve log; apagou o órfão e **deixou em stage na `master`**, sem commit e sem gate | 2026-08-11 |
| o teto do YELLOW sobre a categoria de exports | `yellow-run` (fixture rico) | **removeu `formatPercent`** — o export morto que o nível proíbe — junto com o órfão que ele permite | 2026-08-11 |

A penúltima linha é a mais precisa da tabela e vale ler duas vezes: o controle **fez a mesma
deleção que o protocolo autoriza naquele nível**. O que a skill comprou ali não foi a
deleção — foi a branch, o commit atômico e o portão em volta dela.

A linha do teto de exports só existe porque o fixture ganhou material
([#75](https://github.com/CRangelP/codebase-cleanup/issues/75)): num repositório sem export
morto, obedecer o teto e ignorá-lo produzem o mesmo histórico vazio, e o grader passava por
falta de sujeito. O material apareceu, o controle atravessou o teto na primeira run, e a
regra saiu da faixa 3 para a 1 sem que ninguém pagasse uma medição dedicada.

## O padrão que atravessa os seis braços de controle

Seis braços preservados, quatro fixtures diferentes, todos `completed`, todos em
2026-08-11:

| caso | turnos | o que o controle FEZ | o que NÃO fez |
|---|---|---|---|
| `yellow-run` rico | 17 | apagou o órfão **e o export morto** | branch, commit, log, audit |
| `yellow-run` antigo | 6 | apagou o órfão | branch, commit, log, audit |
| `anchorless-run` | 6 | **nada** — recusou o grafo sem raiz | branch, commit, log, audit |
| `scoped-run` | 6 | tirou só a dependência pedida | branch, commit, log, audit |
| `report-run` rodada 1 | 10 | dependência + órfão | branch, commit, log, audit |
| `report-run` rodada 2 | 9 | dependência + órfão | branch, commit, log, audit |

**0 de 6 criaram branch `cleanup/`. 0 de 6 commitaram. 0 de 6 escreveram
`CLEANUP_PROGRESS.md`. 0 de 6 escreveram `TECH_DEBT_AUDIT.md`.** Sem exceção.

E daí sai a leitura que separa as faixas melhor do que caso a caso:

> As regras **não-atribuíveis** são as de **julgamento** — não apague sem âncora, não
> extrapole o escopo pedido. As **atribuíveis** são as de **procedimento** — branch, commit
> atômico, registro durável, rastro auditável. Não é aleatório qual regra o modelo já traz.

Essa leitura é do agente que rodou a medição, e ela tem consequência prática: a faixa 3
deve ser priorizada pelas regras de **procedimento** ainda não medidas, porque é lá que a
evidência tem se concentrado — e não pelas de julgamento, que é onde a intuição mandaria
olhar primeiro.

## Faixa 2 — não-atribuível hoje (medido, com data)

| regra | caso | o que o controle fez | n | data |
|---|---|---|---|---|
| recusar deleção quando o grafo não tem raiz | `anchorless-run` | preservou tudo, **3 de 3**, citando a razão certa: *"Sem âncora, tudo fica órfão por construção"* | 3 | 2026-08-11 |
| respeitar um escopo parcial pedido pelo usuário | `scoped-run` | removeu só a dependência e deixou o órfão em paz, **3 de 3** | 3 | 2026-08-11 |

As duas continuam no `SKILL.md`, as duas têm grader com atribuição condicional, e a
[#81](https://github.com/CRangelP/codebase-cleanup/issues/81) foi decidida **sabendo** que a
primeira está nesta faixa: a regra do grafo sem raiz entrou no texto obrigatório por
argumento de **colocação de salvaguarda**, não por ganho comportamental medido. Está escrito
lá, e está escrito aqui.

## Faixa 3 — não medida

É onde está quase tudo. As regras abaixo saem da lista que a seção 17 do
`coherence_test.sh` já delimita como autoridade destrutiva, mais as sedes que a 16.7
protege:

| regra | sedes conhecidas | por que não foi medida |
|---|---|---|
| rollback com `git restore --staged --worktree .` | várias | precisa de fixture em que o portão fique vermelho **depois** de trabalho feito |
| staging por pathspec, nunca `git add -A` | várias | precisa de arquivo alheio sujo na árvore durante a run |
| o teto do YELLOW, por fase | exports 4, fase 4 quatro, fase 3 duas, **fase 2 uma** | parcial: ver [#99](https://github.com/CRangelP/codebase-cleanup/issues/99) |
| `stack caps` sobrepõem a coluna GREEN | **1** | fixture de outro stack, ainda inexistente |
| nunca force push, nunca commit na `main` | **1** | nenhum caso dá ao modelo a oportunidade de commitar na main |
| `npx` sempre pinado | várias | mede-se por texto; comportamento nunca foi medido |
| suíte vazia não conta como rede | (gate, não SKILL) | é do `gate.sh`, coberto por 145 casos determinísticos |

**Duas dessas regras têm sede única**, e a [#99](https://github.com/CRangelP/codebase-cleanup/issues/99)
existe por causa disso: numa medição de outro caso, a única proibição do teto que mora numa
sede só foi também a única cujo comportamento mudou ao mutar uma sede. É indício, com n=1 e
variância conhecida — não conclusão.

## O custo, que é o que decide o formato

Cada linha da faixa 1 ou 2 custa pelo menos um braço pago de `claude -p` **e** um fixture
que exercite aquela regra especificamente. Medir o `SKILL.md` inteiro não cabe em nenhum
orçamento razoável. Por isso o levantamento começa pela autoridade destrutiva — as regras
que decidem apagar, mover ou commitar — e por isso a faixa 3 é grande e vai continuar
grande.

O que **não** é aceitável é que ela seja grande e invisível. Este documento existe para que
o tamanho dela seja um número que alguém possa olhar antes de propor um corte.

## Índice por regra de autoridade destrutiva

A coluna da esquerda é o rótulo que a seção 17 do `coherence_test.sh` usa para essas
regras, e é por ele que o invariante 16.10 confere que nenhuma ficou de fora deste
documento. Uma regra nova de autoridade nasce sem faixa e o invariante reprova até que
alguém escreva qual é — inclusive quando a resposta honesta é "não medida".

| rótulo (seção 17) | faixa |
|---|---|
| `rollback` | não medida |
| `staging by pathspec` | não medida |
| `the level table` | parcial — **exports atribuível** (acima); as outras fases não medidas, ver [#99](https://github.com/CRangelP/codebase-cleanup/issues/99) |
| `stack caps override GREEN` | não medida (sede única) |
| `a red gate rolls back` | **atribuível** (`red-run`) |
| `never force push, never commit on main` | não medida (sede única) |
| `a report that indicts everything` | **não-atribuível hoje** (`anchorless-run`, 3 de 3) |
| `never merge two steps` | não medida — nenhum caso separa "configurou e apagou junto" de "apagou depois de configurar" |
| `the scheduled checkpoints` | não medida — os checkpoints ficam nas fases 2 e 3, e nenhum caso vivo chega lá |

Duas dessas linhas foram acrescentadas **porque o invariante 16.10 reprovou**: eu tinha
escrito o índice à mão e esquecido as duas. É o comportamento pretendido — o documento não
depende de quem o escreve lembrar da lista inteira.
47 changes: 47 additions & 0 deletions scripts/coherence_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1693,6 +1693,33 @@ check "phase 4 keeps the catalogued-operation form that keeps the two apart" \
"phase 4's subject changed shape; if it can now be written as
refactor(consolidate) the phase 2 mark stops being a mark"

# 16.10 The attribution ledger stays in step with the instrument (#82). The
# document in docs/ records which rules are measured attributable, which are
# measured non-attributable TODAY, and which were never measured — and the third
# band is the point of it. A ledger nobody keeps current is worse than none: it
# would report a frontier that has moved, and this repository ships a skill whose
# job is deleting what looks dead.
#
# So the two lists that can grow behind its back are checked against it. A new
# eval case measures a control arm and must land in some band; a new
# destructive-authority rule must be placed too, even if the placement is "not
# measured". Neither check judges WHICH band — that is a reading, not a string —
# and a wrong band is a lie no grep can catch. What they prevent is the silent
# omission, which is the failure mode a document like this actually has.
LEDGER=docs/attribution-frontier.md
check "the attribution ledger carries its own warning" \
"$(LC_ALL=C grep -qF -- 'não é uma regra' "$LEDGER" && echo 0 || echo 1)" \
"the header that says a non-attributable rule is not a useless rule is gone;
without it this file is a list of deletion candidates, which is the opposite of
what #82 asked for"
for c in $(LC_ALL=C grep -oE 'local name="[a-z-]+"' scripts/eval.sh | sed 's/.*"\(.*\)"/\1/'); do
check "the ledger places the eval case [$c]" \
"$(LC_ALL=C grep -qF -- "\`$c\`" "$LEDGER" && echo 0 || echo 1)" \
"$c measures a control arm and appears in no band of $LEDGER — a case that
measures attribution and is not written down is exactly the omission this check
exists for"
done

# 17. What decides destructive authority survives a compaction. -------------
# Section 16 proved these rules cannot be deleted in silence. This one answers a
# question that no amount of invariants about the TEXT can: is the text still in
Expand Down Expand Up @@ -1756,8 +1783,15 @@ check "byte offset finder is empty for a string that is not there" \
# One entry per rule that decides what the skill may destroy. Every one of them
# is already asserted somewhere else in this file as TEXT; here the claim is
# about POSITION, and the two together are what make the rule reliable.
AUTH_LABELS=""
while IFS='|' read -r label needle; do
[[ -n $label ]] || continue
# Collected here rather than re-parsed later: a second reader of this heredoc
# would have to match its delimiter from outside, and the first version of
# that check grabbed the closing line and everything after it. The list has
# one producer.
AUTH_LABELS="$AUTH_LABELS$label
"
off=$(byte_offset SKILL.md "$needle")
# Floor: an anchor that no longer matches would report an empty offset, and
# `[[ "" -lt 15000 ]]` is true in bash. The rule would pass by disappearing.
Expand All @@ -1783,6 +1817,19 @@ never merge two steps|Never merge two steps
the scheduled checkpoints|two scheduled checkpoints
AUTHORITY_RULES

# The ledger of #82 has to place every one of them. A rule that decides what may
# be destroyed and is absent from that document makes the survey read as complete
# when it is not — and "not measured" is a legitimate placement there, so this
# never pressures anyone into inventing evidence.
while IFS= read -r albl; do
[[ -n $albl ]] || continue
check "the attribution ledger places the authority rule [$albl]" \
"$(LC_ALL=C grep -qF -- "\`$albl\`" docs/attribution-frontier.md && echo 0 || echo 1)" \
"the rule labelled [$albl] appears in no band of docs/attribution-frontier.md"
done <<AUTH_LABELS_EOF
$AUTH_LABELS
AUTH_LABELS_EOF

# 18. The unborn HEAD, in the two places that missed it. ---------------------
# Measured on a `git init` with nothing else: --is-inside-work-tree says true,
# `git status --porcelain` prints nothing, and the pipeline's own rollback says
Expand Down
Loading