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-001 — Document Reference Resolution Every document-ID reference in governed relationship fields must resolve exactly to a key in config/system/acronyms.json.

Severity: ERROR Auto-fix: prohibited

DL-002 — Unregistered Document-Like Token An uppercase hyphenated or underscored token appears to reference a document but is absent from config/system/acronyms.json.

Severity: WARNING Auto-fix: prohibited

DL-003 — Controlled Vocabulary.

Values of:

• tags • classification • audience • ontology_type • artifact_domain • identifier_type

shall resolve to registered values in config/system.

Severity: ERROR Auto-fix: prohibited

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-107 · 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).

DL-105 · Artifact Namespace (ERROR). Persistent artifacts SHALL use the ARTIF-* namespace.

The following are prohibited:

TG-ATTEST TG-VRES TG-REPORT TG-RESULT

unless explicitly registered as document identifiers.

Every persistent artifact SHALL resolve to exactly one ARTIF-* definition.

DL-106 · Official Module Registry resolution (ERROR). Every value declared in omr_module_ids SHALL resolve exactly to an active entries[].id value in config/system/omr.modules.json.

Module display names, module code values, folder names, component IDs, engine IDs, aliases, and inferred abbreviations SHALL NOT be used in omr_module_ids.

Severity: ERROR
Auto-fix: prohibited

DL-107 · Unregistered module-like token (WARNING). A document appears to declare or describe a top-level platform module that does not resolve to an active entry in config/system/omr.modules.json.

The linter SHALL distinguish modules from components, engines, registries, services, workflows, and artifact domains.

Severity: WARNING
Auto-fix: prohibited

DL-108 · Deprecated tag usage (WARNING). Use of a deprecated tag SHALL emit a warning identifying its registered replaced_by value.

Severity: WARNING
Auto-fix: permitted only where the replacement is one-to-one and no semantic change occurs.

DL-109 · Controlled architectural tag resolution (ERROR). Every value in tags SHALL resolve to an active entry in config/system/tags.json.

DL-110 · Controlled SSSR tag resolution (ERROR). Every value in sssr_tags SHALL resolve to an active entry in config/system/sssr-tags.json.

DL-111 · Deprecated controlled vocabulary (WARNING). Deprecated values SHALL report their registered replacement.

DL-112 · Tag namespace separation (ERROR). A value used solely as an SSSR routing concept SHALL NOT be introduced into ordinary tags, and architectural deployment or quality tags SHALL NOT be introduced into sssr_tags.

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)