@descryy/runtime-evidence-correlation 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,10 @@
1
+ /**
2
+ * `Evidence.collectorVersion`'s source for the `source: "harness"` rows this
3
+ * package writes when the correlation pass itself breaks. Read from this
4
+ * package's own `package.json` rather than hand-duplicated into a second
5
+ * string that can drift from what actually shipped — the same rule
6
+ * `packages/orchestrator/src/collector-version.ts` already states for the
7
+ * orchestrator's own direct emissions.
8
+ */
9
+ export declare const CORRELATOR_VERSION: string;
10
+ //# sourceMappingURL=collector-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector-version.d.ts","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,eAAO,MAAM,kBAAkB,EAAE,MAA6E,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `Evidence.collectorVersion`'s source for the `source: "harness"` rows this
3
+ * package writes when the correlation pass itself breaks. Read from this
4
+ * package's own `package.json` rather than hand-duplicated into a second
5
+ * string that can drift from what actually shipped — the same rule
6
+ * `packages/orchestrator/src/collector-version.ts` already states for the
7
+ * orchestrator's own direct emissions.
8
+ */
9
+ import { createRequire } from "node:module";
10
+ const require = createRequire(import.meta.url);
11
+ export const CORRELATOR_VERSION = require("../package.json").version;
12
+ //# sourceMappingURL=collector-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector-version.js","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,kBAAkB,GAAY,OAAO,CAAC,iBAAiB,CAAkC,CAAC,OAAO,CAAC"}
@@ -0,0 +1,262 @@
1
+ /**
2
+ * **The production correlation pass — the caller RT-230 found missing.**
3
+ *
4
+ * `graph-correlator` answers "which graph node is this evidence about" as
5
+ * pure functions over a `SqlDriver`. `EvidenceStore.attribute()` makes an
6
+ * answer durable. Between those two there was nothing: every real
7
+ * `attribute()` call site in this repository lived inside a `test/` file,
8
+ * and the three per-package wrappers
9
+ * (`openapi-observation/endpoint-comparison.ts`,
10
+ * `database-observation/graph-mapping.ts`, `test-runner/graph-mapping.ts`)
11
+ * each say in their own doc comment that attribution needs an `evidenceId`
12
+ * that only exists after `store.write()` returns — "outside this
13
+ * collector's own reach. The caller that already holds both the store and
14
+ * the graph `driver` attributes; this only resolves."
15
+ *
16
+ * **This module is that caller.** It is the one shipped thing that owns an
17
+ * `EvidenceStore` and a graph `driver` together and performs
18
+ * resolve-then-attribute, so a real Descry run produces evidence that is
19
+ * *correlated* and not merely *correlatable*.
20
+ *
21
+ * ## Why it is a separate module and not part of `runInstrumentedExecution`
22
+ *
23
+ * `instrumented-execution.ts`'s own header states the boundary: it "does not
24
+ * decide whether a finding exists, does not correlate to graph nodes, and
25
+ * does not drive a browser. Those are separate stages with separate
26
+ * contracts, and folding them in here would make the one place that
27
+ * assembles the runtime also the place that judges it." That boundary is
28
+ * kept. This is a **post-run pass**, run after an execution's evidence is in
29
+ * the store, taking the graph as a parameter — the same way every other
30
+ * production function in this repo takes a `SqlDriver` it does not open.
31
+ * The stage order the architecture diagram (§3) already draws — collectors →
32
+ * evidence store → graph correlator → runtime findings — is the order these
33
+ * packages now depend in, with nothing inverted: this package depends on
34
+ * `graph-correlator`, and `finding` depends on neither.
35
+ *
36
+ * ## What it does NOT do, deliberately
37
+ *
38
+ * It does not compose findings (RT-027 places that in the finding layer, and
39
+ * `composeFinding` is where it lives). It does not open a graph, does not
40
+ * walk one (`traceApi` is the caller's call, RT-026), and does not decide
41
+ * confidence. It resolves and it attributes; that is the whole job.
42
+ *
43
+ * ## The OpenAPI family, wired (RT-232) — and how the earlier objection was met
44
+ *
45
+ * This header used to say the OpenAPI comparison family
46
+ * (`openapi-observation`'s `compareObservedEndpoint` /
47
+ * `compareObservedExchange`) was left out because "folding a conformance
48
+ * verdict into an attribution pass would put two different claims in one
49
+ * output." That objection was right about the risk and wrong about the
50
+ * remedy: the two claims must not share **an output**, which is not the same
51
+ * as not sharing **a pass**. So the family is wired, and the separation is
52
+ * structural rather than by omission:
53
+ *
54
+ * - **One graph query, not two.** `compareObservedEndpoint` *calls*
55
+ * `resolveEndpointNode` and returns the very same node under
56
+ * `documented`. Running both would ask the graph the identical question
57
+ * twice and let two families race for `Evidence.graphNodeId`. The HTTP
58
+ * family therefore routes **through** the wrapper, which is strictly more
59
+ * informative and resolves exactly once.
60
+ * - **Identity keeps its own vocabulary.** `attributed` and `refusals` are
61
+ * unchanged: a resolved endpoint is `family: "endpoint"`,
62
+ * `method: "request-url"`; a miss is `not-found`, the same discriminant
63
+ * `resolveEndpointNode` itself returns, carrying the wrapper's reason
64
+ * verbatim. `undocumented` / `wrong-method` are contract words, and they
65
+ * stay out of the identity channel.
66
+ * - **Conformance is its own field** (`conformance`, `CorrelationConformance`),
67
+ * never persisted, never written to the evidence stream, never an
68
+ * `EvidenceAttribution`. A reader that only cares about identity can
69
+ * ignore it entirely, which is what "not one output" has to mean to be
70
+ * worth anything.
71
+ *
72
+ * **What the exchange half needs, and what supplies it.** `compareObservedExchange`
73
+ * additionally consumes an observed **status** and, optionally, the request /
74
+ * response **bodies** — all three come off evidence that already exists:
75
+ * `InboundProxy` emits `{method, path, status}` on `NETWORK_RESPONSE` and
76
+ * `HTTP_ERROR`, and `BrowserNetworkCollector`'s `HTTP_ERROR` adds the captured
77
+ * response `body`. No declared OpenAPI *document* is read here or anywhere at
78
+ * runtime: the contract is whatever `adapter-openapi` already wrote into the
79
+ * graph (`API_ROUTE --SERVES_API--> API_ENDPOINT --`, `--USES_TYPE(roles)--> DTO`),
80
+ * so nothing new has to be supplied by a run. Two honest limits follow, and are
81
+ * reported rather than papered over:
82
+ *
83
+ * 1. A graph whose `API_ENDPOINT` nodes came from a **framework extractor**
84
+ * rather than an OpenAPI document has no DTOs at all, and every declared
85
+ * role reads empty — which `compareObservedExchange` correctly reports as
86
+ * `statusSurprising: true`, meaning "this operation declares no shape for
87
+ * an outcome like this one." Read alone that is indistinguishable from a
88
+ * contract violation, so `contractSchemasDeclared` is reported beside it:
89
+ * `false` means there was no contract to violate.
90
+ * 2. A `NETWORK_REQUEST` carries a request body (`postData`) but no status, so
91
+ * only the endpoint half runs for it — request-body conformance needs the
92
+ * exchange, and a status is not invented to obtain one.
93
+ *
94
+ * Bodies are read **after** `EvidenceStore` redaction, which re-serializes a
95
+ * JSON body with sensitive values replaced by a marker string. Field
96
+ * *presence* survives that intact; a `type-mismatch` on a non-string-typed
97
+ * field whose name matches a credential/PII pattern would be redaction's
98
+ * artifact, not the app's bug.
99
+ *
100
+ * ## Families still not wired here, named rather than left implicit
101
+ *
102
+ * **`resolveObservedFrontendCaller`** is deliberately excluded, not
103
+ * pending. It answers "which frontend function calls this endpoint", which
104
+ * is a question about a *node*, not about an evidence item, and it falls
105
+ * back to a structural answer when the observed stack does not resolve.
106
+ * Attributing evidence to a structurally-derived caller would break the
107
+ * rule the whole confirmed/strongly-supported gate rests on: a named node
108
+ * must be named by the observation itself.
109
+ *
110
+ * ## Refusals stay refusals (RT-229)
111
+ *
112
+ * `not-found` / `ambiguous` / `line-mismatch` / `producer-emitted-none` /
113
+ * `no-table` / `no-location` are correctly-typed **honest refusals**, and
114
+ * RT-229 ruled that writing `COLLECTOR_ERROR` for one would be a false
115
+ * failure signal. They are carried through into `refusals`, verbatim
116
+ * outcome and reason, and nothing about them touches the evidence stream.
117
+ * The only thing that becomes `COLLECTOR_ERROR` is a resolver or the store
118
+ * genuinely **throwing** — see `harnessErrors` below.
119
+ */
120
+ import type { Evidence } from "@descryy/runtime-contracts";
121
+ import type { EvidenceStore } from "@descryy/runtime-evidence-store";
122
+ import type { SqlDriver } from "@descryy/core";
123
+ import { type EndpointComparison, type StatusBucket } from "@descryhq-wq/runtime-openapi-observation";
124
+ /**
125
+ * Which resolver answered (or refused). Not a confidence ranking — the
126
+ * families are disjoint by the evidence they read, except that
127
+ * `log-text-endpoint` is a *second* naming a backend line can carry
128
+ * alongside its own stack frame (RT-052's case: one observation, two real
129
+ * graph entities).
130
+ */
131
+ export type CorrelationFamily = "endpoint" | "symbol" | "database-table" | "test-case" | "log-text-endpoint";
132
+ /**
133
+ * What the caller declares about one service's evidence: which repository
134
+ * its symbols belong to, and the on-disk root its runtime paths are
135
+ * absolute against.
136
+ *
137
+ * **Required, never defaulted.** `resolveSymbolNode` takes `repo` as a
138
+ * required parameter precisely because there is no honest default, and a
139
+ * pass that guessed one would resolve the wrong repository's identically
140
+ * named file — RT-031's identity-proxy error at the correlation layer. A
141
+ * service with no entry here has its symbol-family and test-family evidence
142
+ * left alone and its name reported in `unscopedServices`; it is never
143
+ * resolved against a repository nobody named.
144
+ */
145
+ export interface CorrelationScope {
146
+ readonly repo: string;
147
+ /** Absolute on-disk root, so an observed absolute path can be translated exactly. See `resolveSymbolNode`'s own doc. */
148
+ readonly repoRoot?: string;
149
+ /** The directory the observed process was launched in, for runtimes that echo their invocation argument verbatim (RT-113). */
150
+ readonly cwd?: string;
151
+ }
152
+ export interface CorrelateExecutionInput {
153
+ /** The store the execution's evidence was written to. Provided, never constructed, so the caller owns its lifetime — same rule `InstrumentedExecutionInput.store` states. */
154
+ readonly store: EvidenceStore;
155
+ /** The `descry-core` graph this evidence is resolved against. Consumed, never modified. */
156
+ readonly driver: SqlDriver;
157
+ readonly executionId: string;
158
+ /** Service name (`Evidence.service`) → the repository scope its symbols resolve in. */
159
+ readonly scopeByService?: Readonly<Record<string, CorrelationScope>>;
160
+ }
161
+ /**
162
+ * One (evidence, node) association this pass made. Structurally an
163
+ * `EvidenceAttribution` (`@descryy/runtime-finding`) — `evidenceId`,
164
+ * `graphNodeId`, `method` — so `secondary` can be handed straight to
165
+ * `composeFinding`'s fourth argument without a translation step. That
166
+ * assignability is asserted by an executing test rather than by a
167
+ * dependency, because this package must not depend on the governance layer
168
+ * it feeds (RT-027: resolution has no opinion on confidence).
169
+ */
170
+ export interface CorrelationAttribution {
171
+ readonly evidenceId: string;
172
+ readonly graphNodeId: string;
173
+ /** How the association was made — `EvidenceAttribution.method`'s own vocabulary: `"request-url"`, `"stack-frame"`, `"query-table"`, `"test-location"`, `"log-text-endpoint"`. */
174
+ readonly method: string;
175
+ readonly family: CorrelationFamily;
176
+ /** True when this is the naming persisted onto `Evidence.graphNodeId`; false when it is a second naming the store's single column cannot hold. */
177
+ readonly persisted: boolean;
178
+ }
179
+ /**
180
+ * A resolver looked and could not answer. **Never an error.** The `outcome`
181
+ * is the resolver's own discriminant, unchanged, and the `reason` is the
182
+ * resolver's own sentence — this pass adds no interpretation of its own to
183
+ * either.
184
+ */
185
+ export interface CorrelationRefusal {
186
+ readonly evidenceId: string;
187
+ readonly family: CorrelationFamily;
188
+ /** A resolver's own discriminant — `"not-found"`, `"ambiguous"`, `"line-mismatch"`, `"producer-emitted-none"`, `"no-table"`, `"no-location"` — or one of this pass's two input refusals, `"no-method"` and `"no-path"`, which say the observation itself did not name enough to look anything up. */
189
+ readonly outcome: string;
190
+ readonly reason: string;
191
+ }
192
+ /**
193
+ * A resolver or the store **threw** — not "looked and could not answer",
194
+ * but the correlation machinery itself breaking. Each distinct failure is
195
+ * also written into the evidence stream as `COLLECTOR_ERROR` /
196
+ * `source: "harness"`, which is the whole point: RT-229 declined to add
197
+ * this wrap because there was no production call site to put it at, and
198
+ * this is that call site.
199
+ */
200
+ export interface CorrelationHarnessError {
201
+ /** The `evidenceId` of the `COLLECTOR_ERROR` row written for this failure. */
202
+ readonly evidenceId: string;
203
+ readonly detail: string;
204
+ /** How many times this same failure occurred across the pass. One row is written per distinct failure, not per occurrence. */
205
+ readonly occurrences: number;
206
+ }
207
+ /**
208
+ * What `openapi-observation` concluded about one observed HTTP item's
209
+ * **contract**, as opposed to its identity. Every field is the comparison's
210
+ * own discriminant or boolean, carried verbatim — this pass derives exactly
211
+ * one value of its own, `contractSchemasDeclared`, and it is a read of
212
+ * `ExchangeComparison.declaredRoles`, not a judgement.
213
+ *
214
+ * **Nothing here is ever persisted or written into the evidence stream.** A
215
+ * contract verdict is a claim about the *contract*, not an observation about
216
+ * the run, and the evidence stream holds observations.
217
+ */
218
+ export interface CorrelationConformance {
219
+ readonly evidenceId: string;
220
+ /** `EndpointComparison`'s own discriminant, verbatim. */
221
+ readonly endpointOutcome: EndpointComparison["outcome"];
222
+ /** The comparison's own sentence. `null` for `documented`, which states none. */
223
+ readonly reason: string | null;
224
+ /** Non-empty only for `wrong-method`: the verbs this path IS declared under. */
225
+ readonly declaredUnderMethods: readonly string[];
226
+ /** `null` when the observation carried no numeric status, so no exchange comparison ran. */
227
+ readonly statusBucket: StatusBucket | null;
228
+ /** `ExchangeComparison.statusSurprising`, verbatim. Read together with `contractSchemasDeclared` — see the header. */
229
+ readonly statusSurprising: boolean | null;
230
+ /** `SchemaComparison`'s own discriminant, verbatim; `null` when no exchange comparison ran or the endpoint did not resolve. */
231
+ readonly requestSchema: string | null;
232
+ readonly responseSchema: string | null;
233
+ /**
234
+ * Whether the resolved endpoint's serving routes declare **any** DTO, in any
235
+ * role. `false` with `statusSurprising: true` means "no contract is indexed
236
+ * for this endpoint", never "the contract was violated". `null` when no
237
+ * exchange comparison ran.
238
+ */
239
+ readonly contractSchemasDeclared: boolean | null;
240
+ }
241
+ export interface CorrelationPassResult {
242
+ readonly executionId: string;
243
+ /** Evidence items a family claimed and actually attempted to resolve. */
244
+ readonly considered: number;
245
+ /** Evidence items no family claimed — a CLICK, a SCREENSHOT, a PROCESS_STARTED. Nothing to resolve is not a gap, so these are counted, not refused. */
246
+ readonly skipped: number;
247
+ /** Every association made, persisted ones first. */
248
+ readonly attributed: readonly CorrelationAttribution[];
249
+ /** The subset that could not be persisted because `Evidence.graphNodeId` holds one node — ready for `composeFinding`'s attributions argument. */
250
+ readonly secondary: readonly CorrelationAttribution[];
251
+ readonly refusals: readonly CorrelationRefusal[];
252
+ /** One entry per HTTP item the OpenAPI comparison actually reached. A separate channel from `attributed`/`refusals`, on purpose — see `CorrelationConformance`. */
253
+ readonly conformance: readonly CorrelationConformance[];
254
+ /** Service names carrying symbol/test evidence that `scopeByService` never declared a repository for. Named, never guessed at. */
255
+ readonly unscopedServices: readonly string[];
256
+ /** Non-empty means the pass itself broke. See `CorrelationHarnessError`. */
257
+ readonly harnessErrors: readonly CorrelationHarnessError[];
258
+ }
259
+ /** Which resolver family owns this evidence item, or `null` when none does. */
260
+ export declare function classifyEvidence(evidence: Pick<Evidence, "eventType" | "sourceLocation">): CorrelationFamily | null;
261
+ export declare function correlateExecution(input: CorrelateExecutionInput): CorrelationPassResult;
262
+ //# sourceMappingURL=correlate-execution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlate-execution.d.ts","sourceRoot":"","sources":["../src/correlate-execution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,499 @@
1
+ /**
2
+ * **The production correlation pass — the caller RT-230 found missing.**
3
+ *
4
+ * `graph-correlator` answers "which graph node is this evidence about" as
5
+ * pure functions over a `SqlDriver`. `EvidenceStore.attribute()` makes an
6
+ * answer durable. Between those two there was nothing: every real
7
+ * `attribute()` call site in this repository lived inside a `test/` file,
8
+ * and the three per-package wrappers
9
+ * (`openapi-observation/endpoint-comparison.ts`,
10
+ * `database-observation/graph-mapping.ts`, `test-runner/graph-mapping.ts`)
11
+ * each say in their own doc comment that attribution needs an `evidenceId`
12
+ * that only exists after `store.write()` returns — "outside this
13
+ * collector's own reach. The caller that already holds both the store and
14
+ * the graph `driver` attributes; this only resolves."
15
+ *
16
+ * **This module is that caller.** It is the one shipped thing that owns an
17
+ * `EvidenceStore` and a graph `driver` together and performs
18
+ * resolve-then-attribute, so a real Descry run produces evidence that is
19
+ * *correlated* and not merely *correlatable*.
20
+ *
21
+ * ## Why it is a separate module and not part of `runInstrumentedExecution`
22
+ *
23
+ * `instrumented-execution.ts`'s own header states the boundary: it "does not
24
+ * decide whether a finding exists, does not correlate to graph nodes, and
25
+ * does not drive a browser. Those are separate stages with separate
26
+ * contracts, and folding them in here would make the one place that
27
+ * assembles the runtime also the place that judges it." That boundary is
28
+ * kept. This is a **post-run pass**, run after an execution's evidence is in
29
+ * the store, taking the graph as a parameter — the same way every other
30
+ * production function in this repo takes a `SqlDriver` it does not open.
31
+ * The stage order the architecture diagram (§3) already draws — collectors →
32
+ * evidence store → graph correlator → runtime findings — is the order these
33
+ * packages now depend in, with nothing inverted: this package depends on
34
+ * `graph-correlator`, and `finding` depends on neither.
35
+ *
36
+ * ## What it does NOT do, deliberately
37
+ *
38
+ * It does not compose findings (RT-027 places that in the finding layer, and
39
+ * `composeFinding` is where it lives). It does not open a graph, does not
40
+ * walk one (`traceApi` is the caller's call, RT-026), and does not decide
41
+ * confidence. It resolves and it attributes; that is the whole job.
42
+ *
43
+ * ## The OpenAPI family, wired (RT-232) — and how the earlier objection was met
44
+ *
45
+ * This header used to say the OpenAPI comparison family
46
+ * (`openapi-observation`'s `compareObservedEndpoint` /
47
+ * `compareObservedExchange`) was left out because "folding a conformance
48
+ * verdict into an attribution pass would put two different claims in one
49
+ * output." That objection was right about the risk and wrong about the
50
+ * remedy: the two claims must not share **an output**, which is not the same
51
+ * as not sharing **a pass**. So the family is wired, and the separation is
52
+ * structural rather than by omission:
53
+ *
54
+ * - **One graph query, not two.** `compareObservedEndpoint` *calls*
55
+ * `resolveEndpointNode` and returns the very same node under
56
+ * `documented`. Running both would ask the graph the identical question
57
+ * twice and let two families race for `Evidence.graphNodeId`. The HTTP
58
+ * family therefore routes **through** the wrapper, which is strictly more
59
+ * informative and resolves exactly once.
60
+ * - **Identity keeps its own vocabulary.** `attributed` and `refusals` are
61
+ * unchanged: a resolved endpoint is `family: "endpoint"`,
62
+ * `method: "request-url"`; a miss is `not-found`, the same discriminant
63
+ * `resolveEndpointNode` itself returns, carrying the wrapper's reason
64
+ * verbatim. `undocumented` / `wrong-method` are contract words, and they
65
+ * stay out of the identity channel.
66
+ * - **Conformance is its own field** (`conformance`, `CorrelationConformance`),
67
+ * never persisted, never written to the evidence stream, never an
68
+ * `EvidenceAttribution`. A reader that only cares about identity can
69
+ * ignore it entirely, which is what "not one output" has to mean to be
70
+ * worth anything.
71
+ *
72
+ * **What the exchange half needs, and what supplies it.** `compareObservedExchange`
73
+ * additionally consumes an observed **status** and, optionally, the request /
74
+ * response **bodies** — all three come off evidence that already exists:
75
+ * `InboundProxy` emits `{method, path, status}` on `NETWORK_RESPONSE` and
76
+ * `HTTP_ERROR`, and `BrowserNetworkCollector`'s `HTTP_ERROR` adds the captured
77
+ * response `body`. No declared OpenAPI *document* is read here or anywhere at
78
+ * runtime: the contract is whatever `adapter-openapi` already wrote into the
79
+ * graph (`API_ROUTE --SERVES_API--> API_ENDPOINT --`, `--USES_TYPE(roles)--> DTO`),
80
+ * so nothing new has to be supplied by a run. Two honest limits follow, and are
81
+ * reported rather than papered over:
82
+ *
83
+ * 1. A graph whose `API_ENDPOINT` nodes came from a **framework extractor**
84
+ * rather than an OpenAPI document has no DTOs at all, and every declared
85
+ * role reads empty — which `compareObservedExchange` correctly reports as
86
+ * `statusSurprising: true`, meaning "this operation declares no shape for
87
+ * an outcome like this one." Read alone that is indistinguishable from a
88
+ * contract violation, so `contractSchemasDeclared` is reported beside it:
89
+ * `false` means there was no contract to violate.
90
+ * 2. A `NETWORK_REQUEST` carries a request body (`postData`) but no status, so
91
+ * only the endpoint half runs for it — request-body conformance needs the
92
+ * exchange, and a status is not invented to obtain one.
93
+ *
94
+ * Bodies are read **after** `EvidenceStore` redaction, which re-serializes a
95
+ * JSON body with sensitive values replaced by a marker string. Field
96
+ * *presence* survives that intact; a `type-mismatch` on a non-string-typed
97
+ * field whose name matches a credential/PII pattern would be redaction's
98
+ * artifact, not the app's bug.
99
+ *
100
+ * ## Families still not wired here, named rather than left implicit
101
+ *
102
+ * **`resolveObservedFrontendCaller`** is deliberately excluded, not
103
+ * pending. It answers "which frontend function calls this endpoint", which
104
+ * is a question about a *node*, not about an evidence item, and it falls
105
+ * back to a structural answer when the observed stack does not resolve.
106
+ * Attributing evidence to a structurally-derived caller would break the
107
+ * rule the whole confirmed/strongly-supported gate rests on: a named node
108
+ * must be named by the observation itself.
109
+ *
110
+ * ## Refusals stay refusals (RT-229)
111
+ *
112
+ * `not-found` / `ambiguous` / `line-mismatch` / `producer-emitted-none` /
113
+ * `no-table` / `no-location` are correctly-typed **honest refusals**, and
114
+ * RT-229 ruled that writing `COLLECTOR_ERROR` for one would be a false
115
+ * failure signal. They are carried through into `refusals`, verbatim
116
+ * outcome and reason, and nothing about them touches the evidence stream.
117
+ * The only thing that becomes `COLLECTOR_ERROR` is a resolver or the store
118
+ * genuinely **throwing** — see `harnessErrors` below.
119
+ */
120
+ import { resolveEndpointFromLogText, resolveSymbolNode } from "@descryy/runtime-graph-correlator";
121
+ import { compareObservedEndpoint, compareObservedExchange, } from "@descryhq-wq/runtime-openapi-observation";
122
+ import { resolveObservedDatabaseQuery } from "@descryhq-wq/runtime-database-observation";
123
+ import { resolveObservedTestCase } from "@descryhq-wq/runtime-test-runner";
124
+ import { CORRELATOR_VERSION } from "./collector-version.js";
125
+ const TEST_EVENT_TYPES = new Set([
126
+ "TEST_STARTED",
127
+ "TEST_PASSED",
128
+ "TEST_FAILED",
129
+ "TEST_SKIPPED",
130
+ ]);
131
+ /**
132
+ * HTTP evidence, whichever collector produced it: the browser network
133
+ * collector (`payload.url`, absolute), `InboundProxy` (`payload.path`,
134
+ * already a path) and `ExternalRequestCollector` (`payload.url`).
135
+ *
136
+ * `NETWORK_RESPONSE` is in this set and will usually refuse with
137
+ * `"no-method"` — the browser collector's response payload carries `url`
138
+ * but no `method`, because a response observation does not on its own state
139
+ * which verb produced it. **That is left as a disclosed refusal rather than
140
+ * joined to the matching request by `requestId`.** The failing exchange is
141
+ * already attributed through the `HTTP_ERROR` the same collector emits
142
+ * beside it, which does carry `method`, so the join would buy little and
143
+ * would make an otherwise strictly per-item pass depend on other items.
144
+ */
145
+ const HTTP_EVENT_TYPES = new Set([
146
+ "NETWORK_REQUEST",
147
+ "NETWORK_RESPONSE",
148
+ "HTTP_ERROR",
149
+ "EXTERNAL_REQUEST",
150
+ ]);
151
+ /** Which resolver family owns this evidence item, or `null` when none does. */
152
+ export function classifyEvidence(evidence) {
153
+ if (evidence.eventType === "DATABASE_QUERY")
154
+ return "database-table";
155
+ if (TEST_EVENT_TYPES.has(evidence.eventType))
156
+ return "test-case";
157
+ // Checked before the source-location branch on purpose: the browser's
158
+ // NETWORK_REQUEST carries a `sourceLocation` for the *frontend* frame that
159
+ // issued the call, and treating that as the item's identity would resolve
160
+ // a request to its caller instead of to the endpoint it named.
161
+ if (HTTP_EVENT_TYPES.has(evidence.eventType))
162
+ return "endpoint";
163
+ const location = evidence.sourceLocation;
164
+ if (location !== null && location.file !== null && location.functionName !== null)
165
+ return "symbol";
166
+ return null;
167
+ }
168
+ function asRecord(payload) {
169
+ return typeof payload === "object" && payload !== null ? payload : null;
170
+ }
171
+ function stringOrNull(value) {
172
+ return typeof value === "string" ? value : null;
173
+ }
174
+ /**
175
+ * `{method, path}` from an HTTP evidence payload, or the reason it is not
176
+ * there. Accepts `url` (absolute, browser/fetch collectors) and `path`
177
+ * (`InboundProxy`, which records `req.url` exactly as the client sent it) —
178
+ * a query string is stripped from either, since `API_ENDPOINT` names carry
179
+ * a path and never a query.
180
+ *
181
+ * `status` and the two bodies are the **exchange** half's inputs, and they
182
+ * are read here rather than in a second walker so that one function owns the
183
+ * whole "what did this payload actually observe" question. Each is `null`
184
+ * when the payload does not carry it — never defaulted, since a guessed
185
+ * status would manufacture a status-bucket verdict out of nothing.
186
+ * `postData` is `BrowserNetworkCollector`'s request-body key and `body` is
187
+ * its response-body key; `requestBody`/`responseBody` are accepted as the
188
+ * names a future producer would most plausibly use.
189
+ */
190
+ function httpTarget(payload) {
191
+ const record = asRecord(payload);
192
+ if (record === null) {
193
+ return { ok: false, outcome: "no-path", reason: "The payload is not an object, so it names neither a URL nor a method." };
194
+ }
195
+ const method = typeof record["method"] === "string" ? record["method"] : null;
196
+ const rawUrl = typeof record["url"] === "string" ? record["url"] : null;
197
+ const rawPath = typeof record["path"] === "string" ? record["path"] : null;
198
+ let path = null;
199
+ if (rawUrl !== null) {
200
+ try {
201
+ path = new URL(rawUrl).pathname;
202
+ }
203
+ catch {
204
+ return {
205
+ ok: false,
206
+ outcome: "no-path",
207
+ reason: `payload.url ${JSON.stringify(rawUrl)} is not a parseable absolute URL, so no path can be read from it without guessing at a base.`,
208
+ };
209
+ }
210
+ }
211
+ else if (rawPath !== null) {
212
+ const queryIndex = rawPath.indexOf("?");
213
+ path = queryIndex === -1 ? rawPath : rawPath.slice(0, queryIndex);
214
+ }
215
+ if (path === null) {
216
+ return { ok: false, outcome: "no-path", reason: "The payload carries neither `url` nor `path`, so no request path was observed." };
217
+ }
218
+ if (method === null) {
219
+ return {
220
+ ok: false,
221
+ outcome: "no-method",
222
+ reason: "The payload names a path but no HTTP method. An API_ENDPOINT is identified by method AND path, and this " +
223
+ "observation does not state the method — reported rather than assumed to be GET, and rather than joined to " +
224
+ "another evidence item that happens to share a request id.",
225
+ };
226
+ }
227
+ return {
228
+ ok: true,
229
+ method,
230
+ path,
231
+ status: typeof record["status"] === "number" ? record["status"] : null,
232
+ requestBody: stringOrNull(record["postData"]) ?? stringOrNull(record["requestBody"]),
233
+ responseBody: stringOrNull(record["body"]) ?? stringOrNull(record["responseBody"]),
234
+ };
235
+ }
236
+ /**
237
+ * `EndpointComparison`/`ExchangeComparison` → the two channels, kept apart.
238
+ *
239
+ * The identity half deliberately collapses `undocumented` and `wrong-method`
240
+ * back to `not-found`: both mean "no `API_ENDPOINT` matched this method and
241
+ * path", which is `resolveEndpointNode`'s own answer and the discriminant the
242
+ * identity channel has always used. The reason is the comparison's own
243
+ * sentence, verbatim — for `wrong-method` that sentence is strictly richer
244
+ * than the resolver's, which is the point of routing through the wrapper.
245
+ */
246
+ function splitComparison(evidenceId, comparison, exchange) {
247
+ const identity = comparison.outcome === "documented"
248
+ ? { family: "endpoint", method: "request-url", nodeId: comparison.endpoint.id, refusal: null }
249
+ : {
250
+ family: "endpoint",
251
+ method: "request-url",
252
+ nodeId: null,
253
+ refusal: { outcome: comparison.outcome === "ambiguous" ? "ambiguous" : "not-found", reason: comparison.reason },
254
+ };
255
+ const declaredRoles = exchange?.declaredRoles ?? null;
256
+ const conformance = {
257
+ evidenceId,
258
+ endpointOutcome: comparison.outcome,
259
+ reason: comparison.outcome === "documented" ? null : comparison.reason,
260
+ declaredUnderMethods: comparison.outcome === "wrong-method" ? comparison.declaredUnderMethods : [],
261
+ statusBucket: exchange?.statusBucket ?? null,
262
+ statusSurprising: exchange?.statusSurprising ?? null,
263
+ requestSchema: exchange?.requestSchema?.outcome ?? null,
264
+ responseSchema: exchange?.responseSchema?.outcome ?? null,
265
+ contractSchemasDeclared: declaredRoles === null
266
+ ? null
267
+ : declaredRoles.request.length + declaredRoles.response.length + declaredRoles.errorResponse.length > 0,
268
+ };
269
+ return { identity, conformance };
270
+ }
271
+ export function correlateExecution(input) {
272
+ const { store, driver, executionId } = input;
273
+ const scopeByService = input.scopeByService ?? {};
274
+ const attributed = [];
275
+ const secondary = [];
276
+ const refusals = [];
277
+ const conformance = [];
278
+ const unscopedServices = new Set();
279
+ /** detail → occurrences. Written to the store once each, after the pass, so a dead driver produces one row rather than one per evidence item. */
280
+ const thrown = new Map();
281
+ let considered = 0;
282
+ let skipped = 0;
283
+ /**
284
+ * RT-229's declined wrap, now that a call site exists for it. Every
285
+ * resolver reads the graph through `@descryy/core`'s store reader,
286
+ * which has no try/catch of its own: a `DriverError` from it propagates
287
+ * out of a resolver as a throw, and unguarded here it would reject this
288
+ * whole pass with no evidence trail — the identical "harness machinery
289
+ * breaks, zero evidence trail" shape RT-219 fixed for `collector.start()`
290
+ * and RT-228 for `ExecutionController.run()`.
291
+ *
292
+ * A throw is NOT a refusal and is deliberately not folded into one: the
293
+ * item is left unattributed and the failure is reported as the harness's
294
+ * own, so a reader can tell "we looked and the graph does not have it"
295
+ * from "our own reader broke" without inspecting payload text.
296
+ */
297
+ function attempt(fn, what) {
298
+ try {
299
+ return fn();
300
+ }
301
+ catch (error) {
302
+ const cause = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
303
+ const detail = `${what} threw instead of returning a resolution: ${cause}`;
304
+ thrown.set(detail, (thrown.get(detail) ?? 0) + 1);
305
+ return null;
306
+ }
307
+ }
308
+ for (const evidence of store.getByExecution(executionId)) {
309
+ const family = classifyEvidence(evidence);
310
+ // A backend line carries a possible endpoint naming in its own text
311
+ // whether or not any family claimed it: a `BACKEND_LOG` with no stack
312
+ // frame classifies as nothing, and is still the only record that a
313
+ // particular route was exercised.
314
+ const backendSourced = evidence.source === "backend-log" || evidence.source === "backend-process";
315
+ if (family === null && !backendSourced) {
316
+ skipped += 1;
317
+ continue;
318
+ }
319
+ const outcomes = [];
320
+ if (family === null)
321
+ considered += 1;
322
+ if (family === "endpoint") {
323
+ considered += 1;
324
+ const target = httpTarget(evidence.payload);
325
+ if (!target.ok) {
326
+ outcomes.push({ family, method: "request-url", nodeId: null, refusal: { outcome: target.outcome, reason: target.reason } });
327
+ }
328
+ else {
329
+ const observed = { method: target.method, path: target.path };
330
+ // One graph query, through `openapi-observation`'s wrapper — which is
331
+ // where `resolveEndpointNode` is actually called. Which wrapper
332
+ // depends on whether a status was observed, and nothing else: the
333
+ // exchange comparison needs one and it is never invented.
334
+ const status = target.status;
335
+ const exchange = status === null
336
+ ? null
337
+ : attempt(() => compareObservedExchange(driver, {
338
+ ...observed,
339
+ status,
340
+ requestBody: target.requestBody,
341
+ responseBody: target.responseBody,
342
+ }), "compareObservedExchange");
343
+ const comparison = status === null ? attempt(() => compareObservedEndpoint(driver, observed), "compareObservedEndpoint") : (exchange?.endpoint ?? null);
344
+ if (comparison !== null) {
345
+ const split = splitComparison(evidence.evidenceId, comparison, exchange);
346
+ outcomes.push(split.identity);
347
+ conformance.push(split.conformance);
348
+ }
349
+ }
350
+ }
351
+ else if (family === "database-table") {
352
+ considered += 1;
353
+ const resolution = attempt(() => resolveObservedDatabaseQuery(driver, evidence), "resolveObservedDatabaseQuery");
354
+ if (resolution !== null) {
355
+ outcomes.push({
356
+ family,
357
+ method: "query-table",
358
+ nodeId: resolution.outcome === "resolved" ? resolution.node.id : null,
359
+ refusal: resolution.outcome === "resolved" ? null : { outcome: resolution.outcome, reason: resolution.reason },
360
+ });
361
+ }
362
+ }
363
+ else if (family === "test-case" || family === "symbol") {
364
+ const service = evidence.service;
365
+ const scope = service === null ? undefined : scopeByService[service];
366
+ if (scope === undefined) {
367
+ // Not a refusal: the caller never claimed this service's evidence
368
+ // was resolvable against a repository, so nothing was attempted.
369
+ // Named here so "we did not try" stays distinguishable from "we
370
+ // tried and found nothing" (plan §17). The log-text pass below still
371
+ // runs for backend evidence — `API_ENDPOINT` is workspace-scoped
372
+ // (DEC-054) and needs no repository to resolve against.
373
+ unscopedServices.add(service ?? "(no service)");
374
+ skipped += 1;
375
+ }
376
+ else {
377
+ considered += 1;
378
+ const options = {
379
+ ...(scope.repoRoot === undefined ? {} : { repoRoot: scope.repoRoot }),
380
+ ...(scope.cwd === undefined ? {} : { cwd: scope.cwd }),
381
+ };
382
+ const location = evidence.sourceLocation;
383
+ const resolution = family === "test-case"
384
+ ? attempt(() => resolveObservedTestCase(driver, evidence, scope.repo, options), "resolveObservedTestCase")
385
+ : attempt(() => resolveSymbolNode(driver, {
386
+ file: location.file,
387
+ symbolName: location.functionName,
388
+ ...(location.line === null ? {} : { line: location.line }),
389
+ }, scope.repo, options), "resolveSymbolNode");
390
+ if (resolution !== null) {
391
+ outcomes.push({
392
+ family,
393
+ method: family === "test-case" ? "test-location" : "stack-frame",
394
+ nodeId: resolution.outcome === "resolved" ? resolution.node.id : null,
395
+ refusal: resolution.outcome === "resolved" ? null : { outcome: resolution.outcome, reason: resolution.reason },
396
+ });
397
+ }
398
+ }
399
+ }
400
+ // The second naming a backend line can carry alongside its own frame
401
+ // (RT-052, and `continuous-chain.test.ts`'s `extraAttributions` block,
402
+ // which is the glue this replaces). Attempted for backend-sourced
403
+ // evidence regardless of which family claimed the item — including a
404
+ // BACKEND_LOG with no stack at all, where it becomes the item's only
405
+ // naming and is therefore the one persisted.
406
+ if (backendSourced) {
407
+ const text = typeof evidence.payload === "string" ? evidence.payload : JSON.stringify(evidence.payload);
408
+ const resolution = attempt(() => resolveEndpointFromLogText(driver, text), "resolveEndpointFromLogText");
409
+ if (resolution !== null && resolution.outcome === "resolved") {
410
+ outcomes.push({ family: "log-text-endpoint", method: "log-text-endpoint", nodeId: resolution.nodeId, refusal: null });
411
+ }
412
+ // A `no-mention` is not a refusal worth reporting: most log lines
413
+ // simply are not about an endpoint, and recording one per line would
414
+ // bury the refusals that mean something. `not-found`/`ambiguous` DO
415
+ // mean something -- the line named routes and the graph could not
416
+ // place them -- and are reported.
417
+ else if (resolution !== null && resolution.outcome !== "no-mention") {
418
+ refusals.push({ evidenceId: evidence.evidenceId, family: "log-text-endpoint", outcome: resolution.outcome, reason: resolution.reason });
419
+ }
420
+ }
421
+ let persistedNodeId = evidence.graphNodeId;
422
+ for (const outcome of outcomes) {
423
+ if (outcome.refusal !== null) {
424
+ refusals.push({ evidenceId: evidence.evidenceId, family: outcome.family, outcome: outcome.refusal.outcome, reason: outcome.refusal.reason });
425
+ continue;
426
+ }
427
+ if (outcome.nodeId === null)
428
+ continue;
429
+ if (persistedNodeId === null) {
430
+ // `attribute()` throws for an unknown id and refuses to overwrite a
431
+ // different node. Both are real bugs in a caller, and both are
432
+ // wrapped rather than allowed to abort the pass — the store is the
433
+ // other half of the machinery this wrap exists to observe.
434
+ const written = attempt(() => {
435
+ store.attribute(evidence.evidenceId, outcome.nodeId);
436
+ return true;
437
+ }, "EvidenceStore.attribute()");
438
+ if (written === null)
439
+ continue;
440
+ persistedNodeId = outcome.nodeId;
441
+ attributed.push({ evidenceId: evidence.evidenceId, graphNodeId: outcome.nodeId, method: outcome.method, family: outcome.family, persisted: true });
442
+ continue;
443
+ }
444
+ if (persistedNodeId === outcome.nodeId) {
445
+ // Already durable — a re-run of the pass, or the same node named
446
+ // twice. `attribute()` is idempotent for this case, so nothing is
447
+ // written and the association is still reported.
448
+ attributed.push({ evidenceId: evidence.evidenceId, graphNodeId: outcome.nodeId, method: outcome.method, family: outcome.family, persisted: true });
449
+ continue;
450
+ }
451
+ const association = {
452
+ evidenceId: evidence.evidenceId,
453
+ graphNodeId: outcome.nodeId,
454
+ method: outcome.method,
455
+ family: outcome.family,
456
+ persisted: false,
457
+ };
458
+ attributed.push(association);
459
+ secondary.push(association);
460
+ }
461
+ }
462
+ const harnessErrors = [];
463
+ for (const [detail, occurrences] of thrown) {
464
+ const row = store.write({
465
+ executionId,
466
+ timestamp: new Date().toISOString(),
467
+ source: "harness",
468
+ service: null,
469
+ process: null,
470
+ eventType: "COLLECTOR_ERROR",
471
+ payload: {
472
+ raw: `correlateExecution: ${detail}${occurrences > 1 ? ` (${occurrences} occurrences in this pass)` : ""}`,
473
+ error: detail,
474
+ occurrences,
475
+ },
476
+ traceId: null,
477
+ requestId: null,
478
+ correlationId: null,
479
+ graphNodeId: null,
480
+ sourceLocation: null,
481
+ stackTrace: null,
482
+ confidence: 1,
483
+ collectorVersion: CORRELATOR_VERSION,
484
+ });
485
+ harnessErrors.push({ evidenceId: row.evidenceId, detail, occurrences });
486
+ }
487
+ return {
488
+ executionId,
489
+ considered,
490
+ skipped,
491
+ attributed,
492
+ secondary,
493
+ refusals,
494
+ conformance,
495
+ unscopedServices: [...unscopedServices],
496
+ harnessErrors,
497
+ };
498
+ }
499
+ //# sourceMappingURL=correlate-execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlate-execution.js","sourceRoot":"","sources":["../src/correlate-execution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { correlateExecution, classifyEvidence, type CorrelateExecutionInput, type CorrelationScope, type CorrelationFamily, type CorrelationAttribution, type CorrelationRefusal, type CorrelationConformance, type CorrelationHarnessError, type CorrelationPassResult, } from "./correlate-execution.ts";
2
+ export { CORRELATOR_VERSION } from "./collector-version.ts";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { correlateExecution, classifyEvidence, } from "./correlate-execution.js";
2
+ export { CORRELATOR_VERSION } from "./collector-version.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,gBAAgB,GASjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@descryy/runtime-evidence-correlation",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "description": "The production correlation pass (RT-230): the one shipped component that owns an EvidenceStore and a descry-core graph driver together and performs resolve-then-attribute over a finished execution's stored evidence. graph-correlator's typed refusals are carried through as refusals, never converted into errors.",
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/runtime-evidence-store": "*",
29
+ "@descryy/runtime-graph-correlator": "*",
30
+ "@descryhq-wq/runtime-openapi-observation": "*",
31
+ "@descryhq-wq/runtime-database-observation": "*",
32
+ "@descryhq-wq/runtime-test-runner": "*",
33
+ "@descryy/core": "^0.1.0"
34
+ }
35
+ }