Skip to content

Zenzic vs. Proofreader

Zenzic does not care about your writing style.

Whether you use hyphens or asterisks for lists, whether your lines are 80 or 120 characters long, whether you prefer sentence case or title case in headings — none of these are Zenzic's domain. These are matters of personal or team preference. They do not threaten your project's stability, your users' safety, or your CI pipeline's reliability.

Excellent tools like markdownlint, vale, and prettier govern the aesthetics of prose. Zenzic governs Structural Integrity and Security. These are not competing concerns — they occupy orthogonal categories.


The Integrity Filter

Every rule that ships in the Zenzic Core must pass a three-dimensional admission test. We call this The Integrity Filter: a rule enters Zenzic if and only if it defends one of these three dimensions.

Dimension 1 — Structural Integrity

"Does this rule prevent a broken user experience?"

A documentation project is a graph of interconnected resources. When a node in that graph disappears — a file is renamed, a heading changes its anchor, a directory is restructured — every reference pointing to that node becomes a ghost. The user follows the link and lands on a 404. The CI pipeline succeeds. The damage is invisible at build time.

Structural Integrity rules catch these breaks before the build runs:

  • Orphan pages: An orphan page is a Markdown file present on disk but absent from the site navigation declared in your build engine's configuration file. Because these pages are unreachable by users navigating the site structure, Zenzic reports them to keep you in control.
  • Comprehensive link checking: Zenzic's link validation analyses all Markdown references, including text links, images, reference-style links, and same-page anchors.
Finding Code Name What it catches
Z101 LINK_BROKEN Dead internal links — file not found
Z102 ANCHOR_MISSING Links to headings that no longer exist
Z106 CIRCULAR_LINK Circular link cycles — structural telemetry, not a defect (see architectural rationale)
Z107 CIRCULAR_ANCHOR Self-referential anchor links
Z108 EMPTY_LINK_TEXT Empty or whitespace-only link labels
Z401 MISSING_DIRECTORY_INDEX Directories without a reachable index.md
Z402 ORPHAN_PAGE Files unreachable from any navigation path
Z404 CONFIG_ASSET_MISSING Assets declared in config that do not exist on disk

Dimension 2 — Hardened Security

"Does this rule protect your infrastructure or secrets?"

Documentation source is untrusted input. It is written by humans, accepted from external contributors, and processed by build pipelines that may hold access to production credentials. A single leaked API key in a Markdown file — committed in a rush, pushed to a public repository — is a supply-chain incident, not an editorial oversight.

Security rules are non-suppressible by design. Exit codes 2 and 3 bypass --exit-zero and fail-on-error: false unconditionally:

Finding Code Name What it catches Exit
Z201 CREDENTIAL_SECRET Credentials, API keys, tokens in any source line 2
Z202 PATH_TRAVERSAL System path escape in a link or config value 3
Z203 PATH_TRAVERSAL_SUSPICIOUS Relative traversal patterns escaping the docs root 3

See Exclusion Zone and The Zenzic Trinity for the complete exit code contract.


Dimension 3 — Technical Accessibility

"Does this rule ensure that third-party tools can consume your source?"

Markdown is an input format: it is consumed by build engines, syntax highlighters, snippet validators, and CI quality gates. Some structural properties that appear cosmetic at first glance carry hard technical consequences for downstream tooling.

The canonical example is Z505: UNTAGGED_CODE_BLOCK: a fenced code block with no language specifier renders as plain text in most engines. More critically, it prevents snippet validation and breaks syntax highlighting coverage measurement. The absence of a language tag is not a style preference — it is a missing machine-readable contract between the author and every tool in the pipeline.

Finding Code Name What it catches
Z505 UNTAGGED_CODE_BLOCK Fenced blocks with no language specifier
Z503 SNIPPET_ERROR Code snippets that fail to parse
Z106 CIRCULAR_LINK Link cycles — structural telemetry; documentation forms an interconnected Knowledge Graph where cycles are expected (see architectural rationale)
Z108 EMPTY_LINK_TEXT Links whose label is empty or whitespace-only

The Node.js Tax and Architectural Independence

You might ask: why does Zenzic implement Z505 (Untagged Code Blocks) when linters like markdownlint already detect this?

The answer is Pillar 2: Zero Subprocesses.

Traditional Markdown linters require a full Node.js runtime and hundreds of megabytes of node_modules. For a Python-based DevOps pipeline, a security-conscious enterprise, or any team running CI in a minimal container, this dependency creates friction: additional toolchain configuration, runtime version pinning, and transitive supply-chain exposure. We call this the Node.js Tax — the hidden overhead of requiring a second runtime stack just to validate documentation structure.

Without Zenzic         With Zenzic
─────────────────────  ─────────────────────────
npm install            uvx zenzic check all
node_modules/ ~300 MB  (zero persistent install)
Node ≥ 18 required     Python 3.10+ required
npm audit surface      Zero transitive risk

By providing core structural checks in pure Python, Zenzic enables professional-grade documentation quality without leaving your primary technology stack. Zenzic is not designed to replace every linter in your pipeline — but for structural integrity, security, and technical accessibility in CI, it is the only one you need.


What Zenzic Explicitly Does Not Do

The boundary of what Zenzic rejects is as important as what it enforces. This table is permanent. If a proposed rule does not pass The Integrity Filter, it does not ship.

Category Example Position
Line length Lines exceeding 80 or 120 characters ✗ Not a structural concern
List marker style * vs - vs 1. ✗ Aesthetic preference
Heading casing Sentence case vs. Title Case ✗ Editorial choice
Spell checking Typos and grammar errors ✗ Delegate to vale
Link text phrasing "Click here" vs. descriptive anchor text ✗ Guideline, not a gate
Trailing whitespace Extra spaces at line endings ✗ Auto-fixed by formatters
Prose consistency Uniform use of terminology ✗ Domain-specific — use vale

These categories are not beneath Zenzic — they are outside its mandate. Zenzic enforces the structure. Everything else is editorial sovereignty.


Zenzic works best as one layer in a quality stack, not as a replacement for the entire tooling ecosystem:

Layer Tool What it enforces
Structural Zenzic Broken links, orphans, secrets, path traversal
Style markdownlint List markers, heading levels, code fence format
Prose vale Grammar, terminology, style guides
Format prettier Consistent whitespace and indentation

Configure each as an independent CI step. Zenzic's exit code contract is the non-negotiable gate; the others can be advisories depending on your team's maturity model.


Further Reading