feat(skills): potenzia step4-review e step6-fix con check concreti
step4-review: aggiunge 6 check con grep/python eseguibili (sillabazione, righe orfane, frasi spezzate, header sospetti, sezioni vuote, gerarchia); carica revision_log e structure_profile per contesto immediato. step6-fix: aggiunge Passo 0 di ri-verifica fresca, mostra last_text dei chunk problematici, exit immediato su verdict=ok, delta chunk pre/post.
This commit is contained in:
@@ -6,57 +6,110 @@ argument-hint: <stem>
|
||||
|
||||
Esegui la revisione qualitativa di `step-4/$ARGUMENTS/clean.md`.
|
||||
|
||||
**Profilo struttura:**
|
||||
!`cat step-4/$ARGUMENTS/structure_profile.json 2>/dev/null || echo "ERRORE: step-4/$ARGUMENTS/structure_profile.json non trovato — verifica che lo stem sia corretto"`
|
||||
**Cosa è già stato fatto automaticamente (revision_log):**
|
||||
!`grep -A 12 "^## $ARGUMENTS" step-4/revision_log.md 2>/dev/null || echo "(nessun log trovato per questo stem)"`
|
||||
|
||||
**Statistiche file:**
|
||||
!`wc -l step-4/$ARGUMENTS/clean.md 2>/dev/null && grep -c "^## " step-4/$ARGUMENTS/clean.md 2>/dev/null | xargs -I{} echo "## headers: {}" && grep -c "^### " step-4/$ARGUMENTS/clean.md 2>/dev/null | xargs -I{} echo "### headers: {}"`
|
||||
**Profilo strutturale attuale:**
|
||||
!`python3 -c "
|
||||
import json, sys
|
||||
try:
|
||||
d = json.load(open('step-4/$ARGUMENTS/structure_profile.json'))
|
||||
print(f'Livello: {d[\"livello_struttura\"]} Strategia: {d[\"strategia_chunking\"]}')
|
||||
print(f'h1={d[\"n_h1\"]} h2={d[\"n_h2\"]} h3={d[\"n_h3\"]} paragrafi={d[\"n_paragrafi\"]}')
|
||||
print(f'Lunghezza media sezione: {d[\"lunghezza_media_sezione\"]} char')
|
||||
for a in d.get('avvertenze', []): print(f' ⚠️ {a}')
|
||||
except Exception as e: print(f'ERRORE: {e}')
|
||||
" 2>/dev/null`
|
||||
|
||||
---
|
||||
|
||||
Analizza `step-4/$ARGUMENTS/clean.md` seguendo questi passi. Usa Grep e Read per raccogliere i casi concreti prima di riportarli.
|
||||
Analizza `step-4/$ARGUMENTS/clean.md` eseguendo i grep seguenti e ragionando sui risultati. Per ogni check: esegui il grep, conta i risultati, riporta i casi concreti (max 5 esempi con numero di riga).
|
||||
|
||||
## Passo 1 — Righe orfane in corpo testo
|
||||
## Check 1 — Sillabazione residua
|
||||
|
||||
Cerca blocchi di testo standalone (separati da righe vuote, non header `#`) più corti di 80 caratteri che sembrino artefatti da PDF:
|
||||
- Firme o nomi di persone isolati (tutto maiuscolo o iniziali maiuscole seguite da punto)
|
||||
- Date o luoghi isolati
|
||||
- Titoli del documento ripetuti nel corpo
|
||||
- Numeri di pagina isolati
|
||||
- Riferimenti bibliografici fuori contesto
|
||||
Righe che terminano con trattino seguito da testo nella riga successiva (artefatto PDF non risolto):
|
||||
|
||||
Per ogni caso trovato: riporta numero di riga e testo.
|
||||
```bash
|
||||
grep -n "\-$" step-4/$ARGUMENTS/clean.md | head -20
|
||||
```
|
||||
|
||||
## Passo 2 — Paragrafi spezzati residui
|
||||
Segnala se presenti: numero di riga, testo della riga e della riga successiva.
|
||||
|
||||
Cerca paragrafi che finiscono senza punteggiatura di fine frase (`.?!»)`), escludendo quelli che terminano con ` -` (interruzione stilistica intenzionale).
|
||||
## Check 2 — Righe orfane (artefatti PDF)
|
||||
|
||||
Riporta i primi 5 casi con numero di riga e la fine del testo.
|
||||
Righe standalone (non header `#`, non vuote) di meno di 60 caratteri che sembrano artefatti:
|
||||
|
||||
## Passo 3 — Header sospetti
|
||||
```bash
|
||||
grep -n "^[^#\-\*\|].\{1,59\}$" step-4/$ARGUMENTS/clean.md | grep -v "^\s*$" | head -30
|
||||
```
|
||||
|
||||
Controlla i `##` e `###`:
|
||||
- `### N.` con solo numero e punto → **corretto**, non segnalare
|
||||
- `##` o `###` con contenuto ALL-CAPS non convertito in sentence-case → segnalare
|
||||
- `##` o `###` duplicati (stesso titolo che appare due volte) → segnalare
|
||||
- `##` con testo molto lungo (> 80 char) → segnalare come sospetto
|
||||
Valuta ogni riga: è testo normale breve (legittimo) o artefatto (numero di pagina, nome autore isolato, riga di intestazione ripetuta)?
|
||||
|
||||
## Passo 4 — Sezioni quasi vuote
|
||||
## Check 3 — Paragrafi con frase spezzata
|
||||
|
||||
Cerca `### ` header seguiti da un blocco di testo inferiore a 60 caratteri (sezione priva di contenuto utile per il RAG). Riporta i casi.
|
||||
Blocchi di testo che terminano senza punteggiatura di fine frase (`.?!»)`):
|
||||
|
||||
```bash
|
||||
grep -n "[^.!?»)\]\'\"]$" step-4/$ARGUMENTS/clean.md | grep -v "^[0-9]*:#" | grep -v "^[0-9]*:\s*$" | grep -v "^\s*[-\*]" | head -20
|
||||
```
|
||||
|
||||
Riporta i casi più sospetti (righe brevi che finiscono a metà concetto).
|
||||
|
||||
## Check 4 — Header sospetti
|
||||
|
||||
```bash
|
||||
grep -n "^##\? " step-4/$ARGUMENTS/clean.md | head -40
|
||||
```
|
||||
|
||||
Verifica:
|
||||
- `##` o `###` con contenuto interamente MAIUSCOLO non convertito → segnala
|
||||
- Header duplicati (stesso testo che appare due volte) → segnala
|
||||
- `##` con testo > 80 caratteri (probabile testo che non è un header) → segnala
|
||||
- Salti di livello anomali (es. `###` senza un `##` padre) → segnala
|
||||
|
||||
## Check 5 — Sezioni quasi vuote
|
||||
|
||||
```bash
|
||||
python3 -c "
|
||||
import re, sys
|
||||
text = open('step-4/$ARGUMENTS/clean.md').read()
|
||||
sections = re.split(r'^(#{1,3} .+)$', text, flags=re.MULTILINE)
|
||||
for i in range(1, len(sections)-1, 2):
|
||||
header = sections[i].strip()
|
||||
body = sections[i+1].strip() if i+1 < len(sections) else ''
|
||||
if len(body) < 80 and body:
|
||||
print(f'{header!r} → {len(body)} char: {body[:60]!r}')
|
||||
elif not body:
|
||||
print(f'{header!r} → VUOTA')
|
||||
" 2>/dev/null | head -20
|
||||
```
|
||||
|
||||
Sezioni con body < 80 char o vuote compromettono il chunking. Segnala quelle che non hanno senso come sezione autonoma.
|
||||
|
||||
## Check 6 — Gerarchia strutturale
|
||||
|
||||
```bash
|
||||
grep -n "^#\{1,3\} " step-4/$ARGUMENTS/clean.md | head -50
|
||||
```
|
||||
|
||||
Verifica che la gerarchia sia coerente: `# → ## → ###`. Segnala se ci sono `###` prima del primo `##`, o `##` prima del primo `#`, o `#` multipli (più di un h1).
|
||||
|
||||
---
|
||||
|
||||
## Report finale
|
||||
|
||||
```
|
||||
🔴 BLOCCANTI (compromettono il chunking o la qualità del RAG)
|
||||
🔴 BLOCCANTI (compromettono il chunking o il retrieval)
|
||||
[riga N] descrizione precisa del problema
|
||||
...
|
||||
|
||||
🟡 MINORI (artefatti visibili ma non bloccanti)
|
||||
🟡 MINORI (artefatti visibili, non bloccanti)
|
||||
[riga N] descrizione
|
||||
...
|
||||
|
||||
🟢 OK
|
||||
...
|
||||
🟢 OK — nessun problema rilevato in questa categoria
|
||||
```
|
||||
|
||||
Chiedi all'utente: "Vuoi che applichi le correzioni per i problemi 🔴? E per i 🟡?"
|
||||
Applica solo le correzioni esplicitamente approvate.
|
||||
Poi chiedi: **"Applico le correzioni per i 🔴? E per i 🟡?"**
|
||||
|
||||
Applica solo ciò che viene esplicitamente approvato. Usa Edit per ogni modifica — mai riscrivere l'intero file.
|
||||
|
||||
@@ -1,77 +1,120 @@
|
||||
---
|
||||
description: Legge il report di step 6, mostra le fix pianificate e le applica su approvazione tramite fix_chunks.py.
|
||||
description: Verifica i chunk di step 5, mostra i problemi, propone e applica le fix tramite fix_chunks.py con ri-verifica automatica finale.
|
||||
allowed-tools: Read Bash Grep
|
||||
argument-hint: <stem>
|
||||
---
|
||||
|
||||
Leggi e interpreta `step-6/$ARGUMENTS/report.json`.
|
||||
## Passo 0 — Verifica fresca (sempre)
|
||||
|
||||
**Report:**
|
||||
!`cat step-6/$ARGUMENTS/report.json 2>/dev/null || echo "ERRORE: report.json non trovato — esegui prima: python step-6/verify_chunks.py --stem $ARGUMENTS"`
|
||||
Esegui sempre `verify_chunks.py` per avere un report aggiornato (non fidarti di un report.json preesistente):
|
||||
|
||||
```bash
|
||||
source .venv/bin/activate && python step-6/verify_chunks.py --stem $ARGUMENTS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
In base al contenuto del report, segui le istruzioni qui sotto.
|
||||
Leggi il report appena generato:
|
||||
|
||||
!`python3 -c "
|
||||
import json, sys
|
||||
try:
|
||||
r = json.load(open('step-6/$ARGUMENTS/report.json'))
|
||||
v = r.get('verdict','?')
|
||||
s = r.get('stats', {})
|
||||
t = r.get('thresholds', {})
|
||||
print(f'Verdict: {v}')
|
||||
print(f'Totale chunk: {s.get(\"total\",\"?\")} | OK: {s.get(\"ok\",\"?\")}')
|
||||
print(f'Min: {s.get(\"min_chars\",\"?\")} char Max: {s.get(\"max_chars\",\"?\")} char Media: {s.get(\"avg_chars\",\"?\")} char')
|
||||
print(f'Soglie: MIN={t.get(\"min_chars\",200)} MAX={t.get(\"max_chars\",800)}')
|
||||
bl = r.get('blockers', {})
|
||||
wa = r.get('warnings', {})
|
||||
for cat, label in [('empty','Vuoti'), ('no_prefix','Senza prefisso'), ('incomplete','Frasi spezzate')]:
|
||||
items = bl.get(cat, [])
|
||||
if items:
|
||||
print(f' 🔴 {label}: {len(items)}')
|
||||
for c in items[:3]:
|
||||
print(f' [{c[\"chunk_id\"]}] {c[\"n_chars\"]} char → {c[\"last_text\"][-60:]!r}')
|
||||
for cat, label in [('too_short','Troppo corti'), ('too_long','Troppo lunghi')]:
|
||||
items = wa.get(cat, [])
|
||||
if items:
|
||||
print(f' 🟡 {label}: {len(items)}')
|
||||
for c in items[:3]:
|
||||
print(f' [{c[\"chunk_id\"]}] {c[\"n_chars\"]} char')
|
||||
except Exception as e: print(f'ERRORE lettura report: {e}')
|
||||
" 2>/dev/null`
|
||||
|
||||
---
|
||||
|
||||
## Se verdict == "ok"
|
||||
|
||||
Non c'è nulla da fare. Comunica all'utente che può procedere:
|
||||
✅ Nessun problema. Comunica:
|
||||
|
||||
```
|
||||
✅ Nessun problema — procedi con la vettorizzazione:
|
||||
✅ Chunk puliti — procedi con la vettorizzazione:
|
||||
python step-8/ingest.py --stem $ARGUMENTS
|
||||
```
|
||||
|
||||
Fermati qui. Non eseguire nessun altro passo.
|
||||
|
||||
---
|
||||
|
||||
## Se verdict == "warnings_only" o "blocked"
|
||||
|
||||
### Passo 1 — Mostra le fix pianificate (dry-run)
|
||||
|
||||
Esegui il dry-run e mostra l'output all'utente:
|
||||
### Passo 1 — Dry-run
|
||||
|
||||
```bash
|
||||
source .venv/bin/activate && python step-6/fix_chunks.py --stem $ARGUMENTS --dry-run
|
||||
```
|
||||
|
||||
Spiega brevemente cosa farà ogni operazione:
|
||||
- **rimuovi chunk vuoti**: elimina chunk senza testo
|
||||
- **aggiungi prefisso**: inserisce `[sezione > titolo]` dove manca
|
||||
- **fondi incompleti**: unisce i chunk con frase spezzata al chunk successivo
|
||||
- **fondi troppo corti**: unisce chunk < 200 char con il successivo
|
||||
- **spezza troppo lunghi**: divide chunk > 1200 char al confine di paragrafo/frase
|
||||
Spiega in italiano ogni operazione pianificata:
|
||||
- **rimuovi chunk vuoti** — chunk privi di testo, non contribuiscono al retrieval
|
||||
- **aggiungi prefisso** — il prefisso `[sezione > titolo]` fornisce contesto all'embedding; senza, il chunk è semanticamente decontestualizzato
|
||||
- **fondi incompleti** — frase spezzata a metà: il chunk corrente e il successivo formano una frase unica
|
||||
- **fondi troppo corti** — chunk sotto MIN_CHARS: troppo brevi per portare informazione semantica utile
|
||||
- **spezza troppo lunghi** — chunk sopra MAX_CHARS×1.5: troppo densi, degradano la precision del retrieval
|
||||
|
||||
### Passo 2 — Chiedi conferma
|
||||
Se ci sono solo 🟡 (nessun 🔴), informa che si può procedere anche senza fix e chiedi la preferenza.
|
||||
|
||||
Chiedi all'utente: **"Applico le correzioni?"**
|
||||
### Passo 2 — Conferma
|
||||
|
||||
Applica solo su approvazione esplicita.
|
||||
Chiedi: **"Applico le correzioni?"**
|
||||
|
||||
### Passo 3 — Applica e ri-verifica
|
||||
Applica solo su risposta affermativa esplicita.
|
||||
|
||||
### Passo 3 — Applica
|
||||
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
python step-6/fix_chunks.py --stem $ARGUMENTS
|
||||
python step-6/verify_chunks.py --stem $ARGUMENTS
|
||||
source .venv/bin/activate && python step-6/fix_chunks.py --stem $ARGUMENTS
|
||||
```
|
||||
|
||||
Leggi il nuovo `step-6/$ARGUMENTS/report.json` e comunica:
|
||||
- Il nuovo verdict
|
||||
- Quanti warning/blockers residui rimangono
|
||||
- Se il verdict è `ok` o `warnings_only` senza blockers: comunica che si può procedere con step-8
|
||||
### Passo 4 — Ri-verifica automatica
|
||||
|
||||
## Dopo le correzioni
|
||||
```bash
|
||||
source .venv/bin/activate && python step-6/verify_chunks.py --stem $ARGUMENTS
|
||||
```
|
||||
|
||||
Se il verdict finale è `ok`:
|
||||
Leggi il nuovo `step-6/$ARGUMENTS/report.json` e riporta:
|
||||
- Nuovo verdict
|
||||
- Delta chunk (N prima → N dopo)
|
||||
- Problemi residui se presenti
|
||||
|
||||
### Passo 5 — Conclusione
|
||||
|
||||
Se verdict finale è `ok` o `warnings_only` senza 🔴:
|
||||
|
||||
```
|
||||
✅ chunks.json pulito salvato in step-6/$ARGUMENTS/
|
||||
✅ Chunk pronti in step-6/$ARGUMENTS/chunks.json
|
||||
Procedi con la vettorizzazione:
|
||||
python step-8/ingest.py --stem $ARGUMENTS
|
||||
```
|
||||
|
||||
Se rimangono warning minori (too_short/too_long non risolvibili perché testo non spezzabile):
|
||||
Se rimangono 🔴 dopo il fix (raro — testo non spezzabile o struttura anomala):
|
||||
|
||||
```
|
||||
🟡 X warning residui non risolvibili automaticamente (testo non spezzabile).
|
||||
Puoi procedere comunque con la vettorizzazione:
|
||||
python step-8/ingest.py --stem $ARGUMENTS
|
||||
🔴 X problemi residui non risolvibili automaticamente.
|
||||
Torna a step-4/$ARGUMENTS/clean.md e correggi manualmente le sezioni indicate,
|
||||
poi riesegui nell'ordine:
|
||||
python step-5/chunker.py --stem $ARGUMENTS --force
|
||||
python step-6/verify_chunks.py --stem $ARGUMENTS
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user