@descryy/runtime-graph-correlator 0.0.0 → 0.1.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.
- package/dist/cross-service-call.d.ts +190 -0
- package/dist/cross-service-call.d.ts.map +1 -0
- package/dist/cross-service-call.js +297 -0
- package/dist/cross-service-call.js.map +1 -0
- package/dist/database-table.d.ts +1 -1
- package/dist/database-table.js +1 -1
- package/dist/endpoint.d.ts +1 -1
- package/dist/endpoint.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **A caller in one process, a route in another, joined without a browser.**
|
|
3
|
+
*
|
|
4
|
+
* This is the arrow `observe-runtime`'s own header records as unreachable:
|
|
5
|
+
* *"a backend-only run resolves both kinds of node and writes no edge... the
|
|
6
|
+
* arrow is currently reachable only from a browser-driven run."* That was a
|
|
7
|
+
* true statement about one collector, not about the wire. `NETWORK_REQUEST`
|
|
8
|
+
* evidence carrying a call-site stack came from exactly one place —
|
|
9
|
+
* `@descryhq-wq/runtime-browser`'s `fetch()` initiator capture — and every
|
|
10
|
+
* backend collector set `stackTrace: null`, `ExternalRequestCollector`
|
|
11
|
+
* included, *because the preload never captured one*. It does now
|
|
12
|
+
* (`fetch-instrumentation.ts`), and this file is what turns that capture
|
|
13
|
+
* into an edge.
|
|
14
|
+
*
|
|
15
|
+
* ## The two ends, and why neither is inferred
|
|
16
|
+
*
|
|
17
|
+
* **The caller** is `EXTERNAL_REQUEST` evidence from the calling process,
|
|
18
|
+
* carrying the stack the observed application's own `fetch` call site had at
|
|
19
|
+
* the moment it called. Its site of interest (`primaryFrameLocation`, the
|
|
20
|
+
* identical rule every other stack-to-evidence join here already uses)
|
|
21
|
+
* resolves to a `FUNCTION` node via `resolveSymbolNode`.
|
|
22
|
+
*
|
|
23
|
+
* **The callee** is `NETWORK_REQUEST` evidence observed *at the other
|
|
24
|
+
* process* — `InboundProxy`'s own capture of a request arriving. Its
|
|
25
|
+
* `method`/`path` resolve to an `API_ENDPOINT` node via
|
|
26
|
+
* `resolveEndpointNode`. `API_ENDPOINT` is workspace-scoped, not repo-scoped
|
|
27
|
+
* (DEC-054, and `endpoint.ts`'s own header), so there is no "which repo's
|
|
28
|
+
* route" question to answer and no repo filter to invent.
|
|
29
|
+
*
|
|
30
|
+
* Both ends come from the observation. Nothing here pairs up attributions
|
|
31
|
+
* that merely co-occur in a run — the exact manufacture `observe-runtime`'s
|
|
32
|
+
* header rules out — because a pair of co-occurring observations is not a
|
|
33
|
+
* witnessed relationship.
|
|
34
|
+
*
|
|
35
|
+
* ## The join, which is the whole precision question
|
|
36
|
+
*
|
|
37
|
+
* Two observations of one HTTP exchange, from two processes, have to be
|
|
38
|
+
* shown to be the *same* exchange. Two joins are accepted and each one is
|
|
39
|
+
* named in the result, never averaged into a single confidence number:
|
|
40
|
+
*
|
|
41
|
+
* | join | what it rests on |
|
|
42
|
+
* | --- | --- |
|
|
43
|
+
* | `correlation-id` | both observations carry the same non-null `traceId` or `requestId`, within one execution — the application propagated an id and both sides read it back |
|
|
44
|
+
* | `run-owned-authority` | the outbound URL's authority is a listening post **Descry itself bound** for the named callee service in this run, and that callee independently observed the same method and path |
|
|
45
|
+
*
|
|
46
|
+
* `correlation-id` is preferred whenever it is available. It is the rule
|
|
47
|
+
* `correlateBackendEvidence` (`@descryy/runtime-backend-observation`) already
|
|
48
|
+
* applies to backend evidence, applied here to the same fields; this module
|
|
49
|
+
* does not call that function because it needs a *join decision*, not a
|
|
50
|
+
* `Correlation` record with a fresh UUID, and importing it would put an
|
|
51
|
+
* unpublished-scope package into a published one's dependency list for no
|
|
52
|
+
* gain.
|
|
53
|
+
*
|
|
54
|
+
* `run-owned-authority` exists because requiring `correlation-id` alone
|
|
55
|
+
* would make this whole mechanism conditional on the application under test
|
|
56
|
+
* already propagating trace headers — which the UAT workspace did not, and
|
|
57
|
+
* which is the sort of precondition that turns a capability into a
|
|
58
|
+
* disclosure. It is not a weaker guess: the authority is not matched against
|
|
59
|
+
* a hostname this module recognises, it is matched against a `host:port`
|
|
60
|
+
* **the caller declares Descry allocated for that service in this run**
|
|
61
|
+
* (`observedAuthorities`). Declared, never inferred — the same discipline
|
|
62
|
+
* RT-032 already applies to service start order. A call that reached a port
|
|
63
|
+
* Descry itself bound for service B, answered successfully, and shows up in
|
|
64
|
+
* B's own independent inbound observation of the same method and path, is a
|
|
65
|
+
* call that reached that route.
|
|
66
|
+
*
|
|
67
|
+
* Both joins additionally require what `correlateBackendEvidence` requires:
|
|
68
|
+
* one `executionId`. Evidence from two runs is never joined on a bare
|
|
69
|
+
* identifier.
|
|
70
|
+
*
|
|
71
|
+
* ## What is refused, and why refusal is the point
|
|
72
|
+
*
|
|
73
|
+
* No stack, an unresolvable frame, an ambiguous symbol, an unresolvable or
|
|
74
|
+
* ambiguous endpoint, an outbound call that reached nothing, an authority
|
|
75
|
+
* nobody declared, no matching inbound observation — every one of these
|
|
76
|
+
* returns a named refusal with a reason and **no edge**. Rule 2, stated in
|
|
77
|
+
* the plan that asked for this file: *"a wrong cross-repo edge corrupts diff
|
|
78
|
+
* scoping, impact scores and root-cause traversal in every layer above it.
|
|
79
|
+
* If the join is uncertain, omit the edge and disclose."*
|
|
80
|
+
*
|
|
81
|
+
* ## What this does not do
|
|
82
|
+
*
|
|
83
|
+
* - **No denial arrow.** Identical reasoning to
|
|
84
|
+
* `confirm-observed-caller.ts`: a run establishes that a call happened and
|
|
85
|
+
* can never establish that one did not.
|
|
86
|
+
* - **It does not judge a finding** (RT-027), decide staleness, or invent a
|
|
87
|
+
* node — core's refusals pass through whole.
|
|
88
|
+
*/
|
|
89
|
+
import type { IRNode, RuntimeEdgeObservation } from "@descryy/ir";
|
|
90
|
+
import { type RuntimeConfirmationResult, type SqlDriver } from "@descryy/core";
|
|
91
|
+
import { type Evidence } from "@descryy/runtime-contracts";
|
|
92
|
+
/** How the caller-side and callee-side observations were shown to be one exchange. Always named in the result; never collapsed into a number. */
|
|
93
|
+
export type CrossServiceJoin = {
|
|
94
|
+
readonly kind: "correlation-id";
|
|
95
|
+
/** Which id carried it. `trace-id` is checked first, exactly as `correlateBackendEvidence` orders them. */
|
|
96
|
+
readonly idKind: "trace-id" | "request-id";
|
|
97
|
+
readonly id: string;
|
|
98
|
+
} | {
|
|
99
|
+
readonly kind: "run-owned-authority";
|
|
100
|
+
/** `host:port` as the outbound URL named it. */
|
|
101
|
+
readonly authority: string;
|
|
102
|
+
/** The callee service the caller declared that authority belongs to. */
|
|
103
|
+
readonly service: string;
|
|
104
|
+
};
|
|
105
|
+
export type CrossServiceCallResolution = {
|
|
106
|
+
readonly outcome: "observed";
|
|
107
|
+
/** The `FUNCTION` (or `CLASS`) node the outbound call's own stack resolved to, in the calling repo. */
|
|
108
|
+
readonly callerNode: IRNode;
|
|
109
|
+
/** The `API_ENDPOINT` node the callee's own inbound observation resolved to. */
|
|
110
|
+
readonly endpointNode: IRNode;
|
|
111
|
+
/** The callee-side observation this was joined to — so a reader can audit the pair, not just the conclusion. */
|
|
112
|
+
readonly inbound: Evidence;
|
|
113
|
+
readonly join: CrossServiceJoin;
|
|
114
|
+
readonly reason: string;
|
|
115
|
+
} | {
|
|
116
|
+
/** Named separately from every other refusal because it is the one that says "this capability is not wired here", not "this call could not be resolved". */
|
|
117
|
+
readonly outcome: "no-stack";
|
|
118
|
+
readonly reason: string;
|
|
119
|
+
} | {
|
|
120
|
+
readonly outcome: "caller-unresolved";
|
|
121
|
+
readonly reason: string;
|
|
122
|
+
} | {
|
|
123
|
+
readonly outcome: "endpoint-unresolved";
|
|
124
|
+
readonly reason: string;
|
|
125
|
+
} | {
|
|
126
|
+
readonly outcome: "unjoined";
|
|
127
|
+
readonly reason: string;
|
|
128
|
+
};
|
|
129
|
+
export interface ObservedCrossServiceCallInput {
|
|
130
|
+
/** `EXTERNAL_REQUEST` evidence from the **calling** process, with `stackTrace` set by `ExternalRequestCollector`'s parser. */
|
|
131
|
+
readonly outbound: Evidence;
|
|
132
|
+
/**
|
|
133
|
+
* Every inbound observation from this run's other observed processes —
|
|
134
|
+
* `InboundProxy`'s `NETWORK_REQUEST` items. Passed as a list rather than a
|
|
135
|
+
* single pre-picked item on purpose: choosing which inbound observation
|
|
136
|
+
* corresponds to this outbound call **is** the join, and a caller that had
|
|
137
|
+
* already chosen would be making the precision decision this module exists
|
|
138
|
+
* to make.
|
|
139
|
+
*/
|
|
140
|
+
readonly inbound: readonly Evidence[];
|
|
141
|
+
/** The repository the calling process's source belongs to. `FUNCTION` is repo-scoped and there is no honest default (see `symbol.ts`). */
|
|
142
|
+
readonly callerRepo: string;
|
|
143
|
+
/** The calling repository's absolute root, so an absolute frame path can be translated exactly rather than suffix-matched. */
|
|
144
|
+
readonly callerRepoRoot?: string;
|
|
145
|
+
/**
|
|
146
|
+
* `host:port` → callee service name, for every listening post **this run
|
|
147
|
+
* bound itself** (an `InboundProxy`'s own ephemeral port, the value
|
|
148
|
+
* `InstrumentedExecutionResult`'s `proxyPorts` already reports). Declared
|
|
149
|
+
* by the orchestrating caller, never discovered by this module: a hostname
|
|
150
|
+
* this module recognised on its own would be a lookup table standing in
|
|
151
|
+
* for evidence.
|
|
152
|
+
*
|
|
153
|
+
* Omitted means the `run-owned-authority` join is simply unavailable and
|
|
154
|
+
* only `correlation-id` can join — a disclosed reduction in recall, not a
|
|
155
|
+
* silent one.
|
|
156
|
+
*/
|
|
157
|
+
readonly observedAuthorities?: Readonly<Record<string, string>>;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Resolve one observed outbound call against the route it reached in another
|
|
161
|
+
* observed process. Returns `observed` only when both ends resolved to real
|
|
162
|
+
* nodes **and** the two observations were shown to be one exchange.
|
|
163
|
+
*/
|
|
164
|
+
export declare function resolveObservedCrossServiceCall(driver: SqlDriver, input: ObservedCrossServiceCallInput): CrossServiceCallResolution;
|
|
165
|
+
export interface ConfirmObservedCrossServiceCallInput extends ObservedCrossServiceCallInput {
|
|
166
|
+
/** The run that witnessed this. Becomes `edges.observed_by_run` and `observed_edges.run_id`. */
|
|
167
|
+
readonly runId: string;
|
|
168
|
+
/** The commit the observed application was built from, so a later reader can tell whether the code moved under the observation. */
|
|
169
|
+
readonly commitSha: string;
|
|
170
|
+
}
|
|
171
|
+
export interface ConfirmObservedCrossServiceCallOutcome {
|
|
172
|
+
/** The underlying resolution, unchanged and always present -- including when it produced no observation. */
|
|
173
|
+
readonly resolution: CrossServiceCallResolution;
|
|
174
|
+
/** What was sent to the graph. Empty when the resolution observed nothing. */
|
|
175
|
+
readonly observations: readonly RuntimeEdgeObservation[];
|
|
176
|
+
/** Core's own result, passed through whole -- refusals and `staleR4` included. */
|
|
177
|
+
readonly confirmation: RuntimeConfirmationResult;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Resolve one observed cross-service call and, when it genuinely observed
|
|
181
|
+
* something, record it as R4 evidence against the graph.
|
|
182
|
+
*
|
|
183
|
+
* The `USES_API` edge this writes is the one a static adapter structurally
|
|
184
|
+
* cannot produce when the target URL is assembled at runtime — the caller in
|
|
185
|
+
* the fixture this was proven against builds it from an environment
|
|
186
|
+
* variable — so this is `applyRuntimeObservations`' "recall gap closed" case
|
|
187
|
+
* far more often than its promotion case.
|
|
188
|
+
*/
|
|
189
|
+
export declare function confirmObservedCrossServiceCall(driver: SqlDriver, input: ConfirmObservedCrossServiceCallInput): ConfirmObservedCrossServiceCallOutcome;
|
|
190
|
+
//# sourceMappingURL=cross-service-call.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-service-call.d.ts","sourceRoot":"","sources":["../src/cross-service-call.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **A caller in one process, a route in another, joined without a browser.**
|
|
3
|
+
*
|
|
4
|
+
* This is the arrow `observe-runtime`'s own header records as unreachable:
|
|
5
|
+
* *"a backend-only run resolves both kinds of node and writes no edge... the
|
|
6
|
+
* arrow is currently reachable only from a browser-driven run."* That was a
|
|
7
|
+
* true statement about one collector, not about the wire. `NETWORK_REQUEST`
|
|
8
|
+
* evidence carrying a call-site stack came from exactly one place —
|
|
9
|
+
* `@descryhq-wq/runtime-browser`'s `fetch()` initiator capture — and every
|
|
10
|
+
* backend collector set `stackTrace: null`, `ExternalRequestCollector`
|
|
11
|
+
* included, *because the preload never captured one*. It does now
|
|
12
|
+
* (`fetch-instrumentation.ts`), and this file is what turns that capture
|
|
13
|
+
* into an edge.
|
|
14
|
+
*
|
|
15
|
+
* ## The two ends, and why neither is inferred
|
|
16
|
+
*
|
|
17
|
+
* **The caller** is `EXTERNAL_REQUEST` evidence from the calling process,
|
|
18
|
+
* carrying the stack the observed application's own `fetch` call site had at
|
|
19
|
+
* the moment it called. Its site of interest (`primaryFrameLocation`, the
|
|
20
|
+
* identical rule every other stack-to-evidence join here already uses)
|
|
21
|
+
* resolves to a `FUNCTION` node via `resolveSymbolNode`.
|
|
22
|
+
*
|
|
23
|
+
* **The callee** is `NETWORK_REQUEST` evidence observed *at the other
|
|
24
|
+
* process* — `InboundProxy`'s own capture of a request arriving. Its
|
|
25
|
+
* `method`/`path` resolve to an `API_ENDPOINT` node via
|
|
26
|
+
* `resolveEndpointNode`. `API_ENDPOINT` is workspace-scoped, not repo-scoped
|
|
27
|
+
* (DEC-054, and `endpoint.ts`'s own header), so there is no "which repo's
|
|
28
|
+
* route" question to answer and no repo filter to invent.
|
|
29
|
+
*
|
|
30
|
+
* Both ends come from the observation. Nothing here pairs up attributions
|
|
31
|
+
* that merely co-occur in a run — the exact manufacture `observe-runtime`'s
|
|
32
|
+
* header rules out — because a pair of co-occurring observations is not a
|
|
33
|
+
* witnessed relationship.
|
|
34
|
+
*
|
|
35
|
+
* ## The join, which is the whole precision question
|
|
36
|
+
*
|
|
37
|
+
* Two observations of one HTTP exchange, from two processes, have to be
|
|
38
|
+
* shown to be the *same* exchange. Two joins are accepted and each one is
|
|
39
|
+
* named in the result, never averaged into a single confidence number:
|
|
40
|
+
*
|
|
41
|
+
* | join | what it rests on |
|
|
42
|
+
* | --- | --- |
|
|
43
|
+
* | `correlation-id` | both observations carry the same non-null `traceId` or `requestId`, within one execution — the application propagated an id and both sides read it back |
|
|
44
|
+
* | `run-owned-authority` | the outbound URL's authority is a listening post **Descry itself bound** for the named callee service in this run, and that callee independently observed the same method and path |
|
|
45
|
+
*
|
|
46
|
+
* `correlation-id` is preferred whenever it is available. It is the rule
|
|
47
|
+
* `correlateBackendEvidence` (`@descryy/runtime-backend-observation`) already
|
|
48
|
+
* applies to backend evidence, applied here to the same fields; this module
|
|
49
|
+
* does not call that function because it needs a *join decision*, not a
|
|
50
|
+
* `Correlation` record with a fresh UUID, and importing it would put an
|
|
51
|
+
* unpublished-scope package into a published one's dependency list for no
|
|
52
|
+
* gain.
|
|
53
|
+
*
|
|
54
|
+
* `run-owned-authority` exists because requiring `correlation-id` alone
|
|
55
|
+
* would make this whole mechanism conditional on the application under test
|
|
56
|
+
* already propagating trace headers — which the UAT workspace did not, and
|
|
57
|
+
* which is the sort of precondition that turns a capability into a
|
|
58
|
+
* disclosure. It is not a weaker guess: the authority is not matched against
|
|
59
|
+
* a hostname this module recognises, it is matched against a `host:port`
|
|
60
|
+
* **the caller declares Descry allocated for that service in this run**
|
|
61
|
+
* (`observedAuthorities`). Declared, never inferred — the same discipline
|
|
62
|
+
* RT-032 already applies to service start order. A call that reached a port
|
|
63
|
+
* Descry itself bound for service B, answered successfully, and shows up in
|
|
64
|
+
* B's own independent inbound observation of the same method and path, is a
|
|
65
|
+
* call that reached that route.
|
|
66
|
+
*
|
|
67
|
+
* Both joins additionally require what `correlateBackendEvidence` requires:
|
|
68
|
+
* one `executionId`. Evidence from two runs is never joined on a bare
|
|
69
|
+
* identifier.
|
|
70
|
+
*
|
|
71
|
+
* ## What is refused, and why refusal is the point
|
|
72
|
+
*
|
|
73
|
+
* No stack, an unresolvable frame, an ambiguous symbol, an unresolvable or
|
|
74
|
+
* ambiguous endpoint, an outbound call that reached nothing, an authority
|
|
75
|
+
* nobody declared, no matching inbound observation — every one of these
|
|
76
|
+
* returns a named refusal with a reason and **no edge**. Rule 2, stated in
|
|
77
|
+
* the plan that asked for this file: *"a wrong cross-repo edge corrupts diff
|
|
78
|
+
* scoping, impact scores and root-cause traversal in every layer above it.
|
|
79
|
+
* If the join is uncertain, omit the edge and disclose."*
|
|
80
|
+
*
|
|
81
|
+
* ## What this does not do
|
|
82
|
+
*
|
|
83
|
+
* - **No denial arrow.** Identical reasoning to
|
|
84
|
+
* `confirm-observed-caller.ts`: a run establishes that a call happened and
|
|
85
|
+
* can never establish that one did not.
|
|
86
|
+
* - **It does not judge a finding** (RT-027), decide staleness, or invent a
|
|
87
|
+
* node — core's refusals pass through whole.
|
|
88
|
+
*/
|
|
89
|
+
import { applyRuntimeObservations, } from "@descryy/core";
|
|
90
|
+
import { primaryFrameLocation } from "@descryy/runtime-contracts";
|
|
91
|
+
import { resolveEndpointNode } from "./endpoint.js";
|
|
92
|
+
import { resolveSymbolNode } from "./symbol.js";
|
|
93
|
+
function payloadString(evidence, key) {
|
|
94
|
+
const value = evidence.payload?.[key];
|
|
95
|
+
return typeof value === "string" ? value : null;
|
|
96
|
+
}
|
|
97
|
+
function payloadBoolean(evidence, key) {
|
|
98
|
+
const value = evidence.payload?.[key];
|
|
99
|
+
return typeof value === "boolean" ? value : null;
|
|
100
|
+
}
|
|
101
|
+
/** Path without its query string. A query is not part of a route's identity, and `resolveEndpointNode` matches segment-wise against a template that never contains one. */
|
|
102
|
+
function pathOnly(path) {
|
|
103
|
+
const cut = path.indexOf("?");
|
|
104
|
+
return cut === -1 ? path : path.slice(0, cut);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The same rule `correlateBackendEvidence` applies — one execution, a
|
|
108
|
+
* non-null id, equal on both sides, `traceId` before `requestId` — reading
|
|
109
|
+
* the same canonical `Evidence` fields. See this module's header for why the
|
|
110
|
+
* function itself is not imported.
|
|
111
|
+
*/
|
|
112
|
+
function correlationJoin(a, b) {
|
|
113
|
+
if (a.executionId !== b.executionId)
|
|
114
|
+
return null;
|
|
115
|
+
if (a.traceId !== null && a.traceId === b.traceId) {
|
|
116
|
+
return { kind: "correlation-id", idKind: "trace-id", id: a.traceId };
|
|
117
|
+
}
|
|
118
|
+
if (a.requestId !== null && a.requestId === b.requestId) {
|
|
119
|
+
return { kind: "correlation-id", idKind: "request-id", id: a.requestId };
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
function describeOutbound(outbound) {
|
|
124
|
+
const url = payloadString(outbound, "url");
|
|
125
|
+
const method = payloadString(outbound, "method");
|
|
126
|
+
if (url === null || method === null)
|
|
127
|
+
return null;
|
|
128
|
+
let parsed;
|
|
129
|
+
try {
|
|
130
|
+
parsed = new URL(url);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
return { authority: parsed.host, path: pathOnly(parsed.pathname), method: method.toUpperCase() };
|
|
136
|
+
}
|
|
137
|
+
/** Same method, same path — the minimum for two observations to be describing one exchange at all, checked for both join kinds rather than only the weaker one. */
|
|
138
|
+
function describesSameExchange(target, inbound) {
|
|
139
|
+
const method = payloadString(inbound, "method");
|
|
140
|
+
const path = payloadString(inbound, "path");
|
|
141
|
+
if (method === null || path === null)
|
|
142
|
+
return false;
|
|
143
|
+
return method.toUpperCase() === target.method && pathOnly(path) === target.path;
|
|
144
|
+
}
|
|
145
|
+
function joinFor(input, target) {
|
|
146
|
+
const sameExchange = input.inbound.filter((candidate) => candidate.eventType === "NETWORK_REQUEST" && describesSameExchange(target, candidate));
|
|
147
|
+
// Preferred join first, over the whole candidate set -- an id that both
|
|
148
|
+
// sides carry is a stronger statement than an authority this run bound,
|
|
149
|
+
// and checking it first means the stronger one is never passed over
|
|
150
|
+
// because a weaker one happened to match earlier in the list.
|
|
151
|
+
for (const candidate of sameExchange) {
|
|
152
|
+
const join = correlationJoin(input.outbound, candidate);
|
|
153
|
+
if (join !== null)
|
|
154
|
+
return { inbound: candidate, join };
|
|
155
|
+
}
|
|
156
|
+
const service = input.observedAuthorities?.[target.authority];
|
|
157
|
+
if (service === undefined) {
|
|
158
|
+
return {
|
|
159
|
+
reason: `No inbound observation shares a trace or request id with this outbound ${target.method} ${target.path}, ` +
|
|
160
|
+
`and "${target.authority}" is not among the authorities this run declared it bound ` +
|
|
161
|
+
`(${Object.keys(input.observedAuthorities ?? {}).join(", ") || "none declared"}). ` +
|
|
162
|
+
"Joining on method and path alone would pair two observations that merely look alike.",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
// The outbound call must have reached something. `success` is
|
|
166
|
+
// `fetch`-resolved-rather-than-threw and `status` is the real response
|
|
167
|
+
// code, both captured by the preload before the call returned to the
|
|
168
|
+
// application: a call that threw reached no route, whatever else was
|
|
169
|
+
// observed at the callee in the same window.
|
|
170
|
+
if (payloadBoolean(input.outbound, "success") !== true) {
|
|
171
|
+
return {
|
|
172
|
+
reason: `The outbound ${target.method} ${target.path} to "${target.authority}" did not resolve to a response ` +
|
|
173
|
+
"(`success` is not true), so it reached no route -- whatever the callee observed in the same window " +
|
|
174
|
+
"was some other client's request.",
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const matching = sameExchange.filter((candidate) => candidate.service === service);
|
|
178
|
+
if (matching.length === 0) {
|
|
179
|
+
return {
|
|
180
|
+
reason: `"${target.authority}" is declared as service "${service}", but that service observed no inbound ` +
|
|
181
|
+
`${target.method} ${target.path} in this run. A call Descry saw leave and never saw arrive is a gap, ` +
|
|
182
|
+
"not an edge.",
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
inbound: matching[0],
|
|
187
|
+
join: { kind: "run-owned-authority", authority: target.authority, service },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Resolve one observed outbound call against the route it reached in another
|
|
192
|
+
* observed process. Returns `observed` only when both ends resolved to real
|
|
193
|
+
* nodes **and** the two observations were shown to be one exchange.
|
|
194
|
+
*/
|
|
195
|
+
export function resolveObservedCrossServiceCall(driver, input) {
|
|
196
|
+
if (input.outbound.eventType !== "EXTERNAL_REQUEST") {
|
|
197
|
+
return {
|
|
198
|
+
outcome: "no-stack",
|
|
199
|
+
reason: `Evidence "${input.outbound.evidenceId}" is a ${input.outbound.eventType}, not an EXTERNAL_REQUEST. ` +
|
|
200
|
+
"Only an outbound call captured at its own call site can name a caller.",
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const location = primaryFrameLocation(input.outbound.stackTrace);
|
|
204
|
+
if (location === null || location.file === null || location.functionName === null) {
|
|
205
|
+
return {
|
|
206
|
+
outcome: "no-stack",
|
|
207
|
+
reason: "The outbound call carried no usable call-site stack (none captured, or its site of interest names " +
|
|
208
|
+
"neither a file nor a function). Without a stack the observation names an endpoint and no caller, " +
|
|
209
|
+
"which is the state this whole mechanism exists to leave behind -- reported, not worked around.",
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const target = describeOutbound(input.outbound);
|
|
213
|
+
if (target === null) {
|
|
214
|
+
return {
|
|
215
|
+
outcome: "unjoined",
|
|
216
|
+
reason: "The outbound observation carries no parseable url/method pair, so there is nothing to match a callee " +
|
|
217
|
+
"observation against.",
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const joined = joinFor(input, target);
|
|
221
|
+
if (!("join" in joined))
|
|
222
|
+
return { outcome: "unjoined", reason: joined.reason };
|
|
223
|
+
const inboundMethod = payloadString(joined.inbound, "method") ?? target.method;
|
|
224
|
+
const inboundPath = pathOnly(payloadString(joined.inbound, "path") ?? target.path);
|
|
225
|
+
const endpoint = resolveEndpointNode(driver, inboundMethod, inboundPath);
|
|
226
|
+
if (endpoint.outcome !== "resolved") {
|
|
227
|
+
return {
|
|
228
|
+
outcome: "endpoint-unresolved",
|
|
229
|
+
reason: `The route ${inboundMethod} ${inboundPath} the call actually reached did not resolve to one API_ENDPOINT: ${endpoint.reason}`,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const resolved = resolveSymbolNode(driver, location.line === null
|
|
233
|
+
? { file: location.file, symbolName: location.functionName }
|
|
234
|
+
: { file: location.file, symbolName: location.functionName, line: location.line }, input.callerRepo, input.callerRepoRoot === undefined ? {} : { repoRoot: input.callerRepoRoot });
|
|
235
|
+
if (resolved.outcome !== "resolved") {
|
|
236
|
+
return {
|
|
237
|
+
outcome: "caller-unresolved",
|
|
238
|
+
reason: `The call site "${location.functionName}" (${location.file}) did not resolve to one node in repo ` +
|
|
239
|
+
`"${input.callerRepo}": ${resolved.outcome}. An edge needs a caller this graph actually holds.`,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
outcome: "observed",
|
|
244
|
+
callerNode: resolved.node,
|
|
245
|
+
endpointNode: endpoint.node,
|
|
246
|
+
inbound: joined.inbound,
|
|
247
|
+
join: joined.join,
|
|
248
|
+
reason: `"${resolved.node.name}" issued a real outbound ${target.method} ${target.path}, and ${joined.join.kind === "correlation-id"
|
|
249
|
+
? `the process serving "${endpoint.node.name}" observed the same request under ${joined.join.idKind} "${joined.join.id}"`
|
|
250
|
+
: `service "${joined.join.service}" -- whose listening post at "${joined.join.authority}" this run bound itself -- independently observed that request arriving`}. Two processes, two independent observations, one exchange, no browser involved.`,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const EMPTY = {
|
|
254
|
+
promoted: [], created: [], confirmed: [], contradictions: [], staleR4: [], refused: [],
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Resolve one observed cross-service call and, when it genuinely observed
|
|
258
|
+
* something, record it as R4 evidence against the graph.
|
|
259
|
+
*
|
|
260
|
+
* The `USES_API` edge this writes is the one a static adapter structurally
|
|
261
|
+
* cannot produce when the target URL is assembled at runtime — the caller in
|
|
262
|
+
* the fixture this was proven against builds it from an environment
|
|
263
|
+
* variable — so this is `applyRuntimeObservations`' "recall gap closed" case
|
|
264
|
+
* far more often than its promotion case.
|
|
265
|
+
*/
|
|
266
|
+
export function confirmObservedCrossServiceCall(driver, input) {
|
|
267
|
+
const resolution = resolveObservedCrossServiceCall(driver, input);
|
|
268
|
+
if (resolution.outcome !== "observed") {
|
|
269
|
+
// Deliberately not a call with an empty list: an `adapter_runs` row
|
|
270
|
+
// would be minted for a run that witnessed nothing, which reads in the
|
|
271
|
+
// ledger exactly like a run that observed and found nothing to say.
|
|
272
|
+
// Those are different statements. (`confirm-observed-caller.ts`'s own
|
|
273
|
+
// reasoning, unchanged.)
|
|
274
|
+
return { resolution, observations: [], confirmation: EMPTY };
|
|
275
|
+
}
|
|
276
|
+
const observations = [
|
|
277
|
+
{
|
|
278
|
+
from: resolution.callerNode.id,
|
|
279
|
+
to: resolution.endpointNode.id,
|
|
280
|
+
edgeType: "USES_API",
|
|
281
|
+
held: true,
|
|
282
|
+
detail: `A call-site stack captured on a real outbound HTTP request resolved to ${resolution.callerNode.name} ` +
|
|
283
|
+
`(${resolution.callerNode.file ?? "unknown file"}), and the request was independently observed arriving ` +
|
|
284
|
+
`at ${resolution.endpointNode.name} in another process of the same run (join: ${resolution.join.kind}).`,
|
|
285
|
+
},
|
|
286
|
+
];
|
|
287
|
+
return {
|
|
288
|
+
resolution,
|
|
289
|
+
observations,
|
|
290
|
+
confirmation: applyRuntimeObservations(driver, {
|
|
291
|
+
runId: input.runId,
|
|
292
|
+
commitSha: input.commitSha,
|
|
293
|
+
observations,
|
|
294
|
+
}),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=cross-service-call.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-service-call.js","sourceRoot":"","sources":["../src/cross-service-call.ts"],"names":[],"mappings":"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"}
|
package/dist/database-table.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolving a captured query's target table name (a real, observed string —
|
|
3
|
-
* `extractTargetTable`, `@
|
|
3
|
+
* `extractTargetTable`, `@descryy/runtime-database-observation`) to the
|
|
4
4
|
* `DATABASE_TABLE` node it names — the §10/§18 join `DatabaseQueryCollector`
|
|
5
5
|
* disclosed as missing since RT-141: real query capture, `graphNodeId`
|
|
6
6
|
* always null.
|
package/dist/database-table.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolving a captured query's target table name (a real, observed string —
|
|
3
|
-
* `extractTargetTable`, `@
|
|
3
|
+
* `extractTargetTable`, `@descryy/runtime-database-observation`) to the
|
|
4
4
|
* `DATABASE_TABLE` node it names — the §10/§18 join `DatabaseQueryCollector`
|
|
5
5
|
* disclosed as missing since RT-141: real query capture, `graphNodeId`
|
|
6
6
|
* always null.
|
package/dist/endpoint.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export declare function resolveEndpointNode(driver: SqlDriver, method: string, o
|
|
|
50
50
|
* this path exist under a different method" needs the method filter removed
|
|
51
51
|
* entirely, not relaxed.
|
|
52
52
|
*
|
|
53
|
-
* Built for one caller (`@
|
|
53
|
+
* Built for one caller (`@descryy/runtime-openapi-observation`'s "wrong
|
|
54
54
|
* method" vs "undocumented" distinction, checklist §15): a request whose
|
|
55
55
|
* exact method+path resolves to nothing is a different fact from one whose
|
|
56
56
|
* path resolves under some *other* method — the first says the operation
|
package/dist/endpoint.js
CHANGED
|
@@ -84,7 +84,7 @@ export function resolveEndpointNode(driver, method, observedPath, options = {})
|
|
|
84
84
|
* this path exist under a different method" needs the method filter removed
|
|
85
85
|
* entirely, not relaxed.
|
|
86
86
|
*
|
|
87
|
-
* Built for one caller (`@
|
|
87
|
+
* Built for one caller (`@descryy/runtime-openapi-observation`'s "wrong
|
|
88
88
|
* method" vs "undocumented" distinction, checklist §15): a request whose
|
|
89
89
|
* exact method+path resolves to nothing is a different fact from one whose
|
|
90
90
|
* path resolves under some *other* method — the first says the operation
|
package/dist/index.d.ts
CHANGED
|
@@ -15,5 +15,6 @@ export { resolveEndpointFromLogText, findEndpointMentions, type LogEndpointResol
|
|
|
15
15
|
export { resolveFrontendCallers, type FrontendCallerResolution } from "./frontend-caller.ts";
|
|
16
16
|
export { resolveObservedFrontendCaller, type ObservedFrontendCallerResolution } from "./observed-frontend-caller.ts";
|
|
17
17
|
export { resolveDatabaseTableNode, type DatabaseTableResolution } from "./database-table.ts";
|
|
18
|
+
export { resolveObservedCrossServiceCall, confirmObservedCrossServiceCall, type CrossServiceJoin, type CrossServiceCallResolution, type ObservedCrossServiceCallInput, type ConfirmObservedCrossServiceCallInput, type ConfirmObservedCrossServiceCallOutcome, } from "./cross-service-call.ts";
|
|
18
19
|
export { confirmObservedFrontendCaller, type ConfirmObservedCallerInput, type ConfirmObservedCallerOutcome, } from "./confirm-observed-caller.ts";
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,6BAA6B,EAAE,KAAK,gCAAgC,EAAE,MAAM,+BAA+B,CAAC;AACrH,OAAO,EAAE,wBAAwB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EACL,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,GAClC,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,6BAA6B,EAAE,KAAK,gCAAgC,EAAE,MAAM,+BAA+B,CAAC;AACrH,OAAO,EAAE,wBAAwB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EAClC,KAAK,oCAAoC,EACzC,KAAK,sCAAsC,GAC5C,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,GAClC,MAAM,8BAA8B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,5 +15,6 @@ export { resolveEndpointFromLogText, findEndpointMentions, } from "./log-endpoin
|
|
|
15
15
|
export { resolveFrontendCallers } from "./frontend-caller.js";
|
|
16
16
|
export { resolveObservedFrontendCaller } from "./observed-frontend-caller.js";
|
|
17
17
|
export { resolveDatabaseTableNode } from "./database-table.js";
|
|
18
|
+
export { resolveObservedCrossServiceCall, confirmObservedCrossServiceCall, } from "./cross-service-call.js";
|
|
18
19
|
export { confirmObservedFrontendCaller, } from "./confirm-observed-caller.js";
|
|
19
20
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAA2B,MAAM,eAAe,CAAC;AACzG,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,GAKpB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GAGrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAiC,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,6BAA6B,EAAyC,MAAM,+BAA+B,CAAC;AACrH,OAAO,EAAE,wBAAwB,EAAgC,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EACL,6BAA6B,GAG9B,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAA2B,MAAM,eAAe,CAAC;AACzG,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,GAKpB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GAGrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAiC,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,6BAA6B,EAAyC,MAAM,+BAA+B,CAAC;AACrH,OAAO,EAAE,wBAAwB,EAAgC,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,GAMhC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,6BAA6B,GAG9B,MAAM,8BAA8B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@descryy/runtime-graph-correlator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"type": "module",
|
|
5
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
6
|
"license": "UNLICENSED",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"build": "tsc -b"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@descryy/runtime-contracts": "
|
|
27
|
+
"@descryy/runtime-contracts": "0.1.0",
|
|
28
28
|
"@descryy/core": "^0.1.0",
|
|
29
29
|
"@descryy/ir": "^0.1.0"
|
|
30
30
|
}
|