<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>The Zenzic Blog — Zenzic Engineering Blog</title>
        <link>https://zenzic.dev/blog</link>
        <description>Engineering insights, security post-mortems, and the evolution of Zenzic.</description>
        <lastBuildDate>Wed, 03 Jun 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>© 2026 PythonWoods</copyright>
        <item>
            <title><![CDATA[Why we banned Python's regex module: The algorithm behind Zenzic]]></title>
            <link>https://zenzic.dev/blog/algorithmic-complexity-and-redos-prevention</link>
            <guid>https://zenzic.dev/blog/algorithmic-complexity-and-redos-prevention</guid>
            <pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[In modern CI/CD pipelines, security and performance should be structurally bounded, not just empirically observed. Traditional documentation linters and credential scanners often fail when operating at scale or under adversarial conditions. The primary failure mode is ReDoS (Regular Expression Denial of Service).]]></description>
            <content:encoded><![CDATA[<p>In modern CI/CD pipelines, security and performance should be structurally bounded, not just empirically observed. Traditional documentation linters and credential scanners often fail when operating at scale or under adversarial conditions. The primary failure mode is <strong>ReDoS (Regular Expression Denial of Service)</strong>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-redos-problem-in-cicd">The ReDoS Problem in CI/CD<a href="https://zenzic.dev/blog/algorithmic-complexity-and-redos-prevention#the-redos-problem-in-cicd" class="hash-link" aria-label="Direct link to The ReDoS Problem in CI/CD" title="Direct link to The ReDoS Problem in CI/CD" translate="no">​</a></h2>
<p>Many Python-based linters rely on the standard <code>re</code> module, which uses a backtracking NFA-style regex engine. When evaluating complex regex patterns against large or crafted payloads, backtracking can lead to exponential worst-case time complexity: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msup><mn>2</mn><mi>N</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(2^N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0913em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.109em">N</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span>.</p>
<p>In a CI/CD environment, an attacker or a simple misconfiguration can introduce a payload that triggers this exponential evaluation. This can stall a pipeline for impractically long periods of time, consuming runner minutes and effectively causing a denial of service on the build infrastructure. Traditional tools attempt to mitigate this using timeouts (<code>SIGALRM</code> or runtime canaries), but these are operational bandages, not architectural solutions.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-zenzic-solution-dfa-and-algorithmic-separation">The Zenzic Solution: DFA and Algorithmic Separation<a href="https://zenzic.dev/blog/algorithmic-complexity-and-redos-prevention#the-zenzic-solution-dfa-and-algorithmic-separation" class="hash-link" aria-label="Direct link to The Zenzic Solution: DFA and Algorithmic Separation" title="Direct link to The Zenzic Solution: DFA and Algorithmic Separation" translate="no">​</a></h2>
<p>Zenzic solves this by completely decoupling the algorithmic approaches based on the problem domain, applying domain-appropriate algorithmic bounds to each layer.</p>
<p>By banning Python's <code>re</code> module and adopting <code>google-re2</code>, Zenzic avoids catastrophic backtracking. RE2 processes input without exponential fallback strategies, ensuring a linear time complexity of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>N</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="mclose">)</span></span></span></span>, where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi></mrow><annotation encoding="application/x-tex">N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.109em">N</span></span></span></span> is the length of the text.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="architectural-summary">Architectural Summary<a href="https://zenzic.dev/blog/algorithmic-complexity-and-redos-prevention#architectural-summary" class="hash-link" aria-label="Direct link to Architectural Summary" title="Direct link to Architectural Summary" translate="no">​</a></h3>
<p>The architectural decisions are summarized below:</p>
<table><thead><tr><th style="text-align:left">Layer</th><th style="text-align:left">Complexity</th><th style="text-align:left">Reason</th><th style="text-align:left">Optimization</th></tr></thead><tbody><tr><td style="text-align:left"><strong>Graph/Topology</strong></td><td style="text-align:left"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Θ</mi><mo stretchy="false">(</mo><mi>V</mi><mo>+</mo><mi>E</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\Theta(V+E)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord">Θ</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.2222em">V</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0576em">E</span><span class="mclose">)</span></span></span></span></td><td style="text-align:left">DFS on adjacency list graph</td><td style="text-align:left">Average <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(1)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord">1</span><span class="mclose">)</span></span></span></span> hash sets for subsequent lookups</td></tr><tr><td style="text-align:left"><strong>Credential Scanner</strong></td><td style="text-align:left"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>N</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="mclose">)</span></span></span></span></td><td style="text-align:left">RE2 engine</td><td style="text-align:left">No catastrophic backtracking</td></tr><tr><td style="text-align:left"><strong>Custom Rules</strong></td><td style="text-align:left"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>N</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="mclose">)</span></span></span></span></td><td style="text-align:left">RE2 engine</td><td style="text-align:left">Prevents exponential ReDoS from user-supplied rules</td></tr><tr><td style="text-align:left"><strong>I/O File Discovery</strong></td><td style="text-align:left"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>N</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="mclose">)</span></span></span></span></td><td style="text-align:left">Sequential scanning</td><td style="text-align:left">Parallel process pool execution for large volumes</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="structural-validation-vs-semantic-scanning">Structural Validation vs. Semantic Scanning<a href="https://zenzic.dev/blog/algorithmic-complexity-and-redos-prevention#structural-validation-vs-semantic-scanning" class="hash-link" aria-label="Direct link to Structural Validation vs. Semantic Scanning" title="Direct link to Structural Validation vs. Semantic Scanning" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>Topology (Knowledge Graph)</strong>: Zenzic treats documentation as a directed adjacency graph. Link validation uses an iterative Depth-First Search (DFS). Using an adjacency list representation, the traversal complexity is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Θ</mi><mo stretchy="false">(</mo><mi>V</mi><mo>+</mo><mi>E</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\Theta(V+E)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord">Θ</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.2222em">V</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0576em">E</span><span class="mclose">)</span></span></span></span>. The resulting cycle registries are stored as hash sets, allowing average <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(1)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord">1</span><span class="mclose">)</span></span></span></span> lookups during the secondary validation pass.</p>
</li>
<li class="">
<p><strong>Semantic Scanning</strong>: Credential scanning and custom rules use the aforementioned approach via <code>google-re2</code>. This ensures linear <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>N</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="mclose">)</span></span></span></span> semantic scanning, eliminating ReDoS vulnerabilities based on exponential backtracking.</p>
</li>
<li class="">
<p><strong>I/O Discovery</strong>: The ingestion phase operates in <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>N</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="mclose">)</span></span></span></span> complexity relative to the total volume of processed data. To reduce wall-time without altering the fundamental computational complexity, Zenzic can distribute processing via parallel process pools.</p>
</li>
</ol>
<p>This algorithmic separation ensures that Zenzic remains a structurally sound, security-hardened tool capable of operating safely within enterprise CI/CD gates.</p>]]></content:encoded>
            <category>Architecture</category>
            <category>Security</category>
            <category>Python</category>
        </item>
        <item>
            <title><![CDATA[Release v0.9.0: Deterministic Telemetry]]></title>
            <link>https://zenzic.dev/blog/log-v090</link>
            <guid>https://zenzic.dev/blog/log-v090</guid>
            <pubDate>Sat, 30 May 2026 10:00:00 GMT</pubDate>
            <description><![CDATA[v0.9.0 establishes deterministic telemetry as a release contract: flat-cost DQS semantics, adapter API cleanup, and native badge freshness checks.]]></description>
            <content:encoded><![CDATA[
<!-- -->
<p>v0.9.0 establishes deterministic telemetry as a release-level engineering
contract across core, action, and docs.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-flat-cost-dqs-shift">1) Flat-Cost DQS Shift<a href="https://zenzic.dev/blog/log-v090#1-flat-cost-dqs-shift" class="hash-link" aria-label="Direct link to 1) Flat-Cost DQS Shift" title="Direct link to 1) Flat-Cost DQS Shift" translate="no">​</a></h2>
<p>The quality score now treats every active suppression as a uniform debt signal:</p>
<ul>
<li class="">one suppression equals one score-point deduction;</li>
<li class="">suppression debt is always visible in the final score;</li>
<li class="">governance thresholds are evaluated independently from debt accumulation.</li>
</ul>
<p>This closes long-standing ambiguity between enforcement outcomes and score
telemetry.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-baseadapter-legacy-method-removal">2) BaseAdapter Legacy Method Removal<a href="https://zenzic.dev/blog/log-v090#2-baseadapter-legacy-method-removal" class="hash-link" aria-label="Direct link to 2) BaseAdapter Legacy Method Removal" title="Direct link to 2) BaseAdapter Legacy Method Removal" translate="no">​</a></h2>
<p>v0.9.0 finalizes adapter contract simplification by removing legacy dual-method
surfaces in favor of a single route-information path.</p>
<p>Migration focus:</p>
<ul>
<li class="">remove legacy adapter method surfaces from custom implementations;</li>
<li class="">keep routing semantics deterministic at a single integration boundary;</li>
<li class="">reduce divergence between link resolution and classification behavior.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-native-freshness-gate-via---check-stamp">3) Native Freshness Gate via --check-stamp<a href="https://zenzic.dev/blog/log-v090#3-native-freshness-gate-via---check-stamp" class="hash-link" aria-label="Direct link to 3) Native Freshness Gate via --check-stamp" title="Direct link to 3) Native Freshness Gate via --check-stamp" translate="no">​</a></h2>
<p>Telemetry is now enforced through a native freshness command:</p>
<ul>
<li class=""><code>zenzic score --check-stamp</code> verifies badge freshness deterministically;</li>
<li class="">freshness checks are config-aware through declared stamp targets;</li>
<li class="">CI and local pre-push gates share the same telemetry contract.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="outcome">Outcome<a href="https://zenzic.dev/blog/log-v090#outcome" class="hash-link" aria-label="Direct link to Outcome" title="Direct link to Outcome" translate="no">​</a></h2>
<p>v0.9.0 turns telemetry from a side-channel metric into a deterministic release
surface: inspectable, reproducible, and enforceable in every gate stage.</p>]]></content:encoded>
            <category>Release</category>
            <category>Milestone Record</category>
            <category>Engineering Logs</category>
        </item>
        <item>
            <title><![CDATA[Three Zenzic Deployment Patterns for Teams]]></title>
            <link>https://zenzic.dev/blog/enterprise-use-cases</link>
            <guid>https://zenzic.dev/blog/enterprise-use-cases</guid>
            <pubDate>Thu, 28 May 2026 10:00:00 GMT</pubDate>
            <description><![CDATA[Three concrete deployment patterns for teams operating Zenzic in CI/CD pipelines: quality gates, legacy debt containment, and structural i18n parity.]]></description>
            <content:encoded><![CDATA[
<!-- -->
<p>Zenzic is designed to run inside automated pipelines without configuration drift. On the v0.9.0 line, three patterns appear consistently in production deployments: a quality gate that blocks merges on score regression, a containment strategy for repositories with accumulated link debt, and an i18n parity gate enforcing structural symmetry across translations.</p>
<p>These patterns target different teams at different stages: DevOps teams enforcing merge gates in CI, technical leads scoping governance adoption in repositories with accumulated debt, and documentation engineers maintaining multilingual portals. The patterns are independent and can be combined. A repository with legacy debt can run Pattern 2 to fence exemptions while still enforcing a quality floor via Pattern 1 and structural i18n parity via Pattern 3.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pattern-1--cicd-quality-gate">Pattern 1 — CI/CD Quality Gate<a href="https://zenzic.dev/blog/enterprise-use-cases#pattern-1--cicd-quality-gate" class="hash-link" aria-label="Direct link to Pattern 1 — CI/CD Quality Gate" title="Direct link to Pattern 1 — CI/CD Quality Gate" translate="no">​</a></h2>
<p>Documentation quality drift rarely looks catastrophic in isolation. A broken link here, a suppressed warning there — each individually justifiable. The aggregate effect is a score that drifts down one point per release cycle until the baseline expectation shifts downward to match. The suppression count is the critical signal: when teams learn that adding a <code>zenzic:ignore</code> directive prevents a CI failure, the suppression budget becomes the real quality floor rather than the score threshold. Both conditions need to be gated independently.</p>
<p>A quality gate blocks a merge if the documentation score falls below a threshold or if the active suppression count exceeds a budget. Both conditions can co-exist independently.</p>
<p><strong>Configuration:</strong></p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">.zenzic.toml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">governance</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">fail_under</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token number">80</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">suppression_cap</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token number">15</span><br></div></code></pre></div></div>
<p><code>fail_under</code> is a mathematical floor: Zenzic computes the weighted score and exits with code 1 if it falls below 80. <code>suppression_cap</code> is a count ceiling: if more than 15 <code>zenzic:ignore</code> directives are active at the time of the check, exit code 1 is issued regardless of the computed score.</p>
<p><strong>GitHub Actions integration:</strong></p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">.github/workflows/docs.yml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Check documentation quality</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> zenzic check all </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">strict</span><br></div></code></pre></div></div>
<p><code>--strict</code> elevates all <code>warning</code>-severity findings to <code>error</code>. Combined with <code>fail_under</code>, this enforces both a minimum score and a zero-warning policy. The two controls are independent: removing <code>--strict</code> does not change the score; lowering <code>fail_under</code> does not relax the warning policy.</p>
<p><strong><code>zenzic diff</code> for regression detection:</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic </span><span class="token function" style="color:rgb(80, 250, 123)">diff</span><span class="token plain"> main</span><br></div></code></pre></div></div>
<p>Compares the quality score of the current branch against <code>main</code>. Exits with code 1 on regression. Suitable for pull request checks where the absolute score is acceptable but a branch-local regression is not.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pattern-2--legacy-debt-containment">Pattern 2 — Legacy Debt Containment<a href="https://zenzic.dev/blog/enterprise-use-cases#pattern-2--legacy-debt-containment" class="hash-link" aria-label="Direct link to Pattern 2 — Legacy Debt Containment" title="Direct link to Pattern 2 — Legacy Debt Containment" translate="no">​</a></h2>
<p>The most common reason teams delay governance adoption is accumulated technical debt. A repository with hundreds of broken links in archived migration guides, deprecated API references, or legacy tutorials cannot pass a strict quality gate without a remediation campaign first — which blocks every other improvement. The result is that governance tooling goes unconfigured rather than progressively adopted. <code>governance.directory_policies</code> breaks this deadlock by fencing the debt structurally without touching the affected files.</p>
<p>Repositories with historical documentation debt — archived migration guides, deprecated API references, legacy tutorials — accumulate broken links and stale brand references over time. Eradicating debt from exempted directories blocks releases unnecessarily. <code>governance.directory_policies</code> fences it instead.</p>
<p><strong>Configuration:</strong></p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">.zenzic.toml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">governance.directory_policies</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">"docs/archive/**"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Z101"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Z102"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Z601"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">"docs/legacy/**"</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Z101"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Z601"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></div></code></pre></div></div>
<p>Each key is a glob pattern relative to <code>docs_dir</code>. The value is a list of finding codes suppressed for every file that matches. Suppressed findings do not contribute to the quality score for those files and do not count against <code>suppression_cap</code>.</p>
<p>This approach isolates the debt rather than distributing inline <code>zenzic:ignore</code> directives across hundreds of legacy files. The governance policy remains visible, auditable, and centralized in <code>.zenzic.toml</code>.</p>
<p><strong>Auditing the exempted directories:</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic check all </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--audit</span><br></div></code></pre></div></div>
<p><code>--audit</code> bypasses all suppressions — including <code>governance.directory_policies</code> — and reports every finding with a <code>[POLICY_EXEMPTION]</code> label. Use this during periodic debt review cycles to quantify the residual finding count before deciding whether to reduce the exemption scope.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pattern-3--sovereign-i18n-parity">Pattern 3 — Sovereign I18N Parity<a href="https://zenzic.dev/blog/enterprise-use-cases#pattern-3--sovereign-i18n-parity" class="hash-link" aria-label="Direct link to Pattern 3 — Sovereign I18N Parity" title="Direct link to Pattern 3 — Sovereign I18N Parity" translate="no">​</a></h2>
<p>Locale drift is invisible at authoring time. A contributor adding a new reference page to the English site has no immediate feedback that the Italian mirror is now structurally incomplete. The gap only surfaces when a translated-site user encounters a 404, or when a periodic manual audit catches it — neither of which scales as the documentation site grows. Z602 surfaces this gap at every CI run, before the missing translation reaches production.</p>
<p>Multilingual documentation sites accumulate structural drift: pages added to the default locale are not mirrored in secondary locales, leaving translated sites incomplete. Z602 I18N_PARITY detects this gap at the structural level.</p>
<p><strong>Configuration:</strong></p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">.zenzic.toml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">i18n</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">enabled</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">default_locale</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"en"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">locales</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"en"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"it"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">strict_parity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token boolean">true</span><br></div></code></pre></div></div>
<p>When <code>strict_parity = true</code>, every page present in <code>default_locale</code> must have a counterpart in every other locale. Missing translations surface as <code>Z602 I18N_PARITY</code> findings at <code>error</code> severity.</p>
<p><strong>Enforcement in CI:</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic check all </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--strict</span><br></div></code></pre></div></div>
<p>Z602 findings are <code>error</code>-severity by default. <code>--strict</code> is not required to block the pipeline on I18N_PARITY violations; it ensures that no other <code>warning</code>-class finding silently passes alongside them.</p>
<p><strong>Gradual adoption:</strong></p>
<p>If the translation backlog is substantial, set <code>strict_parity = false</code> initially and use <code>governance.directory_policies</code> to suppress Z602 for specific locale directories that are still under active translation work:</p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">.zenzic.toml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">governance.directory_policies</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">"i18n/it/docusaurus-plugin-content-docs/current/reference/**"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Z602"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></div></code></pre></div></div>
<p>Remove the exemption when the translation reaches structural parity. <code>zenzic diff main</code> confirms the removal does not regress the quality score.</p>]]></content:encoded>
            <category>Governance</category>
            <category>DevTools</category>
            <category>Engineering</category>
        </item>
        <item>
            <title><![CDATA[Terminal UX as a Governance Interface: How Zenzic Renders Diagnostic Contracts]]></title>
            <link>https://zenzic.dev/blog/terminal-ux-documentation-governance</link>
            <guid>https://zenzic.dev/blog/terminal-ux-documentation-governance</guid>
            <pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[An engineering analysis of Zenzic's terminal interface: information density in the run header, caret-precision diagnostic rendering, suppression debt mathematics, and the invariant semantics of exit codes.
]]></description>
            <content:encoded><![CDATA[
<!-- -->
<p>A linter reports violations within individual files. A governance engine verifies
that a set of invariants holds across the entire document graph — and halts the
pipeline when one does not.</p>
<p>This analysis reflects the terminal contract as shipped on the v0.9.0 release line.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="beyond-linting">Beyond Linting<a href="https://zenzic.dev/blog/terminal-ux-documentation-governance#beyond-linting" class="hash-link" aria-label="Direct link to Beyond Linting" title="Direct link to Beyond Linting" translate="no">​</a></h2>
<p>The distinction between a linter and a governance engine is not one of depth.
It is one of scope and contract type.</p>
<p>A linter's analysis terminates at the file boundary. It reports violations of
formatting rules — incorrect indentation, undefined references within a single
file, missing required metadata fields. Each file is processed independently,
in isolation. The diagnostic is local: a violation in <code>file-a.md</code> has no
bearing on the analysis of <code>file-b.md</code>.</p>
<p>Zenzic operates on a different unit: the document graph. A single invocation of
<code>zenzic check all</code> evaluates the entire scope defined by the adapter
configuration — every internal link, every navigation contract, every credential
surface, every suppression directive — as a unified object. No file is analyzed
in isolation, because no documentation system exists in isolation. A broken
internal link is not a property of the page that contains it. It is a property
of the relationship between two nodes in the graph. An orphaned page is not
detectable from within that page. It is detectable only when the navigation
manifest is resolved against the full file tree.</p>
<p>This distinction has a direct consequence for the design of the terminal output.
When the unit of analysis is a graph, a single-line error message is
insufficient. The interface must communicate: what the violation is, where in
the file it occurs, which contract it violates, and enough surrounding context
for the reader to understand the issue without opening the source file.</p>
<p>Zenzic exposes two orthogonal instruments for evaluating the document graph:</p>
<ul>
<li class=""><code>zenzic check</code> — a binary gate. It returns an exit code in <code>{0, 1, 2, 3}</code>
and a structured list of findings. The exit code is the contract with CI:
deterministic, machine-readable, with semantics that hold regardless of
configuration.</li>
<li class=""><code>zenzic score</code> — a weighted penalty model. It returns a Documentation
Quality Score (DQS) in the range 0–100, decomposed by diagnostic category.
The output is audit-oriented: it answers not whether the documentation
passes, but by how much and in which domains it deviates from the
governance baseline.</li>
</ul>
<p>Both instruments share the same analysis engine. They answer different questions.</p>
<p>The rest of this article examines each layer of the terminal interface that
implements these contracts: the run header, the diagnostic renderer, the
suppression audit model, and the exit code semantics.</p>
<div class="zz-terminal-monolith bg-zinc-900/20 backdrop-blur-md border border-zinc-800/60 rounded-xl overflow-hidden font-mono text-[12px] leading-relaxed"><div class="flex items-center gap-2 px-4 py-2 border-b border-zinc-800/40 bg-zinc-900/30"><span class="h-2.5 w-2.5 rounded-full bg-rose-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-amber-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-emerald-500/80"></span><span class="ml-2 text-zinc-500 text-[11px] tracking-wide">zenzic check all</span></div><div class="px-5 py-4 text-zinc-300 whitespace-pre-wrap break-words"><span class="text-zinc-400 block">standalone · 20 files (14 docs, 6 assets) · 0.8 s · 38 files/s</span><span class="text-emerald-500 font-medium block mt-1">✔ All checks passed — exit 0</span></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="information-density-in-the-run-header">Information Density in the Run Header<a href="https://zenzic.dev/blog/terminal-ux-documentation-governance#information-density-in-the-run-header" class="hash-link" aria-label="Direct link to Information Density in the Run Header" title="Direct link to Information Density in the Run Header" translate="no">​</a></h2>
<p>At the end of every <code>zenzic check</code> invocation, a single telemetry line is
printed below the findings list:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">standalone • 20 files (14 docs, 6 assets) • 0.8s • 38 files/s</span><br></div></code></pre></div></div>
<p>This line encodes four independent signals. Each field answers a distinct
operational question.</p>
<p><strong>Adapter mode</strong> (<code>standalone</code>). Zenzic resolves the adapter from the project
configuration at startup. Supported modes include <code>docusaurus</code>, <code>mkdocs</code>,
<code>zensical</code>, and <code>standalone</code>. The adapter determines the navigation contract: which files
constitute the document graph, how routes are resolved, and which structural
checks are active. When no recognized configuration file is present, <code>standalone</code>
is the default.</p>
<p>The adapter label carries a constraint that is not stated elsewhere in the
output. In <code>standalone</code> mode, the navigation manifest is absent. Checks that
require a resolved route graph — orphaned-page detection being the primary
example — are structurally inactive for that run. The label is the sole
communication of this fact.</p>
<p><strong>Scope decomposition</strong> (<code>20 files (14 docs, 6 assets)</code>). The file count is
split into two categories: documents (<code>.md</code> and <code>.mdx</code>) and assets (images,
data files, schema definitions, and any other non-document file within the
analyzed tree). The split is not cosmetic: document checks operate on file
content; asset checks operate on the asset manifest. Different scanners activate
for each category.</p>
<p>The analyzed scope is bounded by <code>docs_dir</code> and <code>excluded_dirs</code> in
<code>.zenzic.toml</code>. Files outside this boundary are not evaluated, regardless of
their position in the repository tree. The counts in the footer reflect exactly
the scope that was evaluated — nothing more, nothing less.</p>
<p><strong>Elapsed time</strong> (<code>0.8s</code>). Wall-clock duration from invocation to the final
diagnostic line. This includes file I/O, adapter resolution, and all analysis
passes. It is not a CPU-time measurement. On the same hardware and the same
scope, consecutive runs produce consistent values, making elapsed time a
reproducibility indicator without additional instrumentation.</p>
<p><strong>Throughput</strong> (<code>38 files/s</code>). Derived as scope divided by elapsed time. The
value is hardware-specific and not portable across machines. Its utility is
local: establishing a baseline on a given host makes performance regressions
in the analysis pipeline detectable before they affect CI wall time.</p>
<table><thead><tr><th>Field</th><th>Example</th><th>What it communicates</th></tr></thead><tbody><tr><td>Adapter mode</td><td><code>standalone</code></td><td>Active navigation contract; which structural checks apply</td></tr><tr><td>Scope</td><td><code>20 files (14 docs, 6 assets)</code></td><td>Exact file boundary of the analysis; nothing outside is evaluated</td></tr><tr><td>Elapsed</td><td><code>0.8s</code></td><td>Wall-clock duration; reproducibility signal on fixed hardware</td></tr><tr><td>Throughput</td><td><code>38 files/s</code></td><td>Analysis rate; baseline for performance regression detection</td></tr></tbody></table>
<p>To enumerate the full scanner manifest active for a given configuration — codes,
capabilities, and exit-code contracts — use <code>zenzic inspect</code>.</p>
<div class="zz-terminal-monolith bg-zinc-900/20 backdrop-blur-md border border-zinc-800/60 rounded-xl overflow-hidden font-mono text-[12px] leading-relaxed"><div class="flex items-center gap-2 px-4 py-2 border-b border-zinc-800/40 bg-zinc-900/30"><span class="h-2.5 w-2.5 rounded-full bg-rose-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-amber-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-emerald-500/80"></span><span class="ml-2 text-zinc-500 text-[11px] tracking-wide">zenzic inspect rules</span></div><div class="px-5 py-4 text-zinc-300 whitespace-pre-wrap break-words"><span class="text-zinc-400 block">Rule Registry · 12 rules loaded</span><span class="text-emerald-500 font-medium block mt-1">✔ exit 0</span></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="diagnostic-rendering">Diagnostic Rendering<a href="https://zenzic.dev/blog/terminal-ux-documentation-governance#diagnostic-rendering" class="hash-link" aria-label="Direct link to Diagnostic Rendering" title="Direct link to Diagnostic Rendering" translate="no">​</a></h2>
<p>A finding is self-describing. It carries enough information for triage without
opening the source file, navigating the repository, or invoking additional tools.
This property is not incidental — it is a design constraint that shapes every
layer of the diagnostic output.</p>
<p>Each finding is rendered as a three-layer block.</p>
<p><strong>Layer 1 — Finding header.</strong> The first line identifies the finding
unambiguously: file path, line number, column (when available), Z-code, and
message. The Z-code is the machine-readable identifier of the violated contract.
The message is a human-readable description of the violation.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">docs/guides/install.md:47:29</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">✘ Z101  Broken internal link → install.md</span><br></div></code></pre></div></div>
<p><strong>Layer 2 — Source snippet.</strong> Five lines of source context are shown: two lines
before the error line, the error line itself, and two lines after. Context lines
are rendered with a <code>│</code> gutter marker in muted style. The error line is rendered
with a <code>❱</code> gutter marker in error style.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">     45  │  ## Installation Prerequisites</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     46  │</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     47  ❱  See the [Installation Guide](install.md) for details.</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     48  │</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     49  │  Continue to the Configuration section when ready.</span><br></div></code></pre></div></div>
<p>This window is the primary triage surface. The two lines of context before the
error establish what the offending line belongs to — a section header, a
paragraph, a list item. The two lines after establish what follows. In a CI
log, this eliminates the need to reproduce the run locally, open the file, or
reconstruct the surrounding context manually. The context-switching overhead
between reading a pipeline failure and understanding its location is zero.</p>
<p><strong>Layer 3 — Caret row.</strong> When the scanner that produced the finding also
provides the exact byte offset of the matched token in the source line, a caret
row is rendered immediately below the error line. The caret spans the matched
token precisely.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">     47  ❱  See the [Installation Guide](install.md) for details.</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            │                             ^^^^^^^^^^</span><br></div></code></pre></div></div>
<p>The caret length equals the length of the matched string. The caret start
position equals the byte offset of that string in the raw source line — the
exact value returned by the pattern match, with no rounding, padding, or
adjustment. If the scanner does not report a native column position, the caret
row is omitted entirely. There is no fallback, no estimation, and no
approximation. A caret in the output is always exact; the absence of a caret
means the scanner operates at line granularity rather than token granularity.</p>
<p>The practical consequence: for findings where column data is available — such
as credential detections and inline link violations — the operator sees the
precise token that triggered the finding. No surrounding content requires manual
inspection.</p>
<p>The three layers together form a self-contained diagnostic unit:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">docs/guides/install.md:47:29</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">✘ Z101  Broken internal link → install.md</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     45  │  ## Installation Prerequisites</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     46  │</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     47  ❱  See the [Installation Guide](install.md) for details.</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            │                             ^^^^^^^^^^</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     48  │</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">     49  │  Continue to the Configuration section when ready.</span><br></div></code></pre></div></div>
<div class="zz-terminal-monolith bg-zinc-900/20 backdrop-blur-md border border-zinc-800/60 rounded-xl overflow-hidden font-mono text-[12px] leading-relaxed"><div class="flex items-center gap-2 px-4 py-2 border-b border-zinc-800/40 bg-zinc-900/30"><span class="h-2.5 w-2.5 rounded-full bg-rose-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-amber-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-emerald-500/80"></span><span class="ml-2 text-zinc-500 text-[11px] tracking-wide">zenzic check all</span></div><div class="px-5 py-4 text-zinc-300 whitespace-pre-wrap break-words"><div class="text-zinc-400 text-[11px] mb-2">docs/guides/install.md:47</div><div class="flex gap-2 items-baseline"><span class="text-rose-500">✘</span><span class="bg-rose-500/10 text-rose-400 px-1 rounded-sm text-[11px]">[Z101]</span><span class="text-zinc-300">Broken internal link → install.md</span></div><div class="mt-2 text-rose-500 font-semibold text-[11px] tracking-wide">FAILED — exit 1</div></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-mathematics-of-suppression-debt">The Mathematics of Suppression Debt<a href="https://zenzic.dev/blog/terminal-ux-documentation-governance#the-mathematics-of-suppression-debt" class="hash-link" aria-label="Direct link to The Mathematics of Suppression Debt" title="Direct link to The Mathematics of Suppression Debt" translate="no">​</a></h2>
<p>The <code>zenzic:ignore</code> inline directive tells Zenzic to skip the finding on the
annotated line. Each active directive — whether applied inline or via the
per-file suppression list in <code>.zenzic.toml</code> — costs exactly one point from the
Documentation Quality Score. No directive is free.</p>
<p>This is the flat-cost model. It replaced an allowance-based model in which a
configured number of suppressions carried no penalty, and costs applied only to
the excess. The allowance model produced a predictable outcome: teams treated
the free allowance as a budget to fill, not a limit to avoid. A model in which
the first N suppressions are free and the (N+1)th costs a point is not a
governance model — it is a permission slip. The incentive it creates is to
suppress freely below the free threshold and worry about governance only after
that line is crossed.</p>
<p>Under the flat-cost model, the first suppression costs one point. The tenth
costs one point. There is no free zone. The <code>suppression_cap</code> value configured
in <code>.zenzic.toml</code> is not an allowance — it is a hard-fail ceiling. When the
suppression count exceeds the cap, the build fails regardless of the numeric
score.</p>
<p><strong>The DQS formula.</strong> The Documentation Quality Score is computed in three
stages. First, per-category subtotals:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>DQS</mtext><mo>=</mo><munder><munder><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mn>4</mn></munderover><mi>max</mi><mo>⁡</mo><mtext> ⁣</mtext><mo fence="true" stretchy="true" minsize="1.2em" maxsize="1.2em">(</mo><mn>0</mn><mo separator="true">,</mo><mtext>&nbsp;</mtext><msub><mi>C</mi><mi>i</mi></msub><mo>−</mo><msub><mi>D</mi><mi>i</mi></msub><mo fence="true" stretchy="true" minsize="1.2em" maxsize="1.2em">)</mo></mrow><mo stretchy="true">⏟</mo></munder><mtext>category&nbsp;subtotal</mtext></munder><mo>−</mo><msub><mi>n</mi><mtext>sup</mtext></msub></mrow><annotation encoding="application/x-tex">\text{DQS} = \underbrace{\sum_{i=1}^{4} \max\!\bigl(0,\ C_i - D_i\bigr)}_{\text{category subtotal}} - n_{\text{sup}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord text"><span class="mord">DQS</span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:4.549em;vertical-align:-2.7479em"></span><span class="minner munder"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8011em"><span style="top:-1.1893em"><span class="pstrut" style="height:3.8011em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">category&nbsp;subtotal</span></span></span></span></span><span style="top:-3.8011em"><span class="pstrut" style="height:3.8011em"></span><span class="minner munder"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8011em"><span class="svg-align" style="top:-1.8754em"><span class="pstrut" style="height:3.8011em"></span><span class="stretchy" style="height:0.548em;min-width:1.6em"><span class="brace-left" style="height:0.548em"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="0.548em" viewBox="0 0 400000 548" preserveAspectRatio="xMinYMin slice"><path d="M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13
 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688
 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7
-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z"></path></svg></span><span class="brace-center" style="height:0.548em"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="0.548em" viewBox="0 0 400000 548" preserveAspectRatio="xMidYMin slice"><path d="M199572 214
c100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14
 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3
 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0
-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z"></path></svg></span><span class="brace-right" style="height:0.548em"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="0.548em" viewBox="0 0 400000 548" preserveAspectRatio="xMaxYMin slice"><path d="M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3
 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237
-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z"></path></svg></span></span></span><span style="top:-3.8011em"><span class="pstrut" style="height:3.8011em"></span><span class="mord"><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8011em"><span style="top:-1.8723em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">4</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2777em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop">max</span><span class="mspace" style="margin-right:-0.1667em"></span><span class="mopen"><span class="delimsizing size1">(</span></span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace">&nbsp;</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mclose"><span class="delimsizing size1">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.9257em"><span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:2.7479em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">sup</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span></span>
<p>Where:</p>
<ul>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>C</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">C_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> is the point cap for category <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em"></span><span class="mord mathnormal">i</span></span></span></span>: Structural (30), Navigation (25),
Content (20), Brand &amp; Governance (25).</li>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>D</mi><mi>i</mi></msub><mo>=</mo><msub><mo>∑</mo><mrow><mi>c</mi><mo>∈</mo><mi>i</mi></mrow></msub><msub><mi>p</mi><mi>c</mi></msub><mo>⋅</mo><msub><mi>k</mi><mi>c</mi></msub></mrow><annotation encoding="application/x-tex">D_i = \sum_{c \in i} p_c \cdot k_c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0771em;vertical-align:-0.3271em"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.162em"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">c</span><span class="mrel mtight">∈</span><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3271em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em">k</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0315em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> is the total penalty for category <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em"></span><span class="mord mathnormal">i</span></span></span></span>:
the sum of per-code penalty <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>p</mi><mi>c</mi></msub></mrow><annotation encoding="application/x-tex">p_c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em"></span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> multiplied by finding count <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>k</mi><mi>c</mi></msub></mrow><annotation encoding="application/x-tex">k_c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em">k</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0315em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span>, for
all codes assigned to that category.</li>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>n</mi><mtext>sup</mtext></msub></mrow><annotation encoding="application/x-tex">n_{\text{sup}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">sup</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span> is the total count of active suppression directives, each
contributing exactly 1 point of deduction.</li>
</ul>
<p>Two invariants constrain the formula:</p>
<ul>
<li class=""><strong>Category Cap Invariant.</strong> Deductions within a category cannot exceed the
category cap. One thousand occurrences of a 1-point finding in the Content
category deduct at most 20 points — the Content cap. The remaining
categories are unaffected.</li>
<li class=""><strong>Gravity Cap.</strong> If the Brand &amp; Governance category is fully zeroed by
findings, the category subtotal is capped at 70. Uncontrolled governance
violations impose a structural ceiling on the total score regardless of how
other categories perform.</li>
</ul>
<p>Suppression debt (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>n</mi><mtext>sup</mtext></msub></mrow><annotation encoding="application/x-tex">n_{\text{sup}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">sup</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span>) is applied after both invariants, as a
final deduction from the adjusted subtotal.</p>
<p><strong>The Quality Breakdown Ledger.</strong> The <code>zenzic score</code> command renders a
per-category table that exposes the deduction mechanics:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain"> Quality Breakdown</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> ─────────────────────────────────────────────────────────</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">   Category      Issues  Weight   Raw Pts      Applied Pts</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> ✔ structural         0    30%          0                0</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> ✔ navigation         0    25%          0                0</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> ✔ content            0    20%          0                0</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> ✘ brand             42    25%        -60     -25 (CAPPED)</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> ─────────────────────────────────────────────────────────</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">   Σ Subtotal                                           75</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  ! Gravity Cap Enforcement (Brand = 0):   -5 pts</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  ! Technical Debt (5 suppressions):       -5 pts</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  = Final Quality Score                    65 / 100</span><br></div></code></pre></div></div>
<p><strong>Raw Pts</strong> is the total deduction accumulated within the category before the
cap is applied. Here, 42 brand findings produced −60 raw points. <strong>Applied Pts</strong>
is the deduction after the category cap: the Brand cap is 25 points, so the
applied penalty is −25. The <code>(CAPPED)</code> marker confirms that the raw deduction
was truncated by the cap boundary. The difference between Raw Pts and Applied
Pts is not recovered — it signals that the category has been fully zeroed.</p>
<p>The <code>! Gravity Cap Enforcement</code> line appears when the zeroed Brand category
causes the subtotal to be reduced from 75 to 70, applying a 5-point structural
penalty. The <code>! Technical Debt</code> line shows the flat-cost deduction: five active
suppression directives produce a deduction of five points, applied after all
category calculations.</p>
<p>The suppression count is also compared to <code>governance.suppression_cap</code>. When
the count exceeds the cap, the build fails with a distinct message:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">FAILED: suppression cap exceeded (36/30).</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">Update governance.suppression_cap in .zenzic.toml if intentional.</span><br></div></code></pre></div></div>
<p>This failure is Exit 1 and remains fail-hard when suppression cap is exceeded.
It cannot be resolved by adding more <code>zenzic:ignore</code> directives — each
additional directive increases the count and the debt simultaneously.</p>
<div class="zz-terminal-monolith bg-zinc-900/20 backdrop-blur-md border border-zinc-800/60 rounded-xl overflow-hidden font-mono text-[12px] leading-relaxed"><div class="flex items-center gap-2 px-4 py-2 border-b border-zinc-800/40 bg-zinc-900/30"><span class="h-2.5 w-2.5 rounded-full bg-rose-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-amber-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-emerald-500/80"></span><span class="ml-2 text-zinc-500 text-[11px] tracking-wide">zenzic check all</span></div><div class="px-5 py-4 text-zinc-300 whitespace-pre-wrap break-words"><span class="text-emerald-500 font-medium">✔ All checks passed — exit 0</span></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="exit-semantics-as-a-ci-contract">Exit Semantics as a CI Contract<a href="https://zenzic.dev/blog/terminal-ux-documentation-governance#exit-semantics-as-a-ci-contract" class="hash-link" aria-label="Direct link to Exit Semantics as a CI Contract" title="Direct link to Exit Semantics as a CI Contract" translate="no">​</a></h2>
<p>The exit code is not a summary of the terminal output. It is the primary
contract between Zenzic and the CI pipeline. The pipeline reads the exit code,
not the display. The display is for operators; the exit code is for automation.
This distinction determines how the exit semantics are designed.</p>
<p>The four exit codes and their contracts:</p>
<table><thead><tr><th>Code</th><th>Trigger</th><th>Suppressible via directive?</th><th><code>--exit-zero</code> effect</th></tr></thead><tbody><tr><td>0</td><td>No error-severity findings in the analyzed scope</td><td>—</td><td>No effect</td></tr><tr><td>1</td><td>Error-severity findings detected</td><td>Yes — via <code>zenzic:ignore</code></td><td>Converts to 0</td></tr><tr><td>1</td><td>Suppression cap exceeded</td><td>No — directives increase debt/cap pressure</td><td>No effect (fail-hard)</td></tr><tr><td>2</td><td>Credential detected in documentation content (Z2xx)</td><td>Never</td><td>No effect</td></tr><tr><td>3</td><td>Path traversal to system directories detected (Z203)</td><td>Never</td><td>No effect</td></tr></tbody></table>
<p><strong>Exit 0.</strong> The analyzed scope contains no error-severity findings. When
<code>fail_under</code> is configured, a score below the threshold also produces Exit 1 —
so Exit 0 confirms both the absence of findings and that the Documentation
Quality Score meets the configured threshold. The scope qualifier is precise:
files outside the configured <code>docs_dir</code> boundary are not evaluated, and their
state is not reflected in the exit code.</p>
<p><strong>Exit 1.</strong> One or more error-severity findings were detected, or the
suppression count exceeded <code>governance.suppression_cap</code>. This is the standard
CI gate. <code>--exit-zero</code> converts Exit 1 to Exit 0 only for the standard
error-findings path; suppression-cap failures remain fail-hard. The conversion
does not suppress findings from the output — they remain visible in the
terminal. <code>--exit-zero</code> cannot be combined with <code>--strict</code>; Zenzic rejects that
combination with Exit 2 at startup.</p>
<div class="zz-terminal-monolith bg-zinc-900/20 backdrop-blur-md border border-zinc-800/60 rounded-xl overflow-hidden font-mono text-[12px] leading-relaxed"><div class="flex items-center gap-2 px-4 py-2 border-b border-zinc-800/40 bg-zinc-900/30"><span class="h-2.5 w-2.5 rounded-full bg-rose-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-amber-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-emerald-500/80"></span><span class="ml-2 text-zinc-500 text-[11px] tracking-wide">zenzic check all</span></div><div class="px-5 py-4 text-zinc-300 whitespace-pre-wrap break-words"><span class="text-rose-500 font-medium">✘ 1 error — exit 1</span></div></div>
<p><strong>Exit 2.</strong> A finding with <code>security_breach</code> severity was produced — meaning a
credential or secret was detected in the documentation source tree. This exit
code cannot be suppressed by <code>zenzic:ignore</code>, cannot be overridden by
<code>--exit-zero</code>, and cannot be silenced by per-file ignore policies. The
credential scanner (Z2xx codes) is active regardless of adapter mode,
<code>--offline</code> flag, or <code>--no-external</code> flag.</p>
<p><strong>Exit 3.</strong> A path traversal to an operating-system system directory was
detected. This is a distinct severity class (<code>security_incident</code>) and
represents the maximum security contract: the <code>docs_dir</code> configuration value or
a scanned path attempted to escape the repository boundary toward system paths.
Like Exit 2, it precedes all other exit-code evaluation. <code>--exit-zero</code> has no
effect.</p>
<div class="zz-terminal-monolith bg-zinc-900/20 backdrop-blur-md border border-rose-900/30 rounded-xl py-5 px-6 font-mono text-[12px] leading-relaxed"><div class="text-rose-500/90 text-xs text-center tracking-[0.2em] font-bold mb-4 border-b border-rose-900/20 pb-3">SECURITY BREACH DETECTED</div><div class="flex items-center gap-3 mb-2"><span class="text-rose-500">✘</span><span class="w-24 text-zinc-500">Finding:</span><span class="text-zinc-200">GitHub token detected</span></div><div class="flex items-center gap-3 mb-2"><span class="text-rose-500">✘</span><span class="w-24 text-zinc-500">Location:</span><span class="text-zinc-200">docs/tutorial.md:42</span></div><div class="flex items-center gap-3 mb-4"><span class="text-rose-500">✘</span><span class="w-24 text-zinc-500">Credential:</span><span class="bg-rose-500/10 text-rose-200 px-2 py-0.5 rounded-sm">ghp_************3456</span></div><div class="flex items-start gap-3 mt-4 pt-4 border-t border-rose-900/20"><span class="w-24 text-zinc-600 pt-0.5">Action:</span><span class="text-zinc-400">Rotate this credential immediately and purge it from the repository history.</span></div></div>
<p>The evaluation order is fixed: Exit 3 conditions are checked first, Exit 2
second, Exit 1 third. This order ensures that security contracts are never
shadowed by governance failures or score thresholds.</p>
<hr>
<p>The four elements of the terminal interface analyzed in this article — the run
header, the diagnostic block, the suppression ledger, and the exit code table —
are not independent display decisions. They form a single interface that makes
the documentation governance policy machine-readable, auditable, and
deterministic.</p>
<p>A <code>fail_under</code> threshold, a <code>suppression_cap</code>, a per-category penalty model,
and an immutable exit code contract are the formal encoding of what a team
considers acceptable documentation quality. The terminal output is where that
encoding is evaluated on every run. Treating it as display-only discards that
evaluation. Treating it as a governance interface — machine-readable exit codes,
auditable debt counters, caret-precise diagnostics — makes it enforceable at
the pipeline boundary.</p>]]></content:encoded>
            <category>Engineering Logs</category>
            <category>Architecture</category>
            <category>Governance</category>
        </item>
        <item>
            <title><![CDATA[The DQS Mathematical Model: Flat-Cost Suppressions and Deterministic Gates]]></title>
            <link>https://zenzic.dev/blog/dqs-mathematical-model</link>
            <guid>https://zenzic.dev/blog/dqs-mathematical-model</guid>
            <pubDate>Mon, 25 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Zenzic's Documentation Quality Score is a deterministic integer from 0 to 100. This post explains the mathematical model behind it: how findings translate to score deductions, why the flat-cost suppression model prevents governance theater, and how the security override ensures binary safety conditions never blend into the quality gradient.
]]></description>
            <content:encoded><![CDATA[<p>The Documentation Quality Score (DQS) is an integer from 0 to 100. Given the same repository state, it always produces the same number. v0.8.0 changed two things: it closed a gate paradox where CI-blocking codes had zero DQS weight, and it replaced the allowance-based suppression model with a flat-cost model.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-gate-paradox">The Gate Paradox<a href="https://zenzic.dev/blog/dqs-mathematical-model#the-gate-paradox" class="hash-link" aria-label="Direct link to The Gate Paradox" title="Direct link to The Gate Paradox" translate="no">​</a></h2>
<p>Before v0.8.0, the scoring engine had two separate tables: <code>CODE_SARIF_LEVELS</code> (used by the CI gate) and a penalty table (used by the DQS calculator). These tables were maintained independently. The invariant — that a CI-blocking code must also deduct from the score — was not enforced.</p>
<p>Three codes broke that invariant:</p>
<table><thead><tr><th style="text-align:left">Code</th><th style="text-align:left">Name</th><th style="text-align:left">SARIF Level</th><th style="text-align:left">DQS Penalty (before v0.8.0)</th></tr></thead><tbody><tr><td style="text-align:left">Z103</td><td style="text-align:left">ORPHAN_LINK</td><td style="text-align:left"><code>error</code></td><td style="text-align:left">0 pts</td></tr><tr><td style="text-align:left">Z111</td><td style="text-align:left">VIRTUAL_ROUTE_BROKEN</td><td style="text-align:left"><code>error</code></td><td style="text-align:left">0 pts</td></tr><tr><td style="text-align:left">Z113</td><td style="text-align:left">AUTHOR_KEY_COLLISION</td><td style="text-align:left"><code>error</code></td><td style="text-align:left">0 pts</td></tr></tbody></table>
<p>The observable consequence: a repository with 50 ORPHAN_LINK findings would fail the CI gate (exit code 1) but report a DQS of 100. The gate and the score were contradicting each other.</p>
<p>v0.8.0 established a single source of truth: <code>CodeDefinition</code>, a <code>NamedTuple</code> that stores <code>severity</code>, <code>penalty</code>, and <code>category</code> for each code in one place. <code>CODE_SARIF_LEVELS</code> is now derived from it. Structural registration is impossible without a penalty — the paradox cannot recur.</p>
<p>The three paradox codes received their penalties in the migration:</p>
<table><thead><tr><th style="text-align:left">Code</th><th style="text-align:left">Name</th><th style="text-align:left">Penalty</th><th style="text-align:left">Category</th></tr></thead><tbody><tr><td style="text-align:left">Z103</td><td style="text-align:left">ORPHAN_LINK</td><td style="text-align:left">2.0 pts</td><td style="text-align:left">Structural</td></tr><tr><td style="text-align:left">Z111</td><td style="text-align:left">VIRTUAL_ROUTE_BROKEN</td><td style="text-align:left">8.0 pts</td><td style="text-align:left">Structural</td></tr><tr><td style="text-align:left">Z113</td><td style="text-align:left">AUTHOR_KEY_COLLISION</td><td style="text-align:left">2.0 pts</td><td style="text-align:left">Structural</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="from-allowance-to-flat-cost">From Allowance to Flat-Cost<a href="https://zenzic.dev/blog/dqs-mathematical-model#from-allowance-to-flat-cost" class="hash-link" aria-label="Direct link to From Allowance to Flat-Cost" title="Direct link to From Allowance to Flat-Cost" translate="no">​</a></h2>
<p>The previous suppression model was allowance-based:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>ω</mi><mtext>debt</mtext></msub><mo>=</mo><mi>max</mi><mo>⁡</mo><mo stretchy="false">(</mo><mn>0</mn><mo separator="true">,</mo><mtext>  </mtext><mi>n</mi><mo>−</mo><mtext>cap</mtext><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\omega_{\text{debt}} = \max(0,\; n - \text{cap})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">ω</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">debt</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mop">max</span><span class="mopen">(</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text"><span class="mord">cap</span></span><span class="mclose">)</span></span></span></span></span>
<p>Suppressions up to <code>suppression_cap</code> were free. Only excess suppressions generated debt. The cap served two roles simultaneously: it was a governance allowance boundary and a hard-fail threshold.</p>
<p>That dual role was the problem. A project with <code>suppression_cap = 30</code> and 30 active suppressions had: score impact = 0, exit code = 0. Suppressions were invisible in the DQS.</p>
<p>The v0.8.0 model decouples the two roles:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>ω</mi><mtext>debt</mtext></msub><mo>=</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">\omega_{\text{debt}} = n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">ω</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">debt</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span></span>
<p>Every suppression deducts 1 point. The cap is exclusively a hard-fail threshold:</p>
<ul>
<li class="">When <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>≤</mo><mtext>cap</mtext></mrow><annotation encoding="application/x-tex">n \leq \text{cap}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719em;vertical-align:-0.136em"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em"></span><span class="mord text"><span class="mord">cap</span></span></span></span></span>: score is reduced by <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span> points. Exit code is determined by the score gate.</li>
<li class="">When <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>&gt;</mo><mtext>cap</mtext></mrow><annotation encoding="application/x-tex">n &gt; \text{cap}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em"></span><span class="mord text"><span class="mord">cap</span></span></span></span></span>: <code>zenzic score</code> exits with code 1 immediately, before score gate evaluation.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-complete-dqs-formula">The Complete DQS Formula<a href="https://zenzic.dev/blog/dqs-mathematical-model#the-complete-dqs-formula" class="hash-link" aria-label="Direct link to The Complete DQS Formula" title="Direct link to The Complete DQS Formula" translate="no">​</a></h2>
<p>Assembling all five stages:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>D</mi><mi>Q</mi><mi>S</mi><mo>=</mo><mrow><mo fence="true">{</mo><mtable rowspacing="0.36em" columnalign="left left" columnspacing="1em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>0</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mtext>if&nbsp;</mtext><msub><mo>∑</mo><mrow><mi>c</mi><mo>∈</mo><mi mathvariant="script">S</mi></mrow></msub><msub><mi>n</mi><mi>c</mi></msub><mo>&gt;</mo><mn>0</mn><mspace width="1em"></mspace><mtext>(Security&nbsp;Override)</mtext></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>max</mi><mo>⁡</mo><mtext> ⁣</mtext><mrow><mo fence="true">(</mo><mn>0</mn><mo separator="true">,</mo><mtext>  </mtext><msub><mi>S</mi><mtext>gravity</mtext></msub><mo>−</mo><mi>n</mi><mo fence="true">)</mo></mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mtext>otherwise</mtext></mstyle></mtd></mtr></mtable></mrow></mrow><annotation encoding="application/x-tex">DQS = \begin{cases}
0 &amp; \text{if } \sum_{c \in \mathcal{S}} n_c &gt; 0 \quad \text{(Security Override)} \\[8pt]
\max\!\left(0,\; S_{\text{gravity}} - n\right) &amp; \text{otherwise}
\end{cases}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="mord mathnormal" style="margin-right:0.0576em">QS</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:3.68em;vertical-align:-1.59em"></span><span class="minner"><span class="mopen"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em"><span style="top:-2.5em"><span class="pstrut" style="height:3.15em"></span><span class="delimsizinginner delim-size4"><span>⎩</span></span></span><span style="top:-2.492em"><span class="pstrut" style="height:3.15em"></span><span style="height:0.016em;width:0.8889em"><svg xmlns="http://www.w3.org/2000/svg" width="0.8889em" height="0.016em" style="width:0.8889em" viewBox="0 0 888.89 16" preserveAspectRatio="xMinYMin"><path d="M384 0 H504 V16 H384z M384 0 H504 V16 H384z"></path></svg></span></span><span style="top:-3.15em"><span class="pstrut" style="height:3.15em"></span><span class="delimsizinginner delim-size4"><span>⎨</span></span></span><span style="top:-4.292em"><span class="pstrut" style="height:3.15em"></span><span style="height:0.016em;width:0.8889em"><svg xmlns="http://www.w3.org/2000/svg" width="0.8889em" height="0.016em" style="width:0.8889em" viewBox="0 0 888.89 16" preserveAspectRatio="xMinYMin"><path d="M384 0 H504 V16 H384z M384 0 H504 V16 H384z"></path></svg></span></span><span style="top:-4.3em"><span class="pstrut" style="height:3.15em"></span><span class="delimsizinginner delim-size4"><span>⎧</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.55em"><span></span></span></span></span></span></span><span class="mord"><span class="mtable"><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.09em"><span style="top:-4.09em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mord">0</span></span></span><span style="top:-1.85em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mop">max</span><span class="mspace" style="margin-right:-0.1667em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em">(</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3175em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">gravity</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord mathnormal">n</span><span class="mclose delimcenter" style="top:0em">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.59em"><span></span></span></span></span></span><span class="arraycolsep" style="width:1em"></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.09em"><span style="top:-4.09em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mord text"><span class="mord">if&nbsp;</span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1786em"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">c</span><span class="mrel mtight">∈</span><span class="mord mathcal mtight" style="margin-right:0.075em">S</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3271em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mord">0</span><span class="mspace" style="margin-right:1em"></span><span class="mord text"><span class="mord">(Security&nbsp;Override)</span></span></span></span><span style="top:-1.85em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mord text"><span class="mord">otherwise</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.59em"><span></span></span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span>
<p>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="script">S</mi><mo>=</mo><mo stretchy="false">{</mo><mi>Z</mi><mn>201</mn><mo separator="true">,</mo><mi>Z</mi><mn>202</mn><mo separator="true">,</mo><mi>Z</mi><mn>203</mn><mo separator="true">,</mo><mi>Z</mi><mn>204</mn><mo stretchy="false">}</mo></mrow><annotation encoding="application/x-tex">\mathcal{S} = \{Z201, Z202, Z203, Z204\}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathcal" style="margin-right:0.075em">S</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">{</span><span class="mord mathnormal" style="margin-right:0.0715em">Z</span><span class="mord">201</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0715em">Z</span><span class="mord">202</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0715em">Z</span><span class="mord">203</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0715em">Z</span><span class="mord">204</span><span class="mclose">}</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span> is the total active suppression count, and:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>S</mi><mtext>gravity</mtext></msub><mo>=</mo><mrow><mo fence="true">{</mo><mtable rowspacing="0.36em" columnalign="left left" columnspacing="1em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>min</mi><mo>⁡</mo><mtext> ⁣</mtext><mrow><mo fence="true">(</mo><msub><mi>S</mi><mtext>base</mtext></msub><mo separator="true">,</mo><mtext>  </mtext><mn>70</mn><mo fence="true">)</mo></mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mtext>if&nbsp;</mtext><msub><mtext>cat_pts</mtext><mtext>brand</mtext></msub><mo>=</mo><mn>0</mn></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><msub><mi>S</mi><mtext>base</mtext></msub></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mtext>otherwise</mtext></mstyle></mtd></mtr></mtable></mrow></mrow><annotation encoding="application/x-tex">S_{\text{gravity}} =
\begin{cases}
\min\!\left(S_{\text{base}},\; 70\right) &amp; \text{if } \text{cat\_pts}_{\text{brand}} = 0 \\
S_{\text{base}} &amp; \text{otherwise}
\end{cases}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3175em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">gravity</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:3em;vertical-align:-1.25em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em"><span class="delimsizing size4">{</span></span><span class="mord"><span class="mtable"><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.69em"><span style="top:-3.69em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mop">min</span><span class="mspace" style="margin-right:-0.1667em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">base</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord">70</span><span class="mclose delimcenter" style="top:0em">)</span></span></span></span><span style="top:-2.25em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">base</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.19em"><span></span></span></span></span></span><span class="arraycolsep" style="width:1em"></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.69em"><span style="top:-3.69em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mord text"><span class="mord">if&nbsp;</span></span><span class="mord"><span class="mord text"><span class="mord">cat_pts</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1264em"><span style="top:-2.3403em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">brand</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3597em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mord">0</span></span></span><span style="top:-2.25em"><span class="pstrut" style="height:3.008em"></span><span class="mord"><span class="mord text"><span class="mord">otherwise</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.19em"><span></span></span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>S</mi><mtext>base</mtext></msub><mo>=</mo><mn>100</mn><mo>−</mo><munder><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mtext>tiers</mtext></mrow></munder><mi>min</mi><mo>⁡</mo><mtext> ⁣</mtext><mrow><mo fence="true">(</mo><msub><mtext>Cap</mtext><mi>i</mi></msub><mo separator="true">,</mo><mtext>  </mtext><munder><mo>∑</mo><mrow><mi>c</mi><mo>∈</mo><msub><mtext>tier</mtext><mi>i</mi></msub></mrow></munder><msub><mtext>penalty</mtext><mi>c</mi></msub><mo>×</mo><msub><mi>n</mi><mi>c</mi></msub><mo fence="true">)</mo></mrow></mrow><annotation encoding="application/x-tex">S_{\text{base}} = 100 - \sum_{i \in \text{tiers}} \min\!\left(\text{Cap}_i,\; \sum_{c \in \text{tier}_i} \text{penalty}_c \times n_c\right)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">base</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">100</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:3.1336em;vertical-align:-1.3836em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8665em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">∈</span><span class="mord text mtight"><span class="mord mtight">tiers</span></span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3109em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop">min</span><span class="mspace" style="margin-right:-0.1667em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em"><span class="delimsizing size4">(</span></span><span class="mord"><span class="mord text"><span class="mord">Cap</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2175em"><span style="top:-2.4559em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8665em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">c</span><span class="mrel mtight">∈</span><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">tier</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3281em"><span style="top:-2.357em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em"><span></span></span></span></span></span></span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3836em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord text"><span class="mord">penalty</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em"><span style="top:-2.4559em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em"><span class="delimsizing size4">)</span></span></span></span></span></span></span>
<p>Or, expanding the full pipeline into a single expression:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>D</mi><mi>Q</mi><mi>S</mi><mo>=</mo><mi>max</mi><mo>⁡</mo><mtext> ⁣</mtext><mrow><mo fence="true">(</mo><mn>0</mn><mo separator="true">,</mo><mtext>  </mtext><msub><mi>S</mi><mtext>gravity</mtext></msub><mo>−</mo><mrow><mo fence="true">∣</mo><msub><mi>F</mi><mi>s</mi></msub><mo fence="true">∣</mo></mrow><mo>×</mo><mtext>DebtCost</mtext><mo fence="true">)</mo></mrow></mrow><annotation encoding="application/x-tex">DQS = \max\!\left(0,\; S_{\text{gravity}} - \left| F_s \right| \times \text{DebtCost}\right)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="mord mathnormal" style="margin-right:0.0576em">QS</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0361em;vertical-align:-0.2861em"></span><span class="mop">max</span><span class="mspace" style="margin-right:-0.1667em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em">(</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3175em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">gravity</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em">∣</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em">∣</span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord text"><span class="mord">DebtCost</span></span><span class="mclose delimcenter" style="top:0em">)</span></span></span></span></span></span>
<p>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo fence="true">∣</mo><msub><mi>F</mi><mi>s</mi></msub><mo fence="true">∣</mo></mrow><annotation encoding="application/x-tex">\left| F_s \right|</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em">∣</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em">∣</span></span></span></span></span> is the total suppression count and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>DebtCost</mtext><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\text{DebtCost} = 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em"></span><span class="mord text"><span class="mord">DebtCost</span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">1</span></span></span></span>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="numerical-properties">Numerical Properties<a href="https://zenzic.dev/blog/dqs-mathematical-model#numerical-properties" class="hash-link" aria-label="Direct link to Numerical Properties" title="Direct link to Numerical Properties" translate="no">​</a></h2>
<p><strong>Maximum achievable score</strong> is now <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>100</mn><mo>−</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">100 - n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">100</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span>, where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span> is the active suppression count. A project with 10 suppressions cannot exceed 90, regardless of finding counts.</p>
<p><strong>Monotonicity</strong>: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>D</mi><mi>Q</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">DQS</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="mord mathnormal" style="margin-right:0.0576em">QS</span></span></span></span> is non-increasing in <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span>. Adding a suppression never improves the score.</p>
<p><strong>Score/gate coupling</strong>: the CI gate threshold (configured via <code>--fail-under</code>) and the hard-fail suppression threshold (<code>suppression_cap</code>) are now independent. A project with a score of 80 and 29 suppressions (cap = 30) passes both. A project with a score of 95 and 31 suppressions (cap = 30) fails the cap gate regardless of the score.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="closing-the-mapping-gap">Closing the Mapping Gap<a href="https://zenzic.dev/blog/dqs-mathematical-model#closing-the-mapping-gap" class="hash-link" aria-label="Direct link to Closing the Mapping Gap" title="Direct link to Closing the Mapping Gap" translate="no">​</a></h2>
<p>The <code>CodeDefinition</code> single source of truth was established to prevent gate/score divergence. But the initial migration targeted only the three paradox codes (Z103, Z111, Z113). A subsequent audit identified four additional codes that the engine could emit (causing Exit 1) while carrying a penalty of 0.0 in the penalty table. The same paradox, at a smaller scale.</p>
<p>Three of the four received penalties in the migration:</p>
<table><thead><tr><th style="text-align:left">Code</th><th style="text-align:left">Name</th><th style="text-align:left">Penalty</th><th style="text-align:left">Category</th><th style="text-align:left">Notes</th></tr></thead><tbody><tr><td style="text-align:left">Z401</td><td style="text-align:left">MISSING_DIRECTORY_INDEX</td><td style="text-align:left">2.0 pts</td><td style="text-align:left">Navigation</td><td style="text-align:left">Directory reachable but no index page present</td></tr><tr><td style="text-align:left">Z403</td><td style="text-align:left">MISSING_ALT</td><td style="text-align:left">1.0 pt</td><td style="text-align:left">Content</td><td style="text-align:left">Image with missing <code>alt</code> attribute (<code>is_warning=True</code>)</td></tr><tr><td style="text-align:left">Z404</td><td style="text-align:left">CONFIG_ASSET_MISSING</td><td style="text-align:left">3.0 pts</td><td style="text-align:left">Brand</td><td style="text-align:left">Favicon or OG image declared in config but absent on disk</td></tr></tbody></table>
<p>The fourth — <strong>Z602 (I18N_PARITY)</strong> — remains frozen at 0.0 by architectural decision.
I18N_PARITY acts as a governance gate: it enforces language parity between documentation
trees and triggers Exit 1 when parity fails. Assigning it a DQS penalty would conflate
two independent quality dimensions (translation completeness vs. link health / content
quality) into a single number, making the score harder to interpret. A separate ADR is
required to add Z602 to the DQS formula. For now, it is excluded from the penalty table, listed in <code>FROZEN_CODES</code>, and defined in <code>CODE_DEFINITIONS</code> with penalty <code>0.0</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="migration-impact-v07x--v080">Migration Impact (v0.7.x → v0.8.0)<a href="https://zenzic.dev/blog/dqs-mathematical-model#migration-impact-v07x--v080" class="hash-link" aria-label="Direct link to Migration Impact (v0.7.x → v0.8.0)" title="Direct link to Migration Impact (v0.7.x → v0.8.0)" translate="no">​</a></h2>
<p>Projects with active suppressions will see their DQS decrease. The magnitude is exactly the active suppression count:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>D</mi><mi>Q</mi><mi>S</mi><mo>=</mo><mo>−</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">\Delta DQS = -n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="mord mathnormal" style="margin-right:0.0576em">QS</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em"></span><span class="mord">−</span><span class="mord mathnormal">n</span></span></span></span></span>
<p>For a project with 10 suppressions previously scoring 75 (under allowance model with <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>≤</mo><mtext>cap</mtext></mrow><annotation encoding="application/x-tex">n \leq \text{cap}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719em;vertical-align:-0.136em"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em"></span><span class="mord text"><span class="mord">cap</span></span></span></span></span>), the new score is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>75</mn><mo>−</mo><mn>10</mn><mo>=</mo><mn>65</mn></mrow><annotation encoding="application/x-tex">75 - 10 = 65</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">75</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">10</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">65</span></span></span></span>.</p>
<p>The suppression audit output in the CLI is unchanged. The label semantics for <code>[MANAGED DEBT]</code> and <code>[EXTENDED DEBT]</code> describe governance posture, not score exemption.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="see-also">See Also<a href="https://zenzic.dev/blog/dqs-mathematical-model#see-also" class="hash-link" aria-label="Direct link to See Also" title="Direct link to See Also" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://zenzic.dev/docs/reference/scoring-algorithm">Scoring Algorithm Reference</a> — Full formula derivation and penalty table</li>
<li class=""><a class="" href="https://zenzic.dev/docs/reference/suppression-policy">Suppression Policy</a> — Three suppression levels and the <code>--audit</code> override</li>
<li class=""><a class="" href="https://zenzic.dev/docs/reference/finding-codes">Finding Codes</a> — Full Zxxx code encyclopedia with remediation steps</li>
</ul>]]></content:encoded>
            <category>Engineering Logs</category>
            <category>Governance</category>
        </item>
        <item>
            <title><![CDATA[Release v0.8.0: Governance Baseline]]></title>
            <link>https://zenzic.dev/blog/log-v080</link>
            <guid>https://zenzic.dev/blog/log-v080</guid>
            <pubDate>Sun, 24 May 2026 10:00:00 GMT</pubDate>
            <description><![CDATA[Historical release baseline for v0.8.0. This entry keeps only the governance-scope commitments frozen at release time.]]></description>
            <content:encoded><![CDATA[
<!-- -->
<p>This page is the historical baseline for the v0.8.0 line.
It intentionally preserves only the scope that was frozen for that milestone.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="baseline-scope-v080">Baseline Scope (v0.8.0)<a href="https://zenzic.dev/blog/log-v080#baseline-scope-v080" class="hash-link" aria-label="Direct link to Baseline Scope (v0.8.0)" title="Direct link to Baseline Scope (v0.8.0)" translate="no">​</a></h2>
<p>The v0.8.0 baseline records the governance foundation used as bridge toward the
next release line:</p>
<ul>
<li class="">strict-vs-score governance boundaries formalized for CI usage;</li>
<li class="">sovereign audit usage documented as maintainers' inspection path;</li>
<li class="">namespace stability contract documented for integration tooling;</li>
<li class="">deterministic runtime constraints and security posture documentation hardened.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="historical-note">Historical Note<a href="https://zenzic.dev/blog/log-v080#historical-note" class="hash-link" aria-label="Direct link to Historical Note" title="Direct link to Historical Note" translate="no">​</a></h2>
<p>Post-freeze work discovered during the epoch shift is intentionally excluded from
this historical page and tracked in the v0.9.0 manifesto.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="compatibility-snapshot">Compatibility Snapshot<a href="https://zenzic.dev/blog/log-v080#compatibility-snapshot" class="hash-link" aria-label="Direct link to Compatibility Snapshot" title="Direct link to Compatibility Snapshot" translate="no">​</a></h2>
<p>v0.8.0 remains a stable historical reference for contributors auditing legacy
repository states and migration decisions.</p>]]></content:encoded>
            <category>Release</category>
            <category>Milestone Record</category>
            <category>Engineering Logs</category>
        </item>
        <item>
            <title><![CDATA[Engineering Deep Dive: v0.8.0 Architecture]]></title>
            <link>https://zenzic.dev/blog/engineering-v080-deep-dive</link>
            <guid>https://zenzic.dev/blog/engineering-v080-deep-dive</guid>
            <pubDate>Sun, 24 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A long-form engineering deep dive into Zenzic v0.8.0: context fragmentation, modular context, VSM reverse mapping, RE2 hardening, and sovereign CI parity.
]]></description>
            <content:encoded><![CDATA[<p>Zenzic emerged as a systems response to a recurring pattern across code reviews and CI incidents: documentation quality pipelines were improving locally but degrading structurally over time. The pipeline was shipping checks, not guarantees — collecting signals, not preserving architecture.</p>
<!-- -->
<p>This deep dive is for software architects and technical stakeholders who want to understand why architecture matters below the changelog line. The central claim of Zenzic is straightforward: zero-config should not mean zero-governance. It should mean deterministic defaults, explicit contracts, and interfaces that remain machine-readable under pressure.</p>
<p>The architecture came from five converging fronts: context fragmentation in complex repositories, dynamic-route ambiguity in static analysis, regex safety risk under adversarial inputs, deployment parity drift between local and CI, and governance blind spots that traditional SSG checks never model.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-the-fragmentation-problem-when-context-stops-scaling">1) The Fragmentation Problem: When Context Stops Scaling<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#1-the-fragmentation-problem-when-context-stops-scaling" class="hash-link" aria-label="Direct link to 1) The Fragmentation Problem: When Context Stops Scaling" title="Direct link to 1) The Fragmentation Problem: When Context Stops Scaling" translate="no">​</a></h2>
<p>The initial symptom looked small: architectural decisions became less reliable during long-lived maintenance sessions. As the instruction corpus and policy body grew, operational consistency dropped. Contributors would correctly apply one rule while violating another that had already been established in the same architectural cycle.</p>
<p>At first glance, this looked like a documentation quality issue. It was not. It was an information scalability issue.</p>
<p>The internal project specification corpus had grown into a dense operational memory: naming rules, historical exceptions, governance gates, invariants, release constraints, and adapter-level contracts. Human readers can often navigate this through intent and pattern recognition. Automation systems cannot guarantee stable retrieval under long, mixed-priority context.</p>
<p>The result was a class of subtle regressions:</p>
<ul>
<li class="">Correct syntax, wrong contract tier.</li>
<li class="">Correct code, stale policy semantics.</li>
<li class="">Correct diagnostics, incomplete provenance.</li>
</ul>
<p>This forced a design decision. Instead of pushing more monolithic text into workflows, context was split into deterministic artifacts that can be requested on demand.</p>
<p>That decision had two outputs:</p>
<ul>
<li class=""><strong>Independent structural context tooling</strong>, for repository cartography.</li>
<li class=""><strong>Zenzic JSON surfaces</strong>, as machine-facing truth exports for routes and codes.</li>
</ul>
<p>In practice, this changes the operating model from "read everything, hope for retention" to "request only the contract you need, exactly when needed."</p>
<p>For deterministic automation workflows, this is decisive. Systems no longer parse long prose to infer architecture. They query canonical interfaces.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="15-shift-left-metrics-you-can-verify-yourself">1.5) Shift-Left Metrics You Can Verify Yourself<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#15-shift-left-metrics-you-can-verify-yourself" class="hash-link" aria-label="Direct link to 1.5) Shift-Left Metrics You Can Verify Yourself" title="Direct link to 1.5) Shift-Left Metrics You Can Verify Yourself" translate="no">​</a></h2>
<p>Performance claims are only useful if readers can reproduce them.</p>
<p>To verify Zenzic timing on your hardware, run the same checks locally and read the footer that Zenzic prints natively at the end of each run. The footer includes both elapsed duration and throughput.</p>
<p>Example footer:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">standalone • 20 files (14 docs, 6 assets) • 0.8s • 38 files/s</span><br></div></code></pre></div></div>
<p>Recommended sequence:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic check references docs/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic check links docs/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic check all docs/</span><br></div></code></pre></div></div>
<p>For each run, record:</p>
<ul>
<li class="">elapsed duration (<code>0.8s</code> field),</li>
<li class="">throughput (<code>38 files/s</code> field),</li>
<li class="">scanned file scope (file count and mode).</li>
</ul>
<p>This provides a hardware-specific baseline without synthetic benchmarking.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-virtual-site-map-and-reverse-mapping-solving-dynamic-routes-without-running-nodejs">2) Virtual Site Map and Reverse Mapping: Solving Dynamic Routes Without Running Node.js<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#2-virtual-site-map-and-reverse-mapping-solving-dynamic-routes-without-running-nodejs" class="hash-link" aria-label="Direct link to 2) Virtual Site Map and Reverse Mapping: Solving Dynamic Routes Without Running Node.js" title="Direct link to 2) Virtual Site Map and Reverse Mapping: Solving Dynamic Routes Without Running Node.js" translate="no">​</a></h2>
<p>Dynamic routes are where traditional static linters lose clarity.</p>
<p>In Docusaurus, a route like <code>/blog/tags/python/</code> may not correspond to a physical Markdown file. It is generated from frontmatter metadata spread across multiple source files. Likewise for paginated indexes and author pages. A filesystem-only linter sees no file, concludes "broken link," and emits false positives.</p>
<p>Build engines can resolve this because they execute generation logic. But that happens late, is expensive, and does not produce source-level diagnostics suited to pre-commit loops.</p>
<p>Zenzic resolves this using the <strong>Virtual Site Map (VSM)</strong> with reverse mapping invariants.</p>
<p>At a high level:</p>
<ol>
<li class="">Parse source Markdown and adapter metadata.</li>
<li class="">Build canonical route entries, including generated virtual routes.</li>
<li class="">Require each virtual route to carry non-empty <code>source_files</code> provenance.</li>
<li class="">Reject route records that cannot be traced to physical origin.</li>
</ol>
<p>This is not heuristic URL guessing. It is a contract.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Simplified idea of the invariant</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(248, 248, 242)">@dataclass</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">frozen</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">class</span><span class="token plain"> </span><span class="token class-name">VirtualRoute</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    url</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    source_files</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">frozenset</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">__post_init__</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">not</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">source_files</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">raise</span><span class="token plain"> ValueError</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"virtual route without provenance is invalid"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></div></code></pre></div></div>
<p>The pay-off is diagnostic quality. When a generated route fails, Zenzic can point to concrete source origins and frontmatter context instead of returning generic route-not-found output.</p>
<p>Example machine output:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic inspect routes </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--json</span><br></div></code></pre></div></div>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"route"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"/blog/tags/python/"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"kind"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"tag"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"status"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"virtual"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"source_files"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"blog/2026-05-01-v080-roadmap.mdx"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"blog/2026-05-07-quartz-retrospective.mdx"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"frontmatter_keys"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"tags"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"slug"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"authors"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div>
<p>Now the error loop becomes actionable:</p>
<ul>
<li class="">you know the failing route,</li>
<li class="">you know which files generate it,</li>
<li class="">you know which frontmatter fields drive generation.</li>
</ul>
<p>No Node.js execution is required to get this answer. That is the mathematical core of the Zenzic route model.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-security-and-redos-the-incident-avoided-by-design">3) Security and ReDoS: The Incident Avoided by Design<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#3-security-and-redos-the-incident-avoided-by-design" class="hash-link" aria-label="Direct link to 3) Security and ReDoS: The Incident Avoided by Design" title="Direct link to 3) Security and ReDoS: The Incident Avoided by Design" translate="no">​</a></h2>
<p>Every documentation scanner eventually faces regex complexity risk. The usual implementation path is Python's standard <code>re</code> module. It is convenient, familiar, and dangerous under adversarial patterns because catastrophic backtracking can explode runtime.</p>
<p>In a benign repository this may look harmless. In CI at scale, under untrusted or malformed content, this becomes a denial-of-service vector.</p>
<p>The architectural response treated this as a systems boundary problem, not a style refactor.</p>
<p>The Zenzic solution is an <strong>Anti-Corruption Layer (Facade)</strong> around regex operations. Contributors keep a simple internal API. The runtime backend is enforced to use RE2 semantics for linear-time matching where policy requires determinism.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># simplified facade pattern</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> zenzic</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">core </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> regex</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">contains_secret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">line</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">bool</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)"># contributor-facing API stays stable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> regex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">search</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">SECRET_PATTERN</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> line</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">is</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">not</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># inside the facade implementation</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># - compile through google-re2 backend</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># - reject unsupported constructs at load time</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># - expose a compatible API surface for callers</span><br></div></code></pre></div></div>
<p>This design gives us three guarantees at once:</p>
<ul>
<li class=""><strong>Complexity bound:</strong> matching remains predictable, avoiding catastrophic backtracking classes.</li>
<li class=""><strong>Policy enforcement:</strong> unsafe or unsupported patterns fail early at load/validation boundaries.</li>
<li class=""><strong>DX continuity:</strong> contributors use one internal import path, not backend-specific code scattered across modules.</li>
</ul>
<p>In architectural terms, the facade prevents dependency leakage. The domain model talks to a local contract; backend details stay behind the boundary. That is why security semantics can be hardened without destabilizing contributor workflows.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-four-gates-in-cicd-security-as-a-supply-chain-not-a-single-check">4) Four Gates in CI/CD: Security as a Supply Chain, Not a Single Check<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#4-four-gates-in-cicd-security-as-a-supply-chain-not-a-single-check" class="hash-link" aria-label="Direct link to 4) Four Gates in CI/CD: Security as a Supply Chain, Not a Single Check" title="Direct link to 4) Four Gates in CI/CD: Security as a Supply Chain, Not a Single Check" translate="no">​</a></h2>
<p>Many teams still treat documentation quality as a final build concern. Zenzic models it as a layered gate system where each stage narrows risk before it becomes expensive.</p>
<p>The gate model has four levels:</p>
<ol>
<li class=""><strong>IDE Gate</strong></li>
<li class=""><strong>Pre-Commit Gate</strong></li>
<li class=""><strong>Pre-Push Gate</strong></li>
<li class=""><strong>GitHub Actions Gate</strong></li>
</ol>
<p>The purpose is not duplication. The purpose is risk distribution.</p>
<ul>
<li class="">The IDE catches immediate authoring drift.</li>
<li class="">Pre-commit blocks local bad states before history contamination.</li>
<li class="">Pre-push enforces integration-level checks before remote divergence.</li>
<li class="">GitHub Actions provides reproducible, shared enforcement at repository boundary.</li>
</ul>
<p>The implementation hinge is the <code>justfile</code>. It is not a convenience wrapper; it is the parity contract.</p>
<div class="language-make codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-make codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain"># concept sketch</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">verify:</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    uvx pre-commit run --all-files</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    uvx nox -s tests</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    uvx nox -s verify-codes-parity</span><br></div></code></pre></div></div>
<p>When local and remote run the same orchestration surfaces, policy drift shrinks. This is <strong>Sovereign Parity</strong>: the same rules, same tooling strata, same exit semantics, regardless of execution location.</p>
<p>That matters for governance and auditability. A failed gate must mean the same thing everywhere, or the gate is procedural theater.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-namespace-contract-why-tier-boundaries-changed-the-system">5) The Namespace Contract: Why Tier Boundaries Changed the System<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#5-the-namespace-contract-why-tier-boundaries-changed-the-system" class="hash-link" aria-label="Direct link to 5) The Namespace Contract: Why Tier Boundaries Changed the System" title="Direct link to 5) The Namespace Contract: Why Tier Boundaries Changed the System" translate="no">​</a></h2>
<p>Before Zenzic, code families existed but ownership semantics were still easy to blur in real contribution flows. A policy rule could be discussed like a core invariant. A plugin rule could be treated like a frozen security guardrail.</p>
<p>The namespace contract was formalized to prevent that bleed.</p>
<ul>
<li class=""><strong>Core</strong>: engine invariants.</li>
<li class=""><strong>Governance</strong>: project policy and lifecycle rules.</li>
<li class=""><strong>Plugin</strong>: third-party extension surfaces.</li>
<li class=""><strong>Custom</strong>: local project constraints.</li>
</ul>
<p>This matters because suppression semantics and enforcement expectations are tier-dependent by design. Zenzic additionally formalizes immutable surfaces such as <code>FROZEN_CODES</code>, <code>NON_SUPPRESSIBLE_CODES</code>, and <code>PLUGIN_FORBIDDEN_EXITS</code> so that security findings cannot be casually reclassified into optional style noise.</p>
<p>Security findings are not suggestions. They are enforcement events.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="55-adapter-refactoring-from-protocol-flexibility-to-abc-contracts">5.5) Adapter Refactoring: From Protocol Flexibility to ABC Contracts<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#55-adapter-refactoring-from-protocol-flexibility-to-abc-contracts" class="hash-link" aria-label="Direct link to 5.5) Adapter Refactoring: From Protocol Flexibility to ABC Contracts" title="Direct link to 5.5) Adapter Refactoring: From Protocol Flexibility to ABC Contracts" translate="no">​</a></h2>
<p>v0.8.0 changed the adapter layer from permissive structural typing to explicit runtime contracts.</p>
<p>In the v0.7 line, adapter compliance relied on a <code>Protocol</code> surface plus runtime duck-typing checks. That model was flexible but late-failing: missing capabilities could escape until scan or validation paths were already running.</p>
<p>In v0.8, the contract is a concrete <code>BaseAdapter</code> Abstract Base Class with required abstract methods and factory-level subclass enforcement. Invalid adapter implementations now fail at instantiation time, not in mid-pipeline execution.</p>
<table><thead><tr><th style="text-align:left">Dimension</th><th style="text-align:left">v0.7 Behavior</th><th style="text-align:left">v0.8 Current Behavior</th></tr></thead><tbody><tr><td style="text-align:left">Contract type</td><td style="text-align:left">Structural <code>Protocol</code> + duck typing</td><td style="text-align:left">Nominal <code>ABC</code> (<code>BaseAdapter</code>)</td></tr><tr><td style="text-align:left">Capability checks</td><td style="text-align:left">Mixed optional probing</td><td style="text-align:left">Mandatory abstract methods</td></tr><tr><td style="text-align:left">Failure point</td><td style="text-align:left">Late (scan/validate path)</td><td style="text-align:left">Early (factory construction)</td></tr><tr><td style="text-align:left">Core coupling</td><td style="text-align:left">Scanner-side engine probes</td><td style="text-align:left">IoC-injected callbacks and roots</td></tr></tbody></table>
<p>This refactor also applies Inversion of Control to the scanner boundary. The Core scanner no longer discovers engine details internally. Adapter context is resolved once by orchestration and injected as explicit callbacks and content roots, keeping the scanner engine-agnostic.</p>
<p>Logical flow:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">BuildContext + repo_root</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  -&gt; get_adapter(...)</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  -&gt; inject adapter callbacks + discovered roots</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  -&gt; scanner/validator execute without engine discovery logic</span><br></div></code></pre></div></div>
<p>MkDocs coverage was upgraded in the same cycle: multi-root discovery is now native in <code>MkDocsAdapter</code>, including recursive monorepo include traversal. Additional roots are mounted into the same VSM and reference-validation perimeter, so external docs trees no longer require manual wiring.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-eradicating-inline-noise-directory-policies">6) Eradicating Inline Noise: Directory Policies<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#6-eradicating-inline-noise-directory-policies" class="hash-link" aria-label="Direct link to 6) Eradicating Inline Noise: Directory Policies" title="Direct link to 6) Eradicating Inline Noise: Directory Policies" translate="no">​</a></h2>
<p>Every governance system eventually encounters a legitimate exemption problem. Brand-term checks are essential for catching stale references in active documentation. But release blogs are historical artifacts. Enforcing <code>Z601</code> (obsolete brand term) against a blog post that intentionally names the old release identifier is not quality enforcement — it is false positive noise.</p>
<p>Before <code>directory_policies</code>, the only escape was an inline suppression comment scattered across every affected line:</p>
<div class="language-mdx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-mdx codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">&lt;!-- zenzic:ignore: Z601 historical release --&gt;</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">Quartz was the internal code name for v0.6.0.</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">&lt;!-- zenzic:ignore: Z601 historical release --&gt;</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">The Obsidian milestone closed the legacy adapter contract.</span><br></div></code></pre></div></div>
<p>This approach accumulates debt. Inline suppressions count against the <code>suppression_cap</code>. Each file that writes its own inline escapes consumes one audit slot. At <code>suppression_cap = 10</code>, a fleet with many historical blog posts can exhaust the cap through legitimate exemptions, leaving no headroom for actual suppression abuse.</p>
<p>The structural fix introduced in v0.8.0 is <code>directory_policies</code>: a governance-level TOML contract that grants zero-debt exemptions to named path patterns.</p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">.zenzic.toml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">governance</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">suppression_cap</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token number">10</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">suppression_cap_fail_hard</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">governance.directory_policies</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">"blog/**"</span><span class="token plain">                         </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Z601"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># historical release posts: brand terms are intentional</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">"explanation/mineral-path.mdx"</span><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Z601"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># SSOT codename registry (EN)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">"it/explanation/mineral-path.mdx"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Z601"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># SSOT codename registry (IT)</span><br></div></code></pre></div></div>
<p>With this configuration in place, the blog posts become clean:</p>
<div class="language-mdx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-mdx codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">Quartz was the internal code name for v0.6.0.</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">The Obsidian milestone closed the legacy adapter contract.</span><br></div></code></pre></div></div>
<p>No inline tags. No suppression comments. No debt. The policy exemption is declared once at the governance contract level, not repeated across every affected line.</p>
<p>When Zenzic applies a policy exemption during a standard scan, findings in those paths are dropped silently; the <code>[POLICY_EXEMPTION]</code> label is emitted only in <code>--audit</code> mode, giving reviewers a complete, centralized record of what was exempted and under which pattern. This preserves auditability without hiding the signal.</p>
<p>The hierarchy that emerges is deliberate:</p>
<ol>
<li class=""><strong>Non-suppressible codes</strong> (<code>NON_SUPPRESSIBLE_CODES</code>) — security findings that cannot be overridden by any mechanism.</li>
<li class=""><strong>Directory policies</strong> — governance-level zero-debt exemptions declared in <code>.zenzic.toml</code>.</li>
<li class=""><strong>Inline suppressions</strong> — per-line escape hatches, counted against the cap and logged.</li>
</ol>
<p>Zero-debt means the suppression cap is preserved for genuine edge cases, and the governance contract remains the authoritative source of intent.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-is-a-zero-config-ecosystem-not-a-zero-policy-tool">Why This Is a Zero-Config Ecosystem, Not a Zero-Policy Tool<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#why-this-is-a-zero-config-ecosystem-not-a-zero-policy-tool" class="hash-link" aria-label="Direct link to Why This Is a Zero-Config Ecosystem, Not a Zero-Policy Tool" title="Direct link to Why This Is a Zero-Config Ecosystem, Not a Zero-Policy Tool" translate="no">​</a></h2>
<p>Zero-config often gets misread as "minimal architecture." In Zenzic, zero-config means deterministic defaults with explicit contracts that remain inspectable.</p>
<p>That is why JSON inspection surfaces and tiered code contracts are first-class in the current architecture:</p>
<ul>
<li class="">They reduce ambiguity for humans.</li>
<li class="">They reduce context burden for automation.</li>
<li class="">They stabilize governance across contributors, integrations, and CI.</li>
</ul>
<p>From an architectural perspective, Zenzic is less about adding checks and more about reducing interpretive entropy.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="closing-perspective">Closing Perspective<a href="https://zenzic.dev/blog/engineering-v080-deep-dive#closing-perspective" class="hash-link" aria-label="Direct link to Closing Perspective" title="Direct link to Closing Perspective" translate="no">​</a></h2>
<p>The old mental model said: "if the site builds, documentation quality is acceptable."</p>
<p>Zenzic rejects that model.</p>
<p>A successful build can still hide leaked credentials, governance drift, unresolved virtual-route provenance, and policy regressions invisible to render pipelines. Build engines remain essential. They are just not sufficient as documentation integrity systems.</p>
<p>The system proves a different path:</p>
<ul>
<li class="">deterministic source-first analysis,</li>
<li class="">machine-consumable architectural truth,</li>
<li class="">linear-time security boundaries,</li>
<li class="">and sovereign parity from local workstation to remote CI.</li>
</ul>
<p>That is what a zero-config ecosystem looks like when engineering contracts are treated as public infrastructure, not internal folklore.</p>]]></content:encoded>
            <category>Engineering Logs</category>
            <category>Architecture</category>
            <category>Release</category>
        </item>
        <item>
            <title><![CDATA[The Namespace Contract]]></title>
            <link>https://zenzic.dev/blog/v080-namespace-contract</link>
            <guid>https://zenzic.dev/blog/v080-namespace-contract</guid>
            <pubDate>Sun, 24 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[v0.8.0 formalizes the namespace contract, tiered code governance, and deterministic diagnostics for virtual routes.
]]></description>
            <content:encoded><![CDATA[<p>The system is built on a contract: explicit tier boundaries, frozen security guarantees,
and a machine-consumable route surface for external tools.</p>
<!-- -->
<p>Italian version available in the Italian locale mirror of this article.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="source-integrity-before-build-integrity">Source Integrity Before Build Integrity<a href="https://zenzic.dev/blog/v080-namespace-contract#source-integrity-before-build-integrity" class="hash-link" aria-label="Direct link to Source Integrity Before Build Integrity" title="Direct link to Source Integrity Before Build Integrity" translate="no">​</a></h2>
<p>Build engines and static analyzers solve different phases of the problem:</p>
<ul>
<li class="">Build engines validate renderability after full site compilation.</li>
<li class="">Zenzic validates source integrity before compilation.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="four-hard-facts">Four hard facts<a href="https://zenzic.dev/blog/v080-namespace-contract#four-hard-facts" class="hash-link" aria-label="Direct link to Four hard facts" title="Direct link to Four hard facts" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">Topic</th><th style="text-align:left">Typical SSG Build Flow</th><th style="text-align:left">Zenzic</th></tr></thead><tbody><tr><td style="text-align:left">Shift-Left and speed</td><td style="text-align:left">Full compile loop (Node.js/Go/Python stack), usually CI-bound and minute-scale feedback.</td><td style="text-align:left">Pre-commit local analysis on source text and metadata, millisecond-scale feedback for targeted checks.</td></tr><tr><td style="text-align:left">Security</td><td style="text-align:left">A build can succeed while secrets remain committed in source files.</td><td style="text-align:left">Security Core enforces security-tier findings (<code>Z2xx</code>) and stops the pipeline on security exits.</td></tr><tr><td style="text-align:left">Governance</td><td style="text-align:left">No native concept of brand obsolescence or translation parity drift.</td><td style="text-align:left">Governance codes enforce policy explicitly (<code>Z601</code> brand obsolescence, <code>Z602</code> i18n parity).</td></tr><tr><td style="text-align:left">Actionable diagnostics</td><td style="text-align:left">Generated-route failures often surface as generic 404/build errors.</td><td style="text-align:left">VSM reverse mapping links the failing virtual route to concrete source files/frontmatter context.</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="execution-time-characteristics-architectural">Execution-time characteristics (architectural)<a href="https://zenzic.dev/blog/v080-namespace-contract#execution-time-characteristics-architectural" class="hash-link" aria-label="Direct link to Execution-time characteristics (architectural)" title="Direct link to Execution-time characteristics (architectural)" translate="no">​</a></h3>
<p>Zenzic's analysis complexity is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>N</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="mclose">)</span></span></span></span> in the number of files and links scanned.
All pattern matching runs on the RE2 DFA engine, which guarantees linear time and
is immune to catastrophic backtracking (ReDoS). There is no Node.js build-pipeline
startup overhead for this pre-build analysis, but Python runtime dependencies must
be installed (including RE2 bindings) and execution runs in the current Python process.</p>
<p>The phase difference relative to a full SSG build (which compiles, bundles, and
emits routes) does not vary by environment — Zenzic always runs before the build
engine is available.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-namespace-contract">The Namespace Contract<a href="https://zenzic.dev/blog/v080-namespace-contract#the-namespace-contract" class="hash-link" aria-label="Direct link to The Namespace Contract" title="Direct link to The Namespace Contract" translate="no">​</a></h2>
<p>Zenzic introduces an explicit tier model for findings and ownership.</p>
<table><thead><tr><th style="text-align:left">Tier</th><th style="text-align:left">Ownership</th><th style="text-align:left">Purpose</th></tr></thead><tbody><tr><td style="text-align:left">Core</td><td style="text-align:left">Engine invariants</td><td style="text-align:left">Structural and safety-critical contracts required by the core runtime.</td></tr><tr><td style="text-align:left">Governance</td><td style="text-align:left">Project policy</td><td style="text-align:left">Cross-repository quality contracts such as naming, parity, and lifecycle policy.</td></tr><tr><td style="text-align:left">Plugin</td><td style="text-align:left">Extension packages</td><td style="text-align:left">Third-party rule surfaces loaded via plugin entry points.</td></tr><tr><td style="text-align:left">Custom</td><td style="text-align:left">Local rules</td><td style="text-align:left">Team-specific constraints declared in project configuration.</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-frozen-codes-exist">Why frozen codes exist<a href="https://zenzic.dev/blog/v080-namespace-contract#why-frozen-codes-exist" class="hash-link" aria-label="Direct link to Why frozen codes exist" title="Direct link to Why frozen codes exist" translate="no">​</a></h3>
<p>Security is not a style preference. It is a non-negotiable contract.</p>
<p>Zenzic formalizes frozen security semantics through immutable code surfaces such as:</p>
<ul>
<li class=""><code>FROZEN_CODES</code></li>
<li class=""><code>NON_SUPPRESSIBLE_CODES</code></li>
<li class=""><code>PLUGIN_FORBIDDEN_EXITS</code></li>
</ul>
<p>The practical implication is simple:</p>
<ul>
<li class="">Security findings like <code>Z201</code> or <code>Z204</code> are not optional suggestions.</li>
<li class="">They cannot be downgraded into decorative warnings by local convenience flags.</li>
<li class="">CI and local gates converge on the same enforcement semantics.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="open-ecosystem-json-api-integration">Open Ecosystem: JSON API Integration<a href="https://zenzic.dev/blog/v080-namespace-contract#open-ecosystem-json-api-integration" class="hash-link" aria-label="Direct link to Open Ecosystem: JSON API Integration" title="Direct link to Open Ecosystem: JSON API Integration" translate="no">​</a></h2>
<p>Zenzic exposes route truth as a machine interface:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">zenzic inspect routes </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--json</span><br></div></code></pre></div></div>
<p>This output is not presentation text. It is deterministic route metadata for automation.</p>
<p>External tools can consume this JSON directly:</p>
<ul>
<li class="">Independent structural analysis systems.</li>
<li class="">Automation tools that need architectural context.</li>
<li class="">CI orchestrators that require stable, typed diagnostics.</li>
</ul>
<p>This removes fragile text scraping from the workflow. Tools consume contracts, not prose.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bottom-line">Bottom line<a href="https://zenzic.dev/blog/v080-namespace-contract#bottom-line" class="hash-link" aria-label="Direct link to Bottom line" title="Direct link to Bottom line" translate="no">​</a></h2>
<p>The system closes a long-standing gap in documentation QA:</p>
<ul>
<li class="">Build validity is no longer mistaken for source integrity.</li>
<li class="">Security is enforced as contract, not convention.</li>
<li class="">Governance is explicit and testable.</li>
<li class="">Virtual-route failures are traced to physical origin, not buried in generic 404 output.</li>
</ul>
<p>That is the end of the SSG illusion.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="publication-decree-sovereign-transition">Publication Decree: Sovereign Transition<a href="https://zenzic.dev/blog/v080-namespace-contract#publication-decree-sovereign-transition" class="hash-link" aria-label="Direct link to Publication Decree: Sovereign Transition" title="Direct link to Publication Decree: Sovereign Transition" translate="no">​</a></h2>
<p>The Sovereign Transition is now formally declared as:</p>
<blockquote>
<p>"The Sovereign Transition. Introducing Suppression CAP, Local Sanctuary, and Avion-Grade Governance."</p>
</blockquote>
<p>The system is operational as fleet standard. The initial rollout dashboard can now be archived,
and repository tagging proceeds under the new protocol.</p>]]></content:encoded>
            <category>Engineering Logs</category>
            <category>Release</category>
        </item>
        <item>
            <title><![CDATA[Tutorial: Get Started with Zenzic]]></title>
            <link>https://zenzic.dev/blog/tutorial-stop-broken-links-60s</link>
            <guid>https://zenzic.dev/blog/tutorial-stop-broken-links-60s</guid>
            <pubDate>Wed, 29 Apr 2026 19:00:00 GMT</pubDate>
            <description><![CDATA[Install Zenzic, run your first audit, and protect your documentation pipeline in under 60 seconds. No setup, no configuration, no build required.
]]></description>
            <content:encoded><![CDATA[<p>Your docs have broken links. You just haven't found them yet.</p>
<p><strong>Zenzic finds them before your readers do</strong> — before you build, before you deploy,
before it's too late.</p>
<!-- -->
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1--launch">Step 1 — Launch<a href="https://zenzic.dev/blog/tutorial-stop-broken-links-60s#step-1--launch" class="hash-link" aria-label="Direct link to Step 1 — Launch" title="Direct link to Step 1 — Launch" translate="no">​</a></h2>
<p>No install. No virtual environment. One command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">Terminal</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">uvx zenzic check all ./docs</span><br></div></code></pre></div></div>
<p>No browser, no build engine, no heavy framework — a single Python tool cached on
first run and ready in seconds from then on.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2--read-the-report">Step 2 — Read the Report<a href="https://zenzic.dev/blog/tutorial-stop-broken-links-60s#step-2--read-the-report" class="hash-link" aria-label="Direct link to Step 2 — Read the Report" title="Direct link to Step 2 — Read the Report" translate="no">​</a></h2>
<p>You'll see one of two results:</p>
<p><strong>All clear:</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">✨ Sentinel Seal: All checks passed. Your documentation is clean.</span><br></div></code></pre></div></div>
<p><strong>Issues found:</strong></p>
<div class="zz-terminal-monolith bg-zinc-900/20 backdrop-blur-md border border-zinc-800/60 rounded-xl overflow-hidden font-mono text-[12px] leading-relaxed"><div class="flex items-center gap-2 px-4 py-2 border-b border-zinc-800/40 bg-zinc-900/30"><span class="h-2.5 w-2.5 rounded-full bg-rose-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-amber-500/80"></span><span class="h-2.5 w-2.5 rounded-full bg-emerald-500/80"></span><span class="ml-2 text-zinc-500 text-[11px] tracking-wide">zenzic check all</span></div><div class="px-5 py-4 text-zinc-300 whitespace-pre-wrap break-words"><div class="flex gap-2 items-baseline mb-1"><span class="text-rose-500">✘</span><span class="bg-rose-500/10 text-rose-400 px-1 rounded-sm text-[11px]">[Z101]</span><span class="text-zinc-300">docs/guide.md:42 — Broken link → ./missing-page.md</span></div><div class="flex gap-2 items-baseline mb-1"><span class="text-amber-500">⚠</span><span class="bg-amber-500/10 text-amber-400 px-1 rounded-sm text-[11px]">[Z402]</span><span class="text-zinc-300">docs/old-api.md — Orphan page, not in navigation</span></div><div class="flex gap-2 items-baseline"><span class="text-rose-500">✘</span><span class="bg-rose-500/10 text-rose-400 px-1 rounded-sm text-[11px]">[Z201]</span><span class="text-zinc-300">docs/config.md:7 — Credential pattern detected</span></div><div class="mt-2 text-rose-500 font-semibold text-[11px] tracking-wide">FAILED — exit 1</div></div></div>
<p>Each finding carries a <code>Zxxx</code> code, a file path, a line number, and a clear description.
Fix what's flagged, re-run, and ship with confidence.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3--protect-your-ci">Step 3 — Protect Your CI<a href="https://zenzic.dev/blog/tutorial-stop-broken-links-60s#step-3--protect-your-ci" class="hash-link" aria-label="Direct link to Step 3 — Protect Your CI" title="Direct link to Step 3 — Protect Your CI" translate="no">​</a></h2>
<p>One line in your GitHub Actions workflow:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">.github/workflows/zenzic.yml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Audit documentation</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> uvx zenzic check all ./docs</span><br></div></code></pre></div></div>
<p>Every pull request is now guarded. Broken links, orphan pages, and leaked credentials
are caught before they reach <code>main</code>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-zenzic">Why Zenzic<a href="https://zenzic.dev/blog/tutorial-stop-broken-links-60s#why-zenzic" class="hash-link" aria-label="Direct link to Why Zenzic" title="Direct link to Why Zenzic" translate="no">​</a></h2>
<ul>
<li class="">
<p><strong>Fast</strong> — Zenzic is fast because it's lightweight. No build step, no Node.js,</p>
<p>no browser launch. Analysis happens directly on your Markdown source files.</p>
</li>
<li class="">
<p><strong>Safe</strong> — Zenzic is secure because it doesn't touch your system files.</p>
<p>Read-only analysis, always. Your repository is observed, never modified.</p>
</li>
<li class="">
<p><strong>Universal</strong> — Works with MkDocs, Docusaurus, Zensical, or any plain Markdown folder.</p>
<p>Point it at your <code>docs/</code> directory and it figures out the rest.</p>
</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="go-further">Go Further<a href="https://zenzic.dev/blog/tutorial-stop-broken-links-60s#go-further" class="hash-link" aria-label="Direct link to Go Further" title="Direct link to Go Further" translate="no">​</a></h2>
<table><thead><tr><th>Command</th><th>What it does</th></tr></thead><tbody><tr><td><code>uvx zenzic check all</code></td><td>Full audit: links, orphans, credentials, snippets</td></tr><tr><td><code>uvx zenzic check links</code></td><td>Link integrity only</td></tr><tr><td><code>uvx zenzic score</code></td><td>Quality score with trend tracking</td></tr><tr><td><code>uvx zenzic check all --format sarif</code></td><td>SARIF output for GitHub Code Scanning</td></tr></tbody></table>
<p>Pin a specific version for reproducible CI:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_OeMC">Terminal</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">uvx </span><span class="token string" style="color:rgb(255, 121, 198)">"zenzic==0.7.0"</span><span class="token plain"> check all ./docs</span><br></div></code></pre></div></div>]]></content:encoded>
            <category>Tutorial</category>
            <category>Quickstart</category>
            <category>Python</category>
            <category>Open Source</category>
            <category>DevTools</category>
            <category>User Tutorials</category>
        </item>
        <item>
            <title><![CDATA[Welcome to The Zenzic Blog]]></title>
            <link>https://zenzic.dev/blog/welcome</link>
            <guid>https://zenzic.dev/blog/welcome</guid>
            <pubDate>Tue, 28 Apr 2026 09:00:00 GMT</pubDate>
            <description><![CDATA[Purpose, content model, and usage guide for the Zenzic blog.]]></description>
            <content:encoded><![CDATA[
<!-- -->
<p>This page defines what the Zenzic blog is for, what is published here, and how to use the content in daily documentation workflows.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="purpose">Purpose<a href="https://zenzic.dev/blog/welcome#purpose" class="hash-link" aria-label="Direct link to Purpose" title="Direct link to Purpose" translate="no">​</a></h2>
<p>The blog documents how to prevent documentation regressions before merge. The focus is operational:</p>
<ul>
<li class="">reduce production 404 risk from broken internal links,</li>
<li class="">prevent credential leakage in public repositories,</li>
<li class="">keep documentation quality gates deterministic in CI/CD.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="contents">Contents<a href="https://zenzic.dev/blog/welcome#contents" class="hash-link" aria-label="Direct link to Contents" title="Direct link to Contents" translate="no">​</a></h2>
<p>Posts are grouped into practical categories:</p>
<ul>
<li class=""><strong>Tutorials</strong>: step-by-step setup and first audit flows.</li>
<li class=""><strong>Engineering</strong>: implementation details that affect integration behavior.</li>
<li class=""><strong>Security</strong>: credential findings and remediation workflows.</li>
<li class=""><strong>Governance</strong>: CI/CD policy patterns and suppression management.</li>
</ul>
<p>Each article is expected to answer one concrete question and provide commands or configuration that can be applied immediately.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="usage">Usage<a href="https://zenzic.dev/blog/welcome#usage" class="hash-link" aria-label="Direct link to Usage" title="Direct link to Usage" translate="no">​</a></h2>
<p>Use this order if you are new:</p>
<ol>
<li class="">Start with <a class="" href="https://zenzic.dev/blog/tutorial-stop-broken-links-60s">Tutorial: Get Started</a>.</li>
<li class="">Apply the command to your repository.</li>
<li class="">Use tags in the sidebar to filter by problem type (security, governance, tutorials).</li>
<li class="">Subscribe to feeds for incremental updates:</li>
</ol>
<ul>
<li class="">RSS: <a href="https://zenzic.dev/blog/rss.xml" data-nobrokenlinkcheck="true">/blog/rss.xml</a></li>
<li class="">Atom: <a href="https://zenzic.dev/blog/atom.xml" data-nobrokenlinkcheck="true">/blog/atom.xml</a></li>
</ul>
<p>If you need clarification on a workflow, use <a href="https://github.com/PythonWoods/zenzic/discussions" target="_blank" rel="noopener noreferrer" class="">GitHub Discussions</a>.</p>]]></content:encoded>
            <category>Community</category>
            <category>Engineering</category>
            <category>Open Source</category>
        </item>
    </channel>
</rss>