Passa al contenuto principale

Metriche di Salute — Perché il 100/100 è l’Unico Numero che Conta

"Un Safe Harbor deve saper dire esattamente quanto è solido il suo molo."

Per i tuoi utenti, un link rotto è un cliente perso. Per il tuo team, una credenziale esposta è una crisi a mezzanotte. Per il tuo brand, un punteggio di 97 significa tre cose che non hai ancora risolto.

Il Punteggio di Qualità di Zenzic non è una metrica di vanità. È un valore deterministico da 0 a 100 calcolato dal conteggio concreto dei problemi rilevati da ogni controllo. Zero problemi significa 100/100 — una prova formale, non una stima. Nessun credito parziale, nessun arrotondamento favorevole, nessuna sorpresa.

Scopri dove sei adesso: uvx zenzic score [PATH] — nessuna installazione, nessuna configurazione richiesta.


Cosa Misura il Punteggio

Il Punteggio di Qualità è un composito pesato di quattro categorie di controllo. Ogni categoria corrisponde direttamente a un sotto-comando zenzic check e ai codici di finding Zxxx che emette.

CategoriaComandoCodici FindingPeso
Integrità Strutturalezenzic check links [PATH]Z101, Z102, Z103, Z104, Z105, Z10740 %
Eccellenza dei Contenutizenzic check all [PATH]Z501, Z502, Z503, Z50530 %
Navigazione & SEOzenzic check orphans [PATH]Z40220 %
Brand & Assetzenzic check assets [PATH]Z903, Z904, Z90510 %
Override di Sicurezza

Se viene rilevato un finding di sicurezza — Z201 (Shield), Z202 o Z203 (Blood Sentinel) — il Punteggio di Qualità crolla a 0/100 incondizionatamente. Una sorgente documentale che perde attivamente una credenziale non può ricevere un Punteggio di Qualità.


La Tabella di Penalità Quartz

Ogni codice di finding porta una deduzione fissa in punti all'interno della sua categoria. Le deduzioni si accumulano; una volta che il contributo di una categoria raggiunge zero, ulteriori violazioni in quella categoria non hanno ulteriori effetti sul punteggio totale — questo è il Category Cap (Tetto di Categoria).

CodiceDescrizionePenalità (pts)Categoria
Z2xxViolazione di SicurezzaOverride → 0/100
Z503Errore Sintassi Snippet10.0Content
Z101Link Interrotto8.0Structural
Z104File Non Trovato8.0Structural
Z102Ancora Mancante5.0Structural
Z402Pagina Orfana4.0Navigation
Z905Brand Obsoleto3.0Brand
Z903Asset Non Utilizzato3.0Brand
Z501Placeholder (TODO / FIXME)2.0Content
Z904Errore Nav Contract2.0Brand
Z105Percorso Assoluto2.0Structural
Z502Contenuto Breve1.0Content
Z505Blocco di Codice Non Etichettato1.0Content
Z107Ancora Circolare1.0Structural
Z106Link Circolare1.0Structural

Invariante del Category Cap

Le deduzioni di categoria sono limitate dal peso della categoria:

  • Tetto Structural: 40 pts (40% × 100)
  • Tetto Content: 30 pts (30% × 100)
  • Tetto Navigation: 20 pts (20% × 100)
  • Tetto Brand: 10 pts (10% × 100)

Esempio: 100 × Z505 (1,0 pt ciascuno) genera 100 pts di deduzione potenziale contro la categoria Content — ma il tetto limita la perdita effettiva a 30 pts. Le altre tre categorie rimangono inalterate: 70/100 totale.

Separazione Score vs. Gate

Lo Score e la soglia fail_under sono indipendenti:

  • Score (la Metrica): Misurazione oggettiva della qualità, limitata dai Category Cap.
  • fail_under (il Gate): La tua policy di enforcement in zenzic.toml.

Uno score di 70/100 con fail_under = 80 esce comunque con codice 1. Il Category Cap impedisce che un tipo di violazione rumoroso mascheri la salute strutturale — non indebolisce il tuo gate.

Il punteggio finale 0–100 è la somma dei contributi di categoria pesati:

score=imax(0, wi×100deduzionii)\text{score} = \left\lfloor \sum_i \max\bigl(0,\ w_i \times 100 - \text{deduzioni}_i\bigr) \right\rceil

Esecuzione del Punteggio

# Calcola e mostra il punteggio (nessun file scritto)
zenzic score [PATH]

# Calcola, mostra e persiste in .zenzic-score.json
zenzic score [PATH] --save

# Calcola e fallisce se il punteggio scende sotto N
zenzic score [PATH] --fail-under 80

# Confronta il punteggio attuale con il baseline salvato (gate di regressione CI)
zenzic diff [PATH]

Lo snapshot è scritto in .zenzic-score.json nella root del repository. È un file JSON leggibile dalle macchine — committalo nel repository affinché zenzic diff abbia un baseline con cui confrontarsi.

Pattern CI consigliato

.github/workflows/zenzic.yml
# Sui push al branch main: salva il nuovo baseline

- run: zenzic score --save --fail-under 80

# Sulle pull request: fallisce se il punteggio è sceso

- run: zenzic diff --threshold 0

zenzic diff esce con 1 se il punteggio attuale è inferiore al baseline salvato (aggiustato da --threshold). Non fallisce se il punteggio è stabile o migliorante.


Regressione di Qualità — Z504

Quando zenzic diff rileva una diminuzione del punteggio, emette Z504 QUALITY_REGRESSION come finding. Questo è l'unico codice di finding che fa da ponte tra il layer di scoring e il layer di finding — significa: "qualcosa che hai cambiato ha peggiorato il punteggio."

Z504 non viene pesato nel punteggio stesso (sarebbe circolare). È il segnale che comunica quale commit ha introdotto una regressione.


Connessione ai Tre Pilastri

Il Punteggio di Qualità è la prova operativa dei Tre Pilastri di Zenzic:

1. Analizza la Sorgente, Non il Build. Il punteggio è calcolato dall'analisi del sorgente Markdown grezzo — mai dall'output HTML o da un server web in esecuzione. Il peso del 40% per la categoria strutturale premia una sorgente che è internamente coerente prima che qualsiasi passo di build venga eseguito.

2. Zero Sottoprocessi. compute_score() in core/scorer.py è una funzione Python pura — nessuna chiamata shell, nessun subprocess.run, nessuna richiesta di rete. Riceve una mappa findings_counts: dict[str, int] e restituisce uno ScoreReport. Questo garantisce risultati identici su ogni OS e versione Python nella matrice CI (ubuntu / windows / macos × Python 3.10–3.14).

3. Funzioni Pure Prima di Tutto. compute_score() non ha effetti collaterali. save_snapshot() è l'unica funzione di I/O e viene chiamata esplicitamente solo quando l'utente passa --save. La suite di test verifica i calcoli del punteggio con test basati su proprietà (Hypothesis) per garantire gli invarianti matematici.


Integrità del Nav Contract — Valutata come Brand & Asset

L’audit del CEO ha segnalato una correzione terminologica: quello che gli utenti chiamano a volte “Nav Isolation” è formalmente Integrità del Nav Contract (Z904).

Z904 si attiva quando un file dichiarato nella configurazione di navigazione del motore (es. una voce nav: di mkdocs.yml o una voce esplicita di sidebars.ts in Docusaurus) non esiste su disco. Ogni violazione Z904 contribuisce alla categoria Brand & Asset (10%) usando la stessa penaltà per codice degli altri finding valutati (Z904: 2,0 pts per violazione).


Safe Harbor Guarantee

Quando zenzic score restituisce 100/100, è una garanzia formale che:

  • Ogni link interno si risolve (zero Z101/Z102/Z103/Z104/Z105)
  • Ogni riferimento ad ancora si risolve (zero Z107)
  • Ogni pagina è raggiungibile da almeno un punto di accesso di navigazione (zero Z402)
  • Ogni snippet di codice è sintatticamente valido (zero Z503)
  • Non esistono contenuti placeholder (zero Z501)
  • Non esistono blocchi di codice non etichettati (zero Z505)
  • Non esistono asset inutilizzati (zero Z903)
  • Non esistono violazioni del nav contract (zero Z904)
  • Non esistono riferimenti di brand obsoleti (zero Z905)
  • Lo Shield non ha trovato credenziali in nessun file (zero Z201 — implicito, fa crollare il punteggio a 0)
Structural Integrity40 pts0 broken links
Content Excellence30 pts0 placeholders
Navigation20 pts0 orphan pages
Brand & Assets10 pts0 brand violations
🏆Quality Score:100 / 100◆ Sentinel Seal
Shield: no credentials detected
Blood Sentinel: no path-traversal attempts
Files scanned: 47  ·  Elapsed: 0.28 s

Questo è il Sentinel Seal: lo stato in cui la documentazione è strutturalmente completa, pulita nel contenuto e verificata per la sicurezza.

Porta il Sigillo nel tuo README: una volta raggiunto il 100/100, esegui zenzic score --save e aggiungi il badge dinamico del punteggio al tuo progetto. Mostra ai contributor lo standard che stanno per rispettare. Vedi Badge Ufficiali per le URL copy-paste.