Passa al contenuto principale

Algoritmo di Scoring

Il Documentation Quality Score (DQS) di Zenzic è un intero deterministico da 0 a 100 calcolato dai risultati di tutti i check attivi. Dato lo stesso stato del repository, l'algoritmo produce sempre lo stesso punteggio.

Per il razionale di design, un esempio pratico e la lettura dell'output CLI, vedi Design dello Scoring.


Architettura Generale

La pipeline di scoring ha cinque stadi sequenziali:

1. Security Gate → Finding Z2xx? score = 0, early return.
2. Tabella Penalità → deduzioni per codice, cap per tier.
3. Governance Esc. → amplificazione esponenziale se Z6xx > 10.
4. Gravity Cap → brand score = 0 ⟹ totale ≤ 70.
5. Suppression Debt → sottrai ω_debt dal totale con cap.

Ogni stadio è descritto di seguito con la formula completa.


Stadio 1 — Security Override

Prima di qualsiasi calcolo del punteggio, il motore controlla la presenza di finding Z2xx:

Sfinal=0se cSnc>0S_{\text{final}} = 0 \quad \text{se } \sum_{c \in \mathcal{S}} n_c > 0

dove S={Z201,Z202,Z203,Z204}\mathcal{S} = \{Z201, Z202, Z203, Z204\}.

Si tratta di un early return incondizionale — nessun flag, nessuna opzione di configurazione e nessuna soppressione può bypassarlo. I quattro codici in S\mathcal{S} rappresentano condizioni di fallimento binarie:

CodiceNomeCondizione
Z201CREDENTIALPattern di credenziale rilevato nel documento
Z202PATH_TRAVERSALIl target del link esce da docs/ verso un percorso non di sistema
Z203PATH_TRAVERSAL_FATALIl target del link si risolve verso un path di sistema operativo
Z204FORBIDDEN_TERMPrivacy Gate — esposizione di termine riservato

Quando si attiva il Security Override, ScoreReport restituisce security_override=True e security_findings=N (conteggio totale Z2xx). Il flag --strict e la configurazione fail-on-error sono irrilevanti — il gate opera prima di entrambi.

:::danger I Codici di Sicurezza Non Sono Sopprimibili Nessun inline <!-- zenzic:ignore -->, nessun per_file_ignores e nessun excluded_dirs può sopprimere un finding Z2xx. Il finding si attiva comunque. Il punteggio è comunque 0. :::


Stadio 2 — Tabella Penalità e Cap per Tier

Se non sono presenti finding Z2xx, il motore calcola un punteggio per tier.

Matrice dei Pesi Zenzic (5-Tier)

TierCategoriaCodiciPesoCap
Security GateZ2xxscore = 0
StructuralstructuralZ1xx30%30 pts
NavigationnavigationZ3xx, Z4xx25%25 pts
ContentcontentZ5xx20%20 pts
GovernancebrandZ404, Z405, Z406, Z6xx25%25 pts

Formula per Categoria

Per ogni tier ii:

cat_ptsi=max ⁣(0,  wi×100ctieripenaltyc×nc)\text{cat\_pts}_i = \max\!\left(0,\; w_i \times 100 - \sum_{c \in \text{tier}_i} \text{penalty}_c \times n_c\right)

L'invariante del Category Cap garantisce che un singolo tier non possa trascinare il punteggio sotto il suo pavimento. Ad esempio, 1 000 occorrenze di Z505 (1 pt ciascuna) esauriscono il bucket content a −20 pts. Gli 80 pts rimanenti dagli altri tier non vengono toccati.

Punteggio Base

Sbase=i{structural, navigation, content, brand}cat_ptsiS_{\text{base}} = \sum_{i \in \{\text{structural, navigation, content, brand}\}} \text{cat\_pts}_i

Tabella di Riferimento delle Penalità

CodiceNomePenalità / occorrenzaTier
Z101LINK_BROKEN8.0 ptsStructural
Z102ANCHOR_MISSING5.0 ptsStructural
Z103ORPHAN_LINK2.0 ptsStructural
Z104FILE_NOT_FOUND8.0 ptsStructural
Z105ABSOLUTE_PATH2.0 ptsStructural
Z107CIRCULAR_ANCHOR1.0 ptsStructural
Z106CIRCULAR_LINK0.0 ptsInformativo (nessun impatto sul DQS)
Z108EMPTY_LINK_TEXT1.0 ptsStructural
Z111VIRTUAL_ROUTE_BROKEN8.0 ptsStructural
Z113AUTHOR_KEY_COLLISION2.0 ptsStructural
Z301DANGLING_REF4.0 ptsNavigation
Z302DEAD_DEF1.0 ptsNavigation
Z303DUPLICATE_DEF3.0 ptsNavigation
Z402ORPHAN_PAGE4.0 ptsNavigation
Z401MISSING_DIRECTORY_INDEX2.0 ptsNavigation
Z501PLACEHOLDER2.0 ptsContent
Z502SHORT_CONTENT1.0 ptsContent
Z503SNIPPET_ERROR10.0 ptsContent
Z505UNTAGGED_CODE_BLOCK1.0 ptsContent
Z403MISSING_ALT1.0 ptsContent
Z405UNUSED_ASSET3.0 ptsGovernance
Z404CONFIG_ASSET_MISSING3.0 ptsGovernance
Z406NAV_CONTRACT2.0 ptsGovernance
Z601BRAND_OBSOLESCENCE2.0 ptsGovernance

::: note Z106 — Telemetria del Knowledge Graph, non un difetto Z106 è escluso dalla tabella delle penalità per scelta progettuale. Elevarlo a finding con punteggio sottrarrebbe punti al Quality Score, spingendo gli ingegneri a rimuovere link utili per soddisfare il linter — un incentivo perverso che degrada la qualità reale della documentazione. I link circolari in un Knowledge Graph sono dati strutturali, non difetti. Z106 viene emesso come telemetria topologica; ispezionalo con --show-info. :::

:::note Z602 non è incluso nel punteggio Z602 (I18N_PARITY) è un gate di Governance che si attiva come finding autonomo. Non contribuisce a nessun bucket DQS e quindi non ha un valore di penalità nella tabella sopra. :::


Stadio 3 — Governance Escalation

Oltre 10 occorrenze Z6xx, il motore applica un amplificatore esponenziale alle deduzioni del bucket Governance:

deductionbrand=min ⁣(capbrand,  deductionbrand×2nexcess/5) \text{deduction}_{\text{brand}}' = \min\!\left(\text{cap}_{\text{brand}},\; \text{deduction}_{\text{brand}} \times 2^{n_{\text{excess}} / 5}\right)

dove nexcess=nZ6xx10n_{\text{excess}} = n_{Z6xx} - 10.

La deduzione è limitata al massimo del tier Governance (25 pts). L'effetto pratico: un repository con 20 violazioni Z601 (10 in eccesso → moltiplicatore =22=4= 2^2 = 4) subisce quattro volte il normale impatto sulla governance.


Stadio 4 — Gravity Cap

Se il bucket Governance viene completamente azzerato dalle deduzioni:

Sbase=min ⁣(Sbase,  70)se cat_ptsbrand=0S_{\text{base}} = \min\!\left(S_{\text{base}},\; 70\right) \quad \text{se } \text{cat\_pts}_{\text{brand}} = 0

Stadio 5 — Suppression Debt

Ogni soppressione attiva è un'assunzione consapevole di responsabilità. Il modello flat-cost deduce esattamente 1 punto per soppressione, indipendentemente da quante soppressioni siano presenti. Non esiste una franchigia gratuita.

suppression_cap (default: 30) è una soglia di hard-fail, non un limite di franchigia. In zenzic score, il gate fail_under viene valutato prima e il gate sul suppression cap viene valutato dopo; restano due controlli indipendenti. La formula della penalità è indipendente dal cap:

ωdebt=n\omega_{\text{debt}} = n

dove:

  • nn = soppressioni attive totali (inline zenzic:ignore + voci per_file_ignores)

Il punteggio finale è:

Sfinal=max ⁣(0,  Sbasen)S_{\text{final}} = \max\!\left(0,\; S_{\text{base}} - n\right)

Riferimento Costo Soppressioni

Numero soppressioniCosto per soppressioneNote
ncapn \leq \text{cap}1 pt ciascunaPostura gestita — ogni soppressione ha un costo
n>capn > \text{cap}1 pt ciascunaHard-fail: zenzic score termina con codice 1

:::info Condizione al Contorno — Invariante di Configurazione Poiché ogni soppressione deduce 1 punto, il punteggio massimo raggiungibile per un repository è:

Punteggio Massimo Raggiungibile=100Fs\text{Punteggio Massimo Raggiungibile} = 100 - |F_s|

dove Fs|F_s| è il conteggio totale delle soppressioni attive. Configurare fail_under > 100 - suppression_cap crea una contraddizione matematica. Regola sicura: fail_under100 - suppression_cap. :::

Vedi Design dello Scoring — Architettura Dual-Gate e Interpretazione per esempi pratici, guida all'output CLI e semantica della postura di governance.


Formula Completa

Assemblando tutti e cinque gli stadi:

Sfinal={0se cSnc>0(Security Override)max ⁣(0,  Sgravityn)altrimentiS_{\text{final}} = \begin{cases} 0 & \text{se } \sum_{c \in \mathcal{S}} n_c > 0 \quad \text{(Security Override)} \\[6pt] \max\!\left(0,\; S_{\text{gravity}} - n\right) & \text{altrimenti} \end{cases}

dove nn è il conteggio totale delle soppressioni attive e:

Sgravity={min ⁣(Sbase,  70)se cat_ptsbrand=0SbasealtrimentiS_{\text{gravity}} = \begin{cases} \min\!\left(S_{\text{base}},\; 70\right) & \text{se } \text{cat\_pts}_{\text{brand}} = 0 \\ S_{\text{base}} & \text{altrimenti} \end{cases}

Vedi Anche