import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
import path from "node:path";

const repoRoot = process.cwd();
const contextRoot = path.join(repoRoot, "packages/agent-runtime/src/context");

const requiredConceptualLayerDirs = [
  "inventory",
  "policy",
  "projection",
  "protocol",
  "protocol/ag-ui",
  "protocol/mastra",
  "source"
];

const requiredSourceSubdomainDirs = [
  "tool-observation",
  "tool-observation/adapters"
];

const requiredFiles = [
  "inventory/context-item.ts",
  "inventory/context-budget.ts",
  "inventory/context-limits.ts",
  "inventory/context-package-builder.ts",
  "inventory/context-package.ts",
  "inventory/context-plan.ts",
  "inventory/context-run-state.ts",
  "inventory/context-source-metadata.ts",
  "inventory/context-text.ts",
  "inventory/context-token-report.ts",
  "policy/context-budget-allocator.ts",
  "policy/context-policy.ts",
  "policy/context-reduction-strategy.ts",
  "policy/context-source-authority-profile.ts",
  "policy/context-source-policy.ts",
  "policy/context-step-planner.ts",
  "policy/context-token-counter.ts",
  "policy/model-context-profile.ts",
  "policy/prompt-token-counter.ts",
  "projection/context-prompt-materializer.ts",
  "projection/context-prompt-message.ts",
  "projection/context-prompt-view.ts",
  "projection/context-source-prompt-materializer.ts",
  "protocol/ag-ui/ag-ui-context-event-sink.ts",
  "protocol/context-protocol-adapter.ts",
  "protocol/context-protocol-event-sink.ts",
  "protocol/mastra/mastra-context-budget-processor.ts",
  "protocol/mastra/mastra-context-compiled-event.ts",
  "protocol/mastra/mastra-context-processor-boundary.ts",
  "protocol/mastra/mastra-context-protocol-adapter.ts",
  "protocol/mastra/mastra-context-runtime-source-processor.ts",
  "protocol/mastra/mastra-custom-data-part-filter-processor.ts",
  "protocol/mastra/mastra-context-prompt-message-adapter.ts",
  "protocol/mastra/mastra-context-source-message.ts",
  "protocol/mastra/mastra-conversation-context-adapter.ts",
  "protocol/mastra/mastra-message-utils.ts",
  "protocol/mastra/mastra-tool-observation-router.ts",
  "protocol/mastra/mastra-provider-prompt-guard-processor.ts",
  "protocol/mastra/mastra-task-state-context-processor.ts",
  "source/long-term-memory-context-source.ts",
  "source/runtime-context-source-boundary.ts",
  "source/runtime-context-source-registry.ts",
  "source/runtime-context-source.ts",
  "source/working-memory-projection-context-source.ts",
  "tool-observation/adapters/base-tool-observation-adapter.ts",
  "tool-observation/adapters/collaboration-tool-observation-adapters.ts",
  "tool-observation/adapters/data-tool-observation-adapters.ts",
  "tool-observation/adapters/mcp-tool-observation-adapter.ts",
  "tool-observation/adapters/schema-tool-observation-adapter.ts",
  "tool-observation/adapters/sql-result-tool-observation-adapter.ts",
  "tool-observation/adapters/task-tool-observation-adapters.ts",
  "tool-observation/adapters/workspace-tool-observation-adapters.ts",
  "tool-observation/default-tool-observation-adapters.ts",
  "tool-observation/tool-observation-adapter-registry.ts",
  "tool-observation/tool-observation-adapter.ts",
  "tool-observation/tool-observation-budget-profile.ts",
  "tool-observation/tool-observation-boundary.ts",
  "tool-observation/tool-observation-dispatcher.ts",
  "tool-observation/tool-observation-history.ts",
  "tool-observation/tool-observation-packager.ts",
  "tool-observation/tool-observation-projection-items.ts",
  "tool-observation/tool-observation-projection-policy.ts",
  "tool-observation/tool-observation-run-scope.ts"
];

const bannedLegacyPaths = [
  "adapters",
  "context-budget-allocator.ts",
  "context-limits.ts",
  "context-budget-processor.ts",
  "context-orchestrator.ts",
  "context-package-builder.ts",
  "context-package.ts",
  "context-policy.ts",
  "context-reduction-strategy.ts",
  "context-run-state.ts",
  "context-source-registry.ts",
  "context-text-policy.ts",
  "defaults.ts",
  "mastra-message-utils.ts",
  "model-context-profile.ts",
  "policy/context-planner.ts",
  "prompt-token-counter.ts",
  "provider-prompt-guard-processor.ts",
  "schema-context-adapter.ts",
  "sql-result-context-adapter.ts",
  "step-context-planner.ts",
  "task-state-context-processor.ts",
  "token-counter.ts",
  "protocol/mastra/context-budget-processor.ts",
  "protocol/mastra/context-runtime-source-processor.ts",
  "protocol/mastra/mastra-conversation-message-context-source.ts",
  "protocol/mastra/provider-prompt-guard-processor.ts",
  "protocol/mastra/task-state-context-processor.ts",
  "source/mastra-context-runtime-source-processor.ts",
  "source/context-source-metadata.ts",
  "source/conversation-messages-context-source.ts",
  "tool-observation/tool-observation-router.ts",
  "tool-observation-router.ts",
  "tool-result-adapter.ts",
  "tool-result-dispatcher.ts"
];

const codeRoots = [
  "apps/api/src",
  "packages/agent-runtime/src",
  "scripts"
];

const bannedCodePatterns = [
  { name: "ContextSourceAdapter", pattern: /\bContextSourceAdapter\b/ },
  { name: "ToolResultAdapter", pattern: /\bToolResultAdapter\b/ },
  { name: "ToolResultDispatcher", pattern: /\bToolResultDispatcher\b/ },
  { name: "ContextOrchestrator", pattern: /\bContextOrchestrator\b/ },
  { name: "ContextPlanner", pattern: /\bContextPlanner\b/ },
  { name: "ContextProjection type", pattern: /\bContextProjection\b(?!Builder|Input)/ },
  { name: "MastraConversationMessageContextSource", pattern: /\bMastraConversationMessageContextSource\b/ },
  { name: "MastraConversationMessageContextSourceOptions", pattern: /\bMastraConversationMessageContextSourceOptions\b/ },
  { name: "createMastraConversationMessageContextItems", pattern: /\bcreateMastraConversationMessageContextItems\b/ },
  { name: "unprefixed ContextBudgetProcessor", pattern: /\bContextBudgetProcessor\b/ },
  { name: "unprefixed ContextRuntimeSourceProcessor", pattern: /\bContextRuntimeSourceProcessor\b/ },
  { name: "unprefixed ProviderPromptGuardProcessor", pattern: /\bProviderPromptGuardProcessor\b/ },
  { name: "unprefixed TaskStateContextProcessor", pattern: /\bTaskStateContextProcessor\b/ },
  { name: "StepContextPlanner", pattern: /\bStepContextPlanner\b/ },
  { name: "bare PromptView", pattern: /(?<!Context)\bPromptView\b/ },
  { name: "bare TokenCounter", pattern: /(?<!Context)(?<!Prompt)\bTokenCounter\b/ },
  { name: "packageToolResult", pattern: /\bpackageToolResult\b/ },
  { name: "legacy context/adapters import", pattern: /context\/adapters/ },
  { name: "legacy context/defaults import", pattern: /context\/defaults/ },
  { name: "legacy context root processor import", pattern: /context\/context-budget-processor/ },
  { name: "legacy task-state processor import", pattern: /context\/task-state-context-processor/ },
  { name: "legacy mastra utils import", pattern: /context\/mastra-message-utils/ },
  { name: "legacy context policy import", pattern: /context\/context-policy/ },
  { name: "legacy context allocator import", pattern: /context\/context-budget-allocator/ },
  { name: "legacy reduction import", pattern: /context\/context-reduction-strategy/ },
  { name: "legacy model profile import", pattern: /context\/model-context-profile/ },
  { name: "legacy prompt counter import", pattern: /context\/prompt-token-counter/ },
  { name: "legacy provider guard import", pattern: /context\/provider-prompt-guard-processor/ },
  { name: "legacy root tool observation router import", pattern: /context\/tool-observation-router/ },
  { name: "legacy tool observation router import", pattern: /context\/tool-observation\/tool-observation-router/ },
  { name: "legacy tool result dispatcher import", pattern: /context\/tool-result-dispatcher/ },
  { name: "legacy tool result adapter import", pattern: /context\/tool-result-adapter/ },
  { name: "legacy schema context adapter import", pattern: /schema-context-adapter/ },
  { name: "legacy SQL context adapter import", pattern: /sql-result-context-adapter/ },
  { name: "contextPackageToItems", pattern: /\bcontextPackageToItems\b/ }
];

const bannedDocPatterns = [
  { name: "Planning Layer", pattern: /\bPlanning Layer\b/i },
  { name: "context/planning", pattern: /context\/planning/ },
  { name: "MemorySourceAdapter", pattern: /\bMemorySourceAdapter\b/ },
  { name: "Mastra Memory Adapter", pattern: /\bMastra Memory Adapter\b/ },
  { name: "KnowledgeSourceAdapter", pattern: /\bKnowledgeSourceAdapter\b/ },
  { name: "Knowledge Source Adapter", pattern: /\bKnowledge Source Adapter\b/ },
  { name: "MastraConversationMessageContextSource", pattern: /\bMastraConversationMessageContextSource\b/ },
  { name: "SystemInstructionAdapter", pattern: /\bSystemInstructionAdapter\b/ },
  { name: "ToolSchemaAdapter", pattern: /\bToolSchemaAdapter\b/ },
  { name: "ToolObservationPackage", pattern: /\bToolObservationPackage\b/ },
  { name: "ContextAdapters alias", pattern: /\bContextAdapters\b/ }
];

const failures = [];

assertContextRootHasOnlyDirectories();
assertRequiredConceptualLayerDirs();
assertRequiredSourceSubdomainDirs();
assertRequiredFiles();
assertLegacyPathsAbsent();
assertCodePatternsAbsent();
assertInventoryLayerDoesNotDependOnUpperLayers();
assertPolicyLayerDoesNotDependOnUpperLayers();
assertProjectionLayerDoesNotDependOnPolicyOrProtocols();
assertSourcePromptMaterializationPolicyIsExplicit();
assertSourceLayerDoesNotDependOnUpperLayers();
assertRuntimeSourceBoundaryStaysInSourceLayer();
assertToolObservationLayerDoesNotDependOnProtocols();
assertGenericContextPolicyStaysToolAgnostic();
assertContextBudgetAllocatorStaysProfileDriven();
assertToolObservationBudgetProfilesStayInToolLayer();
assertDefaultToolObservationAdaptersStayInToolLayer();
assertToolObservationBoundaryDoesNotLeakInternals();
assertMastraContextProcessorAssemblyStaysInBoundary();
assertRuntimeSourceProcessorDoesNotAcceptSharedAllocator();
assertToolObservationRegistryNamingIsExplicit();
assertToolObservationAssemblyStaysInBoundary();
assertProviderNeutralLayersDoNotDependOnMastra();
assertProviderNeutralLayersDoNotDependOnAgentRuntimeTypes();
assertGenericProtocolContractsStayProtocolNeutral();
assertMastraProtocolUsesContextEventSink();
assertMastraBudgetProcessorUsesInventorySystemMessages();
assertMastraBudgetProcessorUsesProtocolAdapter();
assertMastraBudgetProcessorDelegatesCompiledEventPayload();
assertMastraConversationSourceMessageClassificationIsCentralized();
assertSourcePolicyOwnsPackageCandidateSelection();
assertContextPackageDoesNotOwnFoldedToolObservationProjection();
assertToolObservationHistoryDowngradeStaysOutOfInventory();
assertRuntimeSourceProcessorUsesNarrowRunScope();
assertMastraConversationSourceIsNotRuntimeSource();
assertPolicyCountersDoNotOwnInventoryReports();
assertPolicyPlannerDoesNotReExportInventoryPlans();
assertDocPlanningLayerAbsent();
assertRootIndexDoesNotExportContextInternals();
assertAppsDoNotImportTestingEntryPoint();

if (failures.length > 0) {
  console.error("Context architecture smoke failed:");
  for (const failure of failures) {
    console.error(`- ${failure}`);
  }
  process.exit(1);
}

console.log("Context architecture smoke passed");

function assertContextRootHasOnlyDirectories() {
  const entries = readdirSync(contextRoot, { withFileTypes: true });
  const rootFiles = entries.filter((entry) => entry.isFile()).map((entry) => entry.name);

  if (rootFiles.length > 0) {
    failures.push(`context root must not contain files: ${rootFiles.join(", ")}`);
  }
}

function assertRequiredConceptualLayerDirs() {
  for (const layerDir of requiredConceptualLayerDirs) {
    const absolutePath = path.join(contextRoot, layerDir);
    if (!existsSync(absolutePath) || !statSync(absolutePath).isDirectory()) {
      failures.push(`missing context conceptual layer directory: ${layerDir}`);
    }
  }
}

function assertRequiredSourceSubdomainDirs() {
  for (const subdomainDir of requiredSourceSubdomainDirs) {
    const absolutePath = path.join(contextRoot, subdomainDir);
    if (!existsSync(absolutePath) || !statSync(absolutePath).isDirectory()) {
      failures.push(`missing source-side context subdomain directory: ${subdomainDir}`);
    }
  }
}

function assertRequiredFiles() {
  for (const filePath of requiredFiles) {
    const absolutePath = path.join(contextRoot, filePath);
    if (!existsSync(absolutePath) || !statSync(absolutePath).isFile()) {
      failures.push(`missing required context file: ${filePath}`);
    }
  }
}

function assertLegacyPathsAbsent() {
  for (const legacyPath of bannedLegacyPaths) {
    const absolutePath = path.join(contextRoot, legacyPath);
    if (existsSync(absolutePath)) {
      failures.push(`legacy context path must stay removed: ${legacyPath}`);
    }
  }
}

function assertCodePatternsAbsent() {
  for (const filePath of listFiles(codeRoots, [".ts", ".tsx", ".js", ".mjs"])) {
    if (filePath === import.meta.filename) {
      continue;
    }

    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of bannedCodePatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`legacy code pattern "${rule.name}" found in ${relativePath}`);
      }
    }
  }
}

function assertInventoryLayerDoesNotDependOnUpperLayers() {
  const inventoryRoot = path.join(contextRoot, "inventory");
  const forbiddenPatterns = [
    { name: "policy import", pattern: /(?:\.\.\/)+policy\// },
    { name: "projection import", pattern: /(?:\.\.\/)+projection\// },
    { name: "source import", pattern: /(?:\.\.\/)+source\// },
    { name: "tool observation import", pattern: /(?:\.\.\/)+tool-observation\// },
    { name: "protocol import", pattern: /(?:\.\.\/)+protocol\// },
    { name: "tool observation concept", pattern: /tool-observation/ },
    { name: "ToolObservationProjection", pattern: /\bToolObservationProjection\b/ },
    { name: "source-specific observation naming", pattern: /\bObservation\b|\bobservation\b/ }
  ];

  for (const filePath of listFiles([inventoryRoot], [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`inventory layer must stay foundational; found "${rule.name}" in ${relativePath}`);
      }
    }
  }
}

function assertSourceLayerDoesNotDependOnUpperLayers() {
  const sourceRoot = path.join(contextRoot, "source");
  const runtimeSourcePath = path.join(sourceRoot, "runtime-context-source.ts");
  const runtimeSourceCode = readFileSync(runtimeSourcePath, "utf8");
  const workingMemoryPath = path.join(sourceRoot, "working-memory-projection-context-source.ts");
  const workingMemorySource = readFileSync(workingMemoryPath, "utf8");
  const forbiddenPatterns = [
    { name: "@mastra", pattern: /@mastra\// },
    { name: "MastraDBMessage", pattern: /\bMastraDBMessage\b/ },
    { name: "Mastra processor", pattern: /\bProcessInputStep|\bProcessor</ },
    { name: "policy import", pattern: /(?:\.\.\/)+policy\// },
    { name: "projection import", pattern: /(?:\.\.\/)+projection\// },
    { name: "tool observation import", pattern: /(?:\.\.\/)+tool-observation\// },
    { name: "context protocol import", pattern: /(?:\.\.\/)+protocol\// }
  ];

  for (const filePath of listFiles([sourceRoot], [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`source layer must stay protocol-free; found "${rule.name}" in ${relativePath}`);
      }
    }
  }

  if (!/export\s+interface\s+RuntimeContextSource/.test(runtimeSourceCode)) {
    failures.push("source layer must expose RuntimeContextSource as an interface");
  }

  if (!/export\s+interface\s+WorkingMemoryProjectionReader/.test(workingMemorySource)) {
    failures.push("source layer extension contracts such as WorkingMemoryProjectionReader must be interfaces");
  }
}

function assertPolicyLayerDoesNotDependOnUpperLayers() {
  const policyRoot = path.join(contextRoot, "policy");
  const forbiddenPatterns = [
    { name: "projection import", pattern: /(?:\.\.\/)+projection\// },
    { name: "source import", pattern: /(?:\.\.\/)+source\// },
    { name: "tool observation import", pattern: /(?:\.\.\/)+tool-observation\// },
    { name: "protocol import", pattern: /(?:\.\.\/)+protocol\// }
  ];

  for (const filePath of listFiles([policyRoot], [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`policy layer must not depend on upper layers; found "${rule.name}" in ${relativePath}`);
      }
    }
  }
}

function assertProjectionLayerDoesNotDependOnPolicyOrProtocols() {
  const projectionRoot = path.join(contextRoot, "projection");
  const forbiddenPatterns = [
    { name: "policy import", pattern: /(?:\.\.\/)+policy\// },
    { name: "source import", pattern: /(?:\.\.\/)+source\// },
    { name: "tool observation import", pattern: /(?:\.\.\/)+tool-observation\// },
    { name: "protocol import", pattern: /(?:\.\.\/)+protocol\// },
    { name: "source policy import", pattern: /context-source-policy/ }
  ];

  for (const filePath of listFiles([projectionRoot], [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`projection layer must not depend on policy/protocol layers; found "${rule.name}" in ${relativePath}`);
      }
    }
  }
}

function assertSourcePromptMaterializationPolicyIsExplicit() {
  const promptMaterializerPath = path.join(contextRoot, "projection/context-prompt-materializer.ts");
  const promptMaterializerSource = readFileSync(promptMaterializerPath, "utf8");
  const sourceMaterializerPath = path.join(contextRoot, "projection/context-source-prompt-materializer.ts");
  const sourceMaterializerSource = readFileSync(sourceMaterializerPath, "utf8");
  const processorBoundaryPath = path.join(contextRoot, "protocol/mastra/mastra-context-processor-boundary.ts");
  const processorBoundarySource = readFileSync(processorBoundaryPath, "utf8");

  if (!/ContextSourcePromptMaterializer/.test(promptMaterializerSource)) {
    failures.push("ContextPromptMaterializer must delegate source prompt construction to ContextSourcePromptMaterializer");
  }

  if (/role:\s*"user"/.test(promptMaterializerSource) || /id:\s*`context:\$\{groupId\}`/.test(promptMaterializerSource)) {
    failures.push("ContextPromptMaterializer must not hard-code source prompt message shape");
  }

  if (
    !/export\s+interface\s+ContextSourcePromptMaterializer/.test(sourceMaterializerSource) ||
    !/class\s+ContextDefaultSourcePromptMaterializer/.test(sourceMaterializerSource) ||
    !/role\s*=\s*options\.role\s*\?\?\s*"user"/.test(sourceMaterializerSource)
  ) {
    failures.push("projection layer must expose an explicit default source prompt materializer");
  }

  if (
    !/sourceMaterializer\?:\s*ContextSourcePromptMaterializer/.test(processorBoundarySource) ||
    !/new\s+ContextPromptMaterializer\(\{[\s\S]*sourceMaterializer:\s*input\.contextCompilation\.sourceMaterializer/.test(
      processorBoundarySource
    )
  ) {
    failures.push("Mastra context processor boundary must pass configured source materializer into projection");
  }
}

function assertRuntimeSourceBoundaryStaysInSourceLayer() {
  const agentPath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const agentSource = readFileSync(agentPath, "utf8");
  const createDataFoundryBody = agentSource.slice(agentSource.indexOf("export const createDataFoundry"));
  const boundaryPath = path.join(contextRoot, "source/runtime-context-source-boundary.ts");
  const boundarySource = readFileSync(boundaryPath, "utf8");
  const processorBoundaryPath = path.join(contextRoot, "protocol/mastra/mastra-context-processor-boundary.ts");
  const processorBoundarySource = readFileSync(processorBoundaryPath, "utf8");

  if (
    /new\s+RuntimeContextSourceRegistry\(/.test(createDataFoundryBody) ||
    /new\s+LongTermMemoryContextSource\(/.test(createDataFoundryBody) ||
    /new\s+WorkingMemoryProjectionContextSource\(/.test(createDataFoundryBody) ||
    /runtimeSourceRegistry\.register/.test(createDataFoundryBody)
  ) {
    failures.push("createDataFoundry must delegate runtime source registry assembly to the source layer");
  }

  if (!/createDefaultRuntimeContextSourceRegistry/.test(processorBoundarySource)) {
    failures.push("Mastra context processor boundary must call the source-layer runtime registry boundary");
  }

  if (!/additionalSources\?:\s*RuntimeContextSource\[\]/.test(boundarySource)) {
    failures.push("source-layer runtime registry boundary must expose additionalSources for future runtime sources");
  }

  if (!/input\.additionalSources\?\.forEach\(\(source\)\s*=>\s*registry\.register\(source\)\)/.test(boundarySource)) {
    failures.push("source-layer runtime registry boundary must register additional runtime sources");
  }

  if (
    !/additionalRuntimeSources\?:\s*CreateDefaultRuntimeContextSourceRegistryInput\["additionalSources"\]/.test(
      processorBoundarySource
    ) ||
    !/additionalSources:\s*input\.additionalRuntimeSources/.test(processorBoundarySource)
  ) {
    failures.push("Mastra context processor boundary must pass additional runtime sources through source boundary");
  }

  const createDataFoundryInputBlock = agentSource.slice(
    agentSource.indexOf("export type CreateDataFoundryInput"),
    agentSource.indexOf("export const createDataFoundry")
  );

  if (/additionalRuntimeSources\?:/.test(createDataFoundryInputBlock)) {
    failures.push("createDataFoundry public input must not expose runtime source internals");
  }

  if (/additionalToolAdapters\?:|ToolObservationAdapter/.test(createDataFoundryInputBlock)) {
    failures.push("createDataFoundry public input must not expose tool-observation adapter internals");
  }

  if (
    !/createDefaultRuntimeContextSourceRegistry/.test(boundarySource) ||
    !/LongTermMemoryContextSource/.test(boundarySource) ||
    !/WorkingMemoryProjectionContextSource/.test(boundarySource)
  ) {
    failures.push("source layer must own default runtime source registry assembly");
  }
}

function assertToolObservationLayerDoesNotDependOnProtocols() {
  const toolObservationRoot = path.join(contextRoot, "tool-observation");
  const forbiddenPatterns = [
    { name: "source import", pattern: /(?:\.\.\/)+source\// },
    { name: "projection import", pattern: /(?:\.\.\/)+projection\// },
    { name: "protocol import", pattern: /(?:\.\.\/)+protocol\// }
  ];
  const policyCoordinatorPaths = new Set([
    "packages/agent-runtime/src/context/tool-observation/tool-observation-boundary.ts",
    "packages/agent-runtime/src/context/tool-observation/tool-observation-packager.ts"
  ]);
  const policyImportPattern = /(?:\.\.\/)+policy\//;

  for (const filePath of listFiles([toolObservationRoot], [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`tool-observation layer must not depend on source/projection/protocol; found "${rule.name}" in ${relativePath}`);
      }
    }

    if (policyImportPattern.test(source) && !policyCoordinatorPaths.has(relativePath)) {
      failures.push(
        "tool-observation adapters/projection must not depend on policy; " +
          `only tool-observation boundary coordinators may import policy, found in ${relativePath}`
      );
    }
  }
}

function assertGenericContextPolicyStaysToolAgnostic() {
  const filePath = path.join(contextRoot, "policy/context-policy.ts");
  const source = readFileSync(filePath, "utf8");
  const forbiddenPatterns = [
    { name: "data gateway dependency", pattern: /@datafoundry\/data-gateway/ },
    { name: "schema projection policy", pattern: /applySchemaContextPolicy|projectSchemaToolObservation/ },
    { name: "SQL projection policy", pattern: /applySqlModelContextPolicy|projectSqlToolObservation/ },
    { name: "tool observation projection policy", pattern: /ToolObservationProjectionPolicy/ },
    { name: "agent context policy alias", pattern: /AgentContextPolicy/ }
  ];

  for (const rule of forbiddenPatterns) {
    if (rule.pattern.test(source)) {
      failures.push(`generic ContextPolicy must stay tool-agnostic; found "${rule.name}"`);
    }
  }
}

function assertContextBudgetAllocatorStaysProfileDriven() {
  const filePath = path.join(contextRoot, "policy/context-budget-allocator.ts");
  const source = readFileSync(filePath, "utf8");
  const forbiddenPatterns = [
    { name: "schema tool name", pattern: /inspect_schema/ },
    { name: "SQL tool name", pattern: /run_sql_readonly/ },
    { name: "schema limits", pattern: /SCHEMA_MAX_/ },
    { name: "SQL limits", pattern: /SQL_MAX_/ }
  ];

  for (const rule of forbiddenPatterns) {
    if (rule.pattern.test(source)) {
      failures.push(`ContextBudgetAllocator must stay profile-driven; found "${rule.name}"`);
    }
  }
}

function assertToolObservationBudgetProfilesStayInToolLayer() {
  const agentPath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const agentSource = readFileSync(agentPath, "utf8");
  const profilePath = path.join(contextRoot, "tool-observation/tool-observation-budget-profile.ts");
  const profileSource = readFileSync(profilePath, "utf8");

  if (/sourceLimitProfiles:\s*\{/.test(agentSource)) {
    failures.push("createDataFoundry must not inline tool observation source limit profiles");
  }

  if (
    !/DEFAULT_TOOL_OBSERVATION_SOURCE_LIMIT_PROFILES/.test(profileSource) ||
    !/inspect_schema/.test(profileSource) ||
    !/run_sql_readonly/.test(profileSource)
  ) {
    failures.push("tool-observation layer must own default tool source limit profiles");
  }
}

function assertDefaultToolObservationAdaptersStayInToolLayer() {
  const agentPath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const agentSource = readFileSync(agentPath, "utf8");
  const defaultAdaptersPath = path.join(contextRoot, "tool-observation/default-tool-observation-adapters.ts");
  const defaultAdaptersSource = readFileSync(defaultAdaptersPath, "utf8");
  const createDataFoundryBody = agentSource.slice(agentSource.indexOf("export const createDataFoundry"));

  if (
    /new\s+\w+ToolObservationAdapter\(/.test(createDataFoundryBody) ||
    /toolObservationRegistry\.register\(new\s+/.test(createDataFoundryBody) ||
    /registerDefaultToolObservationAdapters/.test(createDataFoundryBody) ||
    !/createToolObservationBoundary/.test(createDataFoundryBody)
  ) {
    failures.push("createDataFoundry must delegate tool observation boundary assembly");
  }

  if (
    !/SchemaToolObservationAdapter/.test(defaultAdaptersSource) ||
    !/SqlResultToolObservationAdapter/.test(defaultAdaptersSource) ||
    !/RetrieveKnowledgeToolObservationAdapter/.test(defaultAdaptersSource) ||
    !/additionalAdapters/.test(defaultAdaptersSource)
  ) {
    failures.push("tool-observation layer must own default adapter registration");
  }
}

function assertToolObservationBoundaryDoesNotLeakInternals() {
  const agentPath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const agentSource = readFileSync(agentPath, "utf8");
  const boundaryPath = path.join(contextRoot, "tool-observation/tool-observation-boundary.ts");
  const boundarySource = readFileSync(boundaryPath, "utf8");

  if (/toolObservationBoundary\.(budgetAllocator|registry)/.test(agentSource)) {
    failures.push("agent assembly must not reach into tool-observation boundary internals");
  }

  if (/budgetAllocator:\s*ContextBudgetAllocator/.test(boundarySource)) {
    failures.push("ToolObservationBoundary must not expose its tool-specific budget allocator");
  }

  if (/registry:\s*ToolObservationAdapterRegistry/.test(boundarySource)) {
    failures.push("ToolObservationBoundary must not expose its adapter registry");
  }
}

function assertMastraContextProcessorAssemblyStaysInBoundary() {
  const agentPath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const agentSource = readFileSync(agentPath, "utf8");
  const createDataFoundryBody = agentSource.slice(agentSource.indexOf("export const createDataFoundry"));
  const processorBoundaryPath = path.join(contextRoot, "protocol/mastra/mastra-context-processor-boundary.ts");
  const processorBoundarySource = readFileSync(processorBoundaryPath, "utf8");
  const forbiddenInAgent = [
    { name: "MastraContextBudgetProcessor", pattern: /new\s+MastraContextBudgetProcessor\(/ },
    { name: "MastraContextRuntimeSourceProcessor", pattern: /new\s+MastraContextRuntimeSourceProcessor\(/ },
    { name: "MastraProviderPromptGuardProcessor", pattern: /new\s+MastraProviderPromptGuardProcessor\(/ },
    { name: "MastraTaskStateContextProcessor", pattern: /new\s+MastraTaskStateContextProcessor\(/ },
    { name: "MastraToolObservationRouter", pattern: /new\s+MastraToolObservationRouter\(/ },
    { name: "ContextPromptMaterializer", pattern: /new\s+ContextPromptMaterializer\(/ },
    { name: "ContextStepPlanner", pattern: /new\s+ContextStepPlanner\(/ },
    { name: "ModelContextProfileRegistry", pattern: /new\s+ModelContextProfileRegistry\(/ },
    { name: "PromptTokenCounter", pattern: /new\s+PromptTokenCounter\(/ },
    { name: "createDefaultContextSourcePolicy", pattern: /createDefaultContextSourcePolicy\(/ },
    { name: "createDefaultRuntimeContextSourceRegistry", pattern: /createDefaultRuntimeContextSourceRegistry\(/ }
  ];
  const requiredInBoundary = [
    "createMastraContextProcessorBoundary",
    "MastraContextBudgetProcessor",
    "MastraContextRuntimeSourceProcessor",
    "MastraProviderPromptGuardProcessor",
    "MastraTaskStateContextProcessor",
    "MastraToolObservationRouter",
    "ContextStepPlanner",
    "ContextPromptMaterializer",
    "createDefaultContextSourcePolicy"
  ];

  if (!/createMastraContextProcessorBoundary\(/.test(createDataFoundryBody)) {
    failures.push("createDataFoundry must delegate Mastra context processor assembly to the protocol boundary");
  }

  for (const rule of forbiddenInAgent) {
    if (rule.pattern.test(createDataFoundryBody)) {
      failures.push(`createDataFoundry must not assemble ${rule.name} directly`);
    }
  }

  for (const symbol of requiredInBoundary) {
    if (!processorBoundarySource.includes(symbol)) {
      failures.push(`Mastra context processor boundary must own ${symbol}`);
    }
  }
}

function assertRuntimeSourceProcessorDoesNotAcceptSharedAllocator() {
  const processorPath = path.join(contextRoot, "protocol/mastra/mastra-context-runtime-source-processor.ts");
  const processorSource = readFileSync(processorPath, "utf8");
  const agentPath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const agentSource = readFileSync(agentPath, "utf8");

  if (/budgetAllocator\?:\s*ContextBudgetAllocator/.test(processorSource)) {
    failures.push("runtime source processor must accept budget options, not shared allocator instances");
  }

  if (/new\s+MastraContextRuntimeSourceProcessor\(\{[\s\S]*budgetAllocator:/m.test(agentSource)) {
    failures.push("agent assembly must not inject shared allocators into runtime source processors");
  }
}

function assertToolObservationRegistryNamingIsExplicit() {
  for (const filePath of listFiles(codeRoots, [".ts", ".tsx", ".js", ".mjs"])) {
    if (filePath === import.meta.filename) {
      continue;
    }

    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    if (
      /(?:const|let|var)\s+sourceRegistry\s*=\s*new\s+ToolObservationAdapterRegistry\(/.test(source) ||
      /new\s+ToolObservationPackager\([^)]*\bsourceRegistry\b/.test(source)
    ) {
      failures.push(
        `ToolObservationAdapterRegistry variables must not be named sourceRegistry in ${relativePath}`
      );
    }
  }
}

function assertToolObservationAssemblyStaysInBoundary() {
  const allowedFiles = new Set([
    "packages/agent-runtime/src/context/tool-observation/tool-observation-boundary.ts",
    "packages/agent-runtime/src/context/protocol/mastra/mastra-context-runtime-source-processor.ts"
  ]);
  const rules = [
    {
      name: "ToolObservationPackager construction",
      pattern: /new\s+ToolObservationPackager\(/
    },
    {
      name: "ToolObservationAdapterRegistry construction",
      pattern: /new\s+ToolObservationAdapterRegistry\(/
    },
    {
      name: "ContextPolicy construction",
      pattern: /new\s+ContextPolicy\(/
    },
    {
      name: "ContextBudgetAllocator construction",
      pattern: /new\s+ContextBudgetAllocator\(/
    }
  ];

  for (const filePath of listFiles(codeRoots, [".ts", ".tsx", ".js", ".mjs"])) {
    if (filePath === import.meta.filename) {
      continue;
    }

    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of rules) {
      if (!rule.pattern.test(source)) {
        continue;
      }

      const isRuntimeAllocator =
        rule.name === "ContextBudgetAllocator construction"
        && relativePath === "packages/agent-runtime/src/context/protocol/mastra/mastra-context-runtime-source-processor.ts";
      const isAllowed = allowedFiles.has(relativePath) && (
        relativePath !== "packages/agent-runtime/src/context/protocol/mastra/mastra-context-runtime-source-processor.ts"
        || isRuntimeAllocator
      );

      if (!isAllowed) {
        failures.push(`${rule.name} must stay inside context boundary assembly, found in ${relativePath}`);
      }
    }
  }
}

function assertProviderNeutralLayersDoNotDependOnMastra() {
  const providerNeutralRoots = [
    path.join(contextRoot, "inventory"),
    path.join(contextRoot, "policy"),
    path.join(contextRoot, "projection"),
    path.join(contextRoot, "source"),
    path.join(contextRoot, "tool-observation")
  ];
  const forbiddenPatterns = [
    { name: "@mastra", pattern: /@mastra\// },
    { name: "MastraDBMessage", pattern: /\bMastraDBMessage\b/ },
    { name: "Mastra processor", pattern: /\bProcessInputStep|\bProcessor</ }
  ];

  for (const filePath of listFiles(providerNeutralRoots, [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(
          `provider-neutral context layer must not depend on Mastra; found "${rule.name}" in ${relativePath}`
        );
      }
    }
  }
}

function assertProviderNeutralLayersDoNotDependOnAgentRuntimeTypes() {
  const providerNeutralRoots = [
    path.join(contextRoot, "inventory"),
    path.join(contextRoot, "policy"),
    path.join(contextRoot, "projection"),
    path.join(contextRoot, "source"),
    path.join(contextRoot, "tool-observation")
  ];
  const forbiddenPatterns = [
    { name: "agent runtime types import", pattern: /(?:\.\.\/)+types\.js/ },
    { name: "AgentRunContext", pattern: /\bAgentRunContext\b/ },
    { name: "AgUiEventEmitter", pattern: /\bAgUiEventEmitter\b/ }
  ];

  for (const filePath of listFiles(providerNeutralRoots, [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(
          `provider-neutral context layer must not depend on agent runtime types; found "${rule.name}" in ${relativePath}`
        );
      }
    }
  }
}

function assertMastraProtocolUsesContextEventSink() {
  const mastraProtocolRoot = path.join(contextRoot, "protocol/mastra");
  const forbiddenPatterns = [
    { name: "@ag-ui/core import", pattern: /@ag-ui\/core/ },
    { name: "agent runtime event helper import", pattern: /(?:\.\.\/)+\.\.\/events\.js|(?:\.\.\/)+events\.js/ },
    { name: "AgUiEventEmitter", pattern: /\bAgUiEventEmitter\b/ },
    { name: "createCustomEvent", pattern: /\bcreateCustomEvent\b/ }
  ];

  for (const filePath of listFiles([mastraProtocolRoot], [".ts"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of forbiddenPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`Mastra context protocol must use ContextProtocolEventSink; found "${rule.name}" in ${relativePath}`);
      }
    }
  }
}

function assertGenericProtocolContractsStayProtocolNeutral() {
  const eventSinkPath = path.join(contextRoot, "protocol/context-protocol-event-sink.ts");
  const eventSinkSource = readFileSync(eventSinkPath, "utf8");
  const adapterPath = path.join(contextRoot, "protocol/context-protocol-adapter.ts");
  const adapterSource = readFileSync(adapterPath, "utf8");
  const forbiddenPatterns = [
    { name: "@ag-ui/core import", pattern: /@ag-ui\/core/ },
    { name: "agent runtime event helper import", pattern: /(?:\.\.\/)+events\.js/ },
    { name: "createCustomEvent", pattern: /\bcreateCustomEvent\b/ },
    { name: "MastraDBMessage", pattern: /\bMastraDBMessage\b/ },
    { name: "BaseEvent", pattern: /\bBaseEvent\b/ }
  ];

  for (const rule of forbiddenPatterns) {
    if (rule.pattern.test(eventSinkSource)) {
      failures.push(`generic ContextProtocolEventSink must stay protocol-neutral; found "${rule.name}"`);
    }
    if (rule.pattern.test(adapterSource)) {
      failures.push(`generic ContextProtocolAdapter must stay protocol-neutral; found "${rule.name}"`);
    }
  }

  if (
    !/export\s+interface\s+ContextProtocolAdapter<TView,\s*TProtocol>/.test(adapterSource) ||
    !/toProtocol\(view:\s*TView\):\s*TProtocol/.test(adapterSource)
  ) {
    failures.push("generic protocol layer must define ContextProtocolAdapter<TView, TProtocol>");
  }

  if (
    !/export\s+interface\s+ContextProtocolEventSink/.test(eventSinkSource) ||
    !/emitContextEvent\(name:\s*string,\s*value:\s*unknown\):\s*void/.test(eventSinkSource)
  ) {
    failures.push("generic protocol layer must define ContextProtocolEventSink");
  }
}

function assertMastraBudgetProcessorUsesInventorySystemMessages() {
  const filePath = path.join(contextRoot, "protocol/mastra/mastra-context-budget-processor.ts");
  const source = readFileSync(filePath, "utf8");

  if (/systemMessages:\s*args\.systemMessages/.test(source)) {
    failures.push("MastraContextBudgetProcessor must project systemMessages from ContextPackage inventory");
  }
}

function assertMastraBudgetProcessorUsesProtocolAdapter() {
  const budgetProcessorPath = path.join(contextRoot, "protocol/mastra/mastra-context-budget-processor.ts");
  const budgetProcessorSource = readFileSync(budgetProcessorPath, "utf8");
  const protocolAdapterPath = path.join(contextRoot, "protocol/mastra/mastra-context-protocol-adapter.ts");
  const protocolAdapterSource = readFileSync(protocolAdapterPath, "utf8");
  const agentIndexPath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const agentIndexSource = readFileSync(agentIndexPath, "utf8");

  if (/toMastraDBMessages\(promptView\.messages\)/.test(budgetProcessorSource)) {
    failures.push("MastraContextBudgetProcessor must convert prompt views through MastraContextProtocolAdapter");
  }

  if (/protocolAdapter\?:\s*MastraContextProtocolAdapter/.test(budgetProcessorSource)) {
    failures.push("MastraContextBudgetProcessor options must depend on ContextProtocolAdapter, not a concrete adapter");
  }

  if (
    !/class\s+MastraContextProtocolAdapter/.test(protocolAdapterSource) ||
    !/implements\s+ContextProtocolAdapter<ContextPromptView,\s*MastraContextProtocolOutput>/.test(protocolAdapterSource) ||
    !/readonly protocol = "mastra"/.test(protocolAdapterSource) ||
    !/toProtocol\(view:\s*ContextPromptView\)/.test(protocolAdapterSource)
  ) {
    failures.push("Mastra protocol layer must provide MastraContextProtocolAdapter for ContextPromptView conversion");
  }

  if (!/protocolAdapter/.test(budgetProcessorSource) || !/\.toProtocol\(promptView\)/.test(budgetProcessorSource)) {
    failures.push("MastraContextBudgetProcessor must use its configured protocol adapter");
  }

  if (/toContextPromptMessage|toMastraDBMessage|toMastraDBMessages/.test(agentIndexSource)) {
    failures.push("agent-runtime public index must not export low-level Mastra message mapper helpers");
  }
}

function assertMastraBudgetProcessorDelegatesCompiledEventPayload() {
  const filePath = path.join(contextRoot, "protocol/mastra/mastra-context-budget-processor.ts");
  const source = readFileSync(filePath, "utf8");
  const compiledEventPath = path.join(contextRoot, "protocol/mastra/mastra-context-compiled-event.ts");
  const compiledEventSource = readFileSync(compiledEventPath, "utf8");
  const planPath = path.join(contextRoot, "inventory/context-plan.ts");
  const planSource = readFileSync(planPath, "utf8");

  if (
    /selected_sources|omitted_sources|createSourceEventEntries|sourcePolicyDecisionsToContextDecisions\s*=/.test(source) ||
    !/createMastraContextCompiledEventPayload/.test(source)
  ) {
    failures.push("MastraContextBudgetProcessor must delegate context.compiled payload construction");
  }

  if (
    !/selectedSourceItemIds:\s*string\[\]/.test(planSource) ||
    !/omittedSourceItemIds:\s*string\[\]/.test(planSource) ||
    !/affectedItemIds\?:\s*string\[\]/.test(planSource) ||
    !/plan\.selectedSourceItemIds/.test(compiledEventSource) ||
    !/plan\.omittedSourceItemIds/.test(compiledEventSource) ||
    !/affectedItemIds:\s*decision\.affectedItemIds/.test(compiledEventSource)
  ) {
    failures.push("context.compiled source entries and decisions must preserve ContextPlan source item ids");
  }

  if (
    !/isContextSourceOmissionDecision/.test(source) ||
    /omittedSourceItemIds:\s*sourcePolicyResult\.decisions\.flatMap/.test(source)
  ) {
    failures.push("MastraContextBudgetProcessor must derive omitted source items only from omission decisions");
  }
}

function assertMastraConversationSourceMessageClassificationIsCentralized() {
  const conversationPath = path.join(contextRoot, "protocol/mastra/mastra-conversation-context-adapter.ts");
  const conversationSource = readFileSync(conversationPath, "utf8");
  const classifierPath = path.join(contextRoot, "protocol/mastra/mastra-context-source-message.ts");
  const classifierSource = readFileSync(classifierPath, "utf8");

  if (
    /memory-summary:/.test(conversationSource) ||
    /context:long-term-memory/.test(conversationSource) ||
    /metadata-summary/.test(conversationSource) ||
    /metadata-ltm/.test(conversationSource)
  ) {
    failures.push("MastraConversationContextAdapter must delegate context source message classification");
  }

  if (
    !/classifyMastraContextSourceMessage/.test(conversationSource) ||
    !/memory-summary:/.test(classifierSource) ||
    !/context:long-term-memory/.test(classifierSource) ||
    !/metadata-summary/.test(classifierSource) ||
    !/metadata-ltm/.test(classifierSource)
  ) {
    failures.push("Mastra context source message classifier must own compact/LTM source message rules");
  }

  if (
    !/message\.id\s*===\s*"context:long-term-memory"[\s\S]*messageKind:\s*"source-message"/.test(classifierSource)
  ) {
    failures.push("Mastra context source classifier must treat protocol-carried LTM as a governed source message");
  }
}

function assertSourcePolicyOwnsPackageCandidateSelection() {
  const processorPath = path.join(contextRoot, "protocol/mastra/mastra-context-budget-processor.ts");
  const processorSource = readFileSync(processorPath, "utf8");
  const policyPath = path.join(contextRoot, "policy/context-source-policy.ts");
  const policySource = readFileSync(policyPath, "utf8");

  if (/sourceItemsForPolicy/.test(processorSource) || !/\.applyPackage\(contextPackage\)/.test(processorSource)) {
    failures.push("MastraContextBudgetProcessor must delegate source candidate selection to ContextSourcePolicy");
  }

  if (!/applyPackage\(contextPackage:\s*ContextPackage\)/.test(policySource)) {
    failures.push("ContextSourcePolicy must own ContextPackage candidate selection");
  }

  if (/\n\s{2}apply\(items:\s*ContextItem\[\]\)/.test(policySource)) {
    failures.push("ContextSourcePolicy must not expose raw item application as a public bypass");
  }

  if (/context-source-authority-profile|DEFAULT_CONTEXT_SOURCE_AUTHORITY_ORDER|withDefaultAuthorityOrder/.test(policySource)) {
    failures.push("ContextSourcePolicy algorithm must not import or construct default source authority profiles");
  }

  const sourceSpecificPatterns = [
    { name: "compact memory source", pattern: /compact-conversation-memory/ },
    { name: "metadata summary owner", pattern: /metadata-summary/ },
    { name: "Mastra working memory owner", pattern: /mastra-working-memory/ },
    { name: "long-term memory source", pattern: /long-term-memory/ },
    { name: "metadata LTM owner", pattern: /metadata-ltm/ }
  ];

  for (const rule of sourceSpecificPatterns) {
    if (rule.pattern.test(policySource)) {
      failures.push(`ContextSourcePolicy algorithm must not hard-code source authority profiles; found "${rule.name}"`);
    }
  }
}

function assertContextPackageDoesNotOwnFoldedToolObservationProjection() {
  const filePath = path.join(contextRoot, "inventory/context-package.ts");
  const source = readFileSync(filePath, "utf8");

  if (/\bmodel:\s*unknown\b/.test(source) || /\bactivity:\s*unknown\b/.test(source)) {
    failures.push("ContextPackage must not own folded model/activity projections");
  }
}

function assertToolObservationHistoryDowngradeStaysOutOfInventory() {
  const runStatePath = path.join(contextRoot, "inventory/context-run-state.ts");
  const runStateSource = readFileSync(runStatePath, "utf8");

  if (/groupKind\s*===\s*"tool-exchange"/.test(runStateSource) || /modelObservation/.test(runStateSource)) {
    failures.push("ContextRunState must not own tool-observation history downgrade policy");
  }

  const projectionItemsPath = path.join(contextRoot, "tool-observation/tool-observation-projection-items.ts");
  const projectionItemsSource = readFileSync(projectionItemsPath, "utf8");
  const historyPath = path.join(contextRoot, "tool-observation/tool-observation-history.ts");
  const historySource = readFileSync(historyPath, "utf8");
  const packagerPath = path.join(contextRoot, "tool-observation/tool-observation-packager.ts");
  const packagerSource = readFileSync(packagerPath, "utf8");

  if (/toolObservationHistoryItemsFromPackage/.test(projectionItemsSource)) {
    failures.push("tool-observation projection items must not own history registration shaping");
  }

  if (
    !/toolObservationHistoryItemsFromPackage/.test(historySource) ||
    !/item\.visibility\s*!==\s*"model"/.test(historySource) ||
    !/visibility:\s*"reference"/.test(historySource) ||
    !/retention:\s*"reference"/.test(historySource)
  ) {
    failures.push("tool-observation layer must downgrade all model-visible tool history to reference inventory");
  }

  if (!/toolObservationHistoryItemsFromPackage/.test(packagerSource) || !/registerPackage/.test(packagerSource)) {
    failures.push("ToolObservationPackager must register downgraded tool observation history with ContextRunState");
  }
}

function assertRuntimeSourceProcessorUsesNarrowRunScope() {
  const filePath = path.join(contextRoot, "protocol/mastra/mastra-context-runtime-source-processor.ts");
  const source = readFileSync(filePath, "utf8");

  if (/\bAgentRunContext\b/.test(source) || /runContext:\s*AgentRunContext/.test(source)) {
    failures.push("MastraContextRuntimeSourceProcessor must use RuntimeContextRunScope, not full AgentRunContext");
  }

  if (!/replaceSourceItems/.test(source) || /items\.length\s*===\s*0[\s\S]*return\s+undefined/.test(source)) {
    failures.push("MastraContextRuntimeSourceProcessor must replace runtime source snapshots even when sources return no items");
  }
}

function assertMastraConversationSourceIsNotRuntimeSource() {
  const filePath = path.join(contextRoot, "protocol/mastra/mastra-conversation-context-adapter.ts");
  const source = readFileSync(filePath, "utf8");

  if (/implements\s+RuntimeContextSource/.test(source) || /RuntimeContextSourceInput/.test(source)) {
    failures.push("MastraConversationContextAdapter must stay a protocol adapter, not a runtime source");
  }
}

function assertPolicyCountersDoNotOwnInventoryReports() {
  const filePath = path.join(contextRoot, "policy/prompt-token-counter.ts");
  const source = readFileSync(filePath, "utf8");

  if (/export\s+type\s+\{\s*PromptTokenReport/.test(source)) {
    failures.push("PromptTokenReport must be exported from inventory, not policy/prompt-token-counter.ts");
  }
}

function assertPolicyPlannerDoesNotReExportInventoryPlans() {
  const filePath = path.join(contextRoot, "policy/context-step-planner.ts");
  const source = readFileSync(filePath, "utf8");

  if (/export\s+type\s+\{\s*ContextDecision,\s*ContextPlan,\s*GlobalContextBudget/.test(source)) {
    failures.push("ContextPlan DTOs must be exported from inventory, not policy/context-step-planner.ts");
  }
}

function assertDocPlanningLayerAbsent() {
  const docsRoot = path.join(repoRoot, "docs");
  for (const filePath of listFiles([docsRoot], [".md", ".mmd", ".html", ".puml"])) {
    const source = readFileSync(filePath, "utf8");
    const relativePath = path.relative(repoRoot, filePath);

    for (const rule of bannedDocPatterns) {
      if (rule.pattern.test(source)) {
        failures.push(`unexpected standalone planning layer wording "${rule.name}" found in ${relativePath}`);
      }
    }
  }
}

function assertRootIndexDoesNotExportContextInternals() {
  const filePath = path.join(repoRoot, "packages/agent-runtime/src/index.ts");
  const source = readFileSync(filePath, "utf8");
  const forbiddenExports = [];
  const exportPattern = /export\s+(?:type\s+)?\{[\s\S]*?\}\s+from\s+"([^"]+)";/g;
  let match;

  while ((match = exportPattern.exec(source)) !== null) {
    const statement = match[0];
    const exportPath = match[1] ?? "";
    const isAllowedContextExport =
      exportPath.endsWith("/context-token-counter.js") && statement.includes("ContextTokenCounter");

    if (exportPath.includes("./context/") && !isAllowedContextExport) {
      forbiddenExports.push(statement.replace(/\s+/g, " "));
    }
  }

  if (forbiddenExports.length > 0) {
    failures.push(`root agent-runtime index must not export context internals: ${forbiddenExports.join(" | ")}`);
  }
}

function assertAppsDoNotImportTestingEntryPoint() {
  const forbiddenImports = [];

  for (const filePath of listFiles(["apps"], [".ts", ".tsx", ".js", ".mjs"])) {
    const source = readFileSync(filePath, "utf8");
    if (/agent-runtime\/(?:dist\/)?testing\.js/.test(source)) {
      forbiddenImports.push(path.relative(repoRoot, filePath));
    }
  }

  if (forbiddenImports.length > 0) {
    failures.push(`apps must not import agent-runtime testing entry point: ${forbiddenImports.join(", ")}`);
  }
}

function listFiles(roots, extensions) {
  const files = [];

  for (const root of roots) {
    const absoluteRoot = path.isAbsolute(root) ? root : path.join(repoRoot, root);
    if (!existsSync(absoluteRoot)) {
      continue;
    }
    collectFiles(absoluteRoot, extensions, files);
  }

  return files;
}

function collectFiles(directory, extensions, files) {
  for (const entry of readdirSync(directory, { withFileTypes: true })) {
    if (entry.name === "node_modules" || entry.name === "dist" || entry.name.startsWith(".")) {
      continue;
    }

    const absolutePath = path.join(directory, entry.name);
    if (entry.isDirectory()) {
      collectFiles(absolutePath, extensions, files);
      continue;
    }

    if (entry.isFile() && extensions.includes(path.extname(entry.name))) {
      files.push(absolutePath);
    }
  }
}