import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts"; import { axisConsumers, silentOnItsOwnAxis } from "../core/validators/declaration.validator.ts"; import { foreignMarkerIn, isDirectory } from "../core/inspectors/taxonomy.inspector.ts"; import { slotText, surfacePath, surfacePrefix } from "../../config/surface.config.ts"; const AXIS_ADAPTER = slotText("project", "runtime_adapter"); const AXIS_GOVERNED = [ `${surfacePath("pipeline")}/`, surfacePrefix().length === 0 ? AXIS_ADAPTER : `${surfacePrefix()}/${AXIS_ADAPTER}`, ]; const AXIS_REACHES = [ "lifetimeOf(", "seededLifetimeOf(", "lifetime.declared", "declared.retention", "declared.mutability", "declared.removal", ]; import { BEHAVIOUR_TREE_PLACEHOLDER, BOOTSTRAP_DOCUMENT, PACKAGE_MANIFEST, SURFACE_ROOT, UPSTREAM_ROOTS, } from "../core/constants/path.constants.ts"; import { existsSync, readFileSync } from "node:fs"; import { toPosix, walk } from "../core/iterators/file.iterator.ts"; import type { Finding } from "../core/types/segment.types.ts"; import { resolve } from "node:path"; import { inspectManifests } from "../core/inspectors/manifest.inspector.ts"; import { resolveArtifactRoots } from "../core/resolvers/artifact.resolver.ts"; import { underRoots } from "../core/filters/scope.filter.ts"; const SSOT = surfacePath("taxonomy_config"); const finding = function finding(kind: string, path: string, locus: string, decide: string): Finding { return { actual: `${path} is declared but absent`, expected: null, healed: false, line: 0, locus, path: SSOT, remediation: { action: "declare", decide, deterministic: false, from: path, target: SSOT, to: null }, rule: `declaration/${kind}`, stack: [ { check: "declared", resolved: locus }, { check: "onDisk", resolved: "absent" }, ], }; }; type Taxonomy = RuleContext["taxonomy"]; const rootFindings = function rootFindings(repoRoot: string, roots: readonly string[], upstream: readonly string[]): Finding[] { return [ ...roots .filter((root) => !isDirectory(repoRoot, root)) .map((root) => finding( "missingRoot", root, `root "${root}"`, "create the root, or remove it from containers / specialContainers / corpusRoots — a root that does not exist governs nothing", ), ), ...upstream .filter((root) => !isDirectory(repoRoot, root)) .map((root) => finding( "missingUpstreamRoot", root, `upstream root "${root}"`, "create the tree, or remove it from the upstream declaration — an upstream root EXEMPTS its contents from the naming, tense and reference gates, so one that resolves to nothing exempts nothing while reading as a considered exclusion, and the next tree that lands under a similar name inherits an exemption nobody granted it", ), ), ]; }; const containerFindings = function containerFindings(repoRoot: string, data: Taxonomy): Finding[] { const declaredFolders: [string, readonly string[]][] = [ ...Object.entries(data.containers), ...Object.entries(data.specialContainers), ]; const missingFolders = declaredFolders .filter(([root]) => isDirectory(repoRoot, root)) .flatMap(([root, folders]) => folders.map((folder) => ({ folder, root }))) .filter(({ folder, root }) => !isDirectory(repoRoot, `${root}/${folder}`)); const missingCorpora = Object.entries(data.corpusRoots).filter( ([root, config]) => !isDirectory(repoRoot, `${root}/${config.filedUnder}`), ); return [ ...missingFolders.map(({ folder, root }) => finding( "missingContainer", `${root}/${folder}`, `"${folder}" under "${root}"`, "create the folder, or drop it from the root's declared set — an undeclared-but-present folder fails placement, while a declared-but-absent one fails nothing at all", ), ), ...missingCorpora.map(([root, config]) => finding( "missingCorpusSubtree", `${root}/${config.filedUnder}`, `filedUnder "${config.filedUnder}" of corpus root "${root}"`, "create the subtree, or correct filedUnder — the facet filing check is skipped entirely when it resolves nowhere", ), ), ]; }; const foreignFindings = function foreignFindings(repoRoot: string, roots: readonly string[], data: Taxonomy): Finding[] { return roots.flatMap((root) => { const marker = isDirectory(repoRoot, root) ? foreignMarkerIn(repoRoot, root, data) : null; if (marker === null) { return []; } return [ { actual: `${root} is declared, and holds ${marker.evidence}`, expected: null, healed: false, line: 0, locus: `root "${root}"`, path: SSOT, remediation: { action: "declare", decide: `${marker.why} Remove the declaration — a tree whose names are load-bearing elsewhere is governed on its own axis, never renamed to satisfy this grammar.`, deterministic: false, from: root, target: SSOT, to: null, }, rule: "declaration/foreignGrammarClaimed", stack: [ { check: "declared", resolved: `root "${root}"` }, { check: "onDisk", resolved: "present" }, { check: "foreignGrammar", resolved: marker.evidence }, ], }, ]; }); }; const artifactFindings = function artifactFindings(repoRoot: string, data: Taxonomy): Finding[] { return resolveArtifactRoots(repoRoot, data).flatMap((root) => root.unresolved === null ? [] : [ { actual: root.unresolved, expected: null, healed: false, line: 0, locus: `artifactRoots "${root.key}"`, path: SSOT, remediation: { action: "declare", decide: "repair the binding, or drop the artifact root — every content rule declaring this " + "jurisdiction currently scans nothing and reports a pass for files it never opened", deterministic: false, from: root.key, target: SSOT, to: null, }, rule: "declaration/unresolvedArtifactRoot", stack: [ { check: "binding", resolved: root.binding }, { check: "field", resolved: root.field }, { check: "resolved", resolved: "absent" }, ], }, ], ); }; type Consumer = ReturnType[number]; const readsOf = function readsOf(consumer: Consumer, separator: string, empty: string): string { return consumer.read.length === 0 ? empty : consumer.read.join(separator); }; const axisFinding = function axisFinding(path: string, consumer: Consumer): Finding { const reads = readsOf(consumer, "+", "no axis"); return { actual: `${consumer.name} names the ${consumer.asserted} axis and never reads it, deciding from ${readsOf(consumer, " and ", "no declared axis")} instead`, expected: `${consumer.name} reads the ${consumer.asserted} field its own identity asserts`, healed: false, line: consumer.line, locus: consumer.name, path, remediation: { action: "declare", decide: "the declared axes are INDEPENDENT by the model this tree governs itself by — no two are derivable from each other — so a predicate deciding one of them from the others takes a derivation the model states is unavailable, and it is wrong from its first line rather than by drifting. THE SCOPE IS A BODY SCAN RATHER THAN A SIGNATURE SCAN, DELIBERATELY: narrowing to functions whose PARAMETER TYPE is the declared record keys on the property the CORRECT members share, so it passes every true negative and never sees a predicate that resolves the record inside its own body, which is the shape this check exists for. The residue is a predicate naming NO axis while reading the wrong fields, invisible here and stated rather than gated weakly, because the general question is what a predicate is FOR and no surface holds that", deterministic: false, from: reads, target: path, to: consumer.asserted, }, rule: "declaration/unreadAssertedAxis", stack: [ { check: "reachesLifetime", resolved: "yes" }, { check: "asserts", resolved: consumer.asserted }, { check: "reads", resolved: reads }, ], }; }; const inSurfaceRoot = function inSurfaceRoot(path: string): string { return SURFACE_ROOT.length === 0 ? path : `${SURFACE_ROOT}/${path}`; }; interface Scanned { readonly path: string; readonly text: string; } const placeholderSources = function placeholderSources(context: RuleContext): Scanned[] { const treeRoot = resolve(context.repoRoot, surfacePath("behaviour_tree")); const treeFiles = existsSync(treeRoot) ? walk({ extensions: [".md"], ignored: [], root: treeRoot }) : []; const manifest = resolve(context.repoRoot, inSurfaceRoot(PACKAGE_MANIFEST)); const onDisk = [...treeFiles, ...(existsSync(manifest) ? [manifest] : [])].map((absolute) => ({ path: toPosix(context.repoRoot, absolute), text: readFileSync(absolute, "utf8"), })); const handed = context.paths .filter((path) => path.endsWith(".md")) .map((path) => ({ path, text: context.read(path) })); const seen = new Set(handed.map((entry) => entry.path)); return [...handed, ...onDisk.filter((entry) => !seen.has(entry.path))].filter( (entry) => entry.path !== BOOTSTRAP_DOCUMENT, ); }; const leftoverFinding = function leftoverFinding(path: string): Finding { return { actual: `${path} names ${BEHAVIOUR_TREE_PLACEHOLDER}, and no folder by that name exists`, expected: `${path} naming ${surfacePath("behaviour_tree")}, the folder the behavior tree was renamed to`, healed: false, line: 0, locus: BEHAVIOUR_TREE_PLACEHOLDER, path, remediation: { action: "rename", decide: "adoption renames the behavior folder from its shipped placeholder and replaces the placeholder wherever the package names it; this file still names the placeholder, so a path in it points at a folder that no longer exists. Replace the placeholder with the folder's new name", deterministic: false, from: BEHAVIOUR_TREE_PLACEHOLDER, target: path, to: null, }, rule: "declaration/unrenamedPlaceholder", stack: [ { check: "placeholderFolder", resolved: "absent" }, { check: "named", resolved: path }, ], }; }; const placeholderFindings = function placeholderFindings(context: RuleContext): Finding[] { if (existsSync(resolve(context.repoRoot, inSurfaceRoot(BEHAVIOUR_TREE_PLACEHOLDER)))) { return []; } return placeholderSources(context) .filter((entry) => entry.text.includes(BEHAVIOUR_TREE_PLACEHOLDER)) .map((entry) => leftoverFinding(entry.path)); }; export const rule: RuleDeclaration = { check(context: RuleContext): RuleResult { const data = context.taxonomy; const { repoRoot } = context; const roots = [ ...new Set([ ...Object.keys(data.containers), ...Object.keys(data.specialContainers), ...Object.keys(data.corpusRoots), ]), ]; const upstream = UPSTREAM_ROOTS.map((root) => (root.endsWith("/") ? root.slice(0, -1) : root)); const resolvedRoots = roots.filter((root) => isDirectory(repoRoot, root)); const resolvedUpstream = upstream.filter((root) => isDirectory(repoRoot, root)); const consumers = underRoots(context.paths, AXIS_GOVERNED).flatMap((path) => axisConsumers(context.read(path), AXIS_REACHES).map((consumer) => ({ consumer, path })), ); const axisInspected = consumers.map( ({ consumer, path }) => `${path}:${consumer.name} asserts ${consumer.asserted}, reads ${readsOf(consumer, "+", "no axis")}`, ); const findings = [ ...rootFindings(repoRoot, roots, upstream), ...containerFindings(repoRoot, data), ...foreignFindings(repoRoot, roots, data), ...artifactFindings(repoRoot, data), ...inspectManifests(repoRoot, data.ignored), ...consumers .filter(({ consumer }) => silentOnItsOwnAxis(consumer)) .map(({ consumer, path }) => axisFinding(path, consumer)), ...placeholderFindings(context), ]; return { derivations: { axisInspected, declarationsWalked: resolvedRoots.length + resolvedUpstream.length, resolvedRoots, resolvedUpstream, }, findings, healed: [], }; }, extensions: [], heals: false, invariant: "every declared root, container, bucket and corpus root resolves to a directory on disk", jurisdiction: "taxonomy", kinds: [ "missingRoot", "missingContainer", "missingCorpusSubtree", "missingUpstreamRoot", "foreignGrammarClaimed", "unresolvedArtifactRoot", "unreadAssertedAxis", "declaredRuntimeDependency", "unreachedDependency", "unrenamedPlaceholder", ], readsTree: "the invariant is that a declared root resolves to a directory that exists, and a declared " + "directory holding no files contributes no paths at all — so a path set cannot tell a root that " + "is declared and empty from one that is declared and absent, which is the case this rule exists " + "to catch", stage: "meta", wholeScopeOnly: true, };