/** * Does the graph still describe code that is there? * * `staleness.ts` has two signals and neither is existence. `byAge` flags anything * not verified in 30 days, which on a real graph is most of it, correct entries * included. `degradeChanged` intersects entity `source` paths with * `git diff --name-only` — so a *deleted* directory goes quiet exactly when its * entries become wrong, because a path that no longer exists stops appearing in * diffs. That is how eight `@rasensio/aidlc-web` module entries and seven `dep-*` * entries survived 17 days past the cutover that deleted `packages/web/`, and why * `aidlc knowledge query "web"` answered with the deleted package first. * * Two classes, one read, because they are one defect at two levels: an entity whose * `source` names nothing, and an edge whose endpoint names no entity. The second * measured 0 across 195 edges before this instance, which makes it the guard on the * fix itself — deleting 15 entities and forgetting their 16 edges would trade one * class for the other. * * Pure over a `LoadedGraph` and one injectable existence predicate: no index, no * subprocess, no network (stale-graph-entries/AC-17). `doctor` calls it, so anything * it reaches is on the default path of a command people run casually. * * Requirements: stale-graph-entries/AC-11, AC-12, AC-14, AC-15 * * @module */ import type { LoadedGraph } from './yaml-source.js'; /** * What a `source` string is, before anything touches the filesystem. * * `not-repo-relative` exists so that classification, not `existsSync`, is what * decides whether a path is safe to probe. `source` arrives from a tracked YAML * file — tracked is not the same as trusted, and `secure-defaults.md` asks for * `..` rejection at the boundary rather than downstream. An absolute * `/etc/passwd` or a `../../` escape is reported as a defect in the entry and is * never handed to a filesystem call, so a graph file cannot make `aidlc doctor` * probe paths outside the repo it is run in (AC-14). */ export type SourceKind = { kind: 'sentinel'; } | { kind: 'empty'; } | { kind: 'not-repo-relative'; reason: 'absolute' | 'escapes-root'; } | { kind: 'repo-relative'; relative: string; }; /** * Classify a `source` without touching the disk. * * Containment is decided on the *resolved* path rather than by looking for `..` * segments: `packages/web/../website` contains `..` and stays inside the root, * while `a/../../b` does not, and only resolution tells them apart. */ export declare function classifySource(source: string, projectRoot: string): SourceKind; /** One entity whose `source` does not describe something on disk. */ export interface UnresolvedSource { entityId: string; entityName: string; source: string; /** * `missing` — a repo-relative path that resolves nowhere. * `absolute` / `escapes-root` — rejected at classification; never probed. */ reason: 'missing' | 'absolute' | 'escapes-root'; } /** One edge whose `from` or `to` names an entity the graph does not hold. */ export interface DanglingRelationship { from: string; to: string; type: string; /** Which endpoint(s) name nothing — both, when an edge lost both ends. */ missing: string[]; } export interface GraphResolution { unresolvedSources: UnresolvedSource[]; danglingRelationships: DanglingRelationship[]; /** How many entities carried a repo-relative `source` and were therefore probed. */ checkedSources: number; } /** * Resolve every `source` against the disk and every edge endpoint against the * entity set. * * @param graph - Output of `YamlSourceStore.loadAll()`. * @param projectRoot - Working tree the relative paths are resolved against. * @param exists - Injected for tests, which assert that no path outside the * fixture root ever reaches it (AC-23). Production passes `existsSync`. */ export declare function resolveGraphAgainstDisk(graph: LoadedGraph, projectRoot: string, exists?: (absolutePath: string) => boolean): GraphResolution; /** True when the graph describes nothing that is not there. */ export declare function isResolved(result: GraphResolution): boolean; /** * One-line-per-class summary, longest-lived detail first. * * Capped at `maxItems` per class with an explicit "and N more", because the * failure this reports is plural by nature — the first run against a graph that * has never been checked found 15 — and a doctor line that scrolls is a doctor * line nobody reads. */ export declare function describeResolution(result: GraphResolution, maxItems?: number): string; //# sourceMappingURL=source-resolution.d.ts.map