Skip to main content

Scoring Algorithm

"Zenzic doesn't grade on a curve. Security and Governance are not optional."

The Zenzic Documentation Quality Score (DQS) is a deterministic, 0–100 integer computed from the findings of every active check. Given the same repository state, the algorithm always produces the same score. There is no weighting heuristic, no interpolation, and no rounding until the final integer cast.


Architecture Overview

The scoring pipeline has five sequential stages:

1. Security Gate → Z2xx finding? score = 0, early return.
2. Penalty Table → per-code deductions, per-tier caps.
3. Governance Esc. → exponential amplification if Z6xx > 10.
4. Gravity Cap → brand score = 0 ⟹ total ≤ 70.
5. Suppression Debt → subtract ω_debt from capped total.

Each stage is described below with its full formula.


Stage 1 — Security Override

Before any score computation, the engine checks for Z2xx findings:

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

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

This is an unconditional early return — no flags, no config options, and no suppressions can bypass it. The four codes in S\mathcal{S} represent binary failure conditions:

CodeNameCondition
Z201CREDENTIALCredential pattern detected in document
Z202PATH_TRAVERSALSystem-path escape attempt in a link
Z203PATTERN_MATCHCustom forbidden-pattern match
Z204FORBIDDEN_TERMPrivacy Gate — confidential term exposure

When the Security Override fires, ScoreReport returns security_override=True and security_findings=N (total Z2xx count). The --strict flag and fail-on-error configuration are irrelevant — the gate operates before all of them.

:::danger Security Codes Are Non-Suppressible No inline <!-- zenzic:ignore -->, no per_file_ignores, and no excluded_dirs can suppress a Z2xx finding. The finding still fires. The score is still 0. :::


Stage 2 — Penalty Table and Tier Caps

If no Z2xx finding is present, the engine computes a per-tier score.

Zenzic Weight Matrix (5-Tier)

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

Per-Category Formula

For each 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)

The Category Cap Invariant guarantees that a single tier cannot drag the score below its floor. For example, 1 000 occurrences of Z505 (1 pt each) exhaust the content bucket at −20 pts. The remaining 80 pts from other tiers are unaffected.

Base Score

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

Penalty Reference Table

CodeNamePenalty / occurrenceTier
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 ptsInformational (no DQS impact)
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 — Knowledge Graph telemetry, not a defect Z106 is excluded from the penalty table by design. Elevating it to a scored finding would deduct Quality Score points, pressuring engineers to remove cross-links to satisfy the linter — a perverse incentive that degrades real documentation quality. Circular links in a Knowledge Graph are structural data, not defects. Z106 is emitted as topological telemetry; inspect it with --show-info. :::

:::note Z602 is not scored Z602 (I18N_PARITY) is a Governance gate that fires as a standalone finding. It does not contribute to any DQS bucket and therefore has no penalty value in the table above. :::


Stage 3 — Governance Escalation

Z6xx violations represent brand and governance decay — the kind that accumulates silently. Beyond 10 occurrences, the engine applies an exponential amplifier to the Governance bucket deductions:

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

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

The deduction is capped at the Governance tier maximum (25 pts) to prevent overflow. The practical effect: a repository with 20 Z601 violations (10 excess → multiplier = 22=42^2 = 4) takes four times the normal governance hit.


Stage 4 — Gravity Cap

If the Governance bucket is fully zeroed by its deductions:

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

Rationale (ADR-031): a documentation set with uncontrolled governance violations — brand decay, stale assets, broken navigation contracts — cannot be considered a high-quality product, regardless of its link graph. The Gravity Cap enforces this constraint structurally.


Stage 5 — Suppression Debt

Every active suppression is an acknowledged assumption of responsibility. The flat-cost model deducts exactly 1 point per suppression, regardless of how many suppressions are present. There is no free allowance.

suppression_cap (default: 30) is a hard-fail threshold, not an allowance boundary. When suppression_count > suppression_cap, zenzic score exits with code 1 immediately, before the score gate is evaluated. The penalty formula is independent of the cap:

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

where:

  • nn = total active suppressions (inline zenzic:ignore + per_file_ignores entries)

The final score is:

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

Suppression Cost Reference

Suppression countCost per suppressionNotes
ncapn \leq \text{cap}1 pt eachManaged posture — every suppression costs
n>capn > \text{cap}1 pt eachHard-fail: zenzic score exits with code 1

:::info Boundary Condition — Configuration Invariant Because every suppression deducts 1 point, the maximum achievable score for a repository is:

Max Achievable Score=100Fs\text{Max Achievable Score} = 100 - |F_s|

where Fs|F_s| is the total active suppression count. Configuring fail_under > 100 - suppression_cap creates a mathematical contradiction: the score gate fires due to suppression debt before the governance cap is reached. Safe configuration rule:

fail_under100suppression_cap\texttt{fail\_under} \leq 100 - \texttt{suppression\_cap} :::

Dual-Gate Architecture — Orthogonal Constraints

fail_under and suppression_cap operate as orthogonal constraints evaluated independently by the CI pipeline. A pipeline run fails if either condition is triggered:

  • Score gate: score < fail_underzenzic score exits with code 1
  • Governance cap: |F_s| > suppression_capzenzic score exits with code 1

This dual-gate architecture enables asymmetric bounding of technical debt. A hybrid policy such as fail_under = 90, suppression_cap = 30 enforces: "Overall quality must never drop below 90/100, and regardless of score, no more than 30 suppressed defects are ever tolerated."

:::tip Suppression Debt in the CLI Run zenzic score to inspect the current suppression posture:

Suppression Audit: 8/30 (inline: 5, per-file: 3)

Run zenzic check all --audit to see findings without applying suppressions. :::

Interpretazione dei Risultati

1) Finding Informativi

Informational findings are non-blocking diagnostics for visibility and observability.

  • They do not reduce DQS.
  • They never trigger the Security Override.
  • In SARIF they are emitted at note level.

Typical examples include Z106 (CIRCULAR_LINK) and informational surfaces such as Z114 or Z906.

2) Audit delle Soppressioni

The Suppression Audit is governance telemetry, not a raw failure counter.

  • It reports the total active suppressions (inline directives + per_file_ignores).
  • It expresses explicitly authorized technical debt envelope.
  • Score impact is applied to every active suppression (flat-cost: 1 pt each).

3) Label Semantics: [MANAGED DEBT] and [EXTENDED DEBT]

  • [MANAGED DEBT]: active suppressions are present and the project remains on sovereign cap profile (suppression_cap <= 30).
  • [EXTENDED DEBT]: active suppressions are present while using an expanded cap profile (suppression_cap > 30).

These labels describe governance posture. They are complementary to score math and help reviewers track suppression growth over time.

:::warning Breaking Change Suppressions are not allowance-based. Every suppression deducts 1 point (flat-cost model), while suppression_cap remains an independent hard-fail exit threshold. Projects with active suppressions always see their maximum achievable score reduced by the suppression count. :::


Complete Formula

Assembling all five stages:

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

where nn is the total active suppression count and:

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

Worked Example

Scenario: A repository has 2 broken links (Z101), 3 orphan pages (Z402), 5 untagged code blocks (Z505), and 15 Z601 brand violations, with 8 active suppressions (cap = 30).

Stage 1 — Security Gate: No Z2xx findings → continue.

Stage 2 — Penalty Table:

TierCapDeductioncat_pts
Structural302 × 8.0 = 16.014.0
Navigation253 × 4.0 = 12.013.0
Content205 × 1.0 = 5.015.0
Governance2515 × 2.0 = 30.0 → cap to 250.0

Sbase=14+13+15+0=42S_{\text{base}} = 14 + 13 + 15 + 0 = 42

Stage 3 — Governance Escalation: 15 Z601 violations → nexcess=5n_{\text{excess}} = 5 → multiplier =25/5=2.0= 2^{5/5} = 2.0 → deduction =30×2=60min(60,25)=25= 30 \times 2 = 60 \to \min(60, 25) = 25. Brand bucket = 0.

Stage 4 — Gravity Cap: cat_ptsbrand=0\text{cat\_pts}_{\text{brand}} = 0Sgravity=min(42,70)=42S_{\text{gravity}} = \min(42, 70) = 42.

Stage 5 — Suppression Debt: n=8n = 8 suppressions → flat-cost: ωdebt=8\omega_{\text{debt}} = 8.

Sfinal=max(0,  428)=34S_{\text{final}} = \max(0,\; 42 - 8) = \mathbf{34}


Reading the CLI Output

Running zenzic score displays a Quality Breakdown Ledger that exposes every arithmetic step — from raw per-tier penalties to the applied cap, the Gravity Cap adjustment, suppression debt, and the final score.

✨ Quality Score: 65/100

╭─ Quality Breakdown ──────────────────────────────────────╮
│ Category Issues Weight Raw Pts Applied Pts │
├──────────────────────────────────────────────────────────┤
│ ✓ structural 0 30% 0 0 │
│ ✓ navigation 0 25% 0 0 │
│ ✗ content 2 20% -4 -4 │
│ ✗ brand 15 25% -30 -25 (CAPPED) │
├──────────────────────────────────────────────────────────┤
│ Σ Subtotal 71 │
╰──────────────────────────────────────────────────────────╯
! Technical Debt (6 suppressions) -6 pts
= Final Quality Score 65 / 100

Column guide:

ColumnMeaning
Raw PtsPost-escalation deduction before the category cap, shown as a negative value (or 0).
Applied PtsDeduction actually subtracted, capped at the tier maximum.
(CAPPED)The raw deduction exceeded the tier cap and was truncated.
Σ SubtotalSum of all retained cat_pts values before Gravity Cap and Suppression Debt.

When the Gravity Cap fires (Brand bucket = 0), an extra line appears between Σ Subtotal and Technical Debt:

│ Σ Subtotal 75 │
╰──────────────────────────────────────────────────────────╯
! Gravity Cap Enforcement (Brand = 0) -5 pts
! Technical Debt (0 suppressions) 0 pts
= Final Quality Score 70 / 100

The arithmetic is always explicit: Σ Subtotal − Gravity Cap − Suppression Debt = Final Score.


See Also