Skip to main content
Jira progress: loading…

VW-DL

Viroway Docs Lint


1. Purpose

In the ZAYAZ pipeline, specifications are not documentation about the system — they are machine-read inputs to the system: Docusaurus frontmatter feeds ticket generation, datasheet generation, and implementation by AI agents (Viktor). A drifted spec is therefore not a stale page; it is a defect injected upstream of code, where it is cheapest to create and most expensive to discover.

The evidence is already on record. A single review pass across the TrustGate corpus surfaced: a pipeline-ordering conflict between the MIB and an engine spec (resolved by CTO ruling, 2026-07); duplicate file generations (*-specification-2, *-specification-3); one engine whose identity table was embedded inside its output-CSI table; and four distinct heading conventions for the same CSI sections. Each was cheap to fix when found and would have been expensive to discover in a sprint.

This specification makes that review pass permanent, automatic, and blocking.


2. Rule Classes

2.1. Class A — Frontmatter Schema (per doc_type)

Every .mdx file SHALL declare doc_type, and each doc_type has a required frontmatter schema:

doc_typeRequired fields
engine-specid, semantic_id, short_id, canonical_name, version, status, hub, omr_module_ids, consumes, produces, replay_profile (per TG-RP §3)
normative-specid, semantic_id, short_id, canonical_name, version, status, governed_by
catalogid, semantic_id, version, status
mibid, semantic_id, version, status

Field-level checks: semantic_id matches grammar zar.component.<hub>.<kind>.<name...>; version is semver; status{draft, review, approved, deprecated}; short_id unique across the corpus.

2.2. Class B — Cross-Document Invariants

These are the rules that catch what humans reliably miss: statements that are individually correct and mutually contradictory.

DL-101 · Canonical pipeline order (ERROR). Any document that enumerates the TrustGate runtime pipeline SHALL present it in the canonical order:

Parser → Structure Validation → Normalizer → Enrichment →
Rule Evaluation → Policy Resolution → Trust Scoring → Decision

The linter extracts ordered engine-name sequences from pipeline diagrams, tables, and position sections, normalizes aliases (per each spec's aliases frontmatter), and fails on any sequence that contradicts the canonical order. The historic MIB/engine-spec conflict becomes a build failure.

DL-102 · Decision exits (ERROR). Any enumeration of Decision Engine outcomes SHALL contain exactly the five exits: ACCEPT, ROUTE, ESCALATE, QUARANTINE, REJECT. Four-exit enumerations (pre-correction documents) fail.

DL-103 · Identity layer separation (ERROR). EID, MEID, and CMI SHALL never be presented as interchangeable; a document that assigns one identifier to two layers fails.

DL-104 · Replay profile completeness (ERROR). Every output CSI declared in produces SHALL appear in replay_profile.outputs or be covered by replay_profile.default (cross-reference: TG-RP §6.1).

DL-105 · No ungoverned scoring parameters (ERROR). Numeric weights, thresholds, modifier values, or ε values appearing outside the weight-bundle specification or example blocks explicitly marked <!-- example --> fail (cross-reference: TG-SG §5.1).

2.3. Class C — Structural Rules

RuleSeverityCheck
DL-201ERRORCanonical Identity table exists under a Canonical Identity heading and nowhere else (the TG-ENRICH failure mode)
DL-202ERRORInput/Output CSI sections use one heading convention: ### Input CSIs / ### Output CSIs
DL-203WARNCSI table rows follow the grammar comp.<SYS>.<DIR>.<NAME>.vN_N (legacy vera.* / siss.* prefixes flagged for migration)
DL-204WARNEvery table has a header row and separator row

2.4. Class D — Hygiene Rules

RuleSeverityCheck
DL-301ERRORNo duplicate-generation filenames (*-2.mdx, *-3.mdx, *-corrected.mdx) on main — corrections replace, never accumulate
DL-302ERRORNo two documents share a semantic_id or short_id
DL-303WARNOrphaned CSIs: referenced in some document's consumes but defined in no document's produces (and vice versa)
DL-304WARNlast_updated older than version change in git history
DL-305INFODead internal links / unresolved slugs

3. Severity Semantics

  • ERROR — CI build fails; the PR cannot merge. Reserved for rules whose violation would propagate a defect into tickets or code.
  • WARN — CI annotates the PR; merge allowed; warnings accumulate in a weekly digest owned by the docs owner.
  • INFO — Reported in lint output only.

Severity assignments are themselves governed: changing a rule's severity is a ZRR ruleset change, not a config edit.


4. CI Integration

Implementation lives in viroway-tools/docs-lint/ (Python; no runtime dependencies beyond PyYAML). It runs:

  1. On every PR touching **/*.mdx — full corpus lint (cross-document invariants require the whole corpus, not just the diff).
  2. Nightly on main — full lint + orphan/link analysis + digest.
# .github/workflows/docs-lint.yml
name: docs-lint
on:
pull_request:
paths: ['**/*.mdx']
schedule:
- cron: '0 4 * * *'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install pyyaml
- run: python viroway-tools/docs-lint/lint.py --config docs-lint.yml --fail-on error
# docs-lint.yml (excerpt)
canonical_pipeline:
- TG-PARSE
- TG-VALIDATE-STRUCTURE
- TG-NORM
- TG-ENRICH
- TG-RULE
- TG-POLICY
- TG-SCORE
- TG-DECISION
decision_exits: [ACCEPT, ROUTE, ESCALATE, QUARANTINE, REJECT]
csi_grammar: '^comp\.[A-Z]+\.(INPUT|OUTPUT|EVENT|SCHEMA)\.[A-Z0-9-]+\.v\d+_\d+$'
legacy_csi_prefixes: [vera., siss.]

The ticket generator SHALL consume only lint-clean corpora: it runs the linter as its first step and refuses drifted input.

The same rule applies to any other offline renderer of the corpus — for example, a future script that regenerates the Figma engine datasheets from spec frontmatter. Such renderers are documentation tooling in the same category as Docusaurus: one-way projections of the source of truth (docs → output, never back). They are not ZAYAZ components, and nothing in the platform depends on them; the rule exists only so that no rendering of the specs — page, diagram, or ticket — can be produced from a drifted corpus. Figma itself is a visualization surface, not part of the system.


5. Normative Rules

  1. Every .mdx document in governed paths SHALL declare a doc_type and satisfy its frontmatter schema.
  2. Class B invariants are constitutional: adding or amending one SHALL be a ZRR ruleset change with CTO approval, DAL-anchored like any other governed artifact.
  3. A correction to a specification SHALL replace the specification in place (same filename, version bump, changelog entry). Suffix-file corrections (-corrected, -2) SHALL NOT exist on main.
  4. New cross-document contradictions discovered by any means (human review, AI session, audit) SHALL be encoded as a Class B rule within one release cycle — every found conflict permanently increases the corpus's immune system.

6. ZRR Ruleset Entry

ruleset: ZRR-DOCS-001
invariant: spec-corpus-is-lint-clean-on-main
scope: all .mdx under key-zayaz-features/
enforcement: CI (blocking on ERROR class) + nightly digest
amendments: Class B rule changes require CTO approval, DAL-anchored

A specification corpus that feeds code generation is code. This document gives it a compiler. Source of truth: Docusaurus.




GitHub RepoRequest for Change (RFC)