Story navigation and details

Source-grounded

The TypeScript/JavaScript scan path: repository inputs become a deterministic file/import graph and compiler-backed semantic facts. Lifelines are local code/API boundaries, not separate services. Repeated per-file/import/declaration work is compressed into single exchanges. Failures stop the path unless explicitly permitted partial evidence is returned. This does not infer the right conceptual architecture or runtime behavior.

  • @topo/languages

    scanProject owns language-capability composition. It requests TypeScript/JavaScript code evidence from the selected scanner adapter so it can build the repository's analysis result. This is the real initiating module, not an unspecified caller. The returned graphs, diagnostics, metrics and authoritative/partial flag feed that composition. Separate Rust/Tauri adapters are outside this view. No model is invoked.

    packages/languages/src/index.ts:158-242
    export async function scanProject(
      options: ScanRepositoryOptions,
      selection: PluginSelection = { languages: ["typescript"], frameworks: [] },
    ): Promise<ScanResult> {
      validateSelection(selection);
      const { createTypeScriptScannerAdapter, ScanError } = await import("@topo/scanner");
      if (selection.languages.length === 1 && selection.languages[0] === "typescript" && !selection.frameworks.length) {
        return createTypeScriptScannerAdapter().scan(options);
      }
      const captured = await captureInventory(options.root);
      const repositoryId = options.repositoryId ?? basename(options.root);
      const hasTypeScript = captured.files.some((file: { path: string }) => /\.(?:[cm]?[jt]s|[jt]sx)$/.test(file.path));
      let result: ScanResult | undefined;
      const contributions: Contribution[] = [];
      if (selection.languages.includes("typescript") && hasTypeScript) {
        result = await createTypeScriptScannerAdapter().scan({ ...options, quality: { ...options.quality, allowPartial: true } });
        contributions.push(typescriptContribution(result));
      } else if (selection.languages.includes("typescript")) {
        contributions.push({
          plugin: { id: "typescript", kind: "language", version: "1.0",
            languages: ["typescript", "javascript"], capabilities: ["compiler-declarations", "static-references"] },
          entities: [], relationships: [], unresolved: [], diagnostics: [], extensions: {},
          coverage: { status: "unsupported", analyzedFiles: [], limitations: ["No TypeScript/JavaScript source was captured for the selected adapter."] },
        });
      }
      if (selection.languages.includes("rust")) contributions.push(await rustContribution(captured));
      if (selection.frameworks.includes("tauri")) {
        const { scanTauri } = await import("./plugins/tauri.mjs");
        contributions.push(await scanTauri(captured, contributions));
      }
      const languageEvidence: LanguageEvidence = { schemaVersion: "1.0", source: captured.snapshot, contributions };
      assertFacts(languageEvidence, captured.files);
      const diagnostics = contributions.flatMap((contribution) => [
        ...contribution.diagnostics,
        ...contribution.coverage.limitations.map((message) => ({
          code: `${contribution.plugin.id}.coverage`, severity: "warning" as const, message,
        })),
      ]);
      const authoritative = contributions.every((item) => item.coverage.status === "complete");
      if (!authoritative && !options.quality?.allowPartial) {
        throw new ScanError("Selected adapters produced partial evidence; use --allow-partial to publish it (exit 2).", diagnostics);
      }
      const graph = result?.graph ?? createGraphDocument({
        graphId: `repo:${repositoryId}`, repository: { id: repositoryId, label: repositoryId,
          ...(options.revision === undefined ? {} : { revision: options.revision }) },
      });
      const knownPaths = new Set(graph.nodes.filter((node) => node.identity.kind === "path").map((node) => node.identity.value));
      for (const file of captured.files) {
        if (file.language !== "rust" && !/(?:^|\/)Cargo\.toml$/.test(file.path)) continue;
        if (!knownPaths.has(file.path)) graph.nodes.push({
          id: createPathNodeId(file.path), label: file.path, kind: "file",
          identity: { kind: "path", value: file.path }, fingerprint: `sha256:${file.sha256}`,
        });
      }
      graph.nodes.sort((a, b) => a.id.localeCompare(b.id, "en"));
      for (const contribution of contributions.filter((item) => item.plugin.id !== "typescript")) {
        graph.modules.push({ id: `@topo/${contribution.plugin.id}`, version: "1.0.0", schemaVersion: "1.0" });
      }
      graph.extensions[LANGUAGE_EVIDENCE_KEY] = json(languageEvidence);
      graph.extensions["dev.topo.scanner"] = json({ authoritative, status: authoritative ? "complete" : "partial", diagnostics });
      assertGraphDocument(graph);
      await assertInventoryCurrent(captured);
      if (options.revision !== undefined && options.revision !== captured.repository.revision) throw new Error("Source revision changed during scan");
      const logicalArchitecture: LogicalArchitectureDocument = result?.logicalArchitecture ?? {
        schemaVersion: "1.0" as const, graphId: graph.graphId,
        ...(options.revision === undefined ? {} : { revision: options.revision }),
        snapshotId: `sha256:${captured.snapshot.sha256}`, positionNamespaceId: `repo:${repositoryId}`,
        coverage: { languages: ["javascript", "typescript"], relationshipKinds: [], completeSourceInventory: false, runtimeBehavior: false },
        entities: [], relationships: [], responsibilities: [], unassignedEntityIds: [], diagnostics: [],
      };
      const metrics = result?.metrics ?? {
        configCount: 0, workspacePackageCount: 0, coveredWorkspacePackageCount: 0,
        sourceFileCount: 0,
        assetFileCount: 0, linesOfCode: 0, localImportCount: 0, assetImportCount: 0,
        externalImportCount: 0, unresolvedImportCount: 0,
      };
      const rustPaths = new Set(contributions.find((item) => item.plugin.id === "rust")?.coverage.analyzedFiles ?? []);
      const rustFiles = captured.files.filter((file) => file.language === "rust" && rustPaths.has(file.path));
      return { graph, logicalArchitecture, diagnostics, authoritative, metrics: {
        ...metrics,
        sourceFileCount: metrics.sourceFileCount + rustFiles.length,
        linesOfCode: metrics.linesOfCode + rustFiles
          .reduce((total, file) => total + file.contents.split(/\r?\n/).filter((line) => line.trim()).length, 0),
      } };
    }
    packages/scanner/src/typescript-scanner.ts:921-1443
    export async function scanRepository(
      input: ScanRepositoryOptions,
    ): Promise<ScanResult> {
      const options = parseScanRepositoryOptions(input);
      const quality = { ...DEFAULT_QUALITY, ...options.quality };
      await assertDirectory(options.root);
      const canonicalRoot = await realpath(options.root);
    
      const files = await walkFiles(options.root);
      const inventoryPaths = new Set(files.map((filePath) => path.resolve(filePath)));
      const configPaths = files.filter(isConfigFile).sort(compareText);
      const sourcePaths = files.filter(isSourceFile).sort(compareText);
      const workspaces = await discoverWorkspacePackages(options.root, files);
      const declaredPackageNames = await discoverDeclaredPackageNames(
        options.root,
        files,
      );
      const diagnostics: ScanDiagnostic[] = [];
      const outputMappings: OutputMapping[] = [];
      const configuredSources = await loadConfiguredSources(
        options.root,
        configPaths,
        diagnostics,
        outputMappings,
        inventoryPaths,
      );
      const unconfiguredPaths = sourcePaths.filter(
        (sourcePath) =>
          !configuredSources.has(toRepositoryPath(options.root, sourcePath)),
      );
      const inferredSources = await loadInferredSources(
        options.root,
        unconfiguredPaths,
      );
      const sources = new Map([...configuredSources, ...inferredSources]);
      if (configuredSources.size > 0 && inferredSources.size > 0) {
        diagnostics.push({
          code: "inferred-source-configuration",
          severity: "warning",
          message: `${inferredSources.size} source files were not covered by a discovered TypeScript config and used default compiler options.`,
        });
      }
      const sortedSources = [...sources.values()].sort((left, right) =>
        compareText(left.repositoryPath, right.repositoryPath),
      );
      const sourceByAbsolutePath = new Map(
        sortedSources.map((source) => [path.resolve(source.absolutePath), source]),
      );
      const filePaths = inventoryPaths;
    
      const nodes = new Map<string, GraphNode>();
      const evidence = new Map<string, Evidence>();
      const assets = new Map<string, AssetRecord>();
      for (const source of sortedSources) {
        const nodeId = createPathNodeId(source.repositoryPath);
        nodes.set(nodeId, {
          id: nodeId,
          label: path.posix.basename(source.repositoryPath),
          kind: "file",
          identity: { kind: "path", value: source.repositoryPath },
          fingerprint: source.fingerprint,
        });
        const item = sourceEvidence(source);
        evidence.set(item.id, item);
      }
    
      const edgeEvidence = new Map<
        string,
        { sourceId: string; targetId: string; evidenceIds: Set<string> }
      >();
      let localImportCount = 0;
      let assetImportCount = 0;
      let externalImportCount = 0;
      let unresolvedImportCount = 0;
    
      for (const source of sortedSources) {
        const imports = [...source.imports].sort(compareText);
        for (const specifier of imports) {
          const importItem = importEvidence(source, specifier);
          const assetPath = assetSpecifierPath(specifier);
          if (assetPath !== undefined) {
            const absoluteAssetPath = path.resolve(
              path.dirname(source.absolutePath),
              assetPath,
            );
            if (
              !isWithin(options.root, absoluteAssetPath) ||
              !filePaths.has(absoluteAssetPath)
            ) {
              unresolvedImportCount += 1;
              diagnostics.push({
                code: "unresolved-local-asset",
                severity: "error",
                message: `Could not resolve local CSS asset "${specifier}" from "${source.repositoryPath}".`,
                path: source.repositoryPath,
                specifier,
              });
              continue;
            }
            let asset = assets.get(absoluteAssetPath);
            if (asset === undefined) {
              const content = await readFile(absoluteAssetPath, "utf8");
              asset = {
                absolutePath: absoluteAssetPath,
                repositoryPath: toRepositoryPath(
                  options.root,
                  absoluteAssetPath,
                ),
                fingerprint: sha256(content),
              };
              assets.set(absoluteAssetPath, asset);
              const assetId = createPathNodeId(asset.repositoryPath);
              nodes.set(assetId, {
                id: assetId,
                label: path.posix.basename(asset.repositoryPath),
                kind: "asset",
                identity: { kind: "path", value: asset.repositoryPath },
                fingerprint: asset.fingerprint,
              });
              const item = assetEvidence(asset);
              evidence.set(item.id, item);
            }
            const sourceId = createPathNodeId(source.repositoryPath);
            const targetId = createPathNodeId(asset.repositoryPath);
            const edgeId = createEdgeId("imports", sourceId, targetId);
            evidence.set(importItem.id, importItem);
            const accumulated = edgeEvidence.get(edgeId) ?? {
              sourceId,
              targetId,
              evidenceIds: new Set<string>(),
            };
            accumulated.evidenceIds.add(importItem.id);
            edgeEvidence.set(edgeId, accumulated);
            assetImportCount += 1;
            continue;
          }
          const resolved = ts.resolveModuleName(
            specifier,
            source.absolutePath,
            source.compilerOptions,
            ts.sys,
            source.moduleResolutionCache,
          ).resolvedModule;
          let targetId: string | undefined;
          const workspace = workspaceForSpecifier(specifier, workspaces);
    
          if (workspace !== undefined) {
            let target: SourceRecord | undefined;
            if (resolved !== undefined) {
              const selected = resolveCompilerSelectedSource(
                options.root,
                canonicalRoot,
                resolved.resolvedFileName,
                outputMappings,
                sourceByAbsolutePath,
              );
              if (selected.kind === "resolved") {
                target = selected.source;
              } else if (selected.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              } else if (
                resolved.resolvedFileName
                  .split(path.sep)
                  .includes("node_modules") ||
                !isWithin(options.root, resolved.resolvedFileName)
              ) {
                const locator = externalLocator(specifier);
                targetId = createExternalNodeId(locator);
                externalImportCount += 1;
                nodes.set(targetId, {
                  id: targetId,
                  label: packageName(specifier),
                  kind: "external",
                  identity: { kind: "external", value: locator },
                });
              }
            } else {
              const suffix =
                specifier === workspace.name
                  ? ""
                  : specifier.slice(workspace.name.length + 1);
              const exportedSubpath =
                suffix.length === 0
                  ? workspace.manifest.exports !== undefined
                  : hasExactWorkspaceExport(
                      workspace.manifest.exports,
                      `./${suffix}`,
                    );
              const physicalPackage = physicalWorkspacePackageState(
                workspace,
                source.absolutePath,
              );
              if (exportedSubpath && physicalPackage !== "other") {
                const virtualResolved = resolveWorkspaceModuleName(
                  options.root,
                  canonicalRoot,
                  workspace,
                  source,
                  specifier,
                  outputMappings,
                  sourceByAbsolutePath,
                );
                if (virtualResolved !== undefined) {
                  const selected = resolveCompilerSelectedSource(
                    options.root,
                    canonicalRoot,
                    virtualResolved.resolvedFileName,
                    outputMappings,
                    sourceByAbsolutePath,
                  );
                  if (selected.kind === "resolved") {
                    target = selected.source;
                  } else if (selected.kind === "ambiguous") {
                    unresolvedImportCount += 1;
                    diagnostics.push({
                      code: "ambiguous-generated-output",
                      severity: "error",
                      message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                      path: source.repositoryPath,
                      specifier,
                    });
                    continue;
                  }
                }
              } else if (physicalPackage !== "other") {
                target = resolveSourceCandidate(
                  sourceCandidatePaths(workspace, specifier),
                  sourceByAbsolutePath,
                );
              }
            }
            if (targetId === undefined) {
              if (target !== undefined) {
                targetId = createPathNodeId(target.repositoryPath);
                localImportCount += 1;
              } else {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "unresolved-workspace-import",
                  severity: "error",
                  message: `Could not resolve workspace import "${specifier}" from "${source.repositoryPath}".`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (
            resolved !== undefined &&
            resolved.resolvedFileName
              .split(path.sep)
              .includes("node_modules")
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          } else if (resolved !== undefined && isWithin(options.root, resolved.resolvedFileName)) {
            const target = sourceByAbsolutePath.get(
              path.resolve(resolved.resolvedFileName),
            );
            if (target !== undefined) {
              targetId = createPathNodeId(target.repositoryPath);
              localImportCount += 1;
            } else {
              const generated = resolveGeneratedOutput(
                path.resolve(resolved.resolvedFileName),
                outputMappings,
                sourceByAbsolutePath,
              );
              if (generated.kind === "resolved") {
                targetId = createPathNodeId(generated.source.repositoryPath);
                localImportCount += 1;
              } else if (generated.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${generated.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (
            resolved !== undefined &&
            !isWithin(options.root, resolved.resolvedFileName)
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          } else {
            const local =
              specifier.startsWith(".") ||
              specifier.startsWith("/") ||
              (isPathAlias(specifier, source.compilerOptions) &&
                !declaredPackageNames.has(packageName(specifier)));
            if (local) {
              unresolvedImportCount += 1;
              diagnostics.push({
                code: "unresolved-local-import",
                severity: "error",
                message: `Could not resolve local import "${specifier}" from "${source.repositoryPath}".`,
                path: source.repositoryPath,
                specifier,
              });
              continue;
            }
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          }
    
          if (targetId === undefined) {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "resolved-import-outside-scan",
              severity: "error",
              message: `Resolved import "${specifier}" is not represented by a scanned source file.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
    
          const sourceId = createPathNodeId(source.repositoryPath);
          const edgeId = createEdgeId("imports", sourceId, targetId);
          evidence.set(importItem.id, importItem);
          const accumulated = edgeEvidence.get(edgeId) ?? {
            sourceId,
            targetId,
            evidenceIds: new Set<string>(),
          };
          accumulated.evidenceIds.add(importItem.id);
          edgeEvidence.set(edgeId, accumulated);
        }
      }
    
      const edges: GraphEdge[] = [...edgeEvidence.entries()]
        .sort(([left], [right]) => compareText(left, right))
        .map(([id, edge]) => ({
          id,
          label: "imports",
          type: "imports",
          sourceId: edge.sourceId,
          targetId: edge.targetId,
          provenance: provenance([...edge.evidenceIds]),
        }));
      const coveredWorkspacePackageCount = workspaces.filter((workspace) =>
        sortedSources.some(
          (source) =>
            source.absolutePath.startsWith(`${workspace.directory}${path.sep}`),
        ),
      ).length;
      const metrics: ScanMetrics = {
        configCount: configPaths.length,
        workspacePackageCount: workspaces.length,
        coveredWorkspacePackageCount,
        sourceFileCount: sortedSources.length,
        assetFileCount: assets.size,
        linesOfCode: sortedSources.reduce((sum, source) => sum + source.lines, 0),
        localImportCount,
        assetImportCount,
        externalImportCount,
        unresolvedImportCount,
      };
      const rootCargo = files.includes(path.join(options.root, "Cargo.toml"));
      diagnostics.push(...qualityDiagnostics(metrics, quality, rootCargo));
      diagnostics.sort(
        (left, right) =>
          compareText(left.path ?? "", right.path ?? "") ||
          compareText(left.code, right.code) ||
          compareText(left.specifier ?? "", right.specifier ?? ""),
      );
    
      const errors = diagnostics.filter(
        (diagnostic) => diagnostic.severity === "error",
      );
      const fatalEmpty = sortedSources.length === 0;
      if (
        errors.length > 0 &&
        (!quality.allowPartial || fatalEmpty)
      ) {
        throw new ScanError(
          `Repository scan failed with ${errors.length} error diagnostic${errors.length === 1 ? "" : "s"}.`,
          diagnostics,
        );
      }
    
      const authoritative = errors.length === 0;
      const repositoryId =
        options.repositoryId ?? path.basename(options.root);
      const rootLabel = path.basename(options.root);
      const scannerExtension: JsonValue = {
        authoritative,
        status: authoritative ? "complete" : "partial",
        adapter: {
          id: TYPESCRIPT_SCANNER_MANIFEST.id,
          version: TYPESCRIPT_SCANNER_MANIFEST.version,
          contractVersion: TYPESCRIPT_SCANNER_MANIFEST.contractVersion,
          capabilities: {
            languages: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.languages],
            granularity: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.granularity],
            relationships: [
              ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.relationships,
            ],
            moduleResolution:
              TYPESCRIPT_SCANNER_MANIFEST.capabilities.moduleResolution,
            workspaceManifests: [
              ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.workspaceManifests,
            ],
            opaqueAssets: [
              ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.opaqueAssets,
            ],
            partialResults:
              TYPESCRIPT_SCANNER_MANIFEST.capabilities.partialResults,
          },
        },
        metrics: { ...metrics },
        diagnostics: diagnostics.map((diagnostic) => ({
          code: diagnostic.code,
          severity: diagnostic.severity,
          message: diagnostic.message,
          ...(diagnostic.path === undefined ? {} : { path: diagnostic.path }),
          ...(diagnostic.specifier === undefined
            ? {}
            : { specifier: diagnostic.specifier }),
        })),
      };
      const graph = createGraphDocument({
        graphId: `repo:${repositoryId}`,
        repository: {
          id: repositoryId,
          label: rootLabel,
          ...(options.revision === undefined
            ? {}
            : { revision: options.revision }),
        },
        modules: [
          {
            id: SCANNER_MODULE_ID,
            version: SCANNER_VERSION,
            schemaVersion: GRAPH_SCHEMA_VERSION,
          },
        ],
        nodes: [...nodes.values()].sort((left, right) =>
          compareText(left.id, right.id),
        ),
        edges,
        containers: directoriesForPaths(
          rootLabel,
          [
            ...sortedSources.map((source) => source.repositoryPath),
            ...[...assets.values()].map((asset) => asset.repositoryPath),
          ].sort(compareText),
        ),
        attributes: sortedSources.flatMap((source) => {
          const nodeId = createPathNodeId(source.repositoryPath);
          const evidenceId = `evidence:source:${source.repositoryPath}`;
          return [
            {
              id: createAttributeId(nodeId, "dev.topo.source.lines"),
              subject: { kind: "node" as const, id: nodeId },
              key: "dev.topo.source.lines",
              value: source.lines,
              provenance: provenance([evidenceId]),
              evidenceIds: [evidenceId],
              confidence: 1,
              witnesses: [
                {
                  nodeId,
                  fingerprint: source.fingerprint,
                  relationship: "self" as const,
                },
              ],
            },
          ];
        }),
        evidence: [...evidence.values()].sort((left, right) =>
          compareText(left.id, right.id),
        ),
        extensions: {
          "dev.topo.scanner": scannerExtension,
        },
      });
      serializeGraphDocument(graph);
      const logicalArchitecture = await extractLogicalArchitecture({
        root: options.root,
        graphId: graph.graphId,
        graph,
        authoritative,
        ...(options.revision ? { revision: options.revision } : {}),
        sources: sortedSources,
        ...(options.responsibilityFile ? { responsibilityFile: options.responsibilityFile } : {}),
      });
      return { graph, logicalArchitecture, diagnostics, metrics, authoritative };
    }
  • Scanner Open Dependency context by role: Code analysisOpen Dependency context by role: Language parsingOpen Dependency context by role: Path selectionOpen Dependency context by role: Ignore matchingOpen Dependency context by role: Build, test, docsOpen Dependency context by role: Development toolsOpen Topocode internal modules: @topo/scanner

    scanRepository inventories files, compiler configs and workspaces; captures source text/fingerprints; and resolves imports. Topocode maps compiler-selected outputs to source, distinguishes local/workspace/external/assets, consolidates duplicate import evidence, sorts canonical output, and applies quality gates before the semantic pass. Unresolved local/workspace imports are diagnostics, not guessed edges. Strict failure stops the scan; explicitly allowed partial output remains marked partial. The scanner returns evidence, not a finished architecture narrative.

    packages/scanner/src/typescript-scanner.ts:921-1443
    export async function scanRepository(
      input: ScanRepositoryOptions,
    ): Promise<ScanResult> {
      const options = parseScanRepositoryOptions(input);
      const quality = { ...DEFAULT_QUALITY, ...options.quality };
      await assertDirectory(options.root);
      const canonicalRoot = await realpath(options.root);
    
      const files = await walkFiles(options.root);
      const inventoryPaths = new Set(files.map((filePath) => path.resolve(filePath)));
      const configPaths = files.filter(isConfigFile).sort(compareText);
      const sourcePaths = files.filter(isSourceFile).sort(compareText);
      const workspaces = await discoverWorkspacePackages(options.root, files);
      const declaredPackageNames = await discoverDeclaredPackageNames(
        options.root,
        files,
      );
      const diagnostics: ScanDiagnostic[] = [];
      const outputMappings: OutputMapping[] = [];
      const configuredSources = await loadConfiguredSources(
        options.root,
        configPaths,
        diagnostics,
        outputMappings,
        inventoryPaths,
      );
      const unconfiguredPaths = sourcePaths.filter(
        (sourcePath) =>
          !configuredSources.has(toRepositoryPath(options.root, sourcePath)),
      );
      const inferredSources = await loadInferredSources(
        options.root,
        unconfiguredPaths,
      );
      const sources = new Map([...configuredSources, ...inferredSources]);
      if (configuredSources.size > 0 && inferredSources.size > 0) {
        diagnostics.push({
          code: "inferred-source-configuration",
          severity: "warning",
          message: `${inferredSources.size} source files were not covered by a discovered TypeScript config and used default compiler options.`,
        });
      }
      const sortedSources = [...sources.values()].sort((left, right) =>
        compareText(left.repositoryPath, right.repositoryPath),
      );
      const sourceByAbsolutePath = new Map(
        sortedSources.map((source) => [path.resolve(source.absolutePath), source]),
      );
      const filePaths = inventoryPaths;
    
      const nodes = new Map<string, GraphNode>();
      const evidence = new Map<string, Evidence>();
      const assets = new Map<string, AssetRecord>();
      for (const source of sortedSources) {
        const nodeId = createPathNodeId(source.repositoryPath);
        nodes.set(nodeId, {
          id: nodeId,
          label: path.posix.basename(source.repositoryPath),
          kind: "file",
          identity: { kind: "path", value: source.repositoryPath },
          fingerprint: source.fingerprint,
        });
        const item = sourceEvidence(source);
        evidence.set(item.id, item);
      }
    
      const edgeEvidence = new Map<
        string,
        { sourceId: string; targetId: string; evidenceIds: Set<string> }
      >();
      let localImportCount = 0;
      let assetImportCount = 0;
      let externalImportCount = 0;
      let unresolvedImportCount = 0;
    
      for (const source of sortedSources) {
        const imports = [...source.imports].sort(compareText);
        for (const specifier of imports) {
          const importItem = importEvidence(source, specifier);
          const assetPath = assetSpecifierPath(specifier);
          if (assetPath !== undefined) {
            const absoluteAssetPath = path.resolve(
              path.dirname(source.absolutePath),
              assetPath,
            );
            if (
              !isWithin(options.root, absoluteAssetPath) ||
              !filePaths.has(absoluteAssetPath)
            ) {
              unresolvedImportCount += 1;
              diagnostics.push({
                code: "unresolved-local-asset",
                severity: "error",
                message: `Could not resolve local CSS asset "${specifier}" from "${source.repositoryPath}".`,
                path: source.repositoryPath,
                specifier,
              });
              continue;
            }
            let asset = assets.get(absoluteAssetPath);
            if (asset === undefined) {
              const content = await readFile(absoluteAssetPath, "utf8");
              asset = {
                absolutePath: absoluteAssetPath,
                repositoryPath: toRepositoryPath(
                  options.root,
                  absoluteAssetPath,
                ),
                fingerprint: sha256(content),
              };
              assets.set(absoluteAssetPath, asset);
              const assetId = createPathNodeId(asset.repositoryPath);
              nodes.set(assetId, {
                id: assetId,
                label: path.posix.basename(asset.repositoryPath),
                kind: "asset",
                identity: { kind: "path", value: asset.repositoryPath },
                fingerprint: asset.fingerprint,
              });
              const item = assetEvidence(asset);
              evidence.set(item.id, item);
            }
            const sourceId = createPathNodeId(source.repositoryPath);
            const targetId = createPathNodeId(asset.repositoryPath);
            const edgeId = createEdgeId("imports", sourceId, targetId);
            evidence.set(importItem.id, importItem);
            const accumulated = edgeEvidence.get(edgeId) ?? {
              sourceId,
              targetId,
              evidenceIds: new Set<string>(),
            };
            accumulated.evidenceIds.add(importItem.id);
            edgeEvidence.set(edgeId, accumulated);
            assetImportCount += 1;
            continue;
          }
          const resolved = ts.resolveModuleName(
            specifier,
            source.absolutePath,
            source.compilerOptions,
            ts.sys,
            source.moduleResolutionCache,
          ).resolvedModule;
          let targetId: string | undefined;
          const workspace = workspaceForSpecifier(specifier, workspaces);
    
          if (workspace !== undefined) {
            let target: SourceRecord | undefined;
            if (resolved !== undefined) {
              const selected = resolveCompilerSelectedSource(
                options.root,
                canonicalRoot,
                resolved.resolvedFileName,
                outputMappings,
                sourceByAbsolutePath,
              );
              if (selected.kind === "resolved") {
                target = selected.source;
              } else if (selected.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              } else if (
                resolved.resolvedFileName
                  .split(path.sep)
                  .includes("node_modules") ||
                !isWithin(options.root, resolved.resolvedFileName)
              ) {
                const locator = externalLocator(specifier);
                targetId = createExternalNodeId(locator);
                externalImportCount += 1;
                nodes.set(targetId, {
                  id: targetId,
                  label: packageName(specifier),
                  kind: "external",
                  identity: { kind: "external", value: locator },
                });
              }
            } else {
              const suffix =
                specifier === workspace.name
                  ? ""
                  : specifier.slice(workspace.name.length + 1);
              const exportedSubpath =
                suffix.length === 0
                  ? workspace.manifest.exports !== undefined
                  : hasExactWorkspaceExport(
                      workspace.manifest.exports,
                      `./${suffix}`,
                    );
              const physicalPackage = physicalWorkspacePackageState(
                workspace,
                source.absolutePath,
              );
              if (exportedSubpath && physicalPackage !== "other") {
                const virtualResolved = resolveWorkspaceModuleName(
                  options.root,
                  canonicalRoot,
                  workspace,
                  source,
                  specifier,
                  outputMappings,
                  sourceByAbsolutePath,
                );
                if (virtualResolved !== undefined) {
                  const selected = resolveCompilerSelectedSource(
                    options.root,
                    canonicalRoot,
                    virtualResolved.resolvedFileName,
                    outputMappings,
                    sourceByAbsolutePath,
                  );
                  if (selected.kind === "resolved") {
                    target = selected.source;
                  } else if (selected.kind === "ambiguous") {
                    unresolvedImportCount += 1;
                    diagnostics.push({
                      code: "ambiguous-generated-output",
                      severity: "error",
                      message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                      path: source.repositoryPath,
                      specifier,
                    });
                    continue;
                  }
                }
              } else if (physicalPackage !== "other") {
                target = resolveSourceCandidate(
                  sourceCandidatePaths(workspace, specifier),
                  sourceByAbsolutePath,
                );
              }
            }
            if (targetId === undefined) {
              if (target !== undefined) {
                targetId = createPathNodeId(target.repositoryPath);
                localImportCount += 1;
              } else {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "unresolved-workspace-import",
                  severity: "error",
                  message: `Could not resolve workspace import "${specifier}" from "${source.repositoryPath}".`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (
            resolved !== undefined &&
            resolved.resolvedFileName
              .split(path.sep)
              .includes("node_modules")
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          } else if (resolved !== undefined && isWithin(options.root, resolved.resolvedFileName)) {
            const target = sourceByAbsolutePath.get(
              path.resolve(resolved.resolvedFileName),
            );
            if (target !== undefined) {
              targetId = createPathNodeId(target.repositoryPath);
              localImportCount += 1;
            } else {
              const generated = resolveGeneratedOutput(
                path.resolve(resolved.resolvedFileName),
                outputMappings,
                sourceByAbsolutePath,
              );
              if (generated.kind === "resolved") {
                targetId = createPathNodeId(generated.source.repositoryPath);
                localImportCount += 1;
              } else if (generated.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${generated.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (
            resolved !== undefined &&
            !isWithin(options.root, resolved.resolvedFileName)
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          } else {
            const local =
              specifier.startsWith(".") ||
              specifier.startsWith("/") ||
              (isPathAlias(specifier, source.compilerOptions) &&
                !declaredPackageNames.has(packageName(specifier)));
            if (local) {
              unresolvedImportCount += 1;
              diagnostics.push({
                code: "unresolved-local-import",
                severity: "error",
                message: `Could not resolve local import "${specifier}" from "${source.repositoryPath}".`,
                path: source.repositoryPath,
                specifier,
              });
              continue;
            }
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          }
    
          if (targetId === undefined) {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "resolved-import-outside-scan",
              severity: "error",
              message: `Resolved import "${specifier}" is not represented by a scanned source file.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
    
          const sourceId = createPathNodeId(source.repositoryPath);
          const edgeId = createEdgeId("imports", sourceId, targetId);
          evidence.set(importItem.id, importItem);
          const accumulated = edgeEvidence.get(edgeId) ?? {
            sourceId,
            targetId,
            evidenceIds: new Set<string>(),
          };
          accumulated.evidenceIds.add(importItem.id);
          edgeEvidence.set(edgeId, accumulated);
        }
      }
    
      const edges: GraphEdge[] = [...edgeEvidence.entries()]
        .sort(([left], [right]) => compareText(left, right))
        .map(([id, edge]) => ({
          id,
          label: "imports",
          type: "imports",
          sourceId: edge.sourceId,
          targetId: edge.targetId,
          provenance: provenance([...edge.evidenceIds]),
        }));
      const coveredWorkspacePackageCount = workspaces.filter((workspace) =>
        sortedSources.some(
          (source) =>
            source.absolutePath.startsWith(`${workspace.directory}${path.sep}`),
        ),
      ).length;
      const metrics: ScanMetrics = {
        configCount: configPaths.length,
        workspacePackageCount: workspaces.length,
        coveredWorkspacePackageCount,
        sourceFileCount: sortedSources.length,
        assetFileCount: assets.size,
        linesOfCode: sortedSources.reduce((sum, source) => sum + source.lines, 0),
        localImportCount,
        assetImportCount,
        externalImportCount,
        unresolvedImportCount,
      };
      const rootCargo = files.includes(path.join(options.root, "Cargo.toml"));
      diagnostics.push(...qualityDiagnostics(metrics, quality, rootCargo));
      diagnostics.sort(
        (left, right) =>
          compareText(left.path ?? "", right.path ?? "") ||
          compareText(left.code, right.code) ||
          compareText(left.specifier ?? "", right.specifier ?? ""),
      );
    
      const errors = diagnostics.filter(
        (diagnostic) => diagnostic.severity === "error",
      );
      const fatalEmpty = sortedSources.length === 0;
      if (
        errors.length > 0 &&
        (!quality.allowPartial || fatalEmpty)
      ) {
        throw new ScanError(
          `Repository scan failed with ${errors.length} error diagnostic${errors.length === 1 ? "" : "s"}.`,
          diagnostics,
        );
      }
    
      const authoritative = errors.length === 0;
      const repositoryId =
        options.repositoryId ?? path.basename(options.root);
      const rootLabel = path.basename(options.root);
      const scannerExtension: JsonValue = {
        authoritative,
        status: authoritative ? "complete" : "partial",
        adapter: {
          id: TYPESCRIPT_SCANNER_MANIFEST.id,
          version: TYPESCRIPT_SCANNER_MANIFEST.version,
          contractVersion: TYPESCRIPT_SCANNER_MANIFEST.contractVersion,
          capabilities: {
            languages: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.languages],
            granularity: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.granularity],
            relationships: [
              ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.relationships,
            ],
            moduleResolution:
              TYPESCRIPT_SCANNER_MANIFEST.capabilities.moduleResolution,
            workspaceManifests: [
              ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.workspaceManifests,
            ],
            opaqueAssets: [
              ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.opaqueAssets,
            ],
            partialResults:
              TYPESCRIPT_SCANNER_MANIFEST.capabilities.partialResults,
          },
        },
        metrics: { ...metrics },
        diagnostics: diagnostics.map((diagnostic) => ({
          code: diagnostic.code,
          severity: diagnostic.severity,
          message: diagnostic.message,
          ...(diagnostic.path === undefined ? {} : { path: diagnostic.path }),
          ...(diagnostic.specifier === undefined
            ? {}
            : { specifier: diagnostic.specifier }),
        })),
      };
      const graph = createGraphDocument({
        graphId: `repo:${repositoryId}`,
        repository: {
          id: repositoryId,
          label: rootLabel,
          ...(options.revision === undefined
            ? {}
            : { revision: options.revision }),
        },
        modules: [
          {
            id: SCANNER_MODULE_ID,
            version: SCANNER_VERSION,
            schemaVersion: GRAPH_SCHEMA_VERSION,
          },
        ],
        nodes: [...nodes.values()].sort((left, right) =>
          compareText(left.id, right.id),
        ),
        edges,
        containers: directoriesForPaths(
          rootLabel,
          [
            ...sortedSources.map((source) => source.repositoryPath),
            ...[...assets.values()].map((asset) => asset.repositoryPath),
          ].sort(compareText),
        ),
        attributes: sortedSources.flatMap((source) => {
          const nodeId = createPathNodeId(source.repositoryPath);
          const evidenceId = `evidence:source:${source.repositoryPath}`;
          return [
            {
              id: createAttributeId(nodeId, "dev.topo.source.lines"),
              subject: { kind: "node" as const, id: nodeId },
              key: "dev.topo.source.lines",
              value: source.lines,
              provenance: provenance([evidenceId]),
              evidenceIds: [evidenceId],
              confidence: 1,
              witnesses: [
                {
                  nodeId,
                  fingerprint: source.fingerprint,
                  relationship: "self" as const,
                },
              ],
            },
          ];
        }),
        evidence: [...evidence.values()].sort((left, right) =>
          compareText(left.id, right.id),
        ),
        extensions: {
          "dev.topo.scanner": scannerExtension,
        },
      });
      serializeGraphDocument(graph);
      const logicalArchitecture = await extractLogicalArchitecture({
        root: options.root,
        graphId: graph.graphId,
        graph,
        authoritative,
        ...(options.revision ? { revision: options.revision } : {}),
        sources: sortedSources,
        ...(options.responsibilityFile ? { responsibilityFile: options.responsibilityFile } : {}),
      });
      return { graph, logicalArchitecture, diagnostics, metrics, authoritative };
    }
    packages/scanner/src/typescript-scanner.ts:224-294
    async function loadConfiguredSources(
      root: string,
      configPaths: readonly string[],
      diagnostics: ScanDiagnostic[],
      outputMappings: OutputMapping[],
      inventoryPaths: ReadonlySet<string>,
    ): Promise<Map<string, SourceRecord>> {
      const records = new Map<string, SourceRecord>();
      const ignoredConfigSources = new Set<string>();
    
      for (const configPath of configPaths) {
        const config = ts.readConfigFile(configPath, ts.sys.readFile);
        if (config.error !== undefined) {
          diagnostics.push(formatTypeScriptDiagnostic(root, config.error));
          continue;
        }
        const parsed = ts.parseJsonConfigFileContent(
          config.config,
          ts.sys,
          path.dirname(configPath),
          undefined,
          configPath,
        );
        diagnostics.push(
          ...parsed.errors.map((diagnostic) =>
            formatTypeScriptDiagnostic(root, diagnostic),
          ),
        );
        validateConfiguredTypeLibraries(
          root,
          configPath,
          parsed.options,
          diagnostics,
        );
        if (
          parsed.options.rootDir !== undefined &&
          parsed.options.outDir !== undefined
        ) {
          outputMappings.push({
            configPath: toRepositoryPath(root, configPath),
            rootDirectory: path.resolve(parsed.options.rootDir),
            outputDirectory: path.resolve(parsed.options.outDir),
          });
        }
        const moduleResolutionCache = ts.createModuleResolutionCache(
          path.dirname(configPath),
          (fileName) => fileName,
          parsed.options,
        );
        await collectConfiguredFiles(
          root,
          parsed.fileNames,
          parsed.options,
          moduleResolutionCache,
          records,
          inventoryPaths,
          ignoredConfigSources,
        );
      }
    
      if (ignoredConfigSources.size > 0) {
        const paths = [...ignoredConfigSources].sort(compareText);
        diagnostics.push({
          code: "ignored-config-source",
          severity: "warning",
          message: `${paths.length} TypeScript-configured files were excluded by Git or ignore rules: ${paths.join(", ")}.`,
        });
      }
    
      return records;
    }
    packages/scanner/src/typescript-scanner.ts:173-197
    async function createSourceRecord(
      root: string,
      absolutePath: string,
      compilerOptions: ts.CompilerOptions,
      moduleResolutionCache: ts.ModuleResolutionCache,
    ): Promise<SourceRecord> {
      const repositoryPath = toRepositoryPath(root, absolutePath);
      const content = await readFile(absolutePath, "utf8");
      const sourceFile = ts.createSourceFile(
        absolutePath,
        content,
        ts.ScriptTarget.Latest,
        false,
        scriptKind(absolutePath),
      );
      return {
        absolutePath,
        repositoryPath,
        compilerOptions,
        moduleResolutionCache,
        imports: importSpecifiers(sourceFile),
        fingerprint: sha256(content),
        lines: content.length === 0 ? 0 : content.split(/\r\n?|\n/u).length,
      };
    }
    packages/scanner/src/typescript-scanner.ts:741-777
    function resolveWorkspaceModuleName(
      root: string,
      canonicalRoot: string,
      workspace: WorkspacePackage,
      source: SourceRecord,
      specifier: string,
      outputMappings: readonly OutputMapping[],
      sourceByAbsolutePath: ReadonlyMap<string, SourceRecord>,
    ): ts.ResolvedModuleFull | undefined {
      for (const allowGeneratedOutput of [false, true]) {
        const resolved = ts.resolveModuleName(
          specifier,
          source.absolutePath,
          source.compilerOptions,
          createWorkspaceModuleResolutionHost(
            root,
            canonicalRoot,
            workspace,
            outputMappings,
            sourceByAbsolutePath,
            allowGeneratedOutput,
          ),
          ts.createModuleResolutionCache(
            path.dirname(source.absolutePath),
            (fileName) =>
              ts.sys.useCaseSensitiveFileNames
                ? fileName
                : fileName.toLowerCase(),
            source.compilerOptions,
          ),
        ).resolvedModule;
        if (resolved !== undefined) {
          return resolved;
        }
      }
      return undefined;
    }
    packages/scanner/package.json:1-32
    {
      "name": "@topo/scanner",
      "version": "0.0.0",
      "private": true,
      "type": "module",
      "files": [
        "dist"
      ],
      "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      },
      "scripts": {
        "build": "tsc -b",
        "fixture": "node dist/fixture.js",
        "typecheck": "tsc -b --pretty false",
        "test": "vitest run src"
      },
      "dependencies": {
        "@topo/schema": "workspace:*",
        "ignore": "^7.0.0",
        "typescript-compiler-api": "npm:typescript@6.0.3"
      },
      "devDependencies": {
        "@types/node": "^22.0.0",
        "typescript": "^7.0.2",
        "vite": "8.2.2",
        "vitest": "^5.0.0"
      }
    }
    
  • TypeScript API

    In-process compiler APIs supply parsed configuration, syntax trees, module resolution and type/symbol information. The scanner's workspace-aware host and source mappings constrain how those results are used. TypeScript does not classify Topocode's graph quality or invent responsibility groups.

    packages/scanner/src/typescript-scanner.ts:224-294
    async function loadConfiguredSources(
      root: string,
      configPaths: readonly string[],
      diagnostics: ScanDiagnostic[],
      outputMappings: OutputMapping[],
      inventoryPaths: ReadonlySet<string>,
    ): Promise<Map<string, SourceRecord>> {
      const records = new Map<string, SourceRecord>();
      const ignoredConfigSources = new Set<string>();
    
      for (const configPath of configPaths) {
        const config = ts.readConfigFile(configPath, ts.sys.readFile);
        if (config.error !== undefined) {
          diagnostics.push(formatTypeScriptDiagnostic(root, config.error));
          continue;
        }
        const parsed = ts.parseJsonConfigFileContent(
          config.config,
          ts.sys,
          path.dirname(configPath),
          undefined,
          configPath,
        );
        diagnostics.push(
          ...parsed.errors.map((diagnostic) =>
            formatTypeScriptDiagnostic(root, diagnostic),
          ),
        );
        validateConfiguredTypeLibraries(
          root,
          configPath,
          parsed.options,
          diagnostics,
        );
        if (
          parsed.options.rootDir !== undefined &&
          parsed.options.outDir !== undefined
        ) {
          outputMappings.push({
            configPath: toRepositoryPath(root, configPath),
            rootDirectory: path.resolve(parsed.options.rootDir),
            outputDirectory: path.resolve(parsed.options.outDir),
          });
        }
        const moduleResolutionCache = ts.createModuleResolutionCache(
          path.dirname(configPath),
          (fileName) => fileName,
          parsed.options,
        );
        await collectConfiguredFiles(
          root,
          parsed.fileNames,
          parsed.options,
          moduleResolutionCache,
          records,
          inventoryPaths,
          ignoredConfigSources,
        );
      }
    
      if (ignoredConfigSources.size > 0) {
        const paths = [...ignoredConfigSources].sort(compareText);
        diagnostics.push({
          code: "ignored-config-source",
          severity: "warning",
          message: `${paths.length} TypeScript-configured files were excluded by Git or ignore rules: ${paths.join(", ")}.`,
        });
      }
    
      return records;
    }
    packages/scanner/src/typescript-scanner.ts:173-197
    async function createSourceRecord(
      root: string,
      absolutePath: string,
      compilerOptions: ts.CompilerOptions,
      moduleResolutionCache: ts.ModuleResolutionCache,
    ): Promise<SourceRecord> {
      const repositoryPath = toRepositoryPath(root, absolutePath);
      const content = await readFile(absolutePath, "utf8");
      const sourceFile = ts.createSourceFile(
        absolutePath,
        content,
        ts.ScriptTarget.Latest,
        false,
        scriptKind(absolutePath),
      );
      return {
        absolutePath,
        repositoryPath,
        compilerOptions,
        moduleResolutionCache,
        imports: importSpecifiers(sourceFile),
        fingerprint: sha256(content),
        lines: content.length === 0 ? 0 : content.split(/\r\n?|\n/u).length,
      };
    }
    packages/scanner/src/typescript-scanner.ts:741-777
    function resolveWorkspaceModuleName(
      root: string,
      canonicalRoot: string,
      workspace: WorkspacePackage,
      source: SourceRecord,
      specifier: string,
      outputMappings: readonly OutputMapping[],
      sourceByAbsolutePath: ReadonlyMap<string, SourceRecord>,
    ): ts.ResolvedModuleFull | undefined {
      for (const allowGeneratedOutput of [false, true]) {
        const resolved = ts.resolveModuleName(
          specifier,
          source.absolutePath,
          source.compilerOptions,
          createWorkspaceModuleResolutionHost(
            root,
            canonicalRoot,
            workspace,
            outputMappings,
            sourceByAbsolutePath,
            allowGeneratedOutput,
          ),
          ts.createModuleResolutionCache(
            path.dirname(source.absolutePath),
            (fileName) =>
              ts.sys.useCaseSensitiveFileNames
                ? fileName
                : fileName.toLowerCase(),
            source.compilerOptions,
          ),
        ).resolvedModule;
        if (resolved !== undefined) {
          return resolved;
        }
      }
      return undefined;
    }
    packages/scanner/src/semantic.ts:172-419
    export async function extractLogicalArchitecture(options: {
      root: string;
      graphId: string;
      revision?: string;
      authoritative: boolean;
      graph: GraphDocument;
      sources: readonly SemanticSource[];
      responsibilityFile?: string;
    }): Promise<LogicalArchitectureDocument> {
      const compilerOptions: ts.CompilerOptions = {
        allowJs: true,
        checkJs: false,
        noEmit: true,
        skipLibCheck: true,
        module: ts.ModuleKind.NodeNext,
        moduleResolution: ts.ModuleResolutionKind.NodeNext,
        target: ts.ScriptTarget.ES2022,
      };
      const sourceOptions = new Map(options.sources.map((source) => [
        path.resolve(source.absolutePath),
        { ...source.compilerOptions, allowJs: true, noEmit: true, skipLibCheck: true },
      ]));
      const nodePath = new Map(options.graph.nodes
        .filter((node) => node.identity.kind === "path")
        .map((node) => [node.id, path.resolve(options.root, node.identity.value)]));
      const evidenceById = new Map(options.graph.evidence.map((item) => [item.id, item]));
      const resolvedByImport = new Map<string, string>();
      for (const edge of options.graph.edges) {
        const target = nodePath.get(edge.targetId);
        if (!target) continue;
        for (const evidenceId of edge.provenance.evidenceIds) {
          const evidence = evidenceById.get(evidenceId);
          if (evidence?.anchor?.path) {
            const specifier = evidence.anchor.symbol?.startsWith("import:")
              ? evidence.anchor.symbol.slice("import:".length)
              : evidence.anchor.contentPattern;
            if (!specifier) continue;
            resolvedByImport.set(
              `${path.resolve(options.root, evidence.anchor.path)}\0${specifier}`,
              target,
            );
          }
        }
      }
      const extension = (fileName: string): ts.Extension => {
        if (fileName.endsWith(".tsx")) return ts.Extension.Tsx;
        if (fileName.endsWith(".jsx")) return ts.Extension.Jsx;
        if (fileName.endsWith(".js") || fileName.endsWith(".mjs") || fileName.endsWith(".cjs")) return ts.Extension.Js;
        return ts.Extension.Ts;
      };
      const host = ts.createCompilerHost(compilerOptions);
      host.resolveModuleNames = (moduleNames, containingFile) => moduleNames.map((moduleName) => {
        const perFileOptions = sourceOptions.get(path.resolve(containingFile)) ?? compilerOptions;
        const mapped = resolvedByImport.get(`${path.resolve(containingFile)}\0${moduleName}`);
        if (mapped) return {
          resolvedFileName: mapped,
          extension: extension(mapped),
          isExternalLibraryImport: false,
        };
        return ts.resolveModuleName(moduleName, containingFile, perFileOptions, host).resolvedModule;
      });
      const program = ts.createProgram({
        rootNames: options.sources.map((source) => source.absolutePath),
        options: compilerOptions,
        host,
      });
      const checker = program.getTypeChecker();
      const sourcePaths = new Set(options.sources.map((source) => path.resolve(source.absolutePath)));
      const entities: SemanticEntity[] = [];
      const entityBySymbol = new Map<ts.Symbol, string>();
      const entityByDeclaration = new Map<ts.Declaration, string>();
      const anchorToEntity = new Map<string, string>();
      const exportedSymbols = new Set<ts.Symbol>();
    
      for (const sourceFile of program.getSourceFiles()) {
        if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
        const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
        if (moduleSymbol) {
          for (const exported of checker.getExportsOfModule(moduleSymbol)) {
            const canonical = canonicalSymbol(checker, exported);
            if (canonical) exportedSymbols.add(canonical);
          }
        }
      }
    
      for (const sourceFile of program.getSourceFiles()) {
        if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
        for (const item of semanticDeclarations(checker, sourceFile)) {
          const symbol = canonicalSymbol(checker, item.symbol);
          const kind = declarationKind(item.declaration);
          if (!symbol || !kind) continue;
          let id = entityBySymbol.get(symbol);
          if (!id) {
            id = entityId(options.root, symbol, kind);
            entityBySymbol.set(symbol, id);
            const declarations = (symbol.declarations ?? [item.declaration])
              .filter((declaration) => sourcePaths.has(path.resolve(declaration.getSourceFile().fileName)))
              .map((declaration) => location(options.root, declaration.getSourceFile(), declaration))
              .sort((left, right) => compareText(left.path, right.path) || left.start.line - right.start.line);
            const type = checker.getTypeOfSymbolAtLocation(symbol, item.declaration);
            entities.push({
              id,
              name: symbol.getName(),
              kind,
              exported: exportedSymbols.has(symbol),
              declarations,
              signatures: checker.getSignaturesOfType(type, ts.SignatureKind.Call)
                .map((signature) => checker.signatureToString(signature)),
              members: memberFacts(checker, symbol.declarations ?? [item.declaration]),
            });
          }
          entityByDeclaration.set(item.declaration, id);
          if (ts.isClassDeclaration(item.declaration) || ts.isInterfaceDeclaration(item.declaration)) {
            for (const member of item.declaration.members) {
              if (!member.name) continue;
              const memberSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(member.name));
              if (memberSymbol) entityBySymbol.set(memberSymbol, id);
            }
          }
          const repositoryPath = path.relative(options.root, sourceFile.fileName).split(path.sep).join("/");
          anchorToEntity.set(`${repositoryPath}\0${item.anchor}`, id);
        }
      }
    
      const relationshipLocations = new Map<string, SourceLocation[]>();
      for (const sourceFile of program.getSourceFiles()) {
        if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
        const visit = (node: ts.Node): void => {
          if (ts.isIdentifier(node)) {
            const sourceId = containingEntity(node, entityByDeclaration);
            const targetSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(node));
            const targetId = targetSymbol ? entityBySymbol.get(targetSymbol) : undefined;
            const kind = relationshipKind(node);
            if (sourceId && targetId && sourceId !== targetId && kind) {
              const key = `${kind}\0${sourceId}\0${targetId}`;
              const locations = relationshipLocations.get(key) ?? [];
              locations.push(location(options.root, sourceFile, node));
              relationshipLocations.set(key, locations);
            }
          }
          ts.forEachChild(node, visit);
        };
        visit(sourceFile);
      }
      const relationships: SemanticRelationship[] = [...relationshipLocations.entries()].map(([key, locations]) => {
        const [kind, sourceId, targetId] = key.split("\0") as [SemanticRelationshipKind, string, string];
        return { id: `semantic-edge:${kind}:${sourceId}:${targetId}`, sourceId, targetId, kind, locations };
      }).sort((left, right) => compareText(left.id, right.id));
    
      const diagnostics: LogicalArchitectureDiagnostic[] = [];
      const responsibilities: LogicalResponsibility[] = [];
      const assigned = new Set<string>();
      if (options.responsibilityFile) {
        let input: ResponsibilityInput;
        try {
          input = parseResponsibilityInput(JSON.parse(await readFile(options.responsibilityFile, "utf8")) as unknown);
        } catch (error) {
          throw new Error(`Invalid responsibility input ${options.responsibilityFile}: ${error instanceof Error ? error.message : String(error)}`);
        }
        const responsibilityIds = new Set<string>();
        for (const item of input.responsibilities) {
          if (responsibilityIds.has(item.id)) throw new Error(`Duplicate responsibility id ${item.id}.`);
          responsibilityIds.add(item.id);
          const entityIds: string[] = [];
          for (const anchor of item.entities) {
            const id = anchorToEntity.get(`${anchor.path}\0${anchor.symbol}`);
            if (!id) throw new Error(`Responsibility ${item.id} references unknown semantic anchor ${anchor.path}#${anchor.symbol}.`);
            if (assigned.has(id)) throw new Error(`Semantic entity ${anchor.path}#${anchor.symbol} has multiple primary responsibility homes.`);
            assigned.add(id);
            entityIds.push(id);
          }
          const contracts = entities.filter((entity) => entityIds.includes(entity.id) && entity.exported &&
            (entity.kind === "function" || entity.kind === "interface" || entity.kind === "type" || entity.kind === "class"))
            .map((entity) => entity.name).sort(compareText).slice(0, 3);
          if (contracts.length === 0) {
            throw new Error(`Responsibility ${item.id} must contain at least one exported function, class, interface, or type contract.`);
          }
          responsibilities.push({
            id: item.id,
            name: item.name,
            purpose: item.purpose,
            provenance: "proposed",
            entityIds: entityIds.sort(compareText),
            contracts,
          });
        }
      } else {
        diagnostics.push({
          code: "missing-responsibility-input",
          severity: "warning",
          message: "No responsibility input was supplied; semantic entities remain explicitly unassigned and the legacy source map remains the default.",
        });
      }
    
      entities.sort((left, right) => compareText(left.id, right.id));
      if (!options.authoritative) {
        diagnostics.push({
          code: "partial-source-inventory",
          severity: "warning",
          message: "The underlying scanner result is partial and the logical architecture is not authoritative.",
        });
      }
      const unassignedEntityIds = entities.filter((entity) => !assigned.has(entity.id)).map((entity) => entity.id);
      if (options.responsibilityFile && unassignedEntityIds.length > 0) {
        responsibilities.push({
          id: "responsibility:unassigned",
          name: "Unassigned",
          purpose: "Compiler-backed entities not assigned by the supplied responsibility proposal.",
          provenance: "unassigned",
          entityIds: unassignedEntityIds,
          contracts: entities.filter((entity) => unassignedEntityIds.includes(entity.id) && entity.exported)
            .map((entity) => entity.name).sort(compareText).slice(0, 3),
        });
        diagnostics.push({
          code: "unassigned-semantic-entities",
          severity: "warning",
          message: `${unassignedEntityIds.length} semantic entities are not assigned by the responsibility proposal.`,
        });
      }
      const sortedResponsibilities = responsibilities.sort((left, right) => compareText(left.id, right.id));
      const snapshotId = createHash("sha256").update(options.graph.nodes
        .map((node) => `${node.id}\0${node.fingerprint ?? ""}`).sort(compareText).join("\0")).digest("hex");
      const positionNamespaceId = createHash("sha256").update(JSON.stringify({
        version: 2,
        revision: options.revision ?? null,
        snapshotId,
        responsibilities: sortedResponsibilities,
        views: ["logical-overview", "logical-drill"],
      })).digest("hex");
      return {
        schemaVersion: "1.0",
        graphId: options.graphId,
        ...(options.revision ? { revision: options.revision } : {}),
        snapshotId,
        positionNamespaceId,
        coverage: {
          languages: ["javascript", "typescript"],
          relationshipKinds: ["calls", "constructs", "type-use", "heritage"],
          completeSourceInventory: options.authoritative,
          runtimeBehavior: false,
        },
        entities,
        relationships,
        responsibilities: sortedResponsibilities,
        unassignedEntityIds,
        diagnostics,
      };
    }
  • Semantic pass

    extractLogicalArchitecture builds a compiler program using per-file options and already-resolved import mappings. It canonicalizes aliases, identifies declarations, signatures and members, then walks identifiers to record static relationships and their locations. Responsibility assignments come from an explicit proposal, not automatic architectural inference. Missing proposals and unassigned entities stay visible. Static references are not runtime reachability.

    packages/scanner/src/semantic.ts:172-419
    export async function extractLogicalArchitecture(options: {
      root: string;
      graphId: string;
      revision?: string;
      authoritative: boolean;
      graph: GraphDocument;
      sources: readonly SemanticSource[];
      responsibilityFile?: string;
    }): Promise<LogicalArchitectureDocument> {
      const compilerOptions: ts.CompilerOptions = {
        allowJs: true,
        checkJs: false,
        noEmit: true,
        skipLibCheck: true,
        module: ts.ModuleKind.NodeNext,
        moduleResolution: ts.ModuleResolutionKind.NodeNext,
        target: ts.ScriptTarget.ES2022,
      };
      const sourceOptions = new Map(options.sources.map((source) => [
        path.resolve(source.absolutePath),
        { ...source.compilerOptions, allowJs: true, noEmit: true, skipLibCheck: true },
      ]));
      const nodePath = new Map(options.graph.nodes
        .filter((node) => node.identity.kind === "path")
        .map((node) => [node.id, path.resolve(options.root, node.identity.value)]));
      const evidenceById = new Map(options.graph.evidence.map((item) => [item.id, item]));
      const resolvedByImport = new Map<string, string>();
      for (const edge of options.graph.edges) {
        const target = nodePath.get(edge.targetId);
        if (!target) continue;
        for (const evidenceId of edge.provenance.evidenceIds) {
          const evidence = evidenceById.get(evidenceId);
          if (evidence?.anchor?.path) {
            const specifier = evidence.anchor.symbol?.startsWith("import:")
              ? evidence.anchor.symbol.slice("import:".length)
              : evidence.anchor.contentPattern;
            if (!specifier) continue;
            resolvedByImport.set(
              `${path.resolve(options.root, evidence.anchor.path)}\0${specifier}`,
              target,
            );
          }
        }
      }
      const extension = (fileName: string): ts.Extension => {
        if (fileName.endsWith(".tsx")) return ts.Extension.Tsx;
        if (fileName.endsWith(".jsx")) return ts.Extension.Jsx;
        if (fileName.endsWith(".js") || fileName.endsWith(".mjs") || fileName.endsWith(".cjs")) return ts.Extension.Js;
        return ts.Extension.Ts;
      };
      const host = ts.createCompilerHost(compilerOptions);
      host.resolveModuleNames = (moduleNames, containingFile) => moduleNames.map((moduleName) => {
        const perFileOptions = sourceOptions.get(path.resolve(containingFile)) ?? compilerOptions;
        const mapped = resolvedByImport.get(`${path.resolve(containingFile)}\0${moduleName}`);
        if (mapped) return {
          resolvedFileName: mapped,
          extension: extension(mapped),
          isExternalLibraryImport: false,
        };
        return ts.resolveModuleName(moduleName, containingFile, perFileOptions, host).resolvedModule;
      });
      const program = ts.createProgram({
        rootNames: options.sources.map((source) => source.absolutePath),
        options: compilerOptions,
        host,
      });
      const checker = program.getTypeChecker();
      const sourcePaths = new Set(options.sources.map((source) => path.resolve(source.absolutePath)));
      const entities: SemanticEntity[] = [];
      const entityBySymbol = new Map<ts.Symbol, string>();
      const entityByDeclaration = new Map<ts.Declaration, string>();
      const anchorToEntity = new Map<string, string>();
      const exportedSymbols = new Set<ts.Symbol>();
    
      for (const sourceFile of program.getSourceFiles()) {
        if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
        const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
        if (moduleSymbol) {
          for (const exported of checker.getExportsOfModule(moduleSymbol)) {
            const canonical = canonicalSymbol(checker, exported);
            if (canonical) exportedSymbols.add(canonical);
          }
        }
      }
    
      for (const sourceFile of program.getSourceFiles()) {
        if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
        for (const item of semanticDeclarations(checker, sourceFile)) {
          const symbol = canonicalSymbol(checker, item.symbol);
          const kind = declarationKind(item.declaration);
          if (!symbol || !kind) continue;
          let id = entityBySymbol.get(symbol);
          if (!id) {
            id = entityId(options.root, symbol, kind);
            entityBySymbol.set(symbol, id);
            const declarations = (symbol.declarations ?? [item.declaration])
              .filter((declaration) => sourcePaths.has(path.resolve(declaration.getSourceFile().fileName)))
              .map((declaration) => location(options.root, declaration.getSourceFile(), declaration))
              .sort((left, right) => compareText(left.path, right.path) || left.start.line - right.start.line);
            const type = checker.getTypeOfSymbolAtLocation(symbol, item.declaration);
            entities.push({
              id,
              name: symbol.getName(),
              kind,
              exported: exportedSymbols.has(symbol),
              declarations,
              signatures: checker.getSignaturesOfType(type, ts.SignatureKind.Call)
                .map((signature) => checker.signatureToString(signature)),
              members: memberFacts(checker, symbol.declarations ?? [item.declaration]),
            });
          }
          entityByDeclaration.set(item.declaration, id);
          if (ts.isClassDeclaration(item.declaration) || ts.isInterfaceDeclaration(item.declaration)) {
            for (const member of item.declaration.members) {
              if (!member.name) continue;
              const memberSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(member.name));
              if (memberSymbol) entityBySymbol.set(memberSymbol, id);
            }
          }
          const repositoryPath = path.relative(options.root, sourceFile.fileName).split(path.sep).join("/");
          anchorToEntity.set(`${repositoryPath}\0${item.anchor}`, id);
        }
      }
    
      const relationshipLocations = new Map<string, SourceLocation[]>();
      for (const sourceFile of program.getSourceFiles()) {
        if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
        const visit = (node: ts.Node): void => {
          if (ts.isIdentifier(node)) {
            const sourceId = containingEntity(node, entityByDeclaration);
            const targetSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(node));
            const targetId = targetSymbol ? entityBySymbol.get(targetSymbol) : undefined;
            const kind = relationshipKind(node);
            if (sourceId && targetId && sourceId !== targetId && kind) {
              const key = `${kind}\0${sourceId}\0${targetId}`;
              const locations = relationshipLocations.get(key) ?? [];
              locations.push(location(options.root, sourceFile, node));
              relationshipLocations.set(key, locations);
            }
          }
          ts.forEachChild(node, visit);
        };
        visit(sourceFile);
      }
      const relationships: SemanticRelationship[] = [...relationshipLocations.entries()].map(([key, locations]) => {
        const [kind, sourceId, targetId] = key.split("\0") as [SemanticRelationshipKind, string, string];
        return { id: `semantic-edge:${kind}:${sourceId}:${targetId}`, sourceId, targetId, kind, locations };
      }).sort((left, right) => compareText(left.id, right.id));
    
      const diagnostics: LogicalArchitectureDiagnostic[] = [];
      const responsibilities: LogicalResponsibility[] = [];
      const assigned = new Set<string>();
      if (options.responsibilityFile) {
        let input: ResponsibilityInput;
        try {
          input = parseResponsibilityInput(JSON.parse(await readFile(options.responsibilityFile, "utf8")) as unknown);
        } catch (error) {
          throw new Error(`Invalid responsibility input ${options.responsibilityFile}: ${error instanceof Error ? error.message : String(error)}`);
        }
        const responsibilityIds = new Set<string>();
        for (const item of input.responsibilities) {
          if (responsibilityIds.has(item.id)) throw new Error(`Duplicate responsibility id ${item.id}.`);
          responsibilityIds.add(item.id);
          const entityIds: string[] = [];
          for (const anchor of item.entities) {
            const id = anchorToEntity.get(`${anchor.path}\0${anchor.symbol}`);
            if (!id) throw new Error(`Responsibility ${item.id} references unknown semantic anchor ${anchor.path}#${anchor.symbol}.`);
            if (assigned.has(id)) throw new Error(`Semantic entity ${anchor.path}#${anchor.symbol} has multiple primary responsibility homes.`);
            assigned.add(id);
            entityIds.push(id);
          }
          const contracts = entities.filter((entity) => entityIds.includes(entity.id) && entity.exported &&
            (entity.kind === "function" || entity.kind === "interface" || entity.kind === "type" || entity.kind === "class"))
            .map((entity) => entity.name).sort(compareText).slice(0, 3);
          if (contracts.length === 0) {
            throw new Error(`Responsibility ${item.id} must contain at least one exported function, class, interface, or type contract.`);
          }
          responsibilities.push({
            id: item.id,
            name: item.name,
            purpose: item.purpose,
            provenance: "proposed",
            entityIds: entityIds.sort(compareText),
            contracts,
          });
        }
      } else {
        diagnostics.push({
          code: "missing-responsibility-input",
          severity: "warning",
          message: "No responsibility input was supplied; semantic entities remain explicitly unassigned and the legacy source map remains the default.",
        });
      }
    
      entities.sort((left, right) => compareText(left.id, right.id));
      if (!options.authoritative) {
        diagnostics.push({
          code: "partial-source-inventory",
          severity: "warning",
          message: "The underlying scanner result is partial and the logical architecture is not authoritative.",
        });
      }
      const unassignedEntityIds = entities.filter((entity) => !assigned.has(entity.id)).map((entity) => entity.id);
      if (options.responsibilityFile && unassignedEntityIds.length > 0) {
        responsibilities.push({
          id: "responsibility:unassigned",
          name: "Unassigned",
          purpose: "Compiler-backed entities not assigned by the supplied responsibility proposal.",
          provenance: "unassigned",
          entityIds: unassignedEntityIds,
          contracts: entities.filter((entity) => unassignedEntityIds.includes(entity.id) && entity.exported)
            .map((entity) => entity.name).sort(compareText).slice(0, 3),
        });
        diagnostics.push({
          code: "unassigned-semantic-entities",
          severity: "warning",
          message: `${unassignedEntityIds.length} semantic entities are not assigned by the responsibility proposal.`,
        });
      }
      const sortedResponsibilities = responsibilities.sort((left, right) => compareText(left.id, right.id));
      const snapshotId = createHash("sha256").update(options.graph.nodes
        .map((node) => `${node.id}\0${node.fingerprint ?? ""}`).sort(compareText).join("\0")).digest("hex");
      const positionNamespaceId = createHash("sha256").update(JSON.stringify({
        version: 2,
        revision: options.revision ?? null,
        snapshotId,
        responsibilities: sortedResponsibilities,
        views: ["logical-overview", "logical-drill"],
      })).digest("hex");
      return {
        schemaVersion: "1.0",
        graphId: options.graphId,
        ...(options.revision ? { revision: options.revision } : {}),
        snapshotId,
        positionNamespaceId,
        coverage: {
          languages: ["javascript", "typescript"],
          relationshipKinds: ["calls", "constructs", "type-use", "heritage"],
          completeSourceInventory: options.authoritative,
          runtimeBehavior: false,
        },
        entities,
        relationships,
        responsibilities: sortedResponsibilities,
        unassignedEntityIds,
        diagnostics,
      };
    }
    packages/scanner/src/semantic.ts:90-93
    function canonicalSymbol(checker: ts.TypeChecker, symbol: ts.Symbol | undefined): ts.Symbol | undefined {
      if (!symbol) return undefined;
      return symbol.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
    }
    packages/scanner/src/semantic.ts:130-143
    function relationshipKind(node: ts.Node): SemanticRelationshipKind | undefined {
      let current: ts.Node | undefined = node;
      let typeUse = false;
      while (current?.parent) {
        const parent: ts.Node = current.parent;
        if (ts.isCallExpression(parent) && parent.expression === current) return "calls";
        if (ts.isNewExpression(parent) && parent.expression === current) return "constructs";
        if (ts.isHeritageClause(parent)) return "heritage";
        if (ts.isTypeNode(parent)) typeUse = true;
        if (ts.isStatement(parent)) break;
        current = parent;
      }
      return typeUse ? "type-use" : undefined;
    }

source-traced: Extract code evidence

@topo/languages.scanProject requests TypeScript/JavaScript evidence through the scanner adapter; scanRepository parses and validates the supplied repository and options.

packages/languages/src/index.ts:158-242
export async function scanProject(
  options: ScanRepositoryOptions,
  selection: PluginSelection = { languages: ["typescript"], frameworks: [] },
): Promise<ScanResult> {
  validateSelection(selection);
  const { createTypeScriptScannerAdapter, ScanError } = await import("@topo/scanner");
  if (selection.languages.length === 1 && selection.languages[0] === "typescript" && !selection.frameworks.length) {
    return createTypeScriptScannerAdapter().scan(options);
  }
  const captured = await captureInventory(options.root);
  const repositoryId = options.repositoryId ?? basename(options.root);
  const hasTypeScript = captured.files.some((file: { path: string }) => /\.(?:[cm]?[jt]s|[jt]sx)$/.test(file.path));
  let result: ScanResult | undefined;
  const contributions: Contribution[] = [];
  if (selection.languages.includes("typescript") && hasTypeScript) {
    result = await createTypeScriptScannerAdapter().scan({ ...options, quality: { ...options.quality, allowPartial: true } });
    contributions.push(typescriptContribution(result));
  } else if (selection.languages.includes("typescript")) {
    contributions.push({
      plugin: { id: "typescript", kind: "language", version: "1.0",
        languages: ["typescript", "javascript"], capabilities: ["compiler-declarations", "static-references"] },
      entities: [], relationships: [], unresolved: [], diagnostics: [], extensions: {},
      coverage: { status: "unsupported", analyzedFiles: [], limitations: ["No TypeScript/JavaScript source was captured for the selected adapter."] },
    });
  }
  if (selection.languages.includes("rust")) contributions.push(await rustContribution(captured));
  if (selection.frameworks.includes("tauri")) {
    const { scanTauri } = await import("./plugins/tauri.mjs");
    contributions.push(await scanTauri(captured, contributions));
  }
  const languageEvidence: LanguageEvidence = { schemaVersion: "1.0", source: captured.snapshot, contributions };
  assertFacts(languageEvidence, captured.files);
  const diagnostics = contributions.flatMap((contribution) => [
    ...contribution.diagnostics,
    ...contribution.coverage.limitations.map((message) => ({
      code: `${contribution.plugin.id}.coverage`, severity: "warning" as const, message,
    })),
  ]);
  const authoritative = contributions.every((item) => item.coverage.status === "complete");
  if (!authoritative && !options.quality?.allowPartial) {
    throw new ScanError("Selected adapters produced partial evidence; use --allow-partial to publish it (exit 2).", diagnostics);
  }
  const graph = result?.graph ?? createGraphDocument({
    graphId: `repo:${repositoryId}`, repository: { id: repositoryId, label: repositoryId,
      ...(options.revision === undefined ? {} : { revision: options.revision }) },
  });
  const knownPaths = new Set(graph.nodes.filter((node) => node.identity.kind === "path").map((node) => node.identity.value));
  for (const file of captured.files) {
    if (file.language !== "rust" && !/(?:^|\/)Cargo\.toml$/.test(file.path)) continue;
    if (!knownPaths.has(file.path)) graph.nodes.push({
      id: createPathNodeId(file.path), label: file.path, kind: "file",
      identity: { kind: "path", value: file.path }, fingerprint: `sha256:${file.sha256}`,
    });
  }
  graph.nodes.sort((a, b) => a.id.localeCompare(b.id, "en"));
  for (const contribution of contributions.filter((item) => item.plugin.id !== "typescript")) {
    graph.modules.push({ id: `@topo/${contribution.plugin.id}`, version: "1.0.0", schemaVersion: "1.0" });
  }
  graph.extensions[LANGUAGE_EVIDENCE_KEY] = json(languageEvidence);
  graph.extensions["dev.topo.scanner"] = json({ authoritative, status: authoritative ? "complete" : "partial", diagnostics });
  assertGraphDocument(graph);
  await assertInventoryCurrent(captured);
  if (options.revision !== undefined && options.revision !== captured.repository.revision) throw new Error("Source revision changed during scan");
  const logicalArchitecture: LogicalArchitectureDocument = result?.logicalArchitecture ?? {
    schemaVersion: "1.0" as const, graphId: graph.graphId,
    ...(options.revision === undefined ? {} : { revision: options.revision }),
    snapshotId: `sha256:${captured.snapshot.sha256}`, positionNamespaceId: `repo:${repositoryId}`,
    coverage: { languages: ["javascript", "typescript"], relationshipKinds: [], completeSourceInventory: false, runtimeBehavior: false },
    entities: [], relationships: [], responsibilities: [], unassignedEntityIds: [], diagnostics: [],
  };
  const metrics = result?.metrics ?? {
    configCount: 0, workspacePackageCount: 0, coveredWorkspacePackageCount: 0,
    sourceFileCount: 0,
    assetFileCount: 0, linesOfCode: 0, localImportCount: 0, assetImportCount: 0,
    externalImportCount: 0, unresolvedImportCount: 0,
  };
  const rustPaths = new Set(contributions.find((item) => item.plugin.id === "rust")?.coverage.analyzedFiles ?? []);
  const rustFiles = captured.files.filter((file) => file.language === "rust" && rustPaths.has(file.path));
  return { graph, logicalArchitecture, diagnostics, authoritative, metrics: {
    ...metrics,
    sourceFileCount: metrics.sourceFileCount + rustFiles.length,
    linesOfCode: metrics.linesOfCode + rustFiles
      .reduce((total, file) => total + file.contents.split(/\r?\n/).filter((line) => line.trim()).length, 0),
  } };
}
packages/scanner/src/typescript-scanner.ts:921-1443
export async function scanRepository(
  input: ScanRepositoryOptions,
): Promise<ScanResult> {
  const options = parseScanRepositoryOptions(input);
  const quality = { ...DEFAULT_QUALITY, ...options.quality };
  await assertDirectory(options.root);
  const canonicalRoot = await realpath(options.root);

  const files = await walkFiles(options.root);
  const inventoryPaths = new Set(files.map((filePath) => path.resolve(filePath)));
  const configPaths = files.filter(isConfigFile).sort(compareText);
  const sourcePaths = files.filter(isSourceFile).sort(compareText);
  const workspaces = await discoverWorkspacePackages(options.root, files);
  const declaredPackageNames = await discoverDeclaredPackageNames(
    options.root,
    files,
  );
  const diagnostics: ScanDiagnostic[] = [];
  const outputMappings: OutputMapping[] = [];
  const configuredSources = await loadConfiguredSources(
    options.root,
    configPaths,
    diagnostics,
    outputMappings,
    inventoryPaths,
  );
  const unconfiguredPaths = sourcePaths.filter(
    (sourcePath) =>
      !configuredSources.has(toRepositoryPath(options.root, sourcePath)),
  );
  const inferredSources = await loadInferredSources(
    options.root,
    unconfiguredPaths,
  );
  const sources = new Map([...configuredSources, ...inferredSources]);
  if (configuredSources.size > 0 && inferredSources.size > 0) {
    diagnostics.push({
      code: "inferred-source-configuration",
      severity: "warning",
      message: `${inferredSources.size} source files were not covered by a discovered TypeScript config and used default compiler options.`,
    });
  }
  const sortedSources = [...sources.values()].sort((left, right) =>
    compareText(left.repositoryPath, right.repositoryPath),
  );
  const sourceByAbsolutePath = new Map(
    sortedSources.map((source) => [path.resolve(source.absolutePath), source]),
  );
  const filePaths = inventoryPaths;

  const nodes = new Map<string, GraphNode>();
  const evidence = new Map<string, Evidence>();
  const assets = new Map<string, AssetRecord>();
  for (const source of sortedSources) {
    const nodeId = createPathNodeId(source.repositoryPath);
    nodes.set(nodeId, {
      id: nodeId,
      label: path.posix.basename(source.repositoryPath),
      kind: "file",
      identity: { kind: "path", value: source.repositoryPath },
      fingerprint: source.fingerprint,
    });
    const item = sourceEvidence(source);
    evidence.set(item.id, item);
  }

  const edgeEvidence = new Map<
    string,
    { sourceId: string; targetId: string; evidenceIds: Set<string> }
  >();
  let localImportCount = 0;
  let assetImportCount = 0;
  let externalImportCount = 0;
  let unresolvedImportCount = 0;

  for (const source of sortedSources) {
    const imports = [...source.imports].sort(compareText);
    for (const specifier of imports) {
      const importItem = importEvidence(source, specifier);
      const assetPath = assetSpecifierPath(specifier);
      if (assetPath !== undefined) {
        const absoluteAssetPath = path.resolve(
          path.dirname(source.absolutePath),
          assetPath,
        );
        if (
          !isWithin(options.root, absoluteAssetPath) ||
          !filePaths.has(absoluteAssetPath)
        ) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-asset",
            severity: "error",
            message: `Could not resolve local CSS asset "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        let asset = assets.get(absoluteAssetPath);
        if (asset === undefined) {
          const content = await readFile(absoluteAssetPath, "utf8");
          asset = {
            absolutePath: absoluteAssetPath,
            repositoryPath: toRepositoryPath(
              options.root,
              absoluteAssetPath,
            ),
            fingerprint: sha256(content),
          };
          assets.set(absoluteAssetPath, asset);
          const assetId = createPathNodeId(asset.repositoryPath);
          nodes.set(assetId, {
            id: assetId,
            label: path.posix.basename(asset.repositoryPath),
            kind: "asset",
            identity: { kind: "path", value: asset.repositoryPath },
            fingerprint: asset.fingerprint,
          });
          const item = assetEvidence(asset);
          evidence.set(item.id, item);
        }
        const sourceId = createPathNodeId(source.repositoryPath);
        const targetId = createPathNodeId(asset.repositoryPath);
        const edgeId = createEdgeId("imports", sourceId, targetId);
        evidence.set(importItem.id, importItem);
        const accumulated = edgeEvidence.get(edgeId) ?? {
          sourceId,
          targetId,
          evidenceIds: new Set<string>(),
        };
        accumulated.evidenceIds.add(importItem.id);
        edgeEvidence.set(edgeId, accumulated);
        assetImportCount += 1;
        continue;
      }
      const resolved = ts.resolveModuleName(
        specifier,
        source.absolutePath,
        source.compilerOptions,
        ts.sys,
        source.moduleResolutionCache,
      ).resolvedModule;
      let targetId: string | undefined;
      const workspace = workspaceForSpecifier(specifier, workspaces);

      if (workspace !== undefined) {
        let target: SourceRecord | undefined;
        if (resolved !== undefined) {
          const selected = resolveCompilerSelectedSource(
            options.root,
            canonicalRoot,
            resolved.resolvedFileName,
            outputMappings,
            sourceByAbsolutePath,
          );
          if (selected.kind === "resolved") {
            target = selected.source;
          } else if (selected.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          } else if (
            resolved.resolvedFileName
              .split(path.sep)
              .includes("node_modules") ||
            !isWithin(options.root, resolved.resolvedFileName)
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          }
        } else {
          const suffix =
            specifier === workspace.name
              ? ""
              : specifier.slice(workspace.name.length + 1);
          const exportedSubpath =
            suffix.length === 0
              ? workspace.manifest.exports !== undefined
              : hasExactWorkspaceExport(
                  workspace.manifest.exports,
                  `./${suffix}`,
                );
          const physicalPackage = physicalWorkspacePackageState(
            workspace,
            source.absolutePath,
          );
          if (exportedSubpath && physicalPackage !== "other") {
            const virtualResolved = resolveWorkspaceModuleName(
              options.root,
              canonicalRoot,
              workspace,
              source,
              specifier,
              outputMappings,
              sourceByAbsolutePath,
            );
            if (virtualResolved !== undefined) {
              const selected = resolveCompilerSelectedSource(
                options.root,
                canonicalRoot,
                virtualResolved.resolvedFileName,
                outputMappings,
                sourceByAbsolutePath,
              );
              if (selected.kind === "resolved") {
                target = selected.source;
              } else if (selected.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (physicalPackage !== "other") {
            target = resolveSourceCandidate(
              sourceCandidatePaths(workspace, specifier),
              sourceByAbsolutePath,
            );
          }
        }
        if (targetId === undefined) {
          if (target !== undefined) {
            targetId = createPathNodeId(target.repositoryPath);
            localImportCount += 1;
          } else {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "unresolved-workspace-import",
              severity: "error",
              message: `Could not resolve workspace import "${specifier}" from "${source.repositoryPath}".`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        resolved.resolvedFileName
          .split(path.sep)
          .includes("node_modules")
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else if (resolved !== undefined && isWithin(options.root, resolved.resolvedFileName)) {
        const target = sourceByAbsolutePath.get(
          path.resolve(resolved.resolvedFileName),
        );
        if (target !== undefined) {
          targetId = createPathNodeId(target.repositoryPath);
          localImportCount += 1;
        } else {
          const generated = resolveGeneratedOutput(
            path.resolve(resolved.resolvedFileName),
            outputMappings,
            sourceByAbsolutePath,
          );
          if (generated.kind === "resolved") {
            targetId = createPathNodeId(generated.source.repositoryPath);
            localImportCount += 1;
          } else if (generated.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${generated.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        !isWithin(options.root, resolved.resolvedFileName)
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else {
        const local =
          specifier.startsWith(".") ||
          specifier.startsWith("/") ||
          (isPathAlias(specifier, source.compilerOptions) &&
            !declaredPackageNames.has(packageName(specifier)));
        if (local) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-import",
            severity: "error",
            message: `Could not resolve local import "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      }

      if (targetId === undefined) {
        unresolvedImportCount += 1;
        diagnostics.push({
          code: "resolved-import-outside-scan",
          severity: "error",
          message: `Resolved import "${specifier}" is not represented by a scanned source file.`,
          path: source.repositoryPath,
          specifier,
        });
        continue;
      }

      const sourceId = createPathNodeId(source.repositoryPath);
      const edgeId = createEdgeId("imports", sourceId, targetId);
      evidence.set(importItem.id, importItem);
      const accumulated = edgeEvidence.get(edgeId) ?? {
        sourceId,
        targetId,
        evidenceIds: new Set<string>(),
      };
      accumulated.evidenceIds.add(importItem.id);
      edgeEvidence.set(edgeId, accumulated);
    }
  }

  const edges: GraphEdge[] = [...edgeEvidence.entries()]
    .sort(([left], [right]) => compareText(left, right))
    .map(([id, edge]) => ({
      id,
      label: "imports",
      type: "imports",
      sourceId: edge.sourceId,
      targetId: edge.targetId,
      provenance: provenance([...edge.evidenceIds]),
    }));
  const coveredWorkspacePackageCount = workspaces.filter((workspace) =>
    sortedSources.some(
      (source) =>
        source.absolutePath.startsWith(`${workspace.directory}${path.sep}`),
    ),
  ).length;
  const metrics: ScanMetrics = {
    configCount: configPaths.length,
    workspacePackageCount: workspaces.length,
    coveredWorkspacePackageCount,
    sourceFileCount: sortedSources.length,
    assetFileCount: assets.size,
    linesOfCode: sortedSources.reduce((sum, source) => sum + source.lines, 0),
    localImportCount,
    assetImportCount,
    externalImportCount,
    unresolvedImportCount,
  };
  const rootCargo = files.includes(path.join(options.root, "Cargo.toml"));
  diagnostics.push(...qualityDiagnostics(metrics, quality, rootCargo));
  diagnostics.sort(
    (left, right) =>
      compareText(left.path ?? "", right.path ?? "") ||
      compareText(left.code, right.code) ||
      compareText(left.specifier ?? "", right.specifier ?? ""),
  );

  const errors = diagnostics.filter(
    (diagnostic) => diagnostic.severity === "error",
  );
  const fatalEmpty = sortedSources.length === 0;
  if (
    errors.length > 0 &&
    (!quality.allowPartial || fatalEmpty)
  ) {
    throw new ScanError(
      `Repository scan failed with ${errors.length} error diagnostic${errors.length === 1 ? "" : "s"}.`,
      diagnostics,
    );
  }

  const authoritative = errors.length === 0;
  const repositoryId =
    options.repositoryId ?? path.basename(options.root);
  const rootLabel = path.basename(options.root);
  const scannerExtension: JsonValue = {
    authoritative,
    status: authoritative ? "complete" : "partial",
    adapter: {
      id: TYPESCRIPT_SCANNER_MANIFEST.id,
      version: TYPESCRIPT_SCANNER_MANIFEST.version,
      contractVersion: TYPESCRIPT_SCANNER_MANIFEST.contractVersion,
      capabilities: {
        languages: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.languages],
        granularity: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.granularity],
        relationships: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.relationships,
        ],
        moduleResolution:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.moduleResolution,
        workspaceManifests: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.workspaceManifests,
        ],
        opaqueAssets: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.opaqueAssets,
        ],
        partialResults:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.partialResults,
      },
    },
    metrics: { ...metrics },
    diagnostics: diagnostics.map((diagnostic) => ({
      code: diagnostic.code,
      severity: diagnostic.severity,
      message: diagnostic.message,
      ...(diagnostic.path === undefined ? {} : { path: diagnostic.path }),
      ...(diagnostic.specifier === undefined
        ? {}
        : { specifier: diagnostic.specifier }),
    })),
  };
  const graph = createGraphDocument({
    graphId: `repo:${repositoryId}`,
    repository: {
      id: repositoryId,
      label: rootLabel,
      ...(options.revision === undefined
        ? {}
        : { revision: options.revision }),
    },
    modules: [
      {
        id: SCANNER_MODULE_ID,
        version: SCANNER_VERSION,
        schemaVersion: GRAPH_SCHEMA_VERSION,
      },
    ],
    nodes: [...nodes.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    edges,
    containers: directoriesForPaths(
      rootLabel,
      [
        ...sortedSources.map((source) => source.repositoryPath),
        ...[...assets.values()].map((asset) => asset.repositoryPath),
      ].sort(compareText),
    ),
    attributes: sortedSources.flatMap((source) => {
      const nodeId = createPathNodeId(source.repositoryPath);
      const evidenceId = `evidence:source:${source.repositoryPath}`;
      return [
        {
          id: createAttributeId(nodeId, "dev.topo.source.lines"),
          subject: { kind: "node" as const, id: nodeId },
          key: "dev.topo.source.lines",
          value: source.lines,
          provenance: provenance([evidenceId]),
          evidenceIds: [evidenceId],
          confidence: 1,
          witnesses: [
            {
              nodeId,
              fingerprint: source.fingerprint,
              relationship: "self" as const,
            },
          ],
        },
      ];
    }),
    evidence: [...evidence.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    extensions: {
      "dev.topo.scanner": scannerExtension,
    },
  });
  serializeGraphDocument(graph);
  const logicalArchitecture = await extractLogicalArchitecture({
    root: options.root,
    graphId: graph.graphId,
    graph,
    authoritative,
    ...(options.revision ? { revision: options.revision } : {}),
    sources: sortedSources,
    ...(options.responsibilityFile ? { responsibilityFile: options.responsibilityFile } : {}),
  });
  return { graph, logicalArchitecture, diagnostics, metrics, authoritative };
}

source-traced: Parse configs and source files

Configured source loading and source-record construction use TypeScript configuration and parsing APIs.

packages/scanner/src/typescript-scanner.ts:224-294
async function loadConfiguredSources(
  root: string,
  configPaths: readonly string[],
  diagnostics: ScanDiagnostic[],
  outputMappings: OutputMapping[],
  inventoryPaths: ReadonlySet<string>,
): Promise<Map<string, SourceRecord>> {
  const records = new Map<string, SourceRecord>();
  const ignoredConfigSources = new Set<string>();

  for (const configPath of configPaths) {
    const config = ts.readConfigFile(configPath, ts.sys.readFile);
    if (config.error !== undefined) {
      diagnostics.push(formatTypeScriptDiagnostic(root, config.error));
      continue;
    }
    const parsed = ts.parseJsonConfigFileContent(
      config.config,
      ts.sys,
      path.dirname(configPath),
      undefined,
      configPath,
    );
    diagnostics.push(
      ...parsed.errors.map((diagnostic) =>
        formatTypeScriptDiagnostic(root, diagnostic),
      ),
    );
    validateConfiguredTypeLibraries(
      root,
      configPath,
      parsed.options,
      diagnostics,
    );
    if (
      parsed.options.rootDir !== undefined &&
      parsed.options.outDir !== undefined
    ) {
      outputMappings.push({
        configPath: toRepositoryPath(root, configPath),
        rootDirectory: path.resolve(parsed.options.rootDir),
        outputDirectory: path.resolve(parsed.options.outDir),
      });
    }
    const moduleResolutionCache = ts.createModuleResolutionCache(
      path.dirname(configPath),
      (fileName) => fileName,
      parsed.options,
    );
    await collectConfiguredFiles(
      root,
      parsed.fileNames,
      parsed.options,
      moduleResolutionCache,
      records,
      inventoryPaths,
      ignoredConfigSources,
    );
  }

  if (ignoredConfigSources.size > 0) {
    const paths = [...ignoredConfigSources].sort(compareText);
    diagnostics.push({
      code: "ignored-config-source",
      severity: "warning",
      message: `${paths.length} TypeScript-configured files were excluded by Git or ignore rules: ${paths.join(", ")}.`,
    });
  }

  return records;
}
packages/scanner/src/typescript-scanner.ts:173-197
async function createSourceRecord(
  root: string,
  absolutePath: string,
  compilerOptions: ts.CompilerOptions,
  moduleResolutionCache: ts.ModuleResolutionCache,
): Promise<SourceRecord> {
  const repositoryPath = toRepositoryPath(root, absolutePath);
  const content = await readFile(absolutePath, "utf8");
  const sourceFile = ts.createSourceFile(
    absolutePath,
    content,
    ts.ScriptTarget.Latest,
    false,
    scriptKind(absolutePath),
  );
  return {
    absolutePath,
    repositoryPath,
    compilerOptions,
    moduleResolutionCache,
    imports: importSpecifiers(sourceFile),
    fingerprint: sha256(content),
    lines: content.length === 0 ? 0 : content.split(/\r\n?|\n/u).length,
  };
}

source-traced: Compiler options and syntax trees

Compiler results feed Topocode source records; file fingerprints and evidence are assembled by Topocode.

packages/scanner/src/typescript-scanner.ts:224-294
async function loadConfiguredSources(
  root: string,
  configPaths: readonly string[],
  diagnostics: ScanDiagnostic[],
  outputMappings: OutputMapping[],
  inventoryPaths: ReadonlySet<string>,
): Promise<Map<string, SourceRecord>> {
  const records = new Map<string, SourceRecord>();
  const ignoredConfigSources = new Set<string>();

  for (const configPath of configPaths) {
    const config = ts.readConfigFile(configPath, ts.sys.readFile);
    if (config.error !== undefined) {
      diagnostics.push(formatTypeScriptDiagnostic(root, config.error));
      continue;
    }
    const parsed = ts.parseJsonConfigFileContent(
      config.config,
      ts.sys,
      path.dirname(configPath),
      undefined,
      configPath,
    );
    diagnostics.push(
      ...parsed.errors.map((diagnostic) =>
        formatTypeScriptDiagnostic(root, diagnostic),
      ),
    );
    validateConfiguredTypeLibraries(
      root,
      configPath,
      parsed.options,
      diagnostics,
    );
    if (
      parsed.options.rootDir !== undefined &&
      parsed.options.outDir !== undefined
    ) {
      outputMappings.push({
        configPath: toRepositoryPath(root, configPath),
        rootDirectory: path.resolve(parsed.options.rootDir),
        outputDirectory: path.resolve(parsed.options.outDir),
      });
    }
    const moduleResolutionCache = ts.createModuleResolutionCache(
      path.dirname(configPath),
      (fileName) => fileName,
      parsed.options,
    );
    await collectConfiguredFiles(
      root,
      parsed.fileNames,
      parsed.options,
      moduleResolutionCache,
      records,
      inventoryPaths,
      ignoredConfigSources,
    );
  }

  if (ignoredConfigSources.size > 0) {
    const paths = [...ignoredConfigSources].sort(compareText);
    diagnostics.push({
      code: "ignored-config-source",
      severity: "warning",
      message: `${paths.length} TypeScript-configured files were excluded by Git or ignore rules: ${paths.join(", ")}.`,
    });
  }

  return records;
}
packages/scanner/src/typescript-scanner.ts:173-197
async function createSourceRecord(
  root: string,
  absolutePath: string,
  compilerOptions: ts.CompilerOptions,
  moduleResolutionCache: ts.ModuleResolutionCache,
): Promise<SourceRecord> {
  const repositoryPath = toRepositoryPath(root, absolutePath);
  const content = await readFile(absolutePath, "utf8");
  const sourceFile = ts.createSourceFile(
    absolutePath,
    content,
    ts.ScriptTarget.Latest,
    false,
    scriptKind(absolutePath),
  );
  return {
    absolutePath,
    repositoryPath,
    compilerOptions,
    moduleResolutionCache,
    imports: importSpecifiers(sourceFile),
    fingerprint: sha256(content),
    lines: content.length === 0 ? 0 : content.split(/\r\n?|\n/u).length,
  };
}

source-traced: Resolve imports and workspace exports

For each import, use compiler resolution and the supported workspace-aware resolution path where applicable.

packages/scanner/src/typescript-scanner.ts:921-1443
export async function scanRepository(
  input: ScanRepositoryOptions,
): Promise<ScanResult> {
  const options = parseScanRepositoryOptions(input);
  const quality = { ...DEFAULT_QUALITY, ...options.quality };
  await assertDirectory(options.root);
  const canonicalRoot = await realpath(options.root);

  const files = await walkFiles(options.root);
  const inventoryPaths = new Set(files.map((filePath) => path.resolve(filePath)));
  const configPaths = files.filter(isConfigFile).sort(compareText);
  const sourcePaths = files.filter(isSourceFile).sort(compareText);
  const workspaces = await discoverWorkspacePackages(options.root, files);
  const declaredPackageNames = await discoverDeclaredPackageNames(
    options.root,
    files,
  );
  const diagnostics: ScanDiagnostic[] = [];
  const outputMappings: OutputMapping[] = [];
  const configuredSources = await loadConfiguredSources(
    options.root,
    configPaths,
    diagnostics,
    outputMappings,
    inventoryPaths,
  );
  const unconfiguredPaths = sourcePaths.filter(
    (sourcePath) =>
      !configuredSources.has(toRepositoryPath(options.root, sourcePath)),
  );
  const inferredSources = await loadInferredSources(
    options.root,
    unconfiguredPaths,
  );
  const sources = new Map([...configuredSources, ...inferredSources]);
  if (configuredSources.size > 0 && inferredSources.size > 0) {
    diagnostics.push({
      code: "inferred-source-configuration",
      severity: "warning",
      message: `${inferredSources.size} source files were not covered by a discovered TypeScript config and used default compiler options.`,
    });
  }
  const sortedSources = [...sources.values()].sort((left, right) =>
    compareText(left.repositoryPath, right.repositoryPath),
  );
  const sourceByAbsolutePath = new Map(
    sortedSources.map((source) => [path.resolve(source.absolutePath), source]),
  );
  const filePaths = inventoryPaths;

  const nodes = new Map<string, GraphNode>();
  const evidence = new Map<string, Evidence>();
  const assets = new Map<string, AssetRecord>();
  for (const source of sortedSources) {
    const nodeId = createPathNodeId(source.repositoryPath);
    nodes.set(nodeId, {
      id: nodeId,
      label: path.posix.basename(source.repositoryPath),
      kind: "file",
      identity: { kind: "path", value: source.repositoryPath },
      fingerprint: source.fingerprint,
    });
    const item = sourceEvidence(source);
    evidence.set(item.id, item);
  }

  const edgeEvidence = new Map<
    string,
    { sourceId: string; targetId: string; evidenceIds: Set<string> }
  >();
  let localImportCount = 0;
  let assetImportCount = 0;
  let externalImportCount = 0;
  let unresolvedImportCount = 0;

  for (const source of sortedSources) {
    const imports = [...source.imports].sort(compareText);
    for (const specifier of imports) {
      const importItem = importEvidence(source, specifier);
      const assetPath = assetSpecifierPath(specifier);
      if (assetPath !== undefined) {
        const absoluteAssetPath = path.resolve(
          path.dirname(source.absolutePath),
          assetPath,
        );
        if (
          !isWithin(options.root, absoluteAssetPath) ||
          !filePaths.has(absoluteAssetPath)
        ) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-asset",
            severity: "error",
            message: `Could not resolve local CSS asset "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        let asset = assets.get(absoluteAssetPath);
        if (asset === undefined) {
          const content = await readFile(absoluteAssetPath, "utf8");
          asset = {
            absolutePath: absoluteAssetPath,
            repositoryPath: toRepositoryPath(
              options.root,
              absoluteAssetPath,
            ),
            fingerprint: sha256(content),
          };
          assets.set(absoluteAssetPath, asset);
          const assetId = createPathNodeId(asset.repositoryPath);
          nodes.set(assetId, {
            id: assetId,
            label: path.posix.basename(asset.repositoryPath),
            kind: "asset",
            identity: { kind: "path", value: asset.repositoryPath },
            fingerprint: asset.fingerprint,
          });
          const item = assetEvidence(asset);
          evidence.set(item.id, item);
        }
        const sourceId = createPathNodeId(source.repositoryPath);
        const targetId = createPathNodeId(asset.repositoryPath);
        const edgeId = createEdgeId("imports", sourceId, targetId);
        evidence.set(importItem.id, importItem);
        const accumulated = edgeEvidence.get(edgeId) ?? {
          sourceId,
          targetId,
          evidenceIds: new Set<string>(),
        };
        accumulated.evidenceIds.add(importItem.id);
        edgeEvidence.set(edgeId, accumulated);
        assetImportCount += 1;
        continue;
      }
      const resolved = ts.resolveModuleName(
        specifier,
        source.absolutePath,
        source.compilerOptions,
        ts.sys,
        source.moduleResolutionCache,
      ).resolvedModule;
      let targetId: string | undefined;
      const workspace = workspaceForSpecifier(specifier, workspaces);

      if (workspace !== undefined) {
        let target: SourceRecord | undefined;
        if (resolved !== undefined) {
          const selected = resolveCompilerSelectedSource(
            options.root,
            canonicalRoot,
            resolved.resolvedFileName,
            outputMappings,
            sourceByAbsolutePath,
          );
          if (selected.kind === "resolved") {
            target = selected.source;
          } else if (selected.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          } else if (
            resolved.resolvedFileName
              .split(path.sep)
              .includes("node_modules") ||
            !isWithin(options.root, resolved.resolvedFileName)
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          }
        } else {
          const suffix =
            specifier === workspace.name
              ? ""
              : specifier.slice(workspace.name.length + 1);
          const exportedSubpath =
            suffix.length === 0
              ? workspace.manifest.exports !== undefined
              : hasExactWorkspaceExport(
                  workspace.manifest.exports,
                  `./${suffix}`,
                );
          const physicalPackage = physicalWorkspacePackageState(
            workspace,
            source.absolutePath,
          );
          if (exportedSubpath && physicalPackage !== "other") {
            const virtualResolved = resolveWorkspaceModuleName(
              options.root,
              canonicalRoot,
              workspace,
              source,
              specifier,
              outputMappings,
              sourceByAbsolutePath,
            );
            if (virtualResolved !== undefined) {
              const selected = resolveCompilerSelectedSource(
                options.root,
                canonicalRoot,
                virtualResolved.resolvedFileName,
                outputMappings,
                sourceByAbsolutePath,
              );
              if (selected.kind === "resolved") {
                target = selected.source;
              } else if (selected.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (physicalPackage !== "other") {
            target = resolveSourceCandidate(
              sourceCandidatePaths(workspace, specifier),
              sourceByAbsolutePath,
            );
          }
        }
        if (targetId === undefined) {
          if (target !== undefined) {
            targetId = createPathNodeId(target.repositoryPath);
            localImportCount += 1;
          } else {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "unresolved-workspace-import",
              severity: "error",
              message: `Could not resolve workspace import "${specifier}" from "${source.repositoryPath}".`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        resolved.resolvedFileName
          .split(path.sep)
          .includes("node_modules")
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else if (resolved !== undefined && isWithin(options.root, resolved.resolvedFileName)) {
        const target = sourceByAbsolutePath.get(
          path.resolve(resolved.resolvedFileName),
        );
        if (target !== undefined) {
          targetId = createPathNodeId(target.repositoryPath);
          localImportCount += 1;
        } else {
          const generated = resolveGeneratedOutput(
            path.resolve(resolved.resolvedFileName),
            outputMappings,
            sourceByAbsolutePath,
          );
          if (generated.kind === "resolved") {
            targetId = createPathNodeId(generated.source.repositoryPath);
            localImportCount += 1;
          } else if (generated.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${generated.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        !isWithin(options.root, resolved.resolvedFileName)
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else {
        const local =
          specifier.startsWith(".") ||
          specifier.startsWith("/") ||
          (isPathAlias(specifier, source.compilerOptions) &&
            !declaredPackageNames.has(packageName(specifier)));
        if (local) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-import",
            severity: "error",
            message: `Could not resolve local import "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      }

      if (targetId === undefined) {
        unresolvedImportCount += 1;
        diagnostics.push({
          code: "resolved-import-outside-scan",
          severity: "error",
          message: `Resolved import "${specifier}" is not represented by a scanned source file.`,
          path: source.repositoryPath,
          specifier,
        });
        continue;
      }

      const sourceId = createPathNodeId(source.repositoryPath);
      const edgeId = createEdgeId("imports", sourceId, targetId);
      evidence.set(importItem.id, importItem);
      const accumulated = edgeEvidence.get(edgeId) ?? {
        sourceId,
        targetId,
        evidenceIds: new Set<string>(),
      };
      accumulated.evidenceIds.add(importItem.id);
      edgeEvidence.set(edgeId, accumulated);
    }
  }

  const edges: GraphEdge[] = [...edgeEvidence.entries()]
    .sort(([left], [right]) => compareText(left, right))
    .map(([id, edge]) => ({
      id,
      label: "imports",
      type: "imports",
      sourceId: edge.sourceId,
      targetId: edge.targetId,
      provenance: provenance([...edge.evidenceIds]),
    }));
  const coveredWorkspacePackageCount = workspaces.filter((workspace) =>
    sortedSources.some(
      (source) =>
        source.absolutePath.startsWith(`${workspace.directory}${path.sep}`),
    ),
  ).length;
  const metrics: ScanMetrics = {
    configCount: configPaths.length,
    workspacePackageCount: workspaces.length,
    coveredWorkspacePackageCount,
    sourceFileCount: sortedSources.length,
    assetFileCount: assets.size,
    linesOfCode: sortedSources.reduce((sum, source) => sum + source.lines, 0),
    localImportCount,
    assetImportCount,
    externalImportCount,
    unresolvedImportCount,
  };
  const rootCargo = files.includes(path.join(options.root, "Cargo.toml"));
  diagnostics.push(...qualityDiagnostics(metrics, quality, rootCargo));
  diagnostics.sort(
    (left, right) =>
      compareText(left.path ?? "", right.path ?? "") ||
      compareText(left.code, right.code) ||
      compareText(left.specifier ?? "", right.specifier ?? ""),
  );

  const errors = diagnostics.filter(
    (diagnostic) => diagnostic.severity === "error",
  );
  const fatalEmpty = sortedSources.length === 0;
  if (
    errors.length > 0 &&
    (!quality.allowPartial || fatalEmpty)
  ) {
    throw new ScanError(
      `Repository scan failed with ${errors.length} error diagnostic${errors.length === 1 ? "" : "s"}.`,
      diagnostics,
    );
  }

  const authoritative = errors.length === 0;
  const repositoryId =
    options.repositoryId ?? path.basename(options.root);
  const rootLabel = path.basename(options.root);
  const scannerExtension: JsonValue = {
    authoritative,
    status: authoritative ? "complete" : "partial",
    adapter: {
      id: TYPESCRIPT_SCANNER_MANIFEST.id,
      version: TYPESCRIPT_SCANNER_MANIFEST.version,
      contractVersion: TYPESCRIPT_SCANNER_MANIFEST.contractVersion,
      capabilities: {
        languages: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.languages],
        granularity: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.granularity],
        relationships: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.relationships,
        ],
        moduleResolution:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.moduleResolution,
        workspaceManifests: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.workspaceManifests,
        ],
        opaqueAssets: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.opaqueAssets,
        ],
        partialResults:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.partialResults,
      },
    },
    metrics: { ...metrics },
    diagnostics: diagnostics.map((diagnostic) => ({
      code: diagnostic.code,
      severity: diagnostic.severity,
      message: diagnostic.message,
      ...(diagnostic.path === undefined ? {} : { path: diagnostic.path }),
      ...(diagnostic.specifier === undefined
        ? {}
        : { specifier: diagnostic.specifier }),
    })),
  };
  const graph = createGraphDocument({
    graphId: `repo:${repositoryId}`,
    repository: {
      id: repositoryId,
      label: rootLabel,
      ...(options.revision === undefined
        ? {}
        : { revision: options.revision }),
    },
    modules: [
      {
        id: SCANNER_MODULE_ID,
        version: SCANNER_VERSION,
        schemaVersion: GRAPH_SCHEMA_VERSION,
      },
    ],
    nodes: [...nodes.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    edges,
    containers: directoriesForPaths(
      rootLabel,
      [
        ...sortedSources.map((source) => source.repositoryPath),
        ...[...assets.values()].map((asset) => asset.repositoryPath),
      ].sort(compareText),
    ),
    attributes: sortedSources.flatMap((source) => {
      const nodeId = createPathNodeId(source.repositoryPath);
      const evidenceId = `evidence:source:${source.repositoryPath}`;
      return [
        {
          id: createAttributeId(nodeId, "dev.topo.source.lines"),
          subject: { kind: "node" as const, id: nodeId },
          key: "dev.topo.source.lines",
          value: source.lines,
          provenance: provenance([evidenceId]),
          evidenceIds: [evidenceId],
          confidence: 1,
          witnesses: [
            {
              nodeId,
              fingerprint: source.fingerprint,
              relationship: "self" as const,
            },
          ],
        },
      ];
    }),
    evidence: [...evidence.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    extensions: {
      "dev.topo.scanner": scannerExtension,
    },
  });
  serializeGraphDocument(graph);
  const logicalArchitecture = await extractLogicalArchitecture({
    root: options.root,
    graphId: graph.graphId,
    graph,
    authoritative,
    ...(options.revision ? { revision: options.revision } : {}),
    sources: sortedSources,
    ...(options.responsibilityFile ? { responsibilityFile: options.responsibilityFile } : {}),
  });
  return { graph, logicalArchitecture, diagnostics, metrics, authoritative };
}
packages/scanner/src/typescript-scanner.ts:741-777
function resolveWorkspaceModuleName(
  root: string,
  canonicalRoot: string,
  workspace: WorkspacePackage,
  source: SourceRecord,
  specifier: string,
  outputMappings: readonly OutputMapping[],
  sourceByAbsolutePath: ReadonlyMap<string, SourceRecord>,
): ts.ResolvedModuleFull | undefined {
  for (const allowGeneratedOutput of [false, true]) {
    const resolved = ts.resolveModuleName(
      specifier,
      source.absolutePath,
      source.compilerOptions,
      createWorkspaceModuleResolutionHost(
        root,
        canonicalRoot,
        workspace,
        outputMappings,
        sourceByAbsolutePath,
        allowGeneratedOutput,
      ),
      ts.createModuleResolutionCache(
        path.dirname(source.absolutePath),
        (fileName) =>
          ts.sys.useCaseSensitiveFileNames
            ? fileName
            : fileName.toLowerCase(),
        source.compilerOptions,
      ),
    ).resolvedModule;
    if (resolved !== undefined) {
      return resolved;
    }
  }
  return undefined;
}

source-traced: Resolved target or missing result

Topocode classifies the returned target, maps generated outputs to source where unambiguous, and records diagnostics for unresolved local/workspace imports.

packages/scanner/src/typescript-scanner.ts:921-1443
export async function scanRepository(
  input: ScanRepositoryOptions,
): Promise<ScanResult> {
  const options = parseScanRepositoryOptions(input);
  const quality = { ...DEFAULT_QUALITY, ...options.quality };
  await assertDirectory(options.root);
  const canonicalRoot = await realpath(options.root);

  const files = await walkFiles(options.root);
  const inventoryPaths = new Set(files.map((filePath) => path.resolve(filePath)));
  const configPaths = files.filter(isConfigFile).sort(compareText);
  const sourcePaths = files.filter(isSourceFile).sort(compareText);
  const workspaces = await discoverWorkspacePackages(options.root, files);
  const declaredPackageNames = await discoverDeclaredPackageNames(
    options.root,
    files,
  );
  const diagnostics: ScanDiagnostic[] = [];
  const outputMappings: OutputMapping[] = [];
  const configuredSources = await loadConfiguredSources(
    options.root,
    configPaths,
    diagnostics,
    outputMappings,
    inventoryPaths,
  );
  const unconfiguredPaths = sourcePaths.filter(
    (sourcePath) =>
      !configuredSources.has(toRepositoryPath(options.root, sourcePath)),
  );
  const inferredSources = await loadInferredSources(
    options.root,
    unconfiguredPaths,
  );
  const sources = new Map([...configuredSources, ...inferredSources]);
  if (configuredSources.size > 0 && inferredSources.size > 0) {
    diagnostics.push({
      code: "inferred-source-configuration",
      severity: "warning",
      message: `${inferredSources.size} source files were not covered by a discovered TypeScript config and used default compiler options.`,
    });
  }
  const sortedSources = [...sources.values()].sort((left, right) =>
    compareText(left.repositoryPath, right.repositoryPath),
  );
  const sourceByAbsolutePath = new Map(
    sortedSources.map((source) => [path.resolve(source.absolutePath), source]),
  );
  const filePaths = inventoryPaths;

  const nodes = new Map<string, GraphNode>();
  const evidence = new Map<string, Evidence>();
  const assets = new Map<string, AssetRecord>();
  for (const source of sortedSources) {
    const nodeId = createPathNodeId(source.repositoryPath);
    nodes.set(nodeId, {
      id: nodeId,
      label: path.posix.basename(source.repositoryPath),
      kind: "file",
      identity: { kind: "path", value: source.repositoryPath },
      fingerprint: source.fingerprint,
    });
    const item = sourceEvidence(source);
    evidence.set(item.id, item);
  }

  const edgeEvidence = new Map<
    string,
    { sourceId: string; targetId: string; evidenceIds: Set<string> }
  >();
  let localImportCount = 0;
  let assetImportCount = 0;
  let externalImportCount = 0;
  let unresolvedImportCount = 0;

  for (const source of sortedSources) {
    const imports = [...source.imports].sort(compareText);
    for (const specifier of imports) {
      const importItem = importEvidence(source, specifier);
      const assetPath = assetSpecifierPath(specifier);
      if (assetPath !== undefined) {
        const absoluteAssetPath = path.resolve(
          path.dirname(source.absolutePath),
          assetPath,
        );
        if (
          !isWithin(options.root, absoluteAssetPath) ||
          !filePaths.has(absoluteAssetPath)
        ) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-asset",
            severity: "error",
            message: `Could not resolve local CSS asset "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        let asset = assets.get(absoluteAssetPath);
        if (asset === undefined) {
          const content = await readFile(absoluteAssetPath, "utf8");
          asset = {
            absolutePath: absoluteAssetPath,
            repositoryPath: toRepositoryPath(
              options.root,
              absoluteAssetPath,
            ),
            fingerprint: sha256(content),
          };
          assets.set(absoluteAssetPath, asset);
          const assetId = createPathNodeId(asset.repositoryPath);
          nodes.set(assetId, {
            id: assetId,
            label: path.posix.basename(asset.repositoryPath),
            kind: "asset",
            identity: { kind: "path", value: asset.repositoryPath },
            fingerprint: asset.fingerprint,
          });
          const item = assetEvidence(asset);
          evidence.set(item.id, item);
        }
        const sourceId = createPathNodeId(source.repositoryPath);
        const targetId = createPathNodeId(asset.repositoryPath);
        const edgeId = createEdgeId("imports", sourceId, targetId);
        evidence.set(importItem.id, importItem);
        const accumulated = edgeEvidence.get(edgeId) ?? {
          sourceId,
          targetId,
          evidenceIds: new Set<string>(),
        };
        accumulated.evidenceIds.add(importItem.id);
        edgeEvidence.set(edgeId, accumulated);
        assetImportCount += 1;
        continue;
      }
      const resolved = ts.resolveModuleName(
        specifier,
        source.absolutePath,
        source.compilerOptions,
        ts.sys,
        source.moduleResolutionCache,
      ).resolvedModule;
      let targetId: string | undefined;
      const workspace = workspaceForSpecifier(specifier, workspaces);

      if (workspace !== undefined) {
        let target: SourceRecord | undefined;
        if (resolved !== undefined) {
          const selected = resolveCompilerSelectedSource(
            options.root,
            canonicalRoot,
            resolved.resolvedFileName,
            outputMappings,
            sourceByAbsolutePath,
          );
          if (selected.kind === "resolved") {
            target = selected.source;
          } else if (selected.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          } else if (
            resolved.resolvedFileName
              .split(path.sep)
              .includes("node_modules") ||
            !isWithin(options.root, resolved.resolvedFileName)
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          }
        } else {
          const suffix =
            specifier === workspace.name
              ? ""
              : specifier.slice(workspace.name.length + 1);
          const exportedSubpath =
            suffix.length === 0
              ? workspace.manifest.exports !== undefined
              : hasExactWorkspaceExport(
                  workspace.manifest.exports,
                  `./${suffix}`,
                );
          const physicalPackage = physicalWorkspacePackageState(
            workspace,
            source.absolutePath,
          );
          if (exportedSubpath && physicalPackage !== "other") {
            const virtualResolved = resolveWorkspaceModuleName(
              options.root,
              canonicalRoot,
              workspace,
              source,
              specifier,
              outputMappings,
              sourceByAbsolutePath,
            );
            if (virtualResolved !== undefined) {
              const selected = resolveCompilerSelectedSource(
                options.root,
                canonicalRoot,
                virtualResolved.resolvedFileName,
                outputMappings,
                sourceByAbsolutePath,
              );
              if (selected.kind === "resolved") {
                target = selected.source;
              } else if (selected.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (physicalPackage !== "other") {
            target = resolveSourceCandidate(
              sourceCandidatePaths(workspace, specifier),
              sourceByAbsolutePath,
            );
          }
        }
        if (targetId === undefined) {
          if (target !== undefined) {
            targetId = createPathNodeId(target.repositoryPath);
            localImportCount += 1;
          } else {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "unresolved-workspace-import",
              severity: "error",
              message: `Could not resolve workspace import "${specifier}" from "${source.repositoryPath}".`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        resolved.resolvedFileName
          .split(path.sep)
          .includes("node_modules")
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else if (resolved !== undefined && isWithin(options.root, resolved.resolvedFileName)) {
        const target = sourceByAbsolutePath.get(
          path.resolve(resolved.resolvedFileName),
        );
        if (target !== undefined) {
          targetId = createPathNodeId(target.repositoryPath);
          localImportCount += 1;
        } else {
          const generated = resolveGeneratedOutput(
            path.resolve(resolved.resolvedFileName),
            outputMappings,
            sourceByAbsolutePath,
          );
          if (generated.kind === "resolved") {
            targetId = createPathNodeId(generated.source.repositoryPath);
            localImportCount += 1;
          } else if (generated.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${generated.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        !isWithin(options.root, resolved.resolvedFileName)
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else {
        const local =
          specifier.startsWith(".") ||
          specifier.startsWith("/") ||
          (isPathAlias(specifier, source.compilerOptions) &&
            !declaredPackageNames.has(packageName(specifier)));
        if (local) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-import",
            severity: "error",
            message: `Could not resolve local import "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      }

      if (targetId === undefined) {
        unresolvedImportCount += 1;
        diagnostics.push({
          code: "resolved-import-outside-scan",
          severity: "error",
          message: `Resolved import "${specifier}" is not represented by a scanned source file.`,
          path: source.repositoryPath,
          specifier,
        });
        continue;
      }

      const sourceId = createPathNodeId(source.repositoryPath);
      const edgeId = createEdgeId("imports", sourceId, targetId);
      evidence.set(importItem.id, importItem);
      const accumulated = edgeEvidence.get(edgeId) ?? {
        sourceId,
        targetId,
        evidenceIds: new Set<string>(),
      };
      accumulated.evidenceIds.add(importItem.id);
      edgeEvidence.set(edgeId, accumulated);
    }
  }

  const edges: GraphEdge[] = [...edgeEvidence.entries()]
    .sort(([left], [right]) => compareText(left, right))
    .map(([id, edge]) => ({
      id,
      label: "imports",
      type: "imports",
      sourceId: edge.sourceId,
      targetId: edge.targetId,
      provenance: provenance([...edge.evidenceIds]),
    }));
  const coveredWorkspacePackageCount = workspaces.filter((workspace) =>
    sortedSources.some(
      (source) =>
        source.absolutePath.startsWith(`${workspace.directory}${path.sep}`),
    ),
  ).length;
  const metrics: ScanMetrics = {
    configCount: configPaths.length,
    workspacePackageCount: workspaces.length,
    coveredWorkspacePackageCount,
    sourceFileCount: sortedSources.length,
    assetFileCount: assets.size,
    linesOfCode: sortedSources.reduce((sum, source) => sum + source.lines, 0),
    localImportCount,
    assetImportCount,
    externalImportCount,
    unresolvedImportCount,
  };
  const rootCargo = files.includes(path.join(options.root, "Cargo.toml"));
  diagnostics.push(...qualityDiagnostics(metrics, quality, rootCargo));
  diagnostics.sort(
    (left, right) =>
      compareText(left.path ?? "", right.path ?? "") ||
      compareText(left.code, right.code) ||
      compareText(left.specifier ?? "", right.specifier ?? ""),
  );

  const errors = diagnostics.filter(
    (diagnostic) => diagnostic.severity === "error",
  );
  const fatalEmpty = sortedSources.length === 0;
  if (
    errors.length > 0 &&
    (!quality.allowPartial || fatalEmpty)
  ) {
    throw new ScanError(
      `Repository scan failed with ${errors.length} error diagnostic${errors.length === 1 ? "" : "s"}.`,
      diagnostics,
    );
  }

  const authoritative = errors.length === 0;
  const repositoryId =
    options.repositoryId ?? path.basename(options.root);
  const rootLabel = path.basename(options.root);
  const scannerExtension: JsonValue = {
    authoritative,
    status: authoritative ? "complete" : "partial",
    adapter: {
      id: TYPESCRIPT_SCANNER_MANIFEST.id,
      version: TYPESCRIPT_SCANNER_MANIFEST.version,
      contractVersion: TYPESCRIPT_SCANNER_MANIFEST.contractVersion,
      capabilities: {
        languages: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.languages],
        granularity: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.granularity],
        relationships: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.relationships,
        ],
        moduleResolution:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.moduleResolution,
        workspaceManifests: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.workspaceManifests,
        ],
        opaqueAssets: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.opaqueAssets,
        ],
        partialResults:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.partialResults,
      },
    },
    metrics: { ...metrics },
    diagnostics: diagnostics.map((diagnostic) => ({
      code: diagnostic.code,
      severity: diagnostic.severity,
      message: diagnostic.message,
      ...(diagnostic.path === undefined ? {} : { path: diagnostic.path }),
      ...(diagnostic.specifier === undefined
        ? {}
        : { specifier: diagnostic.specifier }),
    })),
  };
  const graph = createGraphDocument({
    graphId: `repo:${repositoryId}`,
    repository: {
      id: repositoryId,
      label: rootLabel,
      ...(options.revision === undefined
        ? {}
        : { revision: options.revision }),
    },
    modules: [
      {
        id: SCANNER_MODULE_ID,
        version: SCANNER_VERSION,
        schemaVersion: GRAPH_SCHEMA_VERSION,
      },
    ],
    nodes: [...nodes.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    edges,
    containers: directoriesForPaths(
      rootLabel,
      [
        ...sortedSources.map((source) => source.repositoryPath),
        ...[...assets.values()].map((asset) => asset.repositoryPath),
      ].sort(compareText),
    ),
    attributes: sortedSources.flatMap((source) => {
      const nodeId = createPathNodeId(source.repositoryPath);
      const evidenceId = `evidence:source:${source.repositoryPath}`;
      return [
        {
          id: createAttributeId(nodeId, "dev.topo.source.lines"),
          subject: { kind: "node" as const, id: nodeId },
          key: "dev.topo.source.lines",
          value: source.lines,
          provenance: provenance([evidenceId]),
          evidenceIds: [evidenceId],
          confidence: 1,
          witnesses: [
            {
              nodeId,
              fingerprint: source.fingerprint,
              relationship: "self" as const,
            },
          ],
        },
      ];
    }),
    evidence: [...evidence.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    extensions: {
      "dev.topo.scanner": scannerExtension,
    },
  });
  serializeGraphDocument(graph);
  const logicalArchitecture = await extractLogicalArchitecture({
    root: options.root,
    graphId: graph.graphId,
    graph,
    authoritative,
    ...(options.revision ? { revision: options.revision } : {}),
    sources: sortedSources,
    ...(options.responsibilityFile ? { responsibilityFile: options.responsibilityFile } : {}),
  });
  return { graph, logicalArchitecture, diagnostics, metrics, authoritative };
}
packages/scanner/src/typescript-scanner.ts:741-777
function resolveWorkspaceModuleName(
  root: string,
  canonicalRoot: string,
  workspace: WorkspacePackage,
  source: SourceRecord,
  specifier: string,
  outputMappings: readonly OutputMapping[],
  sourceByAbsolutePath: ReadonlyMap<string, SourceRecord>,
): ts.ResolvedModuleFull | undefined {
  for (const allowGeneratedOutput of [false, true]) {
    const resolved = ts.resolveModuleName(
      specifier,
      source.absolutePath,
      source.compilerOptions,
      createWorkspaceModuleResolutionHost(
        root,
        canonicalRoot,
        workspace,
        outputMappings,
        sourceByAbsolutePath,
        allowGeneratedOutput,
      ),
      ts.createModuleResolutionCache(
        path.dirname(source.absolutePath),
        (fileName) =>
          ts.sys.useCaseSensitiveFileNames
            ? fileName
            : fileName.toLowerCase(),
        source.compilerOptions,
      ),
    ).resolvedModule;
    if (resolved !== undefined) {
      return resolved;
    }
  }
  return undefined;
}

source-traced: Quality-gated graph and source set

After constructing and validating canonical file/import evidence and applying strict/partial quality gates, scanRepository invokes extractLogicalArchitecture.

packages/scanner/src/typescript-scanner.ts:921-1443
export async function scanRepository(
  input: ScanRepositoryOptions,
): Promise<ScanResult> {
  const options = parseScanRepositoryOptions(input);
  const quality = { ...DEFAULT_QUALITY, ...options.quality };
  await assertDirectory(options.root);
  const canonicalRoot = await realpath(options.root);

  const files = await walkFiles(options.root);
  const inventoryPaths = new Set(files.map((filePath) => path.resolve(filePath)));
  const configPaths = files.filter(isConfigFile).sort(compareText);
  const sourcePaths = files.filter(isSourceFile).sort(compareText);
  const workspaces = await discoverWorkspacePackages(options.root, files);
  const declaredPackageNames = await discoverDeclaredPackageNames(
    options.root,
    files,
  );
  const diagnostics: ScanDiagnostic[] = [];
  const outputMappings: OutputMapping[] = [];
  const configuredSources = await loadConfiguredSources(
    options.root,
    configPaths,
    diagnostics,
    outputMappings,
    inventoryPaths,
  );
  const unconfiguredPaths = sourcePaths.filter(
    (sourcePath) =>
      !configuredSources.has(toRepositoryPath(options.root, sourcePath)),
  );
  const inferredSources = await loadInferredSources(
    options.root,
    unconfiguredPaths,
  );
  const sources = new Map([...configuredSources, ...inferredSources]);
  if (configuredSources.size > 0 && inferredSources.size > 0) {
    diagnostics.push({
      code: "inferred-source-configuration",
      severity: "warning",
      message: `${inferredSources.size} source files were not covered by a discovered TypeScript config and used default compiler options.`,
    });
  }
  const sortedSources = [...sources.values()].sort((left, right) =>
    compareText(left.repositoryPath, right.repositoryPath),
  );
  const sourceByAbsolutePath = new Map(
    sortedSources.map((source) => [path.resolve(source.absolutePath), source]),
  );
  const filePaths = inventoryPaths;

  const nodes = new Map<string, GraphNode>();
  const evidence = new Map<string, Evidence>();
  const assets = new Map<string, AssetRecord>();
  for (const source of sortedSources) {
    const nodeId = createPathNodeId(source.repositoryPath);
    nodes.set(nodeId, {
      id: nodeId,
      label: path.posix.basename(source.repositoryPath),
      kind: "file",
      identity: { kind: "path", value: source.repositoryPath },
      fingerprint: source.fingerprint,
    });
    const item = sourceEvidence(source);
    evidence.set(item.id, item);
  }

  const edgeEvidence = new Map<
    string,
    { sourceId: string; targetId: string; evidenceIds: Set<string> }
  >();
  let localImportCount = 0;
  let assetImportCount = 0;
  let externalImportCount = 0;
  let unresolvedImportCount = 0;

  for (const source of sortedSources) {
    const imports = [...source.imports].sort(compareText);
    for (const specifier of imports) {
      const importItem = importEvidence(source, specifier);
      const assetPath = assetSpecifierPath(specifier);
      if (assetPath !== undefined) {
        const absoluteAssetPath = path.resolve(
          path.dirname(source.absolutePath),
          assetPath,
        );
        if (
          !isWithin(options.root, absoluteAssetPath) ||
          !filePaths.has(absoluteAssetPath)
        ) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-asset",
            severity: "error",
            message: `Could not resolve local CSS asset "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        let asset = assets.get(absoluteAssetPath);
        if (asset === undefined) {
          const content = await readFile(absoluteAssetPath, "utf8");
          asset = {
            absolutePath: absoluteAssetPath,
            repositoryPath: toRepositoryPath(
              options.root,
              absoluteAssetPath,
            ),
            fingerprint: sha256(content),
          };
          assets.set(absoluteAssetPath, asset);
          const assetId = createPathNodeId(asset.repositoryPath);
          nodes.set(assetId, {
            id: assetId,
            label: path.posix.basename(asset.repositoryPath),
            kind: "asset",
            identity: { kind: "path", value: asset.repositoryPath },
            fingerprint: asset.fingerprint,
          });
          const item = assetEvidence(asset);
          evidence.set(item.id, item);
        }
        const sourceId = createPathNodeId(source.repositoryPath);
        const targetId = createPathNodeId(asset.repositoryPath);
        const edgeId = createEdgeId("imports", sourceId, targetId);
        evidence.set(importItem.id, importItem);
        const accumulated = edgeEvidence.get(edgeId) ?? {
          sourceId,
          targetId,
          evidenceIds: new Set<string>(),
        };
        accumulated.evidenceIds.add(importItem.id);
        edgeEvidence.set(edgeId, accumulated);
        assetImportCount += 1;
        continue;
      }
      const resolved = ts.resolveModuleName(
        specifier,
        source.absolutePath,
        source.compilerOptions,
        ts.sys,
        source.moduleResolutionCache,
      ).resolvedModule;
      let targetId: string | undefined;
      const workspace = workspaceForSpecifier(specifier, workspaces);

      if (workspace !== undefined) {
        let target: SourceRecord | undefined;
        if (resolved !== undefined) {
          const selected = resolveCompilerSelectedSource(
            options.root,
            canonicalRoot,
            resolved.resolvedFileName,
            outputMappings,
            sourceByAbsolutePath,
          );
          if (selected.kind === "resolved") {
            target = selected.source;
          } else if (selected.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          } else if (
            resolved.resolvedFileName
              .split(path.sep)
              .includes("node_modules") ||
            !isWithin(options.root, resolved.resolvedFileName)
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          }
        } else {
          const suffix =
            specifier === workspace.name
              ? ""
              : specifier.slice(workspace.name.length + 1);
          const exportedSubpath =
            suffix.length === 0
              ? workspace.manifest.exports !== undefined
              : hasExactWorkspaceExport(
                  workspace.manifest.exports,
                  `./${suffix}`,
                );
          const physicalPackage = physicalWorkspacePackageState(
            workspace,
            source.absolutePath,
          );
          if (exportedSubpath && physicalPackage !== "other") {
            const virtualResolved = resolveWorkspaceModuleName(
              options.root,
              canonicalRoot,
              workspace,
              source,
              specifier,
              outputMappings,
              sourceByAbsolutePath,
            );
            if (virtualResolved !== undefined) {
              const selected = resolveCompilerSelectedSource(
                options.root,
                canonicalRoot,
                virtualResolved.resolvedFileName,
                outputMappings,
                sourceByAbsolutePath,
              );
              if (selected.kind === "resolved") {
                target = selected.source;
              } else if (selected.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (physicalPackage !== "other") {
            target = resolveSourceCandidate(
              sourceCandidatePaths(workspace, specifier),
              sourceByAbsolutePath,
            );
          }
        }
        if (targetId === undefined) {
          if (target !== undefined) {
            targetId = createPathNodeId(target.repositoryPath);
            localImportCount += 1;
          } else {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "unresolved-workspace-import",
              severity: "error",
              message: `Could not resolve workspace import "${specifier}" from "${source.repositoryPath}".`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        resolved.resolvedFileName
          .split(path.sep)
          .includes("node_modules")
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else if (resolved !== undefined && isWithin(options.root, resolved.resolvedFileName)) {
        const target = sourceByAbsolutePath.get(
          path.resolve(resolved.resolvedFileName),
        );
        if (target !== undefined) {
          targetId = createPathNodeId(target.repositoryPath);
          localImportCount += 1;
        } else {
          const generated = resolveGeneratedOutput(
            path.resolve(resolved.resolvedFileName),
            outputMappings,
            sourceByAbsolutePath,
          );
          if (generated.kind === "resolved") {
            targetId = createPathNodeId(generated.source.repositoryPath);
            localImportCount += 1;
          } else if (generated.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${generated.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        !isWithin(options.root, resolved.resolvedFileName)
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else {
        const local =
          specifier.startsWith(".") ||
          specifier.startsWith("/") ||
          (isPathAlias(specifier, source.compilerOptions) &&
            !declaredPackageNames.has(packageName(specifier)));
        if (local) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-import",
            severity: "error",
            message: `Could not resolve local import "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      }

      if (targetId === undefined) {
        unresolvedImportCount += 1;
        diagnostics.push({
          code: "resolved-import-outside-scan",
          severity: "error",
          message: `Resolved import "${specifier}" is not represented by a scanned source file.`,
          path: source.repositoryPath,
          specifier,
        });
        continue;
      }

      const sourceId = createPathNodeId(source.repositoryPath);
      const edgeId = createEdgeId("imports", sourceId, targetId);
      evidence.set(importItem.id, importItem);
      const accumulated = edgeEvidence.get(edgeId) ?? {
        sourceId,
        targetId,
        evidenceIds: new Set<string>(),
      };
      accumulated.evidenceIds.add(importItem.id);
      edgeEvidence.set(edgeId, accumulated);
    }
  }

  const edges: GraphEdge[] = [...edgeEvidence.entries()]
    .sort(([left], [right]) => compareText(left, right))
    .map(([id, edge]) => ({
      id,
      label: "imports",
      type: "imports",
      sourceId: edge.sourceId,
      targetId: edge.targetId,
      provenance: provenance([...edge.evidenceIds]),
    }));
  const coveredWorkspacePackageCount = workspaces.filter((workspace) =>
    sortedSources.some(
      (source) =>
        source.absolutePath.startsWith(`${workspace.directory}${path.sep}`),
    ),
  ).length;
  const metrics: ScanMetrics = {
    configCount: configPaths.length,
    workspacePackageCount: workspaces.length,
    coveredWorkspacePackageCount,
    sourceFileCount: sortedSources.length,
    assetFileCount: assets.size,
    linesOfCode: sortedSources.reduce((sum, source) => sum + source.lines, 0),
    localImportCount,
    assetImportCount,
    externalImportCount,
    unresolvedImportCount,
  };
  const rootCargo = files.includes(path.join(options.root, "Cargo.toml"));
  diagnostics.push(...qualityDiagnostics(metrics, quality, rootCargo));
  diagnostics.sort(
    (left, right) =>
      compareText(left.path ?? "", right.path ?? "") ||
      compareText(left.code, right.code) ||
      compareText(left.specifier ?? "", right.specifier ?? ""),
  );

  const errors = diagnostics.filter(
    (diagnostic) => diagnostic.severity === "error",
  );
  const fatalEmpty = sortedSources.length === 0;
  if (
    errors.length > 0 &&
    (!quality.allowPartial || fatalEmpty)
  ) {
    throw new ScanError(
      `Repository scan failed with ${errors.length} error diagnostic${errors.length === 1 ? "" : "s"}.`,
      diagnostics,
    );
  }

  const authoritative = errors.length === 0;
  const repositoryId =
    options.repositoryId ?? path.basename(options.root);
  const rootLabel = path.basename(options.root);
  const scannerExtension: JsonValue = {
    authoritative,
    status: authoritative ? "complete" : "partial",
    adapter: {
      id: TYPESCRIPT_SCANNER_MANIFEST.id,
      version: TYPESCRIPT_SCANNER_MANIFEST.version,
      contractVersion: TYPESCRIPT_SCANNER_MANIFEST.contractVersion,
      capabilities: {
        languages: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.languages],
        granularity: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.granularity],
        relationships: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.relationships,
        ],
        moduleResolution:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.moduleResolution,
        workspaceManifests: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.workspaceManifests,
        ],
        opaqueAssets: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.opaqueAssets,
        ],
        partialResults:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.partialResults,
      },
    },
    metrics: { ...metrics },
    diagnostics: diagnostics.map((diagnostic) => ({
      code: diagnostic.code,
      severity: diagnostic.severity,
      message: diagnostic.message,
      ...(diagnostic.path === undefined ? {} : { path: diagnostic.path }),
      ...(diagnostic.specifier === undefined
        ? {}
        : { specifier: diagnostic.specifier }),
    })),
  };
  const graph = createGraphDocument({
    graphId: `repo:${repositoryId}`,
    repository: {
      id: repositoryId,
      label: rootLabel,
      ...(options.revision === undefined
        ? {}
        : { revision: options.revision }),
    },
    modules: [
      {
        id: SCANNER_MODULE_ID,
        version: SCANNER_VERSION,
        schemaVersion: GRAPH_SCHEMA_VERSION,
      },
    ],
    nodes: [...nodes.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    edges,
    containers: directoriesForPaths(
      rootLabel,
      [
        ...sortedSources.map((source) => source.repositoryPath),
        ...[...assets.values()].map((asset) => asset.repositoryPath),
      ].sort(compareText),
    ),
    attributes: sortedSources.flatMap((source) => {
      const nodeId = createPathNodeId(source.repositoryPath);
      const evidenceId = `evidence:source:${source.repositoryPath}`;
      return [
        {
          id: createAttributeId(nodeId, "dev.topo.source.lines"),
          subject: { kind: "node" as const, id: nodeId },
          key: "dev.topo.source.lines",
          value: source.lines,
          provenance: provenance([evidenceId]),
          evidenceIds: [evidenceId],
          confidence: 1,
          witnesses: [
            {
              nodeId,
              fingerprint: source.fingerprint,
              relationship: "self" as const,
            },
          ],
        },
      ];
    }),
    evidence: [...evidence.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    extensions: {
      "dev.topo.scanner": scannerExtension,
    },
  });
  serializeGraphDocument(graph);
  const logicalArchitecture = await extractLogicalArchitecture({
    root: options.root,
    graphId: graph.graphId,
    graph,
    authoritative,
    ...(options.revision ? { revision: options.revision } : {}),
    sources: sortedSources,
    ...(options.responsibilityFile ? { responsibilityFile: options.responsibilityFile } : {}),
  });
  return { graph, logicalArchitecture, diagnostics, metrics, authoritative };
}
packages/scanner/src/semantic.ts:172-419
export async function extractLogicalArchitecture(options: {
  root: string;
  graphId: string;
  revision?: string;
  authoritative: boolean;
  graph: GraphDocument;
  sources: readonly SemanticSource[];
  responsibilityFile?: string;
}): Promise<LogicalArchitectureDocument> {
  const compilerOptions: ts.CompilerOptions = {
    allowJs: true,
    checkJs: false,
    noEmit: true,
    skipLibCheck: true,
    module: ts.ModuleKind.NodeNext,
    moduleResolution: ts.ModuleResolutionKind.NodeNext,
    target: ts.ScriptTarget.ES2022,
  };
  const sourceOptions = new Map(options.sources.map((source) => [
    path.resolve(source.absolutePath),
    { ...source.compilerOptions, allowJs: true, noEmit: true, skipLibCheck: true },
  ]));
  const nodePath = new Map(options.graph.nodes
    .filter((node) => node.identity.kind === "path")
    .map((node) => [node.id, path.resolve(options.root, node.identity.value)]));
  const evidenceById = new Map(options.graph.evidence.map((item) => [item.id, item]));
  const resolvedByImport = new Map<string, string>();
  for (const edge of options.graph.edges) {
    const target = nodePath.get(edge.targetId);
    if (!target) continue;
    for (const evidenceId of edge.provenance.evidenceIds) {
      const evidence = evidenceById.get(evidenceId);
      if (evidence?.anchor?.path) {
        const specifier = evidence.anchor.symbol?.startsWith("import:")
          ? evidence.anchor.symbol.slice("import:".length)
          : evidence.anchor.contentPattern;
        if (!specifier) continue;
        resolvedByImport.set(
          `${path.resolve(options.root, evidence.anchor.path)}\0${specifier}`,
          target,
        );
      }
    }
  }
  const extension = (fileName: string): ts.Extension => {
    if (fileName.endsWith(".tsx")) return ts.Extension.Tsx;
    if (fileName.endsWith(".jsx")) return ts.Extension.Jsx;
    if (fileName.endsWith(".js") || fileName.endsWith(".mjs") || fileName.endsWith(".cjs")) return ts.Extension.Js;
    return ts.Extension.Ts;
  };
  const host = ts.createCompilerHost(compilerOptions);
  host.resolveModuleNames = (moduleNames, containingFile) => moduleNames.map((moduleName) => {
    const perFileOptions = sourceOptions.get(path.resolve(containingFile)) ?? compilerOptions;
    const mapped = resolvedByImport.get(`${path.resolve(containingFile)}\0${moduleName}`);
    if (mapped) return {
      resolvedFileName: mapped,
      extension: extension(mapped),
      isExternalLibraryImport: false,
    };
    return ts.resolveModuleName(moduleName, containingFile, perFileOptions, host).resolvedModule;
  });
  const program = ts.createProgram({
    rootNames: options.sources.map((source) => source.absolutePath),
    options: compilerOptions,
    host,
  });
  const checker = program.getTypeChecker();
  const sourcePaths = new Set(options.sources.map((source) => path.resolve(source.absolutePath)));
  const entities: SemanticEntity[] = [];
  const entityBySymbol = new Map<ts.Symbol, string>();
  const entityByDeclaration = new Map<ts.Declaration, string>();
  const anchorToEntity = new Map<string, string>();
  const exportedSymbols = new Set<ts.Symbol>();

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
    if (moduleSymbol) {
      for (const exported of checker.getExportsOfModule(moduleSymbol)) {
        const canonical = canonicalSymbol(checker, exported);
        if (canonical) exportedSymbols.add(canonical);
      }
    }
  }

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    for (const item of semanticDeclarations(checker, sourceFile)) {
      const symbol = canonicalSymbol(checker, item.symbol);
      const kind = declarationKind(item.declaration);
      if (!symbol || !kind) continue;
      let id = entityBySymbol.get(symbol);
      if (!id) {
        id = entityId(options.root, symbol, kind);
        entityBySymbol.set(symbol, id);
        const declarations = (symbol.declarations ?? [item.declaration])
          .filter((declaration) => sourcePaths.has(path.resolve(declaration.getSourceFile().fileName)))
          .map((declaration) => location(options.root, declaration.getSourceFile(), declaration))
          .sort((left, right) => compareText(left.path, right.path) || left.start.line - right.start.line);
        const type = checker.getTypeOfSymbolAtLocation(symbol, item.declaration);
        entities.push({
          id,
          name: symbol.getName(),
          kind,
          exported: exportedSymbols.has(symbol),
          declarations,
          signatures: checker.getSignaturesOfType(type, ts.SignatureKind.Call)
            .map((signature) => checker.signatureToString(signature)),
          members: memberFacts(checker, symbol.declarations ?? [item.declaration]),
        });
      }
      entityByDeclaration.set(item.declaration, id);
      if (ts.isClassDeclaration(item.declaration) || ts.isInterfaceDeclaration(item.declaration)) {
        for (const member of item.declaration.members) {
          if (!member.name) continue;
          const memberSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(member.name));
          if (memberSymbol) entityBySymbol.set(memberSymbol, id);
        }
      }
      const repositoryPath = path.relative(options.root, sourceFile.fileName).split(path.sep).join("/");
      anchorToEntity.set(`${repositoryPath}\0${item.anchor}`, id);
    }
  }

  const relationshipLocations = new Map<string, SourceLocation[]>();
  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const visit = (node: ts.Node): void => {
      if (ts.isIdentifier(node)) {
        const sourceId = containingEntity(node, entityByDeclaration);
        const targetSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(node));
        const targetId = targetSymbol ? entityBySymbol.get(targetSymbol) : undefined;
        const kind = relationshipKind(node);
        if (sourceId && targetId && sourceId !== targetId && kind) {
          const key = `${kind}\0${sourceId}\0${targetId}`;
          const locations = relationshipLocations.get(key) ?? [];
          locations.push(location(options.root, sourceFile, node));
          relationshipLocations.set(key, locations);
        }
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
  }
  const relationships: SemanticRelationship[] = [...relationshipLocations.entries()].map(([key, locations]) => {
    const [kind, sourceId, targetId] = key.split("\0") as [SemanticRelationshipKind, string, string];
    return { id: `semantic-edge:${kind}:${sourceId}:${targetId}`, sourceId, targetId, kind, locations };
  }).sort((left, right) => compareText(left.id, right.id));

  const diagnostics: LogicalArchitectureDiagnostic[] = [];
  const responsibilities: LogicalResponsibility[] = [];
  const assigned = new Set<string>();
  if (options.responsibilityFile) {
    let input: ResponsibilityInput;
    try {
      input = parseResponsibilityInput(JSON.parse(await readFile(options.responsibilityFile, "utf8")) as unknown);
    } catch (error) {
      throw new Error(`Invalid responsibility input ${options.responsibilityFile}: ${error instanceof Error ? error.message : String(error)}`);
    }
    const responsibilityIds = new Set<string>();
    for (const item of input.responsibilities) {
      if (responsibilityIds.has(item.id)) throw new Error(`Duplicate responsibility id ${item.id}.`);
      responsibilityIds.add(item.id);
      const entityIds: string[] = [];
      for (const anchor of item.entities) {
        const id = anchorToEntity.get(`${anchor.path}\0${anchor.symbol}`);
        if (!id) throw new Error(`Responsibility ${item.id} references unknown semantic anchor ${anchor.path}#${anchor.symbol}.`);
        if (assigned.has(id)) throw new Error(`Semantic entity ${anchor.path}#${anchor.symbol} has multiple primary responsibility homes.`);
        assigned.add(id);
        entityIds.push(id);
      }
      const contracts = entities.filter((entity) => entityIds.includes(entity.id) && entity.exported &&
        (entity.kind === "function" || entity.kind === "interface" || entity.kind === "type" || entity.kind === "class"))
        .map((entity) => entity.name).sort(compareText).slice(0, 3);
      if (contracts.length === 0) {
        throw new Error(`Responsibility ${item.id} must contain at least one exported function, class, interface, or type contract.`);
      }
      responsibilities.push({
        id: item.id,
        name: item.name,
        purpose: item.purpose,
        provenance: "proposed",
        entityIds: entityIds.sort(compareText),
        contracts,
      });
    }
  } else {
    diagnostics.push({
      code: "missing-responsibility-input",
      severity: "warning",
      message: "No responsibility input was supplied; semantic entities remain explicitly unassigned and the legacy source map remains the default.",
    });
  }

  entities.sort((left, right) => compareText(left.id, right.id));
  if (!options.authoritative) {
    diagnostics.push({
      code: "partial-source-inventory",
      severity: "warning",
      message: "The underlying scanner result is partial and the logical architecture is not authoritative.",
    });
  }
  const unassignedEntityIds = entities.filter((entity) => !assigned.has(entity.id)).map((entity) => entity.id);
  if (options.responsibilityFile && unassignedEntityIds.length > 0) {
    responsibilities.push({
      id: "responsibility:unassigned",
      name: "Unassigned",
      purpose: "Compiler-backed entities not assigned by the supplied responsibility proposal.",
      provenance: "unassigned",
      entityIds: unassignedEntityIds,
      contracts: entities.filter((entity) => unassignedEntityIds.includes(entity.id) && entity.exported)
        .map((entity) => entity.name).sort(compareText).slice(0, 3),
    });
    diagnostics.push({
      code: "unassigned-semantic-entities",
      severity: "warning",
      message: `${unassignedEntityIds.length} semantic entities are not assigned by the responsibility proposal.`,
    });
  }
  const sortedResponsibilities = responsibilities.sort((left, right) => compareText(left.id, right.id));
  const snapshotId = createHash("sha256").update(options.graph.nodes
    .map((node) => `${node.id}\0${node.fingerprint ?? ""}`).sort(compareText).join("\0")).digest("hex");
  const positionNamespaceId = createHash("sha256").update(JSON.stringify({
    version: 2,
    revision: options.revision ?? null,
    snapshotId,
    responsibilities: sortedResponsibilities,
    views: ["logical-overview", "logical-drill"],
  })).digest("hex");
  return {
    schemaVersion: "1.0",
    graphId: options.graphId,
    ...(options.revision ? { revision: options.revision } : {}),
    snapshotId,
    positionNamespaceId,
    coverage: {
      languages: ["javascript", "typescript"],
      relationshipKinds: ["calls", "constructs", "type-use", "heritage"],
      completeSourceInventory: options.authoritative,
      runtimeBehavior: false,
    },
    entities,
    relationships,
    responsibilities: sortedResponsibilities,
    unassignedEntityIds,
    diagnostics,
  };
}

source-traced: Build program; query symbols

The semantic pass creates a program/checker and queries exports, declarations, types, aliases and identifier targets.

packages/scanner/src/semantic.ts:172-419
export async function extractLogicalArchitecture(options: {
  root: string;
  graphId: string;
  revision?: string;
  authoritative: boolean;
  graph: GraphDocument;
  sources: readonly SemanticSource[];
  responsibilityFile?: string;
}): Promise<LogicalArchitectureDocument> {
  const compilerOptions: ts.CompilerOptions = {
    allowJs: true,
    checkJs: false,
    noEmit: true,
    skipLibCheck: true,
    module: ts.ModuleKind.NodeNext,
    moduleResolution: ts.ModuleResolutionKind.NodeNext,
    target: ts.ScriptTarget.ES2022,
  };
  const sourceOptions = new Map(options.sources.map((source) => [
    path.resolve(source.absolutePath),
    { ...source.compilerOptions, allowJs: true, noEmit: true, skipLibCheck: true },
  ]));
  const nodePath = new Map(options.graph.nodes
    .filter((node) => node.identity.kind === "path")
    .map((node) => [node.id, path.resolve(options.root, node.identity.value)]));
  const evidenceById = new Map(options.graph.evidence.map((item) => [item.id, item]));
  const resolvedByImport = new Map<string, string>();
  for (const edge of options.graph.edges) {
    const target = nodePath.get(edge.targetId);
    if (!target) continue;
    for (const evidenceId of edge.provenance.evidenceIds) {
      const evidence = evidenceById.get(evidenceId);
      if (evidence?.anchor?.path) {
        const specifier = evidence.anchor.symbol?.startsWith("import:")
          ? evidence.anchor.symbol.slice("import:".length)
          : evidence.anchor.contentPattern;
        if (!specifier) continue;
        resolvedByImport.set(
          `${path.resolve(options.root, evidence.anchor.path)}\0${specifier}`,
          target,
        );
      }
    }
  }
  const extension = (fileName: string): ts.Extension => {
    if (fileName.endsWith(".tsx")) return ts.Extension.Tsx;
    if (fileName.endsWith(".jsx")) return ts.Extension.Jsx;
    if (fileName.endsWith(".js") || fileName.endsWith(".mjs") || fileName.endsWith(".cjs")) return ts.Extension.Js;
    return ts.Extension.Ts;
  };
  const host = ts.createCompilerHost(compilerOptions);
  host.resolveModuleNames = (moduleNames, containingFile) => moduleNames.map((moduleName) => {
    const perFileOptions = sourceOptions.get(path.resolve(containingFile)) ?? compilerOptions;
    const mapped = resolvedByImport.get(`${path.resolve(containingFile)}\0${moduleName}`);
    if (mapped) return {
      resolvedFileName: mapped,
      extension: extension(mapped),
      isExternalLibraryImport: false,
    };
    return ts.resolveModuleName(moduleName, containingFile, perFileOptions, host).resolvedModule;
  });
  const program = ts.createProgram({
    rootNames: options.sources.map((source) => source.absolutePath),
    options: compilerOptions,
    host,
  });
  const checker = program.getTypeChecker();
  const sourcePaths = new Set(options.sources.map((source) => path.resolve(source.absolutePath)));
  const entities: SemanticEntity[] = [];
  const entityBySymbol = new Map<ts.Symbol, string>();
  const entityByDeclaration = new Map<ts.Declaration, string>();
  const anchorToEntity = new Map<string, string>();
  const exportedSymbols = new Set<ts.Symbol>();

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
    if (moduleSymbol) {
      for (const exported of checker.getExportsOfModule(moduleSymbol)) {
        const canonical = canonicalSymbol(checker, exported);
        if (canonical) exportedSymbols.add(canonical);
      }
    }
  }

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    for (const item of semanticDeclarations(checker, sourceFile)) {
      const symbol = canonicalSymbol(checker, item.symbol);
      const kind = declarationKind(item.declaration);
      if (!symbol || !kind) continue;
      let id = entityBySymbol.get(symbol);
      if (!id) {
        id = entityId(options.root, symbol, kind);
        entityBySymbol.set(symbol, id);
        const declarations = (symbol.declarations ?? [item.declaration])
          .filter((declaration) => sourcePaths.has(path.resolve(declaration.getSourceFile().fileName)))
          .map((declaration) => location(options.root, declaration.getSourceFile(), declaration))
          .sort((left, right) => compareText(left.path, right.path) || left.start.line - right.start.line);
        const type = checker.getTypeOfSymbolAtLocation(symbol, item.declaration);
        entities.push({
          id,
          name: symbol.getName(),
          kind,
          exported: exportedSymbols.has(symbol),
          declarations,
          signatures: checker.getSignaturesOfType(type, ts.SignatureKind.Call)
            .map((signature) => checker.signatureToString(signature)),
          members: memberFacts(checker, symbol.declarations ?? [item.declaration]),
        });
      }
      entityByDeclaration.set(item.declaration, id);
      if (ts.isClassDeclaration(item.declaration) || ts.isInterfaceDeclaration(item.declaration)) {
        for (const member of item.declaration.members) {
          if (!member.name) continue;
          const memberSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(member.name));
          if (memberSymbol) entityBySymbol.set(memberSymbol, id);
        }
      }
      const repositoryPath = path.relative(options.root, sourceFile.fileName).split(path.sep).join("/");
      anchorToEntity.set(`${repositoryPath}\0${item.anchor}`, id);
    }
  }

  const relationshipLocations = new Map<string, SourceLocation[]>();
  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const visit = (node: ts.Node): void => {
      if (ts.isIdentifier(node)) {
        const sourceId = containingEntity(node, entityByDeclaration);
        const targetSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(node));
        const targetId = targetSymbol ? entityBySymbol.get(targetSymbol) : undefined;
        const kind = relationshipKind(node);
        if (sourceId && targetId && sourceId !== targetId && kind) {
          const key = `${kind}\0${sourceId}\0${targetId}`;
          const locations = relationshipLocations.get(key) ?? [];
          locations.push(location(options.root, sourceFile, node));
          relationshipLocations.set(key, locations);
        }
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
  }
  const relationships: SemanticRelationship[] = [...relationshipLocations.entries()].map(([key, locations]) => {
    const [kind, sourceId, targetId] = key.split("\0") as [SemanticRelationshipKind, string, string];
    return { id: `semantic-edge:${kind}:${sourceId}:${targetId}`, sourceId, targetId, kind, locations };
  }).sort((left, right) => compareText(left.id, right.id));

  const diagnostics: LogicalArchitectureDiagnostic[] = [];
  const responsibilities: LogicalResponsibility[] = [];
  const assigned = new Set<string>();
  if (options.responsibilityFile) {
    let input: ResponsibilityInput;
    try {
      input = parseResponsibilityInput(JSON.parse(await readFile(options.responsibilityFile, "utf8")) as unknown);
    } catch (error) {
      throw new Error(`Invalid responsibility input ${options.responsibilityFile}: ${error instanceof Error ? error.message : String(error)}`);
    }
    const responsibilityIds = new Set<string>();
    for (const item of input.responsibilities) {
      if (responsibilityIds.has(item.id)) throw new Error(`Duplicate responsibility id ${item.id}.`);
      responsibilityIds.add(item.id);
      const entityIds: string[] = [];
      for (const anchor of item.entities) {
        const id = anchorToEntity.get(`${anchor.path}\0${anchor.symbol}`);
        if (!id) throw new Error(`Responsibility ${item.id} references unknown semantic anchor ${anchor.path}#${anchor.symbol}.`);
        if (assigned.has(id)) throw new Error(`Semantic entity ${anchor.path}#${anchor.symbol} has multiple primary responsibility homes.`);
        assigned.add(id);
        entityIds.push(id);
      }
      const contracts = entities.filter((entity) => entityIds.includes(entity.id) && entity.exported &&
        (entity.kind === "function" || entity.kind === "interface" || entity.kind === "type" || entity.kind === "class"))
        .map((entity) => entity.name).sort(compareText).slice(0, 3);
      if (contracts.length === 0) {
        throw new Error(`Responsibility ${item.id} must contain at least one exported function, class, interface, or type contract.`);
      }
      responsibilities.push({
        id: item.id,
        name: item.name,
        purpose: item.purpose,
        provenance: "proposed",
        entityIds: entityIds.sort(compareText),
        contracts,
      });
    }
  } else {
    diagnostics.push({
      code: "missing-responsibility-input",
      severity: "warning",
      message: "No responsibility input was supplied; semantic entities remain explicitly unassigned and the legacy source map remains the default.",
    });
  }

  entities.sort((left, right) => compareText(left.id, right.id));
  if (!options.authoritative) {
    diagnostics.push({
      code: "partial-source-inventory",
      severity: "warning",
      message: "The underlying scanner result is partial and the logical architecture is not authoritative.",
    });
  }
  const unassignedEntityIds = entities.filter((entity) => !assigned.has(entity.id)).map((entity) => entity.id);
  if (options.responsibilityFile && unassignedEntityIds.length > 0) {
    responsibilities.push({
      id: "responsibility:unassigned",
      name: "Unassigned",
      purpose: "Compiler-backed entities not assigned by the supplied responsibility proposal.",
      provenance: "unassigned",
      entityIds: unassignedEntityIds,
      contracts: entities.filter((entity) => unassignedEntityIds.includes(entity.id) && entity.exported)
        .map((entity) => entity.name).sort(compareText).slice(0, 3),
    });
    diagnostics.push({
      code: "unassigned-semantic-entities",
      severity: "warning",
      message: `${unassignedEntityIds.length} semantic entities are not assigned by the responsibility proposal.`,
    });
  }
  const sortedResponsibilities = responsibilities.sort((left, right) => compareText(left.id, right.id));
  const snapshotId = createHash("sha256").update(options.graph.nodes
    .map((node) => `${node.id}\0${node.fingerprint ?? ""}`).sort(compareText).join("\0")).digest("hex");
  const positionNamespaceId = createHash("sha256").update(JSON.stringify({
    version: 2,
    revision: options.revision ?? null,
    snapshotId,
    responsibilities: sortedResponsibilities,
    views: ["logical-overview", "logical-drill"],
  })).digest("hex");
  return {
    schemaVersion: "1.0",
    graphId: options.graphId,
    ...(options.revision ? { revision: options.revision } : {}),
    snapshotId,
    positionNamespaceId,
    coverage: {
      languages: ["javascript", "typescript"],
      relationshipKinds: ["calls", "constructs", "type-use", "heritage"],
      completeSourceInventory: options.authoritative,
      runtimeBehavior: false,
    },
    entities,
    relationships,
    responsibilities: sortedResponsibilities,
    unassignedEntityIds,
    diagnostics,
  };
}
packages/scanner/src/semantic.ts:90-93
function canonicalSymbol(checker: ts.TypeChecker, symbol: ts.Symbol | undefined): ts.Symbol | undefined {
  if (!symbol) return undefined;
  return symbol.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
}

source-traced: Declarations and symbol resolutions

Topocode turns compiler facts into stable semantic entities and static relationships with source locations.

packages/scanner/src/semantic.ts:172-419
export async function extractLogicalArchitecture(options: {
  root: string;
  graphId: string;
  revision?: string;
  authoritative: boolean;
  graph: GraphDocument;
  sources: readonly SemanticSource[];
  responsibilityFile?: string;
}): Promise<LogicalArchitectureDocument> {
  const compilerOptions: ts.CompilerOptions = {
    allowJs: true,
    checkJs: false,
    noEmit: true,
    skipLibCheck: true,
    module: ts.ModuleKind.NodeNext,
    moduleResolution: ts.ModuleResolutionKind.NodeNext,
    target: ts.ScriptTarget.ES2022,
  };
  const sourceOptions = new Map(options.sources.map((source) => [
    path.resolve(source.absolutePath),
    { ...source.compilerOptions, allowJs: true, noEmit: true, skipLibCheck: true },
  ]));
  const nodePath = new Map(options.graph.nodes
    .filter((node) => node.identity.kind === "path")
    .map((node) => [node.id, path.resolve(options.root, node.identity.value)]));
  const evidenceById = new Map(options.graph.evidence.map((item) => [item.id, item]));
  const resolvedByImport = new Map<string, string>();
  for (const edge of options.graph.edges) {
    const target = nodePath.get(edge.targetId);
    if (!target) continue;
    for (const evidenceId of edge.provenance.evidenceIds) {
      const evidence = evidenceById.get(evidenceId);
      if (evidence?.anchor?.path) {
        const specifier = evidence.anchor.symbol?.startsWith("import:")
          ? evidence.anchor.symbol.slice("import:".length)
          : evidence.anchor.contentPattern;
        if (!specifier) continue;
        resolvedByImport.set(
          `${path.resolve(options.root, evidence.anchor.path)}\0${specifier}`,
          target,
        );
      }
    }
  }
  const extension = (fileName: string): ts.Extension => {
    if (fileName.endsWith(".tsx")) return ts.Extension.Tsx;
    if (fileName.endsWith(".jsx")) return ts.Extension.Jsx;
    if (fileName.endsWith(".js") || fileName.endsWith(".mjs") || fileName.endsWith(".cjs")) return ts.Extension.Js;
    return ts.Extension.Ts;
  };
  const host = ts.createCompilerHost(compilerOptions);
  host.resolveModuleNames = (moduleNames, containingFile) => moduleNames.map((moduleName) => {
    const perFileOptions = sourceOptions.get(path.resolve(containingFile)) ?? compilerOptions;
    const mapped = resolvedByImport.get(`${path.resolve(containingFile)}\0${moduleName}`);
    if (mapped) return {
      resolvedFileName: mapped,
      extension: extension(mapped),
      isExternalLibraryImport: false,
    };
    return ts.resolveModuleName(moduleName, containingFile, perFileOptions, host).resolvedModule;
  });
  const program = ts.createProgram({
    rootNames: options.sources.map((source) => source.absolutePath),
    options: compilerOptions,
    host,
  });
  const checker = program.getTypeChecker();
  const sourcePaths = new Set(options.sources.map((source) => path.resolve(source.absolutePath)));
  const entities: SemanticEntity[] = [];
  const entityBySymbol = new Map<ts.Symbol, string>();
  const entityByDeclaration = new Map<ts.Declaration, string>();
  const anchorToEntity = new Map<string, string>();
  const exportedSymbols = new Set<ts.Symbol>();

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
    if (moduleSymbol) {
      for (const exported of checker.getExportsOfModule(moduleSymbol)) {
        const canonical = canonicalSymbol(checker, exported);
        if (canonical) exportedSymbols.add(canonical);
      }
    }
  }

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    for (const item of semanticDeclarations(checker, sourceFile)) {
      const symbol = canonicalSymbol(checker, item.symbol);
      const kind = declarationKind(item.declaration);
      if (!symbol || !kind) continue;
      let id = entityBySymbol.get(symbol);
      if (!id) {
        id = entityId(options.root, symbol, kind);
        entityBySymbol.set(symbol, id);
        const declarations = (symbol.declarations ?? [item.declaration])
          .filter((declaration) => sourcePaths.has(path.resolve(declaration.getSourceFile().fileName)))
          .map((declaration) => location(options.root, declaration.getSourceFile(), declaration))
          .sort((left, right) => compareText(left.path, right.path) || left.start.line - right.start.line);
        const type = checker.getTypeOfSymbolAtLocation(symbol, item.declaration);
        entities.push({
          id,
          name: symbol.getName(),
          kind,
          exported: exportedSymbols.has(symbol),
          declarations,
          signatures: checker.getSignaturesOfType(type, ts.SignatureKind.Call)
            .map((signature) => checker.signatureToString(signature)),
          members: memberFacts(checker, symbol.declarations ?? [item.declaration]),
        });
      }
      entityByDeclaration.set(item.declaration, id);
      if (ts.isClassDeclaration(item.declaration) || ts.isInterfaceDeclaration(item.declaration)) {
        for (const member of item.declaration.members) {
          if (!member.name) continue;
          const memberSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(member.name));
          if (memberSymbol) entityBySymbol.set(memberSymbol, id);
        }
      }
      const repositoryPath = path.relative(options.root, sourceFile.fileName).split(path.sep).join("/");
      anchorToEntity.set(`${repositoryPath}\0${item.anchor}`, id);
    }
  }

  const relationshipLocations = new Map<string, SourceLocation[]>();
  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const visit = (node: ts.Node): void => {
      if (ts.isIdentifier(node)) {
        const sourceId = containingEntity(node, entityByDeclaration);
        const targetSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(node));
        const targetId = targetSymbol ? entityBySymbol.get(targetSymbol) : undefined;
        const kind = relationshipKind(node);
        if (sourceId && targetId && sourceId !== targetId && kind) {
          const key = `${kind}\0${sourceId}\0${targetId}`;
          const locations = relationshipLocations.get(key) ?? [];
          locations.push(location(options.root, sourceFile, node));
          relationshipLocations.set(key, locations);
        }
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
  }
  const relationships: SemanticRelationship[] = [...relationshipLocations.entries()].map(([key, locations]) => {
    const [kind, sourceId, targetId] = key.split("\0") as [SemanticRelationshipKind, string, string];
    return { id: `semantic-edge:${kind}:${sourceId}:${targetId}`, sourceId, targetId, kind, locations };
  }).sort((left, right) => compareText(left.id, right.id));

  const diagnostics: LogicalArchitectureDiagnostic[] = [];
  const responsibilities: LogicalResponsibility[] = [];
  const assigned = new Set<string>();
  if (options.responsibilityFile) {
    let input: ResponsibilityInput;
    try {
      input = parseResponsibilityInput(JSON.parse(await readFile(options.responsibilityFile, "utf8")) as unknown);
    } catch (error) {
      throw new Error(`Invalid responsibility input ${options.responsibilityFile}: ${error instanceof Error ? error.message : String(error)}`);
    }
    const responsibilityIds = new Set<string>();
    for (const item of input.responsibilities) {
      if (responsibilityIds.has(item.id)) throw new Error(`Duplicate responsibility id ${item.id}.`);
      responsibilityIds.add(item.id);
      const entityIds: string[] = [];
      for (const anchor of item.entities) {
        const id = anchorToEntity.get(`${anchor.path}\0${anchor.symbol}`);
        if (!id) throw new Error(`Responsibility ${item.id} references unknown semantic anchor ${anchor.path}#${anchor.symbol}.`);
        if (assigned.has(id)) throw new Error(`Semantic entity ${anchor.path}#${anchor.symbol} has multiple primary responsibility homes.`);
        assigned.add(id);
        entityIds.push(id);
      }
      const contracts = entities.filter((entity) => entityIds.includes(entity.id) && entity.exported &&
        (entity.kind === "function" || entity.kind === "interface" || entity.kind === "type" || entity.kind === "class"))
        .map((entity) => entity.name).sort(compareText).slice(0, 3);
      if (contracts.length === 0) {
        throw new Error(`Responsibility ${item.id} must contain at least one exported function, class, interface, or type contract.`);
      }
      responsibilities.push({
        id: item.id,
        name: item.name,
        purpose: item.purpose,
        provenance: "proposed",
        entityIds: entityIds.sort(compareText),
        contracts,
      });
    }
  } else {
    diagnostics.push({
      code: "missing-responsibility-input",
      severity: "warning",
      message: "No responsibility input was supplied; semantic entities remain explicitly unassigned and the legacy source map remains the default.",
    });
  }

  entities.sort((left, right) => compareText(left.id, right.id));
  if (!options.authoritative) {
    diagnostics.push({
      code: "partial-source-inventory",
      severity: "warning",
      message: "The underlying scanner result is partial and the logical architecture is not authoritative.",
    });
  }
  const unassignedEntityIds = entities.filter((entity) => !assigned.has(entity.id)).map((entity) => entity.id);
  if (options.responsibilityFile && unassignedEntityIds.length > 0) {
    responsibilities.push({
      id: "responsibility:unassigned",
      name: "Unassigned",
      purpose: "Compiler-backed entities not assigned by the supplied responsibility proposal.",
      provenance: "unassigned",
      entityIds: unassignedEntityIds,
      contracts: entities.filter((entity) => unassignedEntityIds.includes(entity.id) && entity.exported)
        .map((entity) => entity.name).sort(compareText).slice(0, 3),
    });
    diagnostics.push({
      code: "unassigned-semantic-entities",
      severity: "warning",
      message: `${unassignedEntityIds.length} semantic entities are not assigned by the responsibility proposal.`,
    });
  }
  const sortedResponsibilities = responsibilities.sort((left, right) => compareText(left.id, right.id));
  const snapshotId = createHash("sha256").update(options.graph.nodes
    .map((node) => `${node.id}\0${node.fingerprint ?? ""}`).sort(compareText).join("\0")).digest("hex");
  const positionNamespaceId = createHash("sha256").update(JSON.stringify({
    version: 2,
    revision: options.revision ?? null,
    snapshotId,
    responsibilities: sortedResponsibilities,
    views: ["logical-overview", "logical-drill"],
  })).digest("hex");
  return {
    schemaVersion: "1.0",
    graphId: options.graphId,
    ...(options.revision ? { revision: options.revision } : {}),
    snapshotId,
    positionNamespaceId,
    coverage: {
      languages: ["javascript", "typescript"],
      relationshipKinds: ["calls", "constructs", "type-use", "heritage"],
      completeSourceInventory: options.authoritative,
      runtimeBehavior: false,
    },
    entities,
    relationships,
    responsibilities: sortedResponsibilities,
    unassignedEntityIds,
    diagnostics,
  };
}
packages/scanner/src/semantic.ts:130-143
function relationshipKind(node: ts.Node): SemanticRelationshipKind | undefined {
  let current: ts.Node | undefined = node;
  let typeUse = false;
  while (current?.parent) {
    const parent: ts.Node = current.parent;
    if (ts.isCallExpression(parent) && parent.expression === current) return "calls";
    if (ts.isNewExpression(parent) && parent.expression === current) return "constructs";
    if (ts.isHeritageClause(parent)) return "heritage";
    if (ts.isTypeNode(parent)) typeUse = true;
    if (ts.isStatement(parent)) break;
    current = parent;
  }
  return typeUse ? "type-use" : undefined;
}

source-traced: Semantic facts and assignment status

Return the logical-architecture document, including explicit proposed/unassigned responsibility information and diagnostics.

packages/scanner/src/semantic.ts:172-419
export async function extractLogicalArchitecture(options: {
  root: string;
  graphId: string;
  revision?: string;
  authoritative: boolean;
  graph: GraphDocument;
  sources: readonly SemanticSource[];
  responsibilityFile?: string;
}): Promise<LogicalArchitectureDocument> {
  const compilerOptions: ts.CompilerOptions = {
    allowJs: true,
    checkJs: false,
    noEmit: true,
    skipLibCheck: true,
    module: ts.ModuleKind.NodeNext,
    moduleResolution: ts.ModuleResolutionKind.NodeNext,
    target: ts.ScriptTarget.ES2022,
  };
  const sourceOptions = new Map(options.sources.map((source) => [
    path.resolve(source.absolutePath),
    { ...source.compilerOptions, allowJs: true, noEmit: true, skipLibCheck: true },
  ]));
  const nodePath = new Map(options.graph.nodes
    .filter((node) => node.identity.kind === "path")
    .map((node) => [node.id, path.resolve(options.root, node.identity.value)]));
  const evidenceById = new Map(options.graph.evidence.map((item) => [item.id, item]));
  const resolvedByImport = new Map<string, string>();
  for (const edge of options.graph.edges) {
    const target = nodePath.get(edge.targetId);
    if (!target) continue;
    for (const evidenceId of edge.provenance.evidenceIds) {
      const evidence = evidenceById.get(evidenceId);
      if (evidence?.anchor?.path) {
        const specifier = evidence.anchor.symbol?.startsWith("import:")
          ? evidence.anchor.symbol.slice("import:".length)
          : evidence.anchor.contentPattern;
        if (!specifier) continue;
        resolvedByImport.set(
          `${path.resolve(options.root, evidence.anchor.path)}\0${specifier}`,
          target,
        );
      }
    }
  }
  const extension = (fileName: string): ts.Extension => {
    if (fileName.endsWith(".tsx")) return ts.Extension.Tsx;
    if (fileName.endsWith(".jsx")) return ts.Extension.Jsx;
    if (fileName.endsWith(".js") || fileName.endsWith(".mjs") || fileName.endsWith(".cjs")) return ts.Extension.Js;
    return ts.Extension.Ts;
  };
  const host = ts.createCompilerHost(compilerOptions);
  host.resolveModuleNames = (moduleNames, containingFile) => moduleNames.map((moduleName) => {
    const perFileOptions = sourceOptions.get(path.resolve(containingFile)) ?? compilerOptions;
    const mapped = resolvedByImport.get(`${path.resolve(containingFile)}\0${moduleName}`);
    if (mapped) return {
      resolvedFileName: mapped,
      extension: extension(mapped),
      isExternalLibraryImport: false,
    };
    return ts.resolveModuleName(moduleName, containingFile, perFileOptions, host).resolvedModule;
  });
  const program = ts.createProgram({
    rootNames: options.sources.map((source) => source.absolutePath),
    options: compilerOptions,
    host,
  });
  const checker = program.getTypeChecker();
  const sourcePaths = new Set(options.sources.map((source) => path.resolve(source.absolutePath)));
  const entities: SemanticEntity[] = [];
  const entityBySymbol = new Map<ts.Symbol, string>();
  const entityByDeclaration = new Map<ts.Declaration, string>();
  const anchorToEntity = new Map<string, string>();
  const exportedSymbols = new Set<ts.Symbol>();

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
    if (moduleSymbol) {
      for (const exported of checker.getExportsOfModule(moduleSymbol)) {
        const canonical = canonicalSymbol(checker, exported);
        if (canonical) exportedSymbols.add(canonical);
      }
    }
  }

  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    for (const item of semanticDeclarations(checker, sourceFile)) {
      const symbol = canonicalSymbol(checker, item.symbol);
      const kind = declarationKind(item.declaration);
      if (!symbol || !kind) continue;
      let id = entityBySymbol.get(symbol);
      if (!id) {
        id = entityId(options.root, symbol, kind);
        entityBySymbol.set(symbol, id);
        const declarations = (symbol.declarations ?? [item.declaration])
          .filter((declaration) => sourcePaths.has(path.resolve(declaration.getSourceFile().fileName)))
          .map((declaration) => location(options.root, declaration.getSourceFile(), declaration))
          .sort((left, right) => compareText(left.path, right.path) || left.start.line - right.start.line);
        const type = checker.getTypeOfSymbolAtLocation(symbol, item.declaration);
        entities.push({
          id,
          name: symbol.getName(),
          kind,
          exported: exportedSymbols.has(symbol),
          declarations,
          signatures: checker.getSignaturesOfType(type, ts.SignatureKind.Call)
            .map((signature) => checker.signatureToString(signature)),
          members: memberFacts(checker, symbol.declarations ?? [item.declaration]),
        });
      }
      entityByDeclaration.set(item.declaration, id);
      if (ts.isClassDeclaration(item.declaration) || ts.isInterfaceDeclaration(item.declaration)) {
        for (const member of item.declaration.members) {
          if (!member.name) continue;
          const memberSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(member.name));
          if (memberSymbol) entityBySymbol.set(memberSymbol, id);
        }
      }
      const repositoryPath = path.relative(options.root, sourceFile.fileName).split(path.sep).join("/");
      anchorToEntity.set(`${repositoryPath}\0${item.anchor}`, id);
    }
  }

  const relationshipLocations = new Map<string, SourceLocation[]>();
  for (const sourceFile of program.getSourceFiles()) {
    if (!sourcePaths.has(path.resolve(sourceFile.fileName))) continue;
    const visit = (node: ts.Node): void => {
      if (ts.isIdentifier(node)) {
        const sourceId = containingEntity(node, entityByDeclaration);
        const targetSymbol = canonicalSymbol(checker, checker.getSymbolAtLocation(node));
        const targetId = targetSymbol ? entityBySymbol.get(targetSymbol) : undefined;
        const kind = relationshipKind(node);
        if (sourceId && targetId && sourceId !== targetId && kind) {
          const key = `${kind}\0${sourceId}\0${targetId}`;
          const locations = relationshipLocations.get(key) ?? [];
          locations.push(location(options.root, sourceFile, node));
          relationshipLocations.set(key, locations);
        }
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
  }
  const relationships: SemanticRelationship[] = [...relationshipLocations.entries()].map(([key, locations]) => {
    const [kind, sourceId, targetId] = key.split("\0") as [SemanticRelationshipKind, string, string];
    return { id: `semantic-edge:${kind}:${sourceId}:${targetId}`, sourceId, targetId, kind, locations };
  }).sort((left, right) => compareText(left.id, right.id));

  const diagnostics: LogicalArchitectureDiagnostic[] = [];
  const responsibilities: LogicalResponsibility[] = [];
  const assigned = new Set<string>();
  if (options.responsibilityFile) {
    let input: ResponsibilityInput;
    try {
      input = parseResponsibilityInput(JSON.parse(await readFile(options.responsibilityFile, "utf8")) as unknown);
    } catch (error) {
      throw new Error(`Invalid responsibility input ${options.responsibilityFile}: ${error instanceof Error ? error.message : String(error)}`);
    }
    const responsibilityIds = new Set<string>();
    for (const item of input.responsibilities) {
      if (responsibilityIds.has(item.id)) throw new Error(`Duplicate responsibility id ${item.id}.`);
      responsibilityIds.add(item.id);
      const entityIds: string[] = [];
      for (const anchor of item.entities) {
        const id = anchorToEntity.get(`${anchor.path}\0${anchor.symbol}`);
        if (!id) throw new Error(`Responsibility ${item.id} references unknown semantic anchor ${anchor.path}#${anchor.symbol}.`);
        if (assigned.has(id)) throw new Error(`Semantic entity ${anchor.path}#${anchor.symbol} has multiple primary responsibility homes.`);
        assigned.add(id);
        entityIds.push(id);
      }
      const contracts = entities.filter((entity) => entityIds.includes(entity.id) && entity.exported &&
        (entity.kind === "function" || entity.kind === "interface" || entity.kind === "type" || entity.kind === "class"))
        .map((entity) => entity.name).sort(compareText).slice(0, 3);
      if (contracts.length === 0) {
        throw new Error(`Responsibility ${item.id} must contain at least one exported function, class, interface, or type contract.`);
      }
      responsibilities.push({
        id: item.id,
        name: item.name,
        purpose: item.purpose,
        provenance: "proposed",
        entityIds: entityIds.sort(compareText),
        contracts,
      });
    }
  } else {
    diagnostics.push({
      code: "missing-responsibility-input",
      severity: "warning",
      message: "No responsibility input was supplied; semantic entities remain explicitly unassigned and the legacy source map remains the default.",
    });
  }

  entities.sort((left, right) => compareText(left.id, right.id));
  if (!options.authoritative) {
    diagnostics.push({
      code: "partial-source-inventory",
      severity: "warning",
      message: "The underlying scanner result is partial and the logical architecture is not authoritative.",
    });
  }
  const unassignedEntityIds = entities.filter((entity) => !assigned.has(entity.id)).map((entity) => entity.id);
  if (options.responsibilityFile && unassignedEntityIds.length > 0) {
    responsibilities.push({
      id: "responsibility:unassigned",
      name: "Unassigned",
      purpose: "Compiler-backed entities not assigned by the supplied responsibility proposal.",
      provenance: "unassigned",
      entityIds: unassignedEntityIds,
      contracts: entities.filter((entity) => unassignedEntityIds.includes(entity.id) && entity.exported)
        .map((entity) => entity.name).sort(compareText).slice(0, 3),
    });
    diagnostics.push({
      code: "unassigned-semantic-entities",
      severity: "warning",
      message: `${unassignedEntityIds.length} semantic entities are not assigned by the responsibility proposal.`,
    });
  }
  const sortedResponsibilities = responsibilities.sort((left, right) => compareText(left.id, right.id));
  const snapshotId = createHash("sha256").update(options.graph.nodes
    .map((node) => `${node.id}\0${node.fingerprint ?? ""}`).sort(compareText).join("\0")).digest("hex");
  const positionNamespaceId = createHash("sha256").update(JSON.stringify({
    version: 2,
    revision: options.revision ?? null,
    snapshotId,
    responsibilities: sortedResponsibilities,
    views: ["logical-overview", "logical-drill"],
  })).digest("hex");
  return {
    schemaVersion: "1.0",
    graphId: options.graphId,
    ...(options.revision ? { revision: options.revision } : {}),
    snapshotId,
    positionNamespaceId,
    coverage: {
      languages: ["javascript", "typescript"],
      relationshipKinds: ["calls", "constructs", "type-use", "heritage"],
      completeSourceInventory: options.authoritative,
      runtimeBehavior: false,
    },
    entities,
    relationships,
    responsibilities: sortedResponsibilities,
    unassignedEntityIds,
    diagnostics,
  };
}

source-traced: Graphs, diagnostics and quality

Return ScanResult. A refused scan throws instead; partial evidence never becomes an authoritative success claim.

packages/scanner/src/typescript-scanner.ts:921-1443
export async function scanRepository(
  input: ScanRepositoryOptions,
): Promise<ScanResult> {
  const options = parseScanRepositoryOptions(input);
  const quality = { ...DEFAULT_QUALITY, ...options.quality };
  await assertDirectory(options.root);
  const canonicalRoot = await realpath(options.root);

  const files = await walkFiles(options.root);
  const inventoryPaths = new Set(files.map((filePath) => path.resolve(filePath)));
  const configPaths = files.filter(isConfigFile).sort(compareText);
  const sourcePaths = files.filter(isSourceFile).sort(compareText);
  const workspaces = await discoverWorkspacePackages(options.root, files);
  const declaredPackageNames = await discoverDeclaredPackageNames(
    options.root,
    files,
  );
  const diagnostics: ScanDiagnostic[] = [];
  const outputMappings: OutputMapping[] = [];
  const configuredSources = await loadConfiguredSources(
    options.root,
    configPaths,
    diagnostics,
    outputMappings,
    inventoryPaths,
  );
  const unconfiguredPaths = sourcePaths.filter(
    (sourcePath) =>
      !configuredSources.has(toRepositoryPath(options.root, sourcePath)),
  );
  const inferredSources = await loadInferredSources(
    options.root,
    unconfiguredPaths,
  );
  const sources = new Map([...configuredSources, ...inferredSources]);
  if (configuredSources.size > 0 && inferredSources.size > 0) {
    diagnostics.push({
      code: "inferred-source-configuration",
      severity: "warning",
      message: `${inferredSources.size} source files were not covered by a discovered TypeScript config and used default compiler options.`,
    });
  }
  const sortedSources = [...sources.values()].sort((left, right) =>
    compareText(left.repositoryPath, right.repositoryPath),
  );
  const sourceByAbsolutePath = new Map(
    sortedSources.map((source) => [path.resolve(source.absolutePath), source]),
  );
  const filePaths = inventoryPaths;

  const nodes = new Map<string, GraphNode>();
  const evidence = new Map<string, Evidence>();
  const assets = new Map<string, AssetRecord>();
  for (const source of sortedSources) {
    const nodeId = createPathNodeId(source.repositoryPath);
    nodes.set(nodeId, {
      id: nodeId,
      label: path.posix.basename(source.repositoryPath),
      kind: "file",
      identity: { kind: "path", value: source.repositoryPath },
      fingerprint: source.fingerprint,
    });
    const item = sourceEvidence(source);
    evidence.set(item.id, item);
  }

  const edgeEvidence = new Map<
    string,
    { sourceId: string; targetId: string; evidenceIds: Set<string> }
  >();
  let localImportCount = 0;
  let assetImportCount = 0;
  let externalImportCount = 0;
  let unresolvedImportCount = 0;

  for (const source of sortedSources) {
    const imports = [...source.imports].sort(compareText);
    for (const specifier of imports) {
      const importItem = importEvidence(source, specifier);
      const assetPath = assetSpecifierPath(specifier);
      if (assetPath !== undefined) {
        const absoluteAssetPath = path.resolve(
          path.dirname(source.absolutePath),
          assetPath,
        );
        if (
          !isWithin(options.root, absoluteAssetPath) ||
          !filePaths.has(absoluteAssetPath)
        ) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-asset",
            severity: "error",
            message: `Could not resolve local CSS asset "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        let asset = assets.get(absoluteAssetPath);
        if (asset === undefined) {
          const content = await readFile(absoluteAssetPath, "utf8");
          asset = {
            absolutePath: absoluteAssetPath,
            repositoryPath: toRepositoryPath(
              options.root,
              absoluteAssetPath,
            ),
            fingerprint: sha256(content),
          };
          assets.set(absoluteAssetPath, asset);
          const assetId = createPathNodeId(asset.repositoryPath);
          nodes.set(assetId, {
            id: assetId,
            label: path.posix.basename(asset.repositoryPath),
            kind: "asset",
            identity: { kind: "path", value: asset.repositoryPath },
            fingerprint: asset.fingerprint,
          });
          const item = assetEvidence(asset);
          evidence.set(item.id, item);
        }
        const sourceId = createPathNodeId(source.repositoryPath);
        const targetId = createPathNodeId(asset.repositoryPath);
        const edgeId = createEdgeId("imports", sourceId, targetId);
        evidence.set(importItem.id, importItem);
        const accumulated = edgeEvidence.get(edgeId) ?? {
          sourceId,
          targetId,
          evidenceIds: new Set<string>(),
        };
        accumulated.evidenceIds.add(importItem.id);
        edgeEvidence.set(edgeId, accumulated);
        assetImportCount += 1;
        continue;
      }
      const resolved = ts.resolveModuleName(
        specifier,
        source.absolutePath,
        source.compilerOptions,
        ts.sys,
        source.moduleResolutionCache,
      ).resolvedModule;
      let targetId: string | undefined;
      const workspace = workspaceForSpecifier(specifier, workspaces);

      if (workspace !== undefined) {
        let target: SourceRecord | undefined;
        if (resolved !== undefined) {
          const selected = resolveCompilerSelectedSource(
            options.root,
            canonicalRoot,
            resolved.resolvedFileName,
            outputMappings,
            sourceByAbsolutePath,
          );
          if (selected.kind === "resolved") {
            target = selected.source;
          } else if (selected.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          } else if (
            resolved.resolvedFileName
              .split(path.sep)
              .includes("node_modules") ||
            !isWithin(options.root, resolved.resolvedFileName)
          ) {
            const locator = externalLocator(specifier);
            targetId = createExternalNodeId(locator);
            externalImportCount += 1;
            nodes.set(targetId, {
              id: targetId,
              label: packageName(specifier),
              kind: "external",
              identity: { kind: "external", value: locator },
            });
          }
        } else {
          const suffix =
            specifier === workspace.name
              ? ""
              : specifier.slice(workspace.name.length + 1);
          const exportedSubpath =
            suffix.length === 0
              ? workspace.manifest.exports !== undefined
              : hasExactWorkspaceExport(
                  workspace.manifest.exports,
                  `./${suffix}`,
                );
          const physicalPackage = physicalWorkspacePackageState(
            workspace,
            source.absolutePath,
          );
          if (exportedSubpath && physicalPackage !== "other") {
            const virtualResolved = resolveWorkspaceModuleName(
              options.root,
              canonicalRoot,
              workspace,
              source,
              specifier,
              outputMappings,
              sourceByAbsolutePath,
            );
            if (virtualResolved !== undefined) {
              const selected = resolveCompilerSelectedSource(
                options.root,
                canonicalRoot,
                virtualResolved.resolvedFileName,
                outputMappings,
                sourceByAbsolutePath,
              );
              if (selected.kind === "resolved") {
                target = selected.source;
              } else if (selected.kind === "ambiguous") {
                unresolvedImportCount += 1;
                diagnostics.push({
                  code: "ambiguous-generated-output",
                  severity: "error",
                  message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${selected.configPaths.join(", ")}.`,
                  path: source.repositoryPath,
                  specifier,
                });
                continue;
              }
            }
          } else if (physicalPackage !== "other") {
            target = resolveSourceCandidate(
              sourceCandidatePaths(workspace, specifier),
              sourceByAbsolutePath,
            );
          }
        }
        if (targetId === undefined) {
          if (target !== undefined) {
            targetId = createPathNodeId(target.repositoryPath);
            localImportCount += 1;
          } else {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "unresolved-workspace-import",
              severity: "error",
              message: `Could not resolve workspace import "${specifier}" from "${source.repositoryPath}".`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        resolved.resolvedFileName
          .split(path.sep)
          .includes("node_modules")
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else if (resolved !== undefined && isWithin(options.root, resolved.resolvedFileName)) {
        const target = sourceByAbsolutePath.get(
          path.resolve(resolved.resolvedFileName),
        );
        if (target !== undefined) {
          targetId = createPathNodeId(target.repositoryPath);
          localImportCount += 1;
        } else {
          const generated = resolveGeneratedOutput(
            path.resolve(resolved.resolvedFileName),
            outputMappings,
            sourceByAbsolutePath,
          );
          if (generated.kind === "resolved") {
            targetId = createPathNodeId(generated.source.repositoryPath);
            localImportCount += 1;
          } else if (generated.kind === "ambiguous") {
            unresolvedImportCount += 1;
            diagnostics.push({
              code: "ambiguous-generated-output",
              severity: "error",
              message: `Generated output import "${specifier}" from "${source.repositoryPath}" maps to multiple source projects: ${generated.configPaths.join(", ")}.`,
              path: source.repositoryPath,
              specifier,
            });
            continue;
          }
        }
      } else if (
        resolved !== undefined &&
        !isWithin(options.root, resolved.resolvedFileName)
      ) {
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      } else {
        const local =
          specifier.startsWith(".") ||
          specifier.startsWith("/") ||
          (isPathAlias(specifier, source.compilerOptions) &&
            !declaredPackageNames.has(packageName(specifier)));
        if (local) {
          unresolvedImportCount += 1;
          diagnostics.push({
            code: "unresolved-local-import",
            severity: "error",
            message: `Could not resolve local import "${specifier}" from "${source.repositoryPath}".`,
            path: source.repositoryPath,
            specifier,
          });
          continue;
        }
        const locator = externalLocator(specifier);
        targetId = createExternalNodeId(locator);
        externalImportCount += 1;
        nodes.set(targetId, {
          id: targetId,
          label: packageName(specifier),
          kind: "external",
          identity: { kind: "external", value: locator },
        });
      }

      if (targetId === undefined) {
        unresolvedImportCount += 1;
        diagnostics.push({
          code: "resolved-import-outside-scan",
          severity: "error",
          message: `Resolved import "${specifier}" is not represented by a scanned source file.`,
          path: source.repositoryPath,
          specifier,
        });
        continue;
      }

      const sourceId = createPathNodeId(source.repositoryPath);
      const edgeId = createEdgeId("imports", sourceId, targetId);
      evidence.set(importItem.id, importItem);
      const accumulated = edgeEvidence.get(edgeId) ?? {
        sourceId,
        targetId,
        evidenceIds: new Set<string>(),
      };
      accumulated.evidenceIds.add(importItem.id);
      edgeEvidence.set(edgeId, accumulated);
    }
  }

  const edges: GraphEdge[] = [...edgeEvidence.entries()]
    .sort(([left], [right]) => compareText(left, right))
    .map(([id, edge]) => ({
      id,
      label: "imports",
      type: "imports",
      sourceId: edge.sourceId,
      targetId: edge.targetId,
      provenance: provenance([...edge.evidenceIds]),
    }));
  const coveredWorkspacePackageCount = workspaces.filter((workspace) =>
    sortedSources.some(
      (source) =>
        source.absolutePath.startsWith(`${workspace.directory}${path.sep}`),
    ),
  ).length;
  const metrics: ScanMetrics = {
    configCount: configPaths.length,
    workspacePackageCount: workspaces.length,
    coveredWorkspacePackageCount,
    sourceFileCount: sortedSources.length,
    assetFileCount: assets.size,
    linesOfCode: sortedSources.reduce((sum, source) => sum + source.lines, 0),
    localImportCount,
    assetImportCount,
    externalImportCount,
    unresolvedImportCount,
  };
  const rootCargo = files.includes(path.join(options.root, "Cargo.toml"));
  diagnostics.push(...qualityDiagnostics(metrics, quality, rootCargo));
  diagnostics.sort(
    (left, right) =>
      compareText(left.path ?? "", right.path ?? "") ||
      compareText(left.code, right.code) ||
      compareText(left.specifier ?? "", right.specifier ?? ""),
  );

  const errors = diagnostics.filter(
    (diagnostic) => diagnostic.severity === "error",
  );
  const fatalEmpty = sortedSources.length === 0;
  if (
    errors.length > 0 &&
    (!quality.allowPartial || fatalEmpty)
  ) {
    throw new ScanError(
      `Repository scan failed with ${errors.length} error diagnostic${errors.length === 1 ? "" : "s"}.`,
      diagnostics,
    );
  }

  const authoritative = errors.length === 0;
  const repositoryId =
    options.repositoryId ?? path.basename(options.root);
  const rootLabel = path.basename(options.root);
  const scannerExtension: JsonValue = {
    authoritative,
    status: authoritative ? "complete" : "partial",
    adapter: {
      id: TYPESCRIPT_SCANNER_MANIFEST.id,
      version: TYPESCRIPT_SCANNER_MANIFEST.version,
      contractVersion: TYPESCRIPT_SCANNER_MANIFEST.contractVersion,
      capabilities: {
        languages: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.languages],
        granularity: [...TYPESCRIPT_SCANNER_MANIFEST.capabilities.granularity],
        relationships: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.relationships,
        ],
        moduleResolution:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.moduleResolution,
        workspaceManifests: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.workspaceManifests,
        ],
        opaqueAssets: [
          ...TYPESCRIPT_SCANNER_MANIFEST.capabilities.opaqueAssets,
        ],
        partialResults:
          TYPESCRIPT_SCANNER_MANIFEST.capabilities.partialResults,
      },
    },
    metrics: { ...metrics },
    diagnostics: diagnostics.map((diagnostic) => ({
      code: diagnostic.code,
      severity: diagnostic.severity,
      message: diagnostic.message,
      ...(diagnostic.path === undefined ? {} : { path: diagnostic.path }),
      ...(diagnostic.specifier === undefined
        ? {}
        : { specifier: diagnostic.specifier }),
    })),
  };
  const graph = createGraphDocument({
    graphId: `repo:${repositoryId}`,
    repository: {
      id: repositoryId,
      label: rootLabel,
      ...(options.revision === undefined
        ? {}
        : { revision: options.revision }),
    },
    modules: [
      {
        id: SCANNER_MODULE_ID,
        version: SCANNER_VERSION,
        schemaVersion: GRAPH_SCHEMA_VERSION,
      },
    ],
    nodes: [...nodes.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    edges,
    containers: directoriesForPaths(
      rootLabel,
      [
        ...sortedSources.map((source) => source.repositoryPath),
        ...[...assets.values()].map((asset) => asset.repositoryPath),
      ].sort(compareText),
    ),
    attributes: sortedSources.flatMap((source) => {
      const nodeId = createPathNodeId(source.repositoryPath);
      const evidenceId = `evidence:source:${source.repositoryPath}`;
      return [
        {
          id: createAttributeId(nodeId, "dev.topo.source.lines"),
          subject: { kind: "node" as const, id: nodeId },
          key: "dev.topo.source.lines",
          value: source.lines,
          provenance: provenance([evidenceId]),
          evidenceIds: [evidenceId],
          confidence: 1,
          witnesses: [
            {
              nodeId,
              fingerprint: source.fingerprint,
              relationship: "self" as const,
            },
          ],
        },
      ];
    }),
    evidence: [...evidence.values()].sort((left, right) =>
      compareText(left.id, right.id),
    ),
    extensions: {
      "dev.topo.scanner": scannerExtension,
    },
  });
  serializeGraphDocument(graph);
  const logicalArchitecture = await extractLogicalArchitecture({
    root: options.root,
    graphId: graph.graphId,
    graph,
    authoritative,
    ...(options.revision ? { revision: options.revision } : {}),
    sources: sortedSources,
    ...(options.responsibilityFile ? { responsibilityFile: options.responsibilityFile } : {}),
  });
  return { graph, logicalArchitecture, diagnostics, metrics, authoritative };
}