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.
The Recommended Layered Stack
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
- The Zenzic Trinity — The three non-negotiable pillars: Zero Subprocesses, Pure Functions, Structural Analysis
- Exclusion Zone — The exit code contract and the inviolable security gate
- Finding Codes Reference — The complete Zxxx registry with remediation steps
- Scoring System — How the Deterministic Quality Score is computed