import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
import { dirname, join, relative } from 'path';
import { fileURLToPath } from 'url';
import {
dependencyProfileRules,
forbiddenManifestDependencyRules,
lightweightBoundaryRules,
noCoreDependencyCrates,
} from './rules/crate-rules.mjs';
import {
crateLayoutLayerNames,
crateLayoutRules,
cratePathForName,
} from './rules/crate-layout.mjs';
import { checkTuiLegacyBackendRatchet } from './tui-boundary-ratchet.mjs';
import {
acpClosedFeatureProfileRules,
coreClosedFeatureProfileRules,
coreProductFullFeatureAssemblyRule,
optionalDependencyFeatureOwnerRules,
ownerCrateFeatureAssemblyRules,
reviewedOptionalDependencyAggregateFeatures,
} from './rules/feature-rules.mjs';
import {
facadeOnlyFiles,
forbiddenContentRules,
forbiddenContentUnderRules,
publicApiAllowlistRules,
publicApiContractSlices,
requiredContentRules,
} from './rules/source-rules.mjs';
import { runManifestParserSelfTest } from './self-test.mjs';
import {
featureReferencesDependency,
featureReferencesFeature,
featureReferencesOptionalDependencyOwner,
unexpectedDependencyOwnerFeatures,
unexpectedReachableLocalFeatures,
} from './manifest-feature-helpers.mjs';
import { checkCargoDependencyBoundariesSafely } from './cargo-dependency-boundaries.mjs';
import { checkPeerCommandPolicySync } from './peer-command-policy.mjs';
import {
listTrackedRustRepoPaths,
scanForbiddenContentUnder,
} from './source-content-checks.mjs';
import {
agentRuntimeIntegrationTestTargets,
checkAgentRuntimeIntegrationTestTopology,
checkCliIntegrationTestTopology,
checkExternalSourceIntegrationTestTopologies,
checkReviewedIntegrationTestTopologies,
cliIntegrationTestTargets,
validateExplicitIntegrationTestTopology,
} from './explicit-test-topology.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..', '..');
const failures = [];
const publicApiContractSliceSet = new Set(publicApiContractSlices);
function toRepoPath(path) {
return relative(ROOT, path).replace(/\\/g, '/');
}
function readText(path) {
return readFileSync(path, 'utf8');
}
function repoPathToFsPath(repoPath) {
return join(ROOT, ...repoPath.split('/'));
}
function crateDirForName(crateName) {
const repoPath = cratePathForName(crateName);
if (!repoPath) {
failures.push({
path: ROOT,
line: 1,
message: `missing crate layout rule for ${crateName}`,
});
return join(ROOT, 'src', 'crates', crateName);
}
return repoPathToFsPath(repoPath);
}
function walkFiles(dir, visit) {
for (const entry of readdirSync(dir)) {
const path = join(dir, entry);
const stat = statSync(path);
if (stat.isDirectory()) {
walkFiles(path, visit);
continue;
}
visit(path);
}
}
function rustImportName(depName) {
return depName.replace(/-/g, '_');
}
function escapeRegex(text) {
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function regexSourceContainsContract(ruleText, contract) {
const slashEscapedContract = contract.replaceAll('/', '\\/');
const escapedContract = escapeRegex(contract);
const slashEscapedRegexContract = escapedContract.replaceAll('/', '\\/');
return (
ruleText.includes(contract) ||
ruleText.includes(slashEscapedContract) ||
ruleText.includes(escapedContract) ||
ruleText.includes(slashEscapedRegexContract)
);
}
function manifestDependencyHeaderPattern(depName) {
const depPattern = `(?:${escapeRegex(depName)}|"${escapeRegex(depName)}")`;
return new RegExp(
`^\\[(?:target\\.[^\\]]+\\.)?(?:dependencies|dev-dependencies|build-dependencies)\\.${depPattern}\\]$`,
);
}
function isManifestDependencyDeclaration(trimmedLine, depName) {
const isInlineDependency = new RegExp(`^${escapeRegex(depName)}\\s*=`).test(trimmedLine);
const isDependencyTable = manifestDependencyHeaderPattern(depName).test(trimmedLine);
return isInlineDependency || isDependencyTable;
}
function isDependencyListHeader(trimmedLine, options = {}) {
const workspacePrefix = options.includeWorkspace ? '(?:workspace\\.)?' : '';
return new RegExp(`^\\[(?:target\\.[^\\]]+\\.)?${workspacePrefix}(?:dependencies|dev-dependencies|build-dependencies)\\]$`).test(trimmedLine);
}
function dependencyKindForHeader(trimmedLine, options = {}) {
const workspacePrefix = options.includeWorkspace ? '(?:workspace\\.)?' : '';
const match = trimmedLine.match(
new RegExp(`^\\[(?:target\\.[^\\]]+\\.)?${workspacePrefix}(dependencies|dev-dependencies|build-dependencies)(?:\\.|\\])`),
);
if (!match || match[1] === 'dependencies') {
return 'normal';
}
return match[1] === 'dev-dependencies' ? 'dev' : 'build';
}
function dependencyTablePattern(options = {}) {
const workspacePrefix = options.includeWorkspace ? '(?:workspace\\.)?' : '';
return new RegExp(`^\\[(?:target\\.[^\\]]+\\.)?${workspacePrefix}(?:dependencies|dev-dependencies|build-dependencies)\\.([A-Za-z0-9_-]+|"[A-Za-z0-9_-]+")\\]$`);
}
function parseManifestDependencies(lines, options = {}) {
const deps = [];
let inDependencyList = false;
let dependencyListKind = 'normal';
let currentTable = null;
let currentInline = null;
const tablePattern = dependencyTablePattern(options);
lines.forEach((line, index) => {
const trimmed = line.trim();
if (trimmed.startsWith('#') || trimmed === '') {
return;
}
if (currentInline) {
currentInline.text.push(trimmed);
if (/\boptional\s*=\s*true\b/.test(trimmed)) {
currentInline.optional = true;
}
if (trimmed.includes('}')) {
currentInline = null;
}
return;
}
const headerMatch = trimmed.match(/^\[(.+)]$/);
if (headerMatch) {
inDependencyList = isDependencyListHeader(trimmed, options);
dependencyListKind = dependencyKindForHeader(trimmed, options);
currentTable = null;
const dependencyTableMatch = trimmed.match(tablePattern);
if (dependencyTableMatch) {
currentTable = {
name: dependencyTableMatch[1].replace(/^"|"$/g, ''),
line: index + 1,
kind: dependencyListKind,
optional: false,
text: [trimmed],
};
deps.push(currentTable);
}
return;
}
if (currentTable) {
currentTable.text.push(trimmed);
if (/\boptional\s*=\s*true\b/.test(trimmed)) {
currentTable.optional = true;
}
return;
}
if (!inDependencyList) {
return;
}
const inlineMatch = trimmed.match(/^([A-Za-z0-9_-]+|"[A-Za-z0-9_-]+")\s*=/);
if (inlineMatch) {
const name = inlineMatch[1].replace(/^"|"$/g, '');
deps.push({
name,
line: index + 1,
kind: dependencyListKind,
optional: /\boptional\s*=\s*true\b/.test(trimmed),
text: [trimmed],
});
if (trimmed.includes('{') && !trimmed.includes('}')) {
currentInline = deps[deps.length - 1];
}
return;
}
});
return deps;
}
function manifestDependencyText(dep) {
return dep?.text?.join('\n') ?? '';
}
function parseManifestFeatures(lines) {
const features = new Map();
let inFeatures = false;
let currentFeature = null;
const appendRefs = (feature, text) => {
const refs = [...text.matchAll(/"([^"]+)"/g)].map((match) => match[1]);
feature.refs.push(...refs);
};
lines.forEach((line, index) => {
const trimmed = line.trim();
if (trimmed.startsWith('#') || trimmed === '') {
return;
}
const headerMatch = trimmed.match(/^\[(.+)]$/);
if (headerMatch) {
inFeatures = trimmed === '[features]';
currentFeature = null;
return;
}
if (!inFeatures) {
return;
}
if (currentFeature) {
appendRefs(currentFeature, trimmed);
if (trimmed.includes(']')) {
currentFeature = null;
}
return;
}
const featureMatch = trimmed.match(/^([A-Za-z0-9_-]+)\s*=\s*(.*)$/);
if (!featureMatch) {
return;
}
const feature = {
name: featureMatch[1],
line: index + 1,
refs: [],
};
appendRefs(feature, featureMatch[2]);
features.set(feature.name, feature);
if (featureMatch[2].includes('[') && !featureMatch[2].includes(']')) {
currentFeature = feature;
}
});
return features;
}
function parseWorkspaceMembers() {
const manifestPath = join(ROOT, 'Cargo.toml');
const lines = readText(manifestPath).split(/\r?\n/);
const members = [];
let inMembers = false;
for (const line of lines) {
const trimmed = line.trim();
if (!inMembers) {
if (trimmed === 'members = [' || trimmed.startsWith('members = [')) {
inMembers = true;
}
}
if (!inMembers) {
continue;
}
for (const match of trimmed.matchAll(/"([^"]+)"/g)) {
members.push(match[1]);
}
if (trimmed.includes(']')) {
break;
}
}
return members;
}
function checkCrateLayoutRules() {
const manifestPath = join(ROOT, 'Cargo.toml');
const requiredCrateNames = new Set(['core', ...noCoreDependencyCrates]);
const layoutCrateNames = new Set();
const layoutPaths = new Set();
const workspaceMembers = new Set(parseWorkspaceMembers());
const expectedWorkspaceCratePaths = new Set(crateLayoutRules.map((rule) => rule.path));
for (const rule of crateLayoutRules) {
if (!crateLayoutLayerNames.includes(rule.layer)) {
failures.push({
path: manifestPath,
line: 1,
message: `crate layout rule for ${rule.crateName} uses unknown layer ${rule.layer}`,
});
}
if (layoutCrateNames.has(rule.crateName)) {
failures.push({
path: manifestPath,
line: 1,
message: `duplicate crate layout rule for ${rule.crateName}`,
});
}
if (layoutPaths.has(rule.path)) {
failures.push({
path: manifestPath,
line: 1,
message: `duplicate crate layout path ${rule.path}`,
});
}
layoutCrateNames.add(rule.crateName);
layoutPaths.add(rule.path);
const crateManifestPath = repoPathToFsPath(`${rule.path}/Cargo.toml`);
if (!existsSync(crateManifestPath)) {
failures.push({
path: manifestPath,
line: 1,
message: `crate layout path for ${rule.crateName} is missing Cargo.toml: ${rule.path}`,
});
}
if (!workspaceMembers.has(rule.path)) {
failures.push({
path: manifestPath,
line: 1,
message: `workspace members must include crate layout path: ${rule.path}`,
});
}
}
for (const crateName of requiredCrateNames) {
if (!layoutCrateNames.has(crateName)) {
failures.push({
path: manifestPath,
line: 1,
message: `crate layout rules must cover workspace owner crate: ${crateName}`,
});
}
}
for (const member of workspaceMembers) {
if (!member.startsWith('src/crates/')) {
continue;
}
if (!expectedWorkspaceCratePaths.has(member)) {
failures.push({
path: manifestPath,
line: 1,
message: `workspace crate member must use an approved layered path: ${member}`,
});
}
}
const cratesRoot = join(ROOT, 'src', 'crates');
const allowedRootEntries = new Set([...crateLayoutLayerNames, 'LOGGING.md']);
for (const entry of readdirSync(cratesRoot)) {
if (allowedRootEntries.has(entry)) {
continue;
}
const entryPath = join(cratesRoot, entry);
if (statSync(entryPath).isDirectory() && existsSync(join(entryPath, 'Cargo.toml'))) {
failures.push({
path: entryPath,
line: 1,
message: `workspace crate must live under a layer directory, not directly under src/crates: ${entry}`,
});
}
}
}
function forbiddenRuleTextForPath(path) {
return forbiddenContentRules
.filter((rule) => rule.path === path)
.flatMap((rule) => rule.patterns)
.map((pattern) => pattern.regex.source)
.join('\n');
}
function checkCargoManifest(crateDir) {
checkForbiddenManifestDeps(crateDir, ['bitfun-core'], () => {
return 'extracted crate must not depend on bitfun-core';
});
}
function checkForbiddenManifestDeps(crateDir, forbiddenDeps, messageForDep) {
const manifestPath = join(crateDir, 'Cargo.toml');
const deps = parseManifestDependencies(readText(manifestPath).split(/\r?\n/));
for (const dep of deps) {
const forbidden = matchingForbiddenDependency(dep, forbiddenDeps);
if (forbidden) {
failures.push({
path: manifestPath,
line: dep.line,
message: messageForDep(forbidden),
});
}
}
}
function checkForbiddenNonOptionalManifestDeps(crateDir, forbiddenDeps, messageForDep) {
const manifestPath = join(crateDir, 'Cargo.toml');
const deps = parseManifestDependencies(readText(manifestPath).split(/\r?\n/));
for (const dep of deps) {
const forbidden = matchingForbiddenDependency(dep, forbiddenDeps);
if (!dep.optional && forbidden) {
failures.push({
path: manifestPath,
line: dep.line,
message: messageForDep(forbidden),
});
}
}
}
function matchingForbiddenDependency(dep, forbiddenDeps) {
return forbiddenDeps.find((dependencyName) => manifestDependencyMatches(dep, dependencyName));
}
function manifestDependencyMatches(dep, dependencyName) {
const text = manifestDependencyText(dep);
return dep.name === dependencyName || new RegExp(`\\bpackage\\s*=\\s*["']${escapeRegex(dependencyName)}["']`).test(text);
}
function manifestDependencyUsesWorkspace(dep) {
return /\bworkspace\s*=\s*true\b/.test(manifestDependencyText(dep));
}
function collectForbiddenWorkspaceDependencyAliases(rule) {
const workspaceManifestPath = repoPathToFsPath(rule.workspaceManifestPath ?? 'Cargo.toml');
if (!existsSync(workspaceManifestPath)) {
return new Map();
}
const deps = parseManifestDependencies(readText(workspaceManifestPath).split(/\r?\n/), {
includeWorkspace: true,
});
const aliases = new Map();
for (const dep of deps) {
const matchedDep = rule.dependencyNames.find((dependencyName) =>
manifestDependencyMatches(dep, dependencyName),
);
if (matchedDep) {
aliases.set(dep.name, { dep, matchedDep, workspaceManifestPath });
}
}
return aliases;
}
function checkForbiddenManifestDependencyRule(rule) {
const allowManifestPaths = new Set(rule.allowManifestPaths ?? []);
const workspaceAliases = collectForbiddenWorkspaceDependencyAliases(rule);
if (rule.forbidWorkspaceAliases !== false) {
for (const { dep, matchedDep, workspaceManifestPath } of workspaceAliases.values()) {
failures.push({
path: workspaceManifestPath,
line: dep.line,
message: `${rule.reason}; workspace dependency aliases must not point to ${matchedDep}: ${dep.name}`,
});
}
}
for (const repoDir of rule.scanRoots) {
walkFiles(repoPathToFsPath(repoDir), (path) => {
if (!path.endsWith('Cargo.toml')) {
return;
}
const repoPath = toRepoPath(path);
if (allowManifestPaths.has(repoPath)) {
return;
}
const deps = parseManifestDependencies(readText(path).split(/\r?\n/));
for (const dep of deps) {
const matchedDep = rule.dependencyNames.find((dependencyName) =>
manifestDependencyMatches(dep, dependencyName),
);
const workspaceAlias = workspaceAliases.get(dep.name);
if (!matchedDep && !(workspaceAlias && manifestDependencyUsesWorkspace(dep))) {
continue;
}
failures.push({
path,
line: dep.line,
message: `${rule.reason}; ${rule.message}: ${
matchedDep ?? `${dep.name} -> ${workspaceAlias.matchedDep}`
}`,
});
}
});
}
}
function checkOptionalDependencyFeatureOwners(crateDir, rule) {
const manifestPath = join(crateDir, 'Cargo.toml');
const repoManifestPath = toRepoPath(manifestPath);
const lines = readText(manifestPath).split(/\r?\n/);
const deps = parseManifestDependencies(lines);
const normalDeps = deps.filter((dep) => dep.kind === 'normal');
const depsByName = new Map(normalDeps.map((dep) => [dep.name, dep]));
const features = parseManifestFeatures(lines);
const reviewedAggregateFeatures = new Set([
...reviewedOptionalDependencyAggregateFeatures(repoManifestPath),
...(rule.reviewedAggregateFeatures ?? []),
]);
const declaredOwnerDeps = new Set(rule.dependencies.map((dependency) => dependency.depName));
for (const dependency of rule.dependencies) {
const dep = depsByName.get(dependency.depName);
if (!dep) {
failures.push({
path: manifestPath,
line: 1,
message: `${rule.reason}; missing optional dependency: ${dependency.depName}`,
});
continue;
}
if (!dep.optional) {
failures.push({
path: manifestPath,
line: dep.line,
message: `${rule.reason}; dependency must be optional: ${dependency.depName}`,
});
}
for (const featureName of dependency.ownerFeatures) {
const feature = features.get(featureName);
if (!feature) {
failures.push({
path: manifestPath,
line: dep?.line ?? 1,
message: `${rule.reason}; missing owner feature ${featureName} for ${dependency.depName}`,
});
continue;
}
if (!featureReferencesOptionalDependencyOwner(feature, dependency.depName)) {
failures.push({
path: manifestPath,
line: feature.line,
message: `${rule.reason}; ${featureName} must explicitly enable ${dependency.depName}`,
});
}
}
for (const [featureName, feature] of unexpectedDependencyOwnerFeatures(
features,
dependency,
reviewedAggregateFeatures,
)) {
failures.push({
path: manifestPath,
line: feature.line,
message: `${rule.reason}; ${featureName} enables ${dependency.depName} but is missing from its owner feature coverage`,
});
}
}
const profileRule = dependencyProfileRules.find((profile) => profile.crateName === rule.crateName);
const depsRequiringOwner = new Set(profileRule?.forbiddenNonOptionalDeps ?? []);
const uncoveredDeps = new Map();
for (const dep of normalDeps) {
if (!dep.optional || !depsRequiringOwner.has(dep.name) || declaredOwnerDeps.has(dep.name)) {
continue;
}
if (!uncoveredDeps.has(dep.name)) {
uncoveredDeps.set(dep.name, dep);
}
}
for (const [depName, dep] of uncoveredDeps.entries()) {
failures.push({
path: manifestPath,
line: dep.line,
message: `${rule.reason}; optional runtime dependency must declare owner feature coverage: ${depName}`,
});
}
}
function checkCoreProductFullFeatureAssembly(rule) {
const manifestPath = repoPathToFsPath(rule.manifestPath);
const features = parseManifestFeatures(readText(manifestPath).split(/\r?\n/));
const productFull = features.get(rule.featureName);
if (!productFull) {
failures.push({
path: manifestPath,
line: 1,
message: `${rule.reason}; missing ${rule.featureName} feature declaration`,
});
return;
}
for (const featureName of rule.requiredFeatureRefs) {
if (!featureReferencesFeature(productFull, featureName)) {
failures.push({
path: manifestPath,
line: productFull.line,
message: `${rule.reason}; ${rule.featureName} must explicitly enable ${featureName}`,
});
}
}
}
function checkClosedFeatureProfile(rule) {
const manifestPath = repoPathToFsPath(rule.manifestPath);
const features = parseManifestFeatures(readText(manifestPath).split(/\r?\n/));
const feature = features.get(rule.featureName);
if (!feature) {
failures.push({
path: manifestPath,
line: 1,
message: `${rule.reason}; missing ${rule.featureName} feature declaration`,
});
return;
}
for (const reference of rule.requiredFeatureRefs) {
if (!feature.refs.includes(reference)) {
failures.push({
path: manifestPath,
line: feature.line,
message: `${rule.reason}; ${rule.featureName} must explicitly enable ${reference}`,
});
}
}
if (!rule.exact) {
return;
}
const allowedReferences = new Set(rule.requiredFeatureRefs);
for (const reference of feature.refs) {
if (!allowedReferences.has(reference)) {
failures.push({
path: manifestPath,
line: feature.line,
message: `${rule.reason}; ${rule.featureName} must not enable ${reference}`,
});
}
}
const allowedLocalFeatures = new Set(
[
...rule.requiredFeatureRefs,
...(rule.allowedTransitiveFeatureRefs ?? []),
].filter((reference) => features.has(reference)),
);
for (const unexpected of unexpectedReachableLocalFeatures(
features,
rule.featureName,
allowedLocalFeatures,
)) {
failures.push({
path: manifestPath,
line: features.get(unexpected.featureName)?.line ?? feature.line,
message:
`${rule.reason}; ${rule.featureName} must not reach local feature `
+ `${unexpected.featureName} via ${unexpected.path.join(' -> ')}`,
});
}
}
function checkOwnerCrateFeatureAssembly(rule) {
const manifestPath = repoPathToFsPath(rule.manifestPath);
const features = parseManifestFeatures(readText(manifestPath).split(/\r?\n/));
const allowedProductFullFeatures = new Set(rule.requiredProductFullFeatures);
const defaultFeature = features.get('default');
if (!defaultFeature) {
failures.push({
path: manifestPath,
line: 1,
message: `${rule.reason}; missing default feature declaration`,
});
} else if (defaultFeature.refs.length > 0) {
failures.push({
path: manifestPath,
line: defaultFeature.line,
message: `${rule.reason}; default feature must remain empty`,
});
}
const productFull = features.get('product-full');
if (!productFull) {
failures.push({
path: manifestPath,
line: 1,
message: `${rule.reason}; missing product-full feature declaration`,
});
return;
}
for (const featureName of rule.requiredProductFullFeatures) {
if (!featureReferencesFeature(productFull, featureName)) {
failures.push({
path: manifestPath,
line: productFull.line,
message: `${rule.reason}; product-full must explicitly enable ${featureName}`,
});
}
}
for (const featureName of productFull.refs) {
if (!allowedProductFullFeatures.has(featureName)) {
failures.push({
path: manifestPath,
line: productFull.line,
message: `${rule.reason}; product-full must not include undeclared feature group ${featureName}`,
});
}
}
}
function checkRustImports(crateDir) {
const srcDir = join(crateDir, 'src');
try {
if (!statSync(srcDir).isDirectory()) {
return;
}
} catch {
return;
}
walkFiles(srcDir, (path) => {
if (!path.endsWith('.rs')) {
return;
}
const lines = readText(path).split(/\r?\n/);
lines.forEach((line, index) => {
if (/\bbitfun_core::/.test(line)) {
failures.push({
path,
line: index + 1,
message: 'extracted crate must not import bitfun_core',
});
}
});
});
}
function checkForbiddenRustImports(crateDir, forbiddenDeps, messageForDep) {
const srcDir = join(crateDir, 'src');
try {
if (!statSync(srcDir).isDirectory()) {
return;
}
} catch {
return;
}
const forbiddenImports = forbiddenDeps.map((dep) => ({
dep,
pattern: new RegExp(`\\b${escapeRegex(rustImportName(dep))}::`),
}));
walkFiles(srcDir, (path) => {
if (!path.endsWith('.rs')) {
return;
}
const lines = readText(path).split(/\r?\n/);
lines.forEach((line, index) => {
for (const forbidden of forbiddenImports) {
if (forbidden.pattern.test(line)) {
failures.push({
path,
line: index + 1,
message: messageForDep(forbidden.dep),
});
}
}
});
});
}
function createFacadeLineChecker(importPrefix) {
let inPubUseBlock = false;
const escapedPrefix = escapeRegex(importPrefix);
const singleReexportPattern = new RegExp(
`^pub use ${escapedPrefix}(?:::[A-Za-z_][A-Za-z0-9_]*)*(?:::\\*)?;$`,
);
const blockItemPattern = /^[A-Za-z_][A-Za-z0-9_]*(?:,\s*[A-Za-z_][A-Za-z0-9_]*)*,?$/;
const blockStart = `pub use ${importPrefix}::{`;
const checker = (line) => {
const trimmed = line.trim();
if (
trimmed === '' ||
trimmed.startsWith('//') ||
trimmed.startsWith('/*') ||
trimmed.startsWith('*') ||
trimmed.startsWith('*/')
) {
return true;
}
if (inPubUseBlock) {
if (trimmed === '};') {
inPubUseBlock = false;
return true;
}
return blockItemPattern.test(trimmed);
}
if (singleReexportPattern.test(trimmed)) {
return true;
}
if (trimmed.startsWith(blockStart)) {
if (trimmed.endsWith('};')) {
return true;
}
if (trimmed.endsWith('{')) {
inPubUseBlock = true;
return true;
}
}
return false;
};
checker.isComplete = () => !inPubUseBlock;
return checker;
}
function checkFacadeOnlyFile(repoPath, importPrefix, reason) {
const path = repoPathToFsPath(repoPath);
const acceptsLine = createFacadeLineChecker(importPrefix);
const lines = readText(path).split(/\r?\n/);
lines.forEach((line, index) => {
if (!acceptsLine(line)) {
failures.push({
path,
line: index + 1,
message: reason,
});
}
});
if (!acceptsLine.isComplete()) {
failures.push({
path,
line: lines.length,
message: `${reason}; unterminated pub use block`,
});
}
}
function checkForbiddenContent(repoPath, patterns) {
const path = repoPathToFsPath(repoPath);
const lines = readText(path).split(/\r?\n/);
lines.forEach((line, index) => {
for (const pattern of patterns) {
if (pattern.regex.test(line)) {
failures.push({
path,
line: index + 1,
message: pattern.message,
});
}
}
});
}
function checkRequiredContent(repoPath, patterns, reason) {
const path = repoPathToFsPath(repoPath);
for (const pattern of patterns) {
const patternPath = pattern.path ? repoPathToFsPath(pattern.path) : path;
const text = readText(patternPath);
if (!pattern.regex.test(text)) {
failures.push({
path: patternPath,
line: 1,
message: `${reason}; ${pattern.message}`,
});
}
}
}
function collectRustUseReexportSymbols(usePath) {
const blockMatch = usePath.match(/\{([\s\S]*)\}$/);
if (blockMatch) {
const prefix = usePath.slice(0, blockMatch.index).replace(/::$/, '');
return blockMatch[1].split(',').flatMap((symbol) => {
symbol = symbol.trim();
return symbol ? collectRustUseReexportSymbols(`${prefix}::${symbol}`) : [];
});
}
const aliasMatch = usePath.match(/\bas\s+([A-Za-z_][A-Za-z0-9_]*)$/);
const symbol =
aliasMatch?.[1] ??
usePath
.split('::')
.map((part) => part.trim())
.filter(Boolean)
.pop();
return symbol ? [symbol] : [];
}
function collectTopLevelRustPublicSymbols(text) {
const symbols = Array.from(text.matchAll(/\bexternal_subagent_id!\(\s*([A-Za-z_][A-Za-z0-9_]*)/g), (match) => match[1]);
let braceDepth = 0;
let pendingUsePath = null;
for (const line of text.split(/\r?\n/)) {
const code = line.replace(/\/\/.*$/, '');
if (pendingUsePath) {
pendingUsePath.push(code.trim());
if (code.includes(';')) {
symbols.push(
...collectRustUseReexportSymbols(pendingUsePath.join(' ').replace(/;\s*$/, '')),
);
pendingUsePath = null;
}
continue;
}
if (braceDepth === 0) {
const useMatch = code.match(/^\s*pub\s+use\s+(.+)/);
if (useMatch) {
const usePath = useMatch[1].trim();
if (usePath.includes(';')) {
symbols.push(...collectRustUseReexportSymbols(usePath.replace(/;\s*$/, '')));
} else {
pendingUsePath = [usePath];
}
continue;
}
const match = line.match(
/^\s*pub\s+(?:(?:async|unsafe)\s+)*(?:(?:const\s+fn)|fn|type|struct|enum|trait|mod|const|static)\s+([A-Za-z_][A-Za-z0-9_]*)\b/,
);
if (match) {
symbols.push(match[1]);
}
}
braceDepth += (code.match(/\{/g) || []).length;
braceDepth -= (code.match(/\}/g) || []).length;
if (braceDepth < 0) {
braceDepth = 0;
}
}
return symbols;
}
function collectPluginRootReexports(text) {
const symbols = [];
const publicName = (symbol) => symbol.split(/\s+as\s+/).pop().trim();
const blockRegex = /\bpub\s+use\s+(?:crate::|self::)?plugin::\{([\s\S]*?)\};/g;
for (const match of text.matchAll(blockRegex)) {
symbols.push(
...match[1]
.split(',')
.map((symbol) => symbol.trim())
.filter(Boolean)
.map(publicName),
);
}
const singleRegex = /\bpub\s+use\s+(?:crate::|self::)?plugin::([A-Za-z_][A-Za-z0-9_]*|\*)(?:\s+as\s+([A-Za-z_][A-Za-z0-9_]*))?\s*;/g;
for (const match of text.matchAll(singleRegex)) symbols.push(match[2] || match[1]);
return symbols;
}
const hasPluginWildcardReexport = (text) => /\bpub\s+use\s+(?:crate::|self::)?plugin::\*/.test(text);
function allowedSymbolsForRule(rule, entriesField, symbolsField) {
if (rule[entriesField]) {
return rule[entriesField].map((entry) => entry.symbol);
}
return rule[symbolsField] || [];
}
function checkPublicApiEntryMetadata(path, entries, reason) {
if (!entries) return;
const fail = (entry, message) =>
failures.push({ path, line: 1, message: `${reason}; public API entry ${entry.symbol || '<missing>'} ${message}` });
const requiredFields = ['symbol', 'owner', 'consumer', 'verification', 'p0', 'contractSlice', 'rationale', 'exit'];
for (const entry of entries) {
for (const field of requiredFields) {
if (typeof entry[field] !== 'string' || entry[field].trim().length === 0) {
fail(entry, `is missing ${field}`);
}
}
if (typeof entry.wireImpact !== 'boolean') {
fail(entry, 'must declare wireImpact');
}
if (!publicApiContractSliceSet.has(entry.contractSlice)) {
fail(entry, 'has unknown contractSlice');
}
}
}
function compareSymbolAllowlist(path, actualSymbols, allowedSymbols, reason) {
const allowed = new Set(allowedSymbols);
const actual = new Set(actualSymbols);
for (const symbol of actual) {
if (!allowed.has(symbol)) {
failures.push({
path,
line: 1,
message: `${reason}; unexpected public symbol: ${symbol}`,
});
}
}
for (const symbol of allowed) {
if (!actual.has(symbol)) {
failures.push({
path,
line: 1,
message: `${reason}; missing public symbol: ${symbol}`,
});
}
}
}
function checkPublicApiAllowlist(rule) {
const path = repoPathToFsPath(rule.path);
const text = readText(path);
checkPublicApiEntryMetadata(path, rule.allowedSymbolEntries, rule.reason);
checkPublicApiEntryMetadata(path, rule.allowedPluginReexportEntries, rule.reason);
if (rule.allowedSymbols || rule.allowedSymbolEntries) {
compareSymbolAllowlist(
path,
collectTopLevelRustPublicSymbols(text),
allowedSymbolsForRule(rule, 'allowedSymbolEntries', 'allowedSymbols'),
rule.reason,
);
}
if (rule.allowedPluginReexports || rule.allowedPluginReexportEntries) {
compareSymbolAllowlist(
path,
collectPluginRootReexports(text),
allowedSymbolsForRule(rule, 'allowedPluginReexportEntries', 'allowedPluginReexports'),
rule.reason,
);
if (hasPluginWildcardReexport(text)) {
failures.push({
path,
line: 1,
message: `${rule.reason}; wildcard plugin re-export is forbidden`,
});
}
}
}
function checkForbiddenContentUnder(repoDir, patterns, reason, trackedRustRepoPaths) {
const rule = { path: repoDir, patterns };
for (const finding of scanForbiddenContentUnder(ROOT, rule, trackedRustRepoPaths)) {
failures.push({
path: finding.path,
line: finding.line,
message: `${reason}; ${finding.message}`,
});
}
}
export function runCoreBoundaryCheck() {
failures.length = 0;
if (process.env.BITFUN_BOUNDARY_CHECK_SELF_TEST === '1') {
runManifestParserSelfTest({
isManifestDependencyDeclaration,
parseManifestDependencies,
manifestDependencyMatches,
matchingForbiddenDependency,
coreClosedFeatureProfileRules,
acpClosedFeatureProfileRules,
coreProductFullFeatureAssemblyRule,
ownerCrateFeatureAssemblyRules,
parseManifestFeatures,
optionalDependencyFeatureOwnerRules,
lightweightBoundaryRules,
dependencyProfileRules,
forbiddenManifestDependencyRules,
noCoreDependencyCrates,
requiredContentRules,
forbiddenContentRules,
forbiddenContentUnderRules,
publicApiAllowlistRules,
publicApiContractSlices,
facadeOnlyFiles,
forbiddenRuleTextForPath,
regexSourceContainsContract,
collectTopLevelRustPublicSymbols,
collectPluginRootReexports,
hasPluginWildcardReexport,
createFacadeLineChecker,
escapeRegex,
validateExplicitIntegrationTestTopology,
agentRuntimeIntegrationTestTargets,
cliIntegrationTestTargets,
});
console.log('Core boundary check self-test passed.');
return;
}
checkCrateLayoutRules();
failures.push(...checkTuiLegacyBackendRatchet(ROOT));
failures.push(...checkCargoDependencyBoundariesSafely({ root: ROOT, crateLayoutRules }));
failures.push(...checkAgentRuntimeIntegrationTestTopology(ROOT));
failures.push(...checkCliIntegrationTestTopology(ROOT));
failures.push(...checkExternalSourceIntegrationTestTopologies(ROOT), ...checkReviewedIntegrationTestTopologies(ROOT));
failures.push(...checkPeerCommandPolicySync(ROOT));
const trackedRustRepoPaths = listTrackedRustRepoPaths(ROOT);
for (const rule of forbiddenManifestDependencyRules) {
checkForbiddenManifestDependencyRule(rule);
}
for (const crateName of noCoreDependencyCrates) {
const crateDir = crateDirForName(crateName);
checkCargoManifest(crateDir);
checkRustImports(crateDir);
}
for (const rule of lightweightBoundaryRules) {
const crateDir = crateDirForName(rule.crateName);
const messageForDep = (dep) => `${rule.reason}; forbidden dependency: ${dep}`;
checkForbiddenManifestDeps(crateDir, rule.forbiddenDeps, messageForDep);
checkForbiddenRustImports(crateDir, rule.forbiddenDeps, messageForDep);
}
for (const rule of dependencyProfileRules) {
const crateDir = crateDirForName(rule.crateName);
const messageForDep = (dep) =>
`${rule.reason}; ${rule.profileName} forbids non-optional dependency: ${dep}`;
checkForbiddenNonOptionalManifestDeps(crateDir, rule.forbiddenNonOptionalDeps, messageForDep);
}
for (const rule of optionalDependencyFeatureOwnerRules) {
const crateDir = crateDirForName(rule.crateName);
checkOptionalDependencyFeatureOwners(crateDir, rule);
}
checkCoreProductFullFeatureAssembly(coreProductFullFeatureAssemblyRule);
for (const rule of coreClosedFeatureProfileRules) {
checkClosedFeatureProfile(rule);
}
for (const rule of acpClosedFeatureProfileRules) {
checkClosedFeatureProfile(rule);
}
for (const rule of ownerCrateFeatureAssemblyRules) {
checkOwnerCrateFeatureAssembly(rule);
}
for (const facade of facadeOnlyFiles) {
checkFacadeOnlyFile(facade.path, facade.importPrefix, facade.reason);
}
for (const rule of forbiddenContentRules) {
checkForbiddenContent(rule.path, rule.patterns);
}
for (const rule of forbiddenContentUnderRules) {
checkForbiddenContentUnder(rule.path, rule.patterns, rule.reason, trackedRustRepoPaths);
}
for (const rule of requiredContentRules) {
checkRequiredContent(rule.path, rule.patterns, rule.reason);
}
for (const rule of publicApiAllowlistRules) {
checkPublicApiAllowlist(rule);
}
if (failures.length > 0) {
console.error('Core boundary check failed.');
for (const failure of failures) {
console.error(`${toRepoPath(failure.path)}:${failure.line}: ${failure.message}`);
}
process.exit(1);
}
console.log('Core boundary check passed.');
}