#!/usr/bin/env bash # ============================================================================ # DOC INVARIANTS CHECKER # ============================================================================ # Enforces documentation law for VaultMesh. # Run from repo root: bash scripts/doc-invariants.sh # # Exit codes: # 0 = All invariants pass # 1 = One or more invariants violated # # Governed by: RED-BOOK.md # ============================================================================ set -uo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO_ROOT" FAILED=0 PASSED=0 # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color pass() { echo -e "${GREEN}✓${NC} $1" ((PASSED++)) } fail() { echo -e "${RED}✗${NC} $1" ((FAILED++)) } warn() { echo -e "${YELLOW}⚠${NC} $1" } echo "============================================" echo " VaultMesh Documentation Invariants Check" echo "============================================" echo "" # ============================================================================ # 1. STRUCTURAL INVARIANTS # ============================================================================ echo "── 1. Structural Invariants ──" # 1.1 Single Front Door if [[ -f "README.md" ]]; then if grep -q "STRUCTURE.md" README.md && grep -q "FIRST_RUN.md\|DEPLOYMENT_GUIDE.md" README.md; then pass "1.1 Single Front Door: README.md exists and links to STRUCTURE.md + guides" else fail "1.1 Single Front Door: README.md missing links to STRUCTURE.md or guides" fi else fail "1.1 Single Front Door: README.md does not exist" fi # 1.2 Single Index if [[ -f "STRUCTURE.md" ]]; then pass "1.2 Single Index: STRUCTURE.md exists" else fail "1.2 Single Index: STRUCTURE.md does not exist" fi # Check for competing indexes (forbidden patterns) COMPETING_INDEXES=$(find . -maxdepth 1 -name "README_STRUCTURE*.md" -o -name "INDEX*.md" 2>/dev/null | grep -v archive_docs || true) if [[ -z "$COMPETING_INDEXES" ]]; then pass "1.2 Single Index: No competing index files found" else fail "1.2 Single Index: Found competing index files: $COMPETING_INDEXES" fi # 1.3 Archive Boundary if [[ -d "archive_docs" ]]; then pass "1.3 Archive Boundary: archive_docs/ directory exists" else warn "1.3 Archive Boundary: archive_docs/ directory does not exist (optional)" fi echo "" # ============================================================================ # 2. CONTENT INVARIANTS # ============================================================================ echo "── 2. Content Invariants ──" # 2.1 Multi-Account Single Source of Truth if [[ -f "MULTI_ACCOUNT_AUTH.md" ]]; then pass "2.1 Multi-Account SSOT: MULTI_ACCOUNT_AUTH.md exists" else fail "2.1 Multi-Account SSOT: MULTI_ACCOUNT_AUTH.md does not exist" fi # 2.2 One Doctrine if [[ -f "RED-BOOK.md" ]]; then pass "2.2 One Doctrine: RED-BOOK.md exists" else fail "2.2 One Doctrine: RED-BOOK.md does not exist" fi # 2.3 Playbooks Own Incidents REQUIRED_PLAYBOOKS=( "playbooks/DNS-COMPROMISE-PLAYBOOK.md" "playbooks/TUNNEL-ROTATION-PROTOCOL.md" "playbooks/waf_incident_playbook.md" ) ALL_PLAYBOOKS_EXIST=true for pb in "${REQUIRED_PLAYBOOKS[@]}"; do if [[ ! -f "$pb" ]]; then fail "2.3 Playbooks: Missing $pb" ALL_PLAYBOOKS_EXIST=false fi done if $ALL_PLAYBOOKS_EXIST; then pass "2.3 Playbooks: All required playbooks exist" fi echo "" # ============================================================================ # 3. LINK & REFERENCE INVARIANTS # ============================================================================ echo "── 3. Link & Reference Invariants ──" # 3.1 No Dead Links in Active Space # Check for known deprecated filenames outside archive_docs/ DEPRECATED_PATTERNS=( "dns_compromise_playbook\.md" "tunnel_rotation_protocol\.md" "ONE-PAGE-SECURITY-SHEET\.md" "README_STRUCTURE\.md" ) DEAD_LINK_FOUND=false for pattern in "${DEPRECATED_PATTERNS[@]}"; do # Search for pattern, excluding archive_docs/ HITS=$(grep -r "$pattern" . --include="*.md" --include="*.yml" --include="*.yaml" --include="*.py" 2>/dev/null | grep -v "archive_docs/" | grep -v "doc-invariants.sh" || true) if [[ -n "$HITS" ]]; then fail "3.1 Dead Links: Found deprecated reference '$pattern' outside archive_docs/" echo " $HITS" | head -3 DEAD_LINK_FOUND=true fi done if ! $DEAD_LINK_FOUND; then pass "3.1 Dead Links: No deprecated references found in active space" fi # 3.2 Case-Exact Playbook Paths # Check for WRONG casing - lowercase variants when they should be uppercase # DNS-COMPROMISE-PLAYBOOK.md should NOT appear as dns-compromise-playbook.md CASE_VIOLATIONS=$(grep -r "dns-compromise-playbook\.md\|dns_compromise_playbook\.md" . --include="*.md" --include="*.yml" --include="*.yaml" 2>/dev/null | grep -v archive_docs/ | grep -v "DNS-COMPROMISE-PLAYBOOK" || true) if [[ -z "$CASE_VIOLATIONS" ]]; then pass "3.2 Case-Exact Paths: Playbook references use correct casing" else fail "3.2 Case-Exact Paths: Found lowercase playbook references (should be UPPERCASE)" echo " $CASE_VIOLATIONS" | head -3 fi echo "" # ============================================================================ # 4. COGNITIVE / AI LAYER INVARIANTS # ============================================================================ echo "── 4. Cognitive Layer Invariants ──" # 4.1 Cognition ≈ Fourfold Work COGNITION_DOCS=("COGNITION_FLOW.md" "DEMO_COGNITION.md") for doc in "${COGNITION_DOCS[@]}"; do if [[ -f "$doc" ]]; then if grep -qi "RED-BOOK\|Fourfold Work\|Nigredo.*Albedo.*Citrinitas.*Rubedo" "$doc"; then pass "4.1 Cognition Doctrine: $doc references Red Book" else fail "4.1 Cognition Doctrine: $doc does not reference Red Book / Fourfold Work" fi fi done # 4.2 Guardrails Reference Doctrine if [[ -f "AGENT_GUARDRAILS.md" ]]; then if grep -qi "RED-BOOK" "AGENT_GUARDRAILS.md"; then pass "4.2 Guardrails Doctrine: AGENT_GUARDRAILS.md references Red Book" else fail "4.2 Guardrails Doctrine: AGENT_GUARDRAILS.md does not reference Red Book" fi fi echo "" # ============================================================================ # 5. PLAYBOOK REGISTRATION # ============================================================================ echo "── 5. Playbook Registration ──" # Check that all playbooks are registered in STRUCTURE.md for pb in "${REQUIRED_PLAYBOOKS[@]}"; do pb_name=$(basename "$pb") if grep -q "$pb_name" STRUCTURE.md 2>/dev/null; then pass "5.1 Registration: $pb_name listed in STRUCTURE.md" else fail "5.1 Registration: $pb_name NOT listed in STRUCTURE.md" fi done echo "" # ============================================================================ # 6. TOP-LEVEL DOC REGISTRY # ============================================================================ echo "── 6. Doc Registry ──" # Every top-level .md (except README.md, STRUCTURE.md, LICENSE) must be in STRUCTURE.md UNREGISTERED_DOCS=false for f in *.md; do [[ "$f" == "README.md" || "$f" == "STRUCTURE.md" || "$f" == "LICENSE.md" ]] && continue if ! grep -q "$f" STRUCTURE.md 2>/dev/null; then fail "6.1 Registry: $f not listed in STRUCTURE.md" UNREGISTERED_DOCS=true fi done if ! $UNREGISTERED_DOCS; then pass "6.1 Registry: All top-level docs are indexed in STRUCTURE.md" fi echo "" # ============================================================================ # SUMMARY # ============================================================================ echo "============================================" echo " Summary" echo "============================================" echo -e " ${GREEN}Passed:${NC} $PASSED" echo -e " ${RED}Failed:${NC} $FAILED" echo "" if [[ $FAILED -gt 0 ]]; then echo -e "${RED}Doc invariants violated. Fix before merging.${NC}" exit 1 else echo -e "${GREEN}All doc invariants pass. ✓${NC}" exit 0 fi