# tools/core/validators/governance.validator.ts

> 293 lines of code and 76 definitions.

Tree: Coordination tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-validators-governance-validator-ts
Source text: https://banes-lab.com/assets/sources/source.97b7e072374619c225b6b4e1bf9e359e0e1bd9503323a94ecc8a43c3e5cf68fd.generated.txt

## Definitions

- `reportsIn` (lexical_declaration, line 42)
- `idsDeclaredIn` (lexical_declaration, line 117)
- `reportIdOf` (lexical_declaration, line 33)
- `reportEntries` (lexical_declaration, line 37)
- `unevaluableScopes` (lexical_declaration, line 193, exported)
- `selfAuditedReports` (lexical_declaration, line 203, exported)
- `findingShapeGaps` (lexical_declaration, line 339, exported)
- `stepEmittedIds` (lexical_declaration, line 127, exported)
- `contradiction` (lexical_declaration, line 226)
- `withdrawnStandings` (lexical_declaration, line 314, exported)
- `missingFindingFields` (lexical_declaration, line 324, exported)
- `missingReportIdentity` (lexical_declaration, line 74, exported)
- `emittedIds` (lexical_declaration, line 102, exported)
- `deleteReport` (lexical_declaration, line 142, exported)
- `isVerdictBearing` (lexical_declaration, line 185)
- `unrepairableLoci` (lexical_declaration, line 293, exported)
- `claimedReportIds` (lexical_declaration, line 131, exported)
- `orphanReports` (lexical_declaration, line 135, exported)
- `scopeGap` (lexical_declaration, line 159)
- `unaccountedScopeGaps` (lexical_declaration, line 176, exported)
- `publishesAPopulation` (lexical_declaration, line 189)
- `reachedSurfaces` (lexical_declaration, line 216)
- `contradictedContracts` (lexical_declaration, line 247, exported)
- `candidateOf` (lexical_declaration, line 280)
- `SOURCE_EXTENSION` (lexical_declaration, line 19)
- `QUOTE` (lexical_declaration, line 21)
- `COMPOSITE_SEPARATOR` (lexical_declaration, line 23)
- `COMPOSITE_KEYED` (lexical_declaration, line 25)
- `ParsedReport` (interface_declaration, line 27)
- `path` (lexical_declaration, line 45)
- `textOf` (lexical_declaration, line 51)
- `countOf` (lexical_declaration, line 55)
- `isConstructShaped` (lexical_declaration, line 59, exported)
- `reportMissing` (lexical_declaration, line 68, exported)
- `REPORT_IDENTITY_FIELDS` (lexical_declaration, line 72, exported)
- `quotedArgument` (lexical_declaration, line 87)
- `comma` (lexical_declaration, line 88)
- `open` (lexical_declaration, line 89)
- `close` (lexical_declaration, line 97)
- `value` (lexical_declaration, line 98, exported)
- `out` (lexical_declaration, line 103, exported)
- `at` (lexical_declaration, line 104, exported)
- `id` (lexical_declaration, line 107, exported)
- `dir` (lexical_declaration, line 118)
- `ScopeGap` (interface_declaration, line 146, exported)
- `namedSkips` (lexical_declaration, line 153)
- `reachedList` (lexical_declaration, line 161)
- `reached` (lexical_declaration, line 171)
- `named` (lexical_declaration, line 172)
- `UnevaluableScope` (interface_declaration, line 180, exported)
- `handed` (lexical_declaration, line 197, exported)
- `published` (lexical_declaration, line 198, exported)
- `ReportStanding` (interface_declaration, line 207, exported)
- `stampOf` (lexical_declaration, line 212)
- `derivations` (lexical_declaration, line 217)
- `subject` (lexical_declaration, line 231)
- `flat` (lexical_declaration, line 237)
- `UnrepairableLocus` (interface_declaration, line 251, exported)
- `UnrepairableCandidate` (interface_declaration, line 258)
- `RepairJudges` (interface_declaration, line 263)
- `reasonOf` (lexical_declaration, line 268)
- `remediation` (lexical_declaration, line 281)
- `target` (lexical_declaration, line 282, exported)
- `locus` (lexical_declaration, line 287)
- `reason` (lexical_declaration, line 288)
- `rule` (lexical_declaration, line 289)
- `judges` (lexical_declaration, line 298, exported)
- `candidates` (lexical_declaration, line 299, exported)
- `held` (lexical_declaration, line 300, exported)
- `seen` (lexical_declaration, line 304, exported)
- `fresh` (lexical_declaration, line 307, exported)
- `written` (lexical_declaration, line 316, exported)
- `stale` (lexical_declaration, line 317, exported)
- `reachable` (lexical_declaration, line 330, exported)
- `ShapeGap` (interface_declaration, line 334, exported)
- `known` (lexical_declaration, line 344, exported)

## Uses

- [tools/core/predicates/schema.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/schema.predicate.ts.md)
- [tools/core/predicates/source.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/source.predicate.ts.md)
- [tools/core/registries/rule.registry.ts](https://banes-lab.com/source/coordination/tools/core/registries/rule.registry.ts.md)

## Used by

- [tools/rules/governance.rule.ts](https://banes-lab.com/source/coordination/tools/rules/governance.rule.ts.md)

## Source

```typescript
import {
    EMISSION_CALL,
    FINDING_EMISSION,
    REPORT_SUFFIX,
    RULE_DIR,
    SKIP_PREFIX,
    STEP_DIR,
} from "../constants/report.constants.ts";
import { containsInCode, declaresProperty } from "../predicates/source.predicate.ts";

import { existsSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
import { fieldOf, tryParse } from "../readers/json.reader.ts";
import { GENERATED_DIR } from "../constants/path.constants.ts";
import { identityOf } from "../registries/rule.registry.ts";
import { isObject } from "../predicates/schema.predicate.ts";
import { moduleSource } from "../analyzers/graph.analyzer.ts";
import { resolve } from "node:path";

const SOURCE_EXTENSION = ".ts";

const QUOTE = '"';

const COMPOSITE_SEPARATOR = "/";

const COMPOSITE_KEYED = "composite-keyed";

interface ParsedReport {
    readonly entry: string;
    readonly path: string;
    readonly value: object;
}

const reportIdOf = function reportIdOf(entry: string): string {
    return entry.slice(0, entry.length - REPORT_SUFFIX.length);
};

const reportEntries = function reportEntries(repoRoot: string): string[] {
    const dir = resolve(repoRoot, GENERATED_DIR);
    return existsSync(dir) ? readdirSync(dir).filter((entry) => entry.endsWith(REPORT_SUFFIX)) : [];
};

const reportsIn = function reportsIn(repoRoot: string): ParsedReport[] {
    const dir = resolve(repoRoot, GENERATED_DIR);
    return reportEntries(repoRoot).flatMap((entry) => {
        const path = resolve(dir, entry);
        const value = tryParse(readFileSync(path, "utf8"))?.value;
        return typeof value === "object" && value !== null ? [{ entry, path, value }] : [];
    });
};

const textOf = function textOf(value: unknown): string {
    return typeof value === "string" ? value : "";
};

const countOf = function countOf(value: unknown): number {
    return typeof value === "number" ? value : 0;
};

export const isConstructShaped = function isConstructShaped(id: string): boolean {
    for (const char of id) {
        if (char < "a" || char > "z") {
            return false;
        }
    }
    return id.length > 0;
};

export const reportMissing = function reportMissing(repoRoot: string, id: string): boolean {
    return !existsSync(resolve(repoRoot, GENERATED_DIR, `${id}${REPORT_SUFFIX}`));
};

export const REPORT_IDENTITY_FIELDS = ["scope", "authoritative", "verdict"];

export const missingReportIdentity = function missingReportIdentity(repoRoot: string, id: string): string[] {
    const target = resolve(repoRoot, GENERATED_DIR, `${id}${REPORT_SUFFIX}`);
    if (!existsSync(target)) {
        return [];
    }

    const value = tryParse(readFileSync(target, "utf8"))?.value;
    if (typeof value !== "object" || value === null) {
        return [...REPORT_IDENTITY_FIELDS];
    }
    return REPORT_IDENTITY_FIELDS.filter((field) => fieldOf(value, field) === undefined);
};

const quotedArgument = function quotedArgument(source: string, at: number): string | null {
    const comma = source.indexOf(",", at);
    let open = comma === -1 ? source.length + 1 : comma + 1;
    while (source.charAt(open) === " ") {
        open += 1;
    }
    if (source.charAt(open) !== QUOTE) {
        return null;
    }

    const close = source.indexOf(QUOTE, open + 1);
    const value = close === -1 ? source.slice(open + 1) : source.slice(open + 1, close);
    return value.length > 0 ? value : null;
};

export const emittedIds = function emittedIds(source: string): string[] {
    const out = new Set<string>();
    let at = source.indexOf(EMISSION_CALL);

    while (at !== -1) {
        const id = quotedArgument(source, at + EMISSION_CALL.length);
        if (id !== null) {
            out.add(id);
        }
        at = source.indexOf(EMISSION_CALL, at + 1);
    }

    return [...out];
};

const idsDeclaredIn = function idsDeclaredIn(repoRoot: string, relativeDir: string): string[] {
    const dir = resolve(repoRoot, relativeDir);
    if (!existsSync(dir)) {
        return [];
    }
    return readdirSync(dir)
        .filter((entry) => entry.endsWith(SOURCE_EXTENSION))
        .flatMap((entry) => [identityOf(entry), ...emittedIds(readFileSync(resolve(dir, entry), "utf8"))]);
};

export const stepEmittedIds = function stepEmittedIds(repoRoot: string): string[] {
    return [...new Set(idsDeclaredIn(repoRoot, STEP_DIR))];
};

export const claimedReportIds = function claimedReportIds(repoRoot: string): Set<string> {
    return new Set([...stepEmittedIds(repoRoot), ...idsDeclaredIn(repoRoot, RULE_DIR)]);
};

export const orphanReports = function orphanReports(repoRoot: string, claimed: ReadonlySet<string>): string[] {
    return reportsIn(repoRoot)
        .filter((report) => !claimed.has(reportIdOf(report.entry)))
        .filter((report) => fieldOf(report.value, "rule") !== undefined && fieldOf(report.value, "stage") !== undefined)
        .map((report) => report.entry);
};

export const deleteReport = function deleteReport(repoRoot: string, name: string): void {
    rmSync(resolve(repoRoot, GENERATED_DIR, name), { force: true });
};

export interface ScopeGap {
    readonly report: string;
    readonly handed: number;
    readonly reached: number;
    readonly named: number;
}

const namedSkips = function namedSkips(derivations: Readonly<Record<string, unknown>>): number {
    return Object.entries(derivations)
        .filter(([key]) => key.startsWith(SKIP_PREFIX))
        .flatMap(([, value]): unknown[] => (Array.isArray(value) ? value : [])).length;
};

const scopeGap = function scopeGap(report: ParsedReport): ScopeGap[] {
    const derivations = fieldOf(report.value, "derivations");
    const reachedList = isObject(derivations) ? derivations["reached"] : undefined;
    if (!isObject(derivations) || reachedList === undefined) {
        return [];
    }

    const handed = countOf(fieldOf(report.value, "scanned"));
    if (!Array.isArray(reachedList)) {
        return [{ handed, named: 0, reached: -1, report: report.entry }];
    }

    const reached = reachedList.length;
    const named = namedSkips(derivations);
    return handed <= reached || handed - reached === named ? [] : [{ handed, named, reached, report: report.entry }];
};

export const unaccountedScopeGaps = function unaccountedScopeGaps(repoRoot: string): ScopeGap[] {
    return reportsIn(repoRoot).flatMap(scopeGap);
};

export interface UnevaluableScope {
    readonly report: string;
    readonly handed: number;
}

const isVerdictBearing = function isVerdictBearing(value: object): boolean {
    return typeof fieldOf(value, "verdict") === "string" && typeof fieldOf(value, "scanned") === "number";
};

const publishesAPopulation = function publishesAPopulation(derivations: unknown): boolean {
    return isObject(derivations) && Object.values(derivations).some((value) => Array.isArray(value));
};

export const unevaluableScopes = function unevaluableScopes(repoRoot: string): UnevaluableScope[] {
    return reportsIn(repoRoot)
        .filter((report) => isVerdictBearing(report.value))
        .flatMap((report) => {
            const handed = countOf(fieldOf(report.value, "scanned"));
            const published = publishesAPopulation(fieldOf(report.value, "derivations"));
            return handed === 0 || published ? [] : [{ handed, report: report.entry }];
        });
};

export const selfAuditedReports = function selfAuditedReports(repoRoot: string, auditor: string): string[] {
    return reportEntries(repoRoot).filter((entry) => reportIdOf(entry) === auditor);
};

export interface ReportStanding {
    readonly report: string;
    readonly staleSurfaces: readonly string[];
}

const stampOf = function stampOf(absolute: string): number {
    return existsSync(absolute) ? statSync(absolute).mtimeMs : 0;
};

const reachedSurfaces = function reachedSurfaces(value: object): string[] {
    const derivations = fieldOf(value, "derivations");
    if (!isObject(derivations)) {
        return [];
    }
    return Object.values(derivations)
        .flatMap((held): unknown[] => (Array.isArray(held) ? held : []))
        .filter((member): member is string => typeof member === "string" && member.includes(COMPOSITE_SEPARATOR));
};

const contradiction = function contradiction(
    name: string,
    value: unknown,
    derivations: Readonly<Record<string, unknown>>,
): string[] {
    const subject = isObject(value) ? value["subject"] : undefined;
    if (!isObject(value) || value["property"] !== COMPOSITE_KEYED || typeof subject !== "string") {
        return [];
    }

    const held = derivations[subject];
    const flat = Array.isArray(held)
        ? held.filter((member: unknown): member is string => typeof member === "string" && !member.includes(COMPOSITE_SEPARATOR))
        : [];
    return flat.length === 0
        ? []
        : [
              `${name} declares ${subject} composite-keyed and that key carries ${String(flat.length)} member(s) with no separator: ${flat.join(", ")}`,
          ];
};

export const contradictedContracts = function contradictedContracts(derivations: Record<string, unknown>): string[] {
    return Object.entries(derivations).flatMap(([name, value]) => contradiction(name, value, derivations));
};

export interface UnrepairableLocus {
    readonly report: string;
    readonly rule: string;
    readonly target: string;
    readonly reason: "frozenTarget" | "permanentSpan";
}

interface UnrepairableCandidate {
    readonly key: string;
    readonly locus: UnrepairableLocus;
}

interface RepairJudges {
    readonly frozen: (target: string) => boolean;
    readonly permanentSpan: (path: string, locus: string) => boolean;
}

const reasonOf = function reasonOf(
    target: string,
    reported: string,
    locus: string,
    judges: RepairJudges,
): UnrepairableLocus["reason"] | null {
    if (judges.frozen(target)) {
        return "frozenTarget";
    }
    return judges.permanentSpan(reported, locus) ? "permanentSpan" : null;
};

const candidateOf = function candidateOf(entry: string, finding: unknown, judges: RepairJudges): UnrepairableCandidate[] {
    const remediation = isObject(finding) ? finding["remediation"] : undefined;
    const target = isObject(remediation) ? remediation["target"] : undefined;
    if (!isObject(finding) || typeof target !== "string") {
        return [];
    }

    const locus = textOf(finding["locus"]);
    const reason = reasonOf(target, textOf(finding["path"]), locus, judges);
    const rule = textOf(finding["rule"]);
    return reason === null ? [] : [{ key: `${entry}|${rule}|${target}|${locus}`, locus: { reason, report: entry, rule, target } }];
};

export const unrepairableLoci = function unrepairableLoci(
    repoRoot: string,
    frozen: (target: string) => boolean,
    permanentSpan: (path: string, locus: string) => boolean,
): UnrepairableLocus[] {
    const judges: RepairJudges = { frozen, permanentSpan };
    const candidates = reportsIn(repoRoot).flatMap((report) => {
        const held = fieldOf(report.value, "findings");
        return Array.isArray(held) ? held.flatMap((finding: unknown) => candidateOf(report.entry, finding, judges)) : [];
    });

    const seen = new Set<string>();
    return candidates
        .filter((candidate) => {
            const fresh = !seen.has(candidate.key);
            seen.add(candidate.key);
            return fresh;
        })
        .map((candidate) => candidate.locus);
};

export const withdrawnStandings = function withdrawnStandings(repoRoot: string): ReportStanding[] {
    return reportsIn(repoRoot).flatMap((report) => {
        const written = stampOf(report.path);
        const stale = reachedSurfaces(report.value)
            .filter((surface) => stampOf(resolve(repoRoot, surface)) > written)
            .toSorted((left, right) => left.localeCompare(right, "en"));
        return stale.length === 0 ? [] : [{ report: report.entry, staleSurfaces: stale }];
    });
};

export const missingFindingFields = function missingFindingFields(
    path: string,
    read: (path: string) => string,
    known: ReadonlySet<string>,
    required: readonly string[],
): string[] {
    const reachable = moduleSource(path, read, known);
    return required.filter((field) => !declaresProperty(reachable, field));
};

export interface ShapeGap {
    readonly path: string;
    readonly field: string;
}

export const findingShapeGaps = function findingShapeGaps(
    paths: readonly string[],
    read: (path: string) => string,
    required: readonly string[],
): ShapeGap[] {
    const known = new Set(paths);
    return paths
        .filter((path) => path.endsWith(SOURCE_EXTENSION) && containsInCode(read(path), FINDING_EMISSION))
        .flatMap((path) => missingFindingFields(path, read, known, required).map((field) => ({ field, path })));
};
```
