@descryy/runtime-graph-correlator 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Resolving source-mapped evidence (a stack frame or backend log line naming
3
+ * a file + symbol) to the `FUNCTION`/`CLASS` node it came from.
4
+ *
5
+ * Unlike `endpoint.ts`, this *is* a "wrong repository" risk: `FUNCTION` and
6
+ * `CLASS` are repo-scoped (DEC-054), and a runtime session that merges more
7
+ * than one repository into one store (frontend + backend, to trace across
8
+ * them — DEC-228) can hold two same-named, same-relative-path symbols that
9
+ * belong to different repositories. `repo` is therefore required here, not
10
+ * optional — there is no honest default for it, and guessing one is exactly
11
+ * the failure `resolveOneNode` (descry-core's own MCP lookup) refuses to
12
+ * make. This function inherits that discipline rather than reimplementing
13
+ * it differently: return every match, never pick one by heuristic, refuse
14
+ * ambiguity to the caller instead of resolving it silently.
15
+ *
16
+ * `line`, when the caller has one (a stack frame almost always does), is a
17
+ * second, independent check after name+file+repo resolve to exactly one
18
+ * node: does the evidence's own claimed line actually fall inside that
19
+ * node's range? A source map can point at the right *file* and even the
20
+ * right *function name* while still landing on a stale line — a stripped
21
+ * build, a moved function whose body shifted, a webpack virtual path that
22
+ * resolves near but not into the real range. Name+file+repo agreeing is not
23
+ * the same claim as the line agreeing, so a mismatch is its own outcome
24
+ * (`line-mismatch`) rather than a silent `resolved` that hides a real
25
+ * discrepancy, or a `not-found` that discards a symbol that plainly exists.
26
+ */
27
+ import type { IRNode } from "@descryy/ir";
28
+ import { type SqlDriver } from "@descryy/core";
29
+ export type SymbolResolution = {
30
+ readonly outcome: "resolved";
31
+ readonly node: IRNode;
32
+ } | {
33
+ readonly outcome: "not-found";
34
+ readonly reason: string;
35
+ } | {
36
+ readonly outcome: "ambiguous";
37
+ readonly candidates: readonly IRNode[];
38
+ readonly reason: string;
39
+ } | {
40
+ readonly outcome: "line-mismatch";
41
+ readonly node: IRNode;
42
+ readonly reason: string;
43
+ };
44
+ export declare function resolveSymbolNode(driver: SqlDriver, location: {
45
+ readonly file: string;
46
+ readonly symbolName: string;
47
+ readonly line?: number;
48
+ }, repo: string,
49
+ /**
50
+ * `cwd`: the directory the process that produced `location.file` was
51
+ * actually launched in. Pass it whenever the caller knows it and the
52
+ * evidence's runtime is one that echoes its invocation argument verbatim
53
+ * (RT-113: Ruby) -- omitting it is not "safer", it is the passthrough
54
+ * behaviour every other caller already relies on for an already
55
+ * repo-relative path.
56
+ */
57
+ options?: {
58
+ readonly repoRoot?: string;
59
+ readonly cwd?: string;
60
+ }): SymbolResolution;
61
+ /**
62
+ * `resolveSymbolNode`, tried across every repo the caller knows about,
63
+ * for the evidence shape RT-008 names but `resolveSymbolNode` itself
64
+ * cannot serve: a signal with **no known scope at all** (a raw log line
65
+ * naming a symbol, no service/repo hint), arriving into a session that
66
+ * spans more than one repository. `resolveSymbolNode` already refuses
67
+ * ambiguity *within* one repo by requiring `repo` as a mandatory parameter
68
+ * — this function is the layer above that: trying repos in sequence and
69
+ * keeping the first hit would smuggle a guess back in through the one door
70
+ * `resolveSymbolNode` closed, so a match in more than one repo is refused
71
+ * here too, naming every repo that matched.
72
+ *
73
+ * Negative control #1 (`next_tasks.md` T6): two repos, identically-named
74
+ * symbol at the same relative path, no scope given — must refuse, not pick
75
+ * either.
76
+ */
77
+ export type CrossRepoSymbolResolution = {
78
+ readonly outcome: "resolved";
79
+ readonly repo: string;
80
+ readonly node: IRNode;
81
+ } | {
82
+ readonly outcome: "not-found";
83
+ readonly reason: string;
84
+ } | {
85
+ readonly outcome: "cross-repo-ambiguous";
86
+ readonly matches: readonly {
87
+ readonly repo: string;
88
+ readonly node: IRNode;
89
+ }[];
90
+ readonly reason: string;
91
+ };
92
+ export declare function resolveSymbolAcrossRepos(driver: SqlDriver, location: {
93
+ readonly file: string;
94
+ readonly symbolName: string;
95
+ readonly line?: number;
96
+ }, knownRepos: readonly string[], options?: {
97
+ readonly repoRoot?: string;
98
+ readonly cwd?: string;
99
+ }): CrossRepoSymbolResolution;
100
+ /**
101
+ * The **coarser** answer: which `MODULE` node is declared in the file this
102
+ * evidence named.
103
+ *
104
+ * §10 asks the runtime to correlate evidence to each graph node type where
105
+ * applicable. Measured across `descry-adapters` rather than assumed, the
106
+ * picture for the file-shaped types is:
107
+ *
108
+ * | type | producers | so |
109
+ * | --- | --- | --- |
110
+ * | `MODULE` | 10 of 15 adapters | correlatable, and this is it |
111
+ * | `FILE` | **zero** | nothing to correlate to, on any repository |
112
+ *
113
+ * **`FILE` is not a gap in this file.** No shipped adapter emits one —
114
+ * `descry-core`'s `capabilities/preconditions.ts` records the same fact and
115
+ * exists because three static checks read `nodesOfType("FILE")` and were
116
+ * dead on every real repository while 48 tests stayed green. A runtime
117
+ * resolver targeting `FILE` would reproduce that exactly: a function that
118
+ * always returns `not-found`, indistinguishable from a clean answer.
119
+ *
120
+ * ## Why this is a separate function, not a fallback inside `resolveSymbolNode`
121
+ *
122
+ * A caller must **ask** for the coarser answer. `resolveSymbolNode` silently
123
+ * degrading to a module when the symbol did not resolve would be the
124
+ * honest-degradation rule broken in the one place it matters most: the
125
+ * refusal would disappear, and a consumer would see a resolution where the
126
+ * truth is "we could not find the function, here is the file it claims to be
127
+ * in." Two outcomes that mean different things must not arrive through the
128
+ * same door.
129
+ *
130
+ * ## The outcome is `module-level`, never `resolved`
131
+ *
132
+ * Following RT-055's `sole-structural-caller`: the vocabulary carries the
133
+ * claim's strength at the type level, so a consumer cannot treat a
134
+ * file-granularity answer as a symbol-granularity one by writing
135
+ * `outcome === "resolved"`. This matters for the resolution cap — a finding
136
+ * resting on a module-level correlation knows *which file* failed and does
137
+ * not know *which function*, and those are different findings.
138
+ */
139
+ export type ModuleResolution = {
140
+ readonly outcome: "module-level";
141
+ readonly node: IRNode;
142
+ } | {
143
+ readonly outcome: "not-found";
144
+ readonly reason: string;
145
+ } | {
146
+ readonly outcome: "ambiguous";
147
+ readonly candidates: readonly IRNode[];
148
+ readonly reason: string;
149
+ };
150
+ export declare function resolveContainingModule(driver: SqlDriver, file: string, repo: string,
151
+ /** See `resolveSymbolNode`'s `cwd` -- same translation, same opt-in. */
152
+ options?: {
153
+ readonly repoRoot?: string;
154
+ readonly cwd?: string;
155
+ }): ModuleResolution;
156
+ /**
157
+ * Resolving an **observed** test — a `test:pass`/`test:fail` event from a real
158
+ * runner, carrying the test's own name, file and line — to the `TEST_CASE`
159
+ * node an adapter minted for it.
160
+ *
161
+ * This is the join that lets a failing test stop being a parallel silo. Once
162
+ * the observed test is a graph node, the `TESTS` edges already leaving that
163
+ * node answer "what does this test cover" with **no runtime guessing at all**
164
+ * — the subject was resolved statically, by an adapter, at index time. The
165
+ * runtime's job is to identify the node, not to infer the relationship.
166
+ *
167
+ * ## Why the fifth outcome exists, and the measurement behind it
168
+ *
169
+ * Counted across `descry-adapters` rather than assumed, by looking for actual
170
+ * node construction (`type: "TEST_CASE"`) rather than references to the
171
+ * string — six of the ten language adapters mention `TEST_CASE` while
172
+ * constructing none, because they use it for the `TESTS` *edge* and for
173
+ * container checks:
174
+ *
175
+ * | | adapters |
176
+ * | --- | --- |
177
+ * | construct `TEST_CASE` nodes | 4 |
178
+ * | mention it, construct none | 6 |
179
+ *
180
+ * So a four-outcome resolver copied from `resolveSymbolNode` would return
181
+ * `not-found` forever for the six, and `not-found` already means *"this graph
182
+ * has no such node"* — which a consumer reads as "that test isn't indexed."
183
+ * The truth is that nothing was ever going to index it. That is the same
184
+ * always-returns-not-found shape that killed the `FILE` resolver idea one
185
+ * function above, displaced rather than avoided, and it is RT-060's
186
+ * producer-versus-consumer attribution restated: a refusal has to say **whose**
187
+ * gap it is.
188
+ *
189
+ * ## `producer-emitted-none` claims exactly what was measured, and no more
190
+ *
191
+ * The name is not `producer-does-not-emit`, because this function cannot
192
+ * observe an adapter — it observes a store. Zero `TEST_CASE` nodes in a
193
+ * language admits two readings: no adapter for that language emits them, or
194
+ * this store simply holds no tests written in it. **Both are producer-side,
195
+ * and neither is "your test is missing"** — which is the whole distinction a
196
+ * consumer needs. The reason string carries the disjunction instead of the
197
+ * outcome name resolving it by fiat.
198
+ *
199
+ * And when the scan truncates, this outcome is **withheld**: a set-property
200
+ * question answered over a silently truncated set is a fact computed from a
201
+ * sample, which is the warning `nodesOfType` carries in its own doc comment.
202
+ * A truncated scan that found nothing degrades to `not-found` naming the
203
+ * truncation, never to a confident claim about a producer.
204
+ *
205
+ * ## This reads `language`; it does not branch on one
206
+ *
207
+ * `IRNode.language` is provenance and must never be branched on above the IR
208
+ * boundary. Nothing here compares it to a literal — no language name appears
209
+ * in this file. It groups by the value the graph itself supplied, the same way
210
+ * `findNodes` narrows by a `repo` string it was handed. A hardcoded set of
211
+ * "languages whose adapters emit TEST_CASE" would have been the violation, and
212
+ * it would also have gone stale the first time an adapter started emitting.
213
+ */
214
+ export type TestCaseResolution = {
215
+ readonly outcome: "resolved";
216
+ readonly node: IRNode;
217
+ } | {
218
+ readonly outcome: "not-found";
219
+ readonly reason: string;
220
+ } | {
221
+ readonly outcome: "ambiguous";
222
+ readonly candidates: readonly IRNode[];
223
+ readonly reason: string;
224
+ } | {
225
+ readonly outcome: "line-mismatch";
226
+ readonly node: IRNode;
227
+ readonly reason: string;
228
+ } | {
229
+ readonly outcome: "producer-emitted-none";
230
+ readonly language: string | null;
231
+ readonly reason: string;
232
+ };
233
+ export declare function resolveTestCaseNode(driver: SqlDriver, location: {
234
+ readonly file: string;
235
+ readonly testName: string;
236
+ readonly line?: number;
237
+ }, repo: string,
238
+ /** `cwd`: see `resolveSymbolNode`'s doc -- same translation, same opt-in. */
239
+ options?: {
240
+ readonly repoRoot?: string;
241
+ readonly cwd?: string;
242
+ readonly producerScanLimit?: number;
243
+ }): TestCaseResolution;
244
+ //# sourceMappingURL=symbol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol.d.ts","sourceRoot":"","sources":["../src/symbol.ts"],"names":[],"mappings":"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"}
package/dist/symbol.js ADDED
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Resolving source-mapped evidence (a stack frame or backend log line naming
3
+ * a file + symbol) to the `FUNCTION`/`CLASS` node it came from.
4
+ *
5
+ * Unlike `endpoint.ts`, this *is* a "wrong repository" risk: `FUNCTION` and
6
+ * `CLASS` are repo-scoped (DEC-054), and a runtime session that merges more
7
+ * than one repository into one store (frontend + backend, to trace across
8
+ * them — DEC-228) can hold two same-named, same-relative-path symbols that
9
+ * belong to different repositories. `repo` is therefore required here, not
10
+ * optional — there is no honest default for it, and guessing one is exactly
11
+ * the failure `resolveOneNode` (descry-core's own MCP lookup) refuses to
12
+ * make. This function inherits that discipline rather than reimplementing
13
+ * it differently: return every match, never pick one by heuristic, refuse
14
+ * ambiguity to the caller instead of resolving it silently.
15
+ *
16
+ * `line`, when the caller has one (a stack frame almost always does), is a
17
+ * second, independent check after name+file+repo resolve to exactly one
18
+ * node: does the evidence's own claimed line actually fall inside that
19
+ * node's range? A source map can point at the right *file* and even the
20
+ * right *function name* while still landing on a stale line — a stripped
21
+ * build, a moved function whose body shifted, a webpack virtual path that
22
+ * resolves near but not into the real range. Name+file+repo agreeing is not
23
+ * the same claim as the line agreeing, so a mismatch is its own outcome
24
+ * (`line-mismatch`) rather than a silent `resolved` that hides a real
25
+ * discrepancy, or a `not-found` that discards a symbol that plainly exists.
26
+ */
27
+ import { isAbsolute, relative, resolve as resolvePath } from "node:path";
28
+ import { findNodes, nodesOfType } from "@descryy/core";
29
+ const SYMBOL_NODE_TYPES = new Set(["FUNCTION", "CLASS"]);
30
+ /**
31
+ * **Runtime evidence and the graph do not speak the same path language, and
32
+ * they should not.** A stack frame names an absolute on-disk path — that is
33
+ * what was actually observed, and rewriting it at capture time would
34
+ * destroy the observation. Graph nodes carry repo-relative paths, because a
35
+ * path-dependent identity churns on every checkout location. Something has
36
+ * to translate, and this is the function whose entire job is mapping
37
+ * runtime evidence onto graph entities, so it translates here.
38
+ *
39
+ * **Found by the continuous-chain test, and only by it.** Every earlier
40
+ * test supplied a path in whichever convention it happened to need — the
41
+ * vertical slice pre-relativised with its own helper, the collector tests
42
+ * never resolved to a node — so the two halves each looked right and the
43
+ * seam between them had never been crossed. The first run that crossed it
44
+ * failed with `not-found` on a symbol that plainly exists.
45
+ *
46
+ * **The old failure was worse than a failure: it was a misleading one.**
47
+ * An absolute path simply matched nothing, and the refusal read `No
48
+ * FUNCTION/CLASS node named "deleteInvoice" in
49
+ * "/home/.../server.mjs"` — which a reader takes as "that symbol is not in
50
+ * the graph" when the truth is "you handed me a path in the other
51
+ * coordinate system." Both refusals below now say which of the two it is.
52
+ *
53
+ * Relativising is exact, never a guess: the path must actually live under
54
+ * `repoRoot`, and a path outside it is a **different repository's file**,
55
+ * reported as such. Matching on basename instead would be RT-031's
56
+ * identity-proxy error — `server.mjs` exists in both fixture repos.
57
+ */
58
+ /**
59
+ * Absolute observed path → repo-relative graph path, or a refusal saying
60
+ * which of the two coordinate systems went wrong.
61
+ *
62
+ * **Shared rather than copied**, because both resolvers in this file must
63
+ * translate identically. A second copy would hold in one of them; measured
64
+ * elsewhere in this project at a two-week silent drift, and here the drift
65
+ * would be between "we found the symbol" and "we found the module in the
66
+ * same file", which no test comparing only outcomes would notice.
67
+ *
68
+ * **A third coordinate system, alongside absolute and repo-relative:
69
+ * relative-to-whatever-cwd-the-process-was-launched-in.** RT-113 measured it
70
+ * against Ruby — a backtrace prints the path exactly as invoked, never
71
+ * normalized — but nothing about the fact is Ruby-specific: any runtime that
72
+ * echoes its own invocation argument verbatim produces the same shape, and
73
+ * this function cannot tell that class of relative path from an
74
+ * already-repo-relative one by looking at it. It can only be told, by a
75
+ * caller that knows the directory the process actually ran in. `cwd` is that
76
+ * signal: passing it is how a caller opts a relative path into this
77
+ * resolution instead of the passthrough below, so every existing caller that
78
+ * never supplies it keeps exactly its old behaviour (`resolveSymbolNode: a
79
+ * relative path still works unchanged`, `symbol.test.ts`). When given, a
80
+ * relative path is resolved against it into an absolute path and handed to
81
+ * the same repoRoot-relativisation the absolute branch already does below —
82
+ * one coordinate translation, not two.
83
+ */
84
+ function toRepoRelative(file, repo, repoRoot, cwd) {
85
+ if (!isAbsolute(file)) {
86
+ if (cwd === undefined) {
87
+ // A leading `./` is not a second repository's file and not a missing
88
+ // symbol -- it is `rustc`'s own path language. Compiled with a relative
89
+ // source argument (`rustc -g -o bin self-failing-server.rs`, exactly
90
+ // what a managed spawn does), the panic header embeds
91
+ // `./self-failing-server.rs` verbatim; `discover()` (adapter-common)
92
+ // never produces a `./`-prefixed path, so the two would otherwise agree
93
+ // on everything but this one cosmetic prefix and report `not-found`.
94
+ // Stripped unconditionally: a leading `./` never carries identity,
95
+ // unlike `..` which genuinely means "outside" and is left alone.
96
+ //
97
+ // No `cwd` known means no way to distinguish "already repo-relative"
98
+ // from "relative to some other, unrecorded base" -- passthrough is the
99
+ // existing, deliberately narrow default, not a guess that this path is
100
+ // correct.
101
+ return { ok: true, file: file.startsWith("./") ? file.slice(2) : file };
102
+ }
103
+ file = resolvePath(cwd, file);
104
+ }
105
+ if (repoRoot === undefined) {
106
+ return {
107
+ ok: false,
108
+ reason: `Evidence named the absolute path "${file}", but graph nodes carry repo-relative paths. ` +
109
+ `Pass \`repoRoot\` so this can be translated exactly. Reported rather than searched for a ` +
110
+ `suffix match, which would resolve the wrong repository's identically-named file.`,
111
+ };
112
+ }
113
+ const relativePath = relative(repoRoot, file);
114
+ if (relativePath.startsWith("..") || isAbsolute(relativePath)) {
115
+ return {
116
+ ok: false,
117
+ reason: `Evidence named "${file}", which is not under repo "${repo}"'s root "${repoRoot}" — ` +
118
+ `it belongs to a different repository, not to a missing symbol in this one.`,
119
+ };
120
+ }
121
+ return { ok: true, file: relativePath };
122
+ }
123
+ export function resolveSymbolNode(driver, location, repo,
124
+ /**
125
+ * `cwd`: the directory the process that produced `location.file` was
126
+ * actually launched in. Pass it whenever the caller knows it and the
127
+ * evidence's runtime is one that echoes its invocation argument verbatim
128
+ * (RT-113: Ruby) -- omitting it is not "safer", it is the passthrough
129
+ * behaviour every other caller already relies on for an already
130
+ * repo-relative path.
131
+ */
132
+ options = {}) {
133
+ const translated = toRepoRelative(location.file, repo, options.repoRoot, options.cwd);
134
+ if (!translated.ok)
135
+ return { outcome: "not-found", reason: translated.reason };
136
+ const file = translated.file;
137
+ const matches = findNodes(driver, {
138
+ name: location.symbolName,
139
+ file,
140
+ repo,
141
+ limit: 10,
142
+ }).filter((n) => SYMBOL_NODE_TYPES.has(n.type));
143
+ if (matches.length === 0) {
144
+ return {
145
+ outcome: "not-found",
146
+ reason: `No FUNCTION/CLASS node named "${location.symbolName}" in "${file}" within repo ` +
147
+ `"${repo}". This does not mean it does not exist — it may mean no adapter read it, or the ` +
148
+ "graph predates it.",
149
+ };
150
+ }
151
+ if (matches.length > 1) {
152
+ return {
153
+ outcome: "ambiguous",
154
+ candidates: matches,
155
+ reason: `${matches.length} nodes named "${location.symbolName}" exist in "${file}" within ` +
156
+ `repo "${repo}" — ${matches.map((n) => n.type).join(", ")}. Picking one by a heuristic would ` +
157
+ "be reasoning confidently about a symbol the evidence did not actually distinguish.",
158
+ };
159
+ }
160
+ const node = matches[0];
161
+ // `null` joins `undefined` here deliberately: a frame that carried no
162
+ // line (a JVM `Unknown Source` frame) has nothing to check the range
163
+ // against, and treating "no line" as a mismatch would reject a correct
164
+ // name-and-file match on the strength of information nobody captured.
165
+ if (location.line !== undefined && location.line !== null && node.range !== null) {
166
+ const { startLine, endLine } = node.range;
167
+ if (location.line < startLine || location.line > endLine) {
168
+ return {
169
+ outcome: "line-mismatch",
170
+ node,
171
+ reason: `Evidence claims line ${location.line}, but "${location.symbolName}" spans lines ` +
172
+ `${startLine}-${endLine}. Name and file agree; the line does not — treat the source ` +
173
+ "location as unreliable rather than silently trusting the name match.",
174
+ };
175
+ }
176
+ }
177
+ return { outcome: "resolved", node };
178
+ }
179
+ export function resolveSymbolAcrossRepos(driver, location, knownRepos, options = {}) {
180
+ const resolved = [];
181
+ for (const repo of knownRepos) {
182
+ const result = resolveSymbolNode(driver, location, repo, options);
183
+ // Only a clean `resolved` counts as a match here -- `ambiguous` (two
184
+ // symbols within that one repo) and `line-mismatch` are that repo's own
185
+ // refusal, not a hit to compare against the other repos' results, and
186
+ // folding them in would understate the ambiguity rather than report it.
187
+ if (result.outcome === "resolved")
188
+ resolved.push({ repo, node: result.node });
189
+ }
190
+ if (resolved.length === 0) {
191
+ return {
192
+ outcome: "not-found",
193
+ reason: `No FUNCTION/CLASS node named "${location.symbolName}" in "${location.file}" was found in any ` +
194
+ `of the ${knownRepos.length} known repositories (${knownRepos.join(", ") || "none"}).`,
195
+ };
196
+ }
197
+ if (resolved.length > 1) {
198
+ return {
199
+ outcome: "cross-repo-ambiguous",
200
+ matches: resolved,
201
+ reason: `"${location.symbolName}" in "${location.file}" resolved in ${resolved.length} different ` +
202
+ `repositories (${resolved.map((m) => m.repo).join(", ")}), and this evidence carries no repo ` +
203
+ "scope to pick one. Trying repos in sequence and keeping the first hit would be a guess; " +
204
+ "refused instead.",
205
+ };
206
+ }
207
+ return { outcome: "resolved", repo: resolved[0].repo, node: resolved[0].node };
208
+ }
209
+ export function resolveContainingModule(driver, file, repo,
210
+ /** See `resolveSymbolNode`'s `cwd` -- same translation, same opt-in. */
211
+ options = {}) {
212
+ const translated = toRepoRelative(file, repo, options.repoRoot, options.cwd);
213
+ if (!translated.ok)
214
+ return { outcome: "not-found", reason: translated.reason };
215
+ const relativeFile = translated.file;
216
+ const matches = findNodes(driver, { file: relativeFile, repo, limit: 10 }).filter((n) => n.type === "MODULE");
217
+ if (matches.length === 0) {
218
+ return {
219
+ outcome: "not-found",
220
+ reason: `No MODULE node is declared in "${relativeFile}" within repo "${repo}". Either no adapter read ` +
221
+ "that file, or the adapter that read it does not emit MODULE — ten of fifteen do, so the " +
222
+ "absence is a producer question, not evidence that the file is uninteresting.",
223
+ };
224
+ }
225
+ if (matches.length > 1) {
226
+ // Two modules declared in one file is legitimate in several languages
227
+ // (Ruby, C#, Python's nested scopes) — the observed file does not say
228
+ // which one the frame was inside, and neither does a line, since module
229
+ // ranges routinely nest. Refused rather than ranked.
230
+ return {
231
+ outcome: "ambiguous",
232
+ candidates: matches,
233
+ reason: `${matches.length} MODULE nodes are declared in "${relativeFile}" within repo "${repo}" — ` +
234
+ `${matches.map((n) => n.name).join(", ")}. A file-level observation cannot say which, and ` +
235
+ "picking the outermost or the first would be a guess dressed as a coarse answer.",
236
+ };
237
+ }
238
+ return { outcome: "module-level", node: matches[0] };
239
+ }
240
+ /** Cap on the `TEST_CASE` scan backing `producer-emitted-none`. Truncation withholds the claim. */
241
+ const PRODUCER_SCAN_LIMIT = 5000;
242
+ export function resolveTestCaseNode(driver, location, repo,
243
+ /** `cwd`: see `resolveSymbolNode`'s doc -- same translation, same opt-in. */
244
+ options = {}) {
245
+ const translated = toRepoRelative(location.file, repo, options.repoRoot, options.cwd);
246
+ if (!translated.ok)
247
+ return { outcome: "not-found", reason: translated.reason };
248
+ const file = translated.file;
249
+ const matches = findNodes(driver, { name: location.testName, file, repo, limit: 10 }).filter((n) => n.type === "TEST_CASE");
250
+ if (matches.length > 1) {
251
+ // Two tests of the same name in one file is ordinary — `describe` blocks
252
+ // nest, and several runners scope a name to its block rather than to the
253
+ // file. The observed event carries a line, but test ranges nest just as
254
+ // module ranges do, so the innermost is not reliably the right one.
255
+ // Refused rather than ranked, exactly as above.
256
+ return {
257
+ outcome: "ambiguous",
258
+ candidates: matches,
259
+ reason: `${matches.length} TEST_CASE nodes named "${location.testName}" exist in "${file}" within ` +
260
+ `repo "${repo}". Test names repeat across nested blocks, and picking by line would rank ` +
261
+ "nested ranges — a guess dressed as a resolution.",
262
+ };
263
+ }
264
+ if (matches.length === 1) {
265
+ const node = matches[0];
266
+ if (location.line !== undefined && location.line !== null && node.range !== null) {
267
+ const { startLine, endLine } = node.range;
268
+ if (location.line < startLine || location.line > endLine) {
269
+ return {
270
+ outcome: "line-mismatch",
271
+ node,
272
+ reason: `The runner reported line ${location.line}, but TEST_CASE "${location.testName}" spans ` +
273
+ `lines ${startLine}-${endLine}. Name and file agree; the line does not — the graph is ` +
274
+ "likely older than the file, so treat the node as identified but the position as stale.",
275
+ };
276
+ }
277
+ }
278
+ return { outcome: "resolved", node };
279
+ }
280
+ return explainMissingTestCase(driver, file, repo, location.testName, options.producerScanLimit);
281
+ }
282
+ /**
283
+ * Why nothing matched — the part that has to distinguish four genuinely
284
+ * different situations that all present as an empty result set.
285
+ *
286
+ * Kept separate from the resolver so the resolver reads as one decision, and
287
+ * so this can be exercised directly: three of the four branches need a store
288
+ * shaped a particular way, and reaching them through the happy path would
289
+ * mean every test also depended on name matching working.
290
+ */
291
+ function explainMissingTestCase(driver, file, repo, testName, scanLimit) {
292
+ const inFile = findNodes(driver, { file, repo, limit: 200 });
293
+ // (1) Nothing at all from this file. No adapter read it — an excluded path,
294
+ // an unsupported extension, a file newer than the graph. Reporting a
295
+ // producer claim here would be wrong in a specific way: it would blame the
296
+ // language when the file was never opened.
297
+ if (inFile.length === 0) {
298
+ return {
299
+ outcome: "not-found",
300
+ reason: `No node of any type was produced from "${file}" within repo "${repo}", so the file itself ` +
301
+ "was never read — not excluded from test extraction, excluded from parsing. Check the " +
302
+ "adapter's file selection before concluding anything about test support.",
303
+ };
304
+ }
305
+ const language = inFile.find((n) => n.language !== null)?.language ?? null;
306
+ const limit = scanLimit ?? PRODUCER_SCAN_LIMIT;
307
+ const { nodes: testCases, truncated } = nodesOfType(driver, "TEST_CASE", limit);
308
+ const sameLanguage = testCases.filter((n) => n.language === language);
309
+ if (sameLanguage.length === 0) {
310
+ // (2) The scan hit its cap, so "none" was measured over a sample. The
311
+ // producer claim is withheld rather than made cheaply.
312
+ if (truncated) {
313
+ return {
314
+ outcome: "not-found",
315
+ reason: `No TEST_CASE node named "${testName}" in "${file}". A scan for TEST_CASE nodes of the ` +
316
+ `same provenance found none, but the scan truncated at ${limit} rows — that is a sample, ` +
317
+ "not the set, so no claim about the producer is made from it. Raise `producerScanLimit`.",
318
+ };
319
+ }
320
+ // (3) The whole store holds no TEST_CASE node of this provenance. Not a
321
+ // consumer-side miss, and the reason says so without deciding which of
322
+ // the two producer-side readings applies.
323
+ return {
324
+ outcome: "producer-emitted-none",
325
+ language,
326
+ reason: `This store holds no TEST_CASE node of the same provenance as "${file}" — ${testCases.length} ` +
327
+ "TEST_CASE nodes exist in total, none of them from this language. Either no adapter for it " +
328
+ "emits TEST_CASE, or nothing indexed here is written in it. Both are producer-side: the " +
329
+ `runner observed "${testName}" and the graph was never going to contain it, which is not the ` +
330
+ "same as the test being absent from a graph that could have held it.",
331
+ };
332
+ }
333
+ // (4) The producer does emit for this provenance, and this particular test
334
+ // still is not there — a real consumer-side miss, and the only branch where
335
+ // "the graph does not have your test" is the honest sentence.
336
+ return {
337
+ outcome: "not-found",
338
+ reason: `No TEST_CASE node named "${testName}" in "${file}" within repo "${repo}", though ` +
339
+ `${sameLanguage.length} TEST_CASE nodes of the same provenance exist elsewhere in this store — ` +
340
+ "so the producer does emit them and this one genuinely is not indexed. A renamed test, a " +
341
+ "dynamically generated name, or a graph older than the file.",
342
+ };
343
+ }
344
+ //# sourceMappingURL=symbol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol.js","sourceRoot":"","sources":["../src/symbol.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@descryy/runtime-graph-correlator",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "description": "Resolves runtime evidence to descry-core graph nodes and builds the observed graph path between them. Deliverable of the correlation/graph-integration row — depends on @descryy/runtime-contracts, @descryy/core and @descryy/ir; consumes the graph, does not modify it.",
6
+ "license": "UNLICENSED",
7
+ "engines": {
8
+ "node": ">=22.5"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "registry": "https://registry.npmjs.org",
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc -b"
25
+ },
26
+ "dependencies": {
27
+ "@descryy/runtime-contracts": "*",
28
+ "@descryy/core": "^0.1.0",
29
+ "@descryy/ir": "^0.1.0"
30
+ }
31
+ }