@descryy/runtime-contracts 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,296 @@
1
+ /**
2
+ * Evidence contract.
3
+ *
4
+ * Field list is verbatim from `documents/descry-runtime-plan.md` §13
5
+ * (Evidence model), plus `evidenceId` (needed for the ID-reference pattern
6
+ * Execution uses) and `stackTrace` (structured detail for the plan's
7
+ * STACK_TRACE event type, per Agent 3's stack-fidelity finding below). Also
8
+ * grounded in the architecture doc's §18.2 (evidence bundling —
9
+ * screenshot/console/network/backend log, "none of these individually
10
+ * would have been enough"), §17.2 (the observe stream), §9 (the three
11
+ * confidence axes — this file's `confidence` field is the resolution-
12
+ * honesty axis, never conflated with environment fidelity, which lives on
13
+ * Execution/Capability instead) and §25 (redaction before storage).
14
+ *
15
+ * Static facts and runtime observations stay separate. Evidence never
16
+ * embeds a graph node's data — `graphNodeId` is a reference into
17
+ * @descryy/ir's identity scheme, resolved by whoever reads it. This file
18
+ * does not, and must not, redefine graph identity or storage.
19
+ */
20
+ import type { RuntimeEventType } from "./runtime-event.ts";
21
+ export declare const EVIDENCE_SOURCES: readonly ["browser-dom", "browser-console", "browser-network", "backend-log", "backend-process", "process-exit", "http-response-payload", "test-runner", "harness", "dependency-check", "environment-check"];
22
+ export type EvidenceSource = (typeof EVIDENCE_SOURCES)[number];
23
+ export declare const REDACTION_STATUSES: readonly ["not-required", "redacted", "pending-redaction"];
24
+ export type RedactionStatus = (typeof REDACTION_STATUSES)[number];
25
+ /**
26
+ * Source-location reliability is not one axis with a probabilistic middle —
27
+ * it is three structurally different classes (Agent 3's finding), and
28
+ * conflating them into a single confidence number loses exactly the
29
+ * information a reader needs to judge a location claim:
30
+ *
31
+ * - self-contained: the location came from the process's own captured
32
+ * state (a Python traceback, a Ruby backtrace, a Go `recover()` frame).
33
+ * Accurate when captured; the risk is *capture completeness*, not
34
+ * correctness.
35
+ * - debug-info-present / debug-info-stripped: a binary's own line-number
36
+ * table (Java/Kotlin). A binary outcome — there is no partial case.
37
+ * - side-artifact-resolved / side-artifact-stale / side-artifact-missing:
38
+ * resolution went through a separate file that can drift or vanish
39
+ * (a Node source map, a C# PDB, a Swift dSYM). "We mapped it and it's
40
+ * right" and "we mapped it through an artifact that may be stale" are
41
+ * different confidence claims, and this type is what lets Evidence say
42
+ * which one it is instead of reporting both identically.
43
+ * - self-contained-eval-line: same mechanism as self-contained — the
44
+ * process's own captured backtrace, nothing translated through a side
45
+ * artifact — but the *line* does not index the named file. Ruby's
46
+ * `instance_eval`/`eval` frames print a synthetic path,
47
+ * `(eval at file.rb:12):1`, where `12` is where `eval` was called from
48
+ * but `1` counts lines within the evaluated string, not within
49
+ * `file.rb`. Opening `file.rb` at line `1` shows unrelated code, so this
50
+ * is not a plain self-contained claim; it is not a side-artifact claim
51
+ * either, since nothing was resolved through a separate file. See
52
+ * `packages/adapter-ruby/src/ruby-source-location-resolver.ts` for the
53
+ * one producer of this value.
54
+ */
55
+ export declare const SOURCE_LOCATION_RELIABILITIES: readonly ["self-contained", "debug-info-present", "debug-info-stripped", "side-artifact-resolved", "side-artifact-stale", "side-artifact-missing", "self-contained-eval-line"];
56
+ export type SourceLocationReliability = (typeof SOURCE_LOCATION_RELIABILITIES)[number];
57
+ export interface SourceLocation {
58
+ /**
59
+ * **Null when the runtime named no source file**, for the same reason
60
+ * `line` can be null and discovered by the same adapter.
61
+ *
62
+ * A stripped JVM frame is `at com.example.Thrower.handler(Unknown Source)`
63
+ * and a native one is `(Native Method)`: neither carries a filename. The
64
+ * method name is still real evidence and still resolves against the graph
65
+ * by symbol, so dropping such frames would delete an entire stack for a
66
+ * release build.
67
+ *
68
+ * The filename is **not** derived from the class name, though the JVM
69
+ * convention makes that look safe. Kotlin breaks it outright — a class
70
+ * `Foo` may be declared in `Bar.kt` — and this parser serves both
71
+ * languages, so the derivation would be right for one and wrong for the
72
+ * other. Null is the honest answer.
73
+ */
74
+ readonly file: string | null;
75
+ /**
76
+ * **Null when the runtime genuinely captured no line**, which is a real
77
+ * state rather than a failure to look — and one this type could not
78
+ * express until a JVM adapter existed to need it.
79
+ *
80
+ * A JVM class compiled without a `LineNumberTable` (`javac -g:none`, and
81
+ * the default for many release builds) prints
82
+ * `at com.example.Thrower.handler(Unknown Source)`: the class is real,
83
+ * the method is real, and there is no line. So is a `(Native Method)`
84
+ * frame. `reliability: "debug-info-stripped"` describes exactly that
85
+ * situation — meaning that while this field was required, that enum value
86
+ * could only ever be attached to a **fabricated** number. The type and
87
+ * the enum contradicted each other, and the type was wrong.
88
+ *
89
+ * A frame with no line is still real evidence: the symbol name alone
90
+ * resolves against the graph. Dropping such frames would discard an
91
+ * entire stack for a stripped build, which is the "we could not read it"
92
+ * case that must degrade honestly rather than vanish.
93
+ */
94
+ readonly line: number | null;
95
+ readonly column: number | null;
96
+ readonly functionName: string | null;
97
+ readonly reliability: SourceLocationReliability;
98
+ /** Set only for the side-artifact-* reliabilities — names the specific map/PDB/dSYM, so a stale-artifact finding is traceable to the file that drifted. Null otherwise. */
99
+ readonly resolvedVia: string | null;
100
+ }
101
+ /**
102
+ * Whether a captured stack reflects the actual logical call chain is a
103
+ * third, orthogonal axis (Agent 3's finding): concurrency models
104
+ * (coroutines, goroutines, async/await, tokio tasks) can capture a stack
105
+ * successfully while structurally breaking the "reflects the logical
106
+ * caller" guarantee. That is not a low-confidence stack — it is a
107
+ * different kind of evidence, and gets its own field rather than a lower
108
+ * number folded into `confidence`.
109
+ */
110
+ export declare const STACK_FIDELITIES: readonly ["synchronous", "concurrency-fragmented", "unavailable"];
111
+ export type StackFidelity = (typeof STACK_FIDELITIES)[number];
112
+ export interface StackFrame {
113
+ readonly location: SourceLocation;
114
+ /** The frame's original, unparsed text — kept for audit even after structured parsing. */
115
+ readonly raw: string;
116
+ }
117
+ export interface StackTrace {
118
+ readonly fidelity: StackFidelity;
119
+ /**
120
+ * **Most-recent call first**, always — `frames[0]` is the innermost frame,
121
+ * the one where execution actually was. Every parser normalises to this;
122
+ * callers may rely on it.
123
+ *
124
+ * This was unstated while TypeScript was the only language, because V8
125
+ * emits this order natively and nothing had to convert. It is not a
126
+ * universal convention: a CPython traceback prints **oldest call first**,
127
+ * with the failing frame last, and so does a Java `printStackTrace` cause
128
+ * chain read naively. An adapter for such a runtime reverses during
129
+ * parsing — the ordering decision belongs in the language adapter, which
130
+ * knows its own runtime's convention, never in a consumer that would have
131
+ * to ask which language produced the trace to know which end to read.
132
+ *
133
+ * Getting this wrong is quiet rather than loud: the trace still has the
134
+ * right frames and the right count, and root-cause traversal simply
135
+ * points at whichever end of the call chain happens to be first —
136
+ * typically the process entry point instead of the failing line.
137
+ */
138
+ readonly frames: readonly StackFrame[];
139
+ /**
140
+ * Which frame is the **failure site** — the one a developer should be sent
141
+ * to. Usually `0`; not always, and the exceptions are not exotic.
142
+ *
143
+ * ## Why an index and not `frames[0]`
144
+ *
145
+ * `frames[0]` is reliably the *innermost* frame. On several runtimes the
146
+ * innermost frame is the runtime's own, sitting above the application's,
147
+ * and is therefore innermost and useless. Measured on live still-running
148
+ * servers (Lane C, RT-120/121):
149
+ *
150
+ * | runtime | `frames[0]` | the failure site |
151
+ * | --- | --- | --- |
152
+ * | Go, recovered `net/http` handler panic | `net/http.(*conn).serve.func1` at `server.go:1897` | several frames down |
153
+ * | Rust, threaded server | `__rustc::rust_begin_unwind` at `panicking.rs:698` | after five `std`/`core` frames |
154
+ *
155
+ * The JVM's `Caused by:` chains, C#'s `--- End of stack trace from previous
156
+ * location ---` and Kotlin's coroutine frames are the same shape.
157
+ *
158
+ * ## Why this is not a heuristic
159
+ *
160
+ * **Each runtime marks the boundary itself**, which is the entire reason
161
+ * this is expressible as an index rather than as a filter:
162
+ *
163
+ * - Go prints a `panic(` frame **only** when the stack was walked through a
164
+ * recover — an unrecovered panic has none. Measured both ways.
165
+ * - Rust's header names the panic site with line *and column*, and exactly
166
+ * one frame matches it.
167
+ *
168
+ * So the adapter that knows its runtime reads that runtime's own marker.
169
+ * Nothing above the IR boundary names a language, and nothing anywhere
170
+ * denylists a stdlib path — a path-shaped filter is the thing this field
171
+ * exists to make unnecessary, and it would break on any application that
172
+ * legitimately fails inside a library frame.
173
+ *
174
+ * ## Nothing is dropped
175
+ *
176
+ * Every frame stays in `frames`, including the unwinding frames above the
177
+ * failure site. This is a **view**, not a filter, which is what keeps
178
+ * `adapter-rust`'s standing decision intact — *"std/core frames are kept;
179
+ * filtering them would be a readability judgment applied to evidence"* —
180
+ * rather than superseding it. `payload.raw` keeps the verbatim block as
181
+ * well, as always.
182
+ *
183
+ * ## Required, deliberately
184
+ *
185
+ * Not optional, for the reason RT-056 records about `processLifecycle`:
186
+ * **an optional field is one every existing adapter may silently omit**, and
187
+ * an adapter that never considered the question would keep today's behaviour
188
+ * with no signal that it never considered it. Where the innermost frame
189
+ * genuinely is the failure site the answer is `0` — but stated, not
190
+ * defaulted.
191
+ *
192
+ * Consumers must treat an out-of-range value as a fault rather than
193
+ * clamping to `0`: a silent fallback would reintroduce exactly the defect
194
+ * this field removes, through the error path instead of the happy one.
195
+ */
196
+ readonly primaryFrameIndex: number;
197
+ }
198
+ export interface Evidence {
199
+ readonly evidenceId: string;
200
+ readonly executionId: string;
201
+ readonly timestamp: string;
202
+ readonly source: EvidenceSource;
203
+ /** Which owned system this came from (§16.7) — null when not applicable. */
204
+ readonly service: string | null;
205
+ /** ProcessHandle.processId, when this evidence is attributable to one process. */
206
+ readonly process: string | null;
207
+ readonly eventType: RuntimeEventType;
208
+ /** Redacted per `redactionStatus` before this is readable by anything upstream (§25) — never raw secrets in transit. */
209
+ readonly payload: unknown;
210
+ readonly traceId: string | null;
211
+ readonly requestId: string | null;
212
+ /** Set only after the Correlation Engine resolves it (correlation.ts) — never assigned speculatively here. */
213
+ readonly correlationId: string | null;
214
+ /** @descryy/ir node ID, set only when resolved via the graph's own identity scheme. This file does not define graph identity. */
215
+ readonly graphNodeId: string | null;
216
+ readonly sourceLocation: SourceLocation | null;
217
+ readonly stackTrace: StackTrace | null;
218
+ /** Resolution-honesty confidence (§9), 0-1. Independent of environment fidelity level and of a Correlation's own confidence. */
219
+ readonly confidence: number;
220
+ readonly redactionStatus: RedactionStatus;
221
+ /**
222
+ * The `version` field of the `package.json` that owns the collector which
223
+ * produced this row (e.g. `@descryhq-wq/runtime-browser`'s own version for
224
+ * browser-sourced evidence) — read from the package at module load, never
225
+ * hand-duplicated into a second string that can drift from what actually
226
+ * shipped. Same idea as `nodeVersion` elsewhere in this repo (`process.version`,
227
+ * always known, never probed) and as `@descryy/ir`'s `producedBy` (`adapterId@version`,
228
+ * "drives graph invalidation on adapter upgrade") applied to evidence instead of
229
+ * IR nodes — see RUNTIME-CHECKLIST.md §3/§19/§23: without this, evidence "cannot
230
+ * be invalidated by collector version the way IR nodes can."
231
+ *
232
+ * Required, not optional, for the same reason `primaryFrameIndex` above is
233
+ * required: an optional field is one an existing collector can silently omit,
234
+ * with no signal that it never considered the question.
235
+ */
236
+ readonly collectorVersion: string;
237
+ }
238
+ /**
239
+ * Which `SourceLocation` an `Evidence` carries for a given stack — one rule,
240
+ * in one place, for every collector that turns a trace into evidence.
241
+ *
242
+ * ## Why it lives in the contract rather than in each collector
243
+ *
244
+ * It was written twice. `backend-observation`'s collector was moved onto
245
+ * `primaryFrameIndex` (RT-083); `browser`'s console collector kept its own
246
+ * `frames[0]` copy and nothing failed, because V8 reports
247
+ * `primaryFrameIndex: 0` and the two rules agree there **by coincidence**.
248
+ * A copied rule is a rule that will hold in one of them, and this one held
249
+ * in one of them for exactly as long as one runtime was involved.
250
+ *
251
+ * ## The empty location, which is the part that is not obvious
252
+ *
253
+ * `StackFrame.location` is not nullable, so a frame that resolved nothing
254
+ * still carries a `SourceLocation` — one whose `file`, `line` and
255
+ * `functionName` are all null. Returning it would set
256
+ * `Evidence.sourceLocation` to a non-null object naming nothing, and
257
+ * `evidence-package.ts` censuses located evidence with `sourceLocation !==
258
+ * null`. An unsymbolicated crash would be counted as *located* in the very
259
+ * artifact handed to a model — RT-124's shape (a thing reported as the thing
260
+ * it failed to be), one field over.
261
+ *
262
+ * Measured rather than imagined (Lane C, RT-126): on a CI runner a real
263
+ * Swift crash produced a real three-thread backtrace in which every frame is
264
+ * address-only — no symbol, no `at file:line`.
265
+ *
266
+ * ## The discriminator is `functionName`, not `file`
267
+ *
268
+ * A stripped JVM frame (`at com.example.Thrower.handler(Unknown Source)`)
269
+ * and a Rust release frame both have a null file **and a real symbol**,
270
+ * which `SourceLocation.file`'s own doc calls real evidence that still
271
+ * resolves against the graph by name. `adapter-jvm` and `adapter-rust` each
272
+ * assert exactly that. Keying emptiness on a null file would delete the
273
+ * location for every stripped build in both languages — the case this type
274
+ * was widened to express.
275
+ *
276
+ * ## Nothing is lost by returning null
277
+ *
278
+ * The frames stay on `Evidence.stackTrace` with their raw text and their
279
+ * `reliability`. "There was no stack" and "there was a stack that could name
280
+ * nothing" therefore remain distinguishable **on the same record**, because
281
+ * `stackTrace` separates them. That recoverability is the test for whether
282
+ * nulling a field is honest degradation or information loss; here it is the
283
+ * first.
284
+ */
285
+ export declare function primaryFrameLocation(stackTrace: StackTrace | null): SourceLocation | null;
286
+ /**
287
+ * True when a location identifies no place in any source.
288
+ *
289
+ * `column` is deliberately not consulted: a column is an offset into a line,
290
+ * so with no line it names no position and cannot make an otherwise-empty
291
+ * location informative. `reliability` and `resolvedVia` are not consulted
292
+ * either — they record *why* nothing resolved, which describes the failure
293
+ * rather than a place.
294
+ */
295
+ export declare function locationNamesNothing(location: SourceLocation): boolean;
296
+ //# sourceMappingURL=evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../src/evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Evidence contract.
3
+ *
4
+ * Field list is verbatim from `documents/descry-runtime-plan.md` §13
5
+ * (Evidence model), plus `evidenceId` (needed for the ID-reference pattern
6
+ * Execution uses) and `stackTrace` (structured detail for the plan's
7
+ * STACK_TRACE event type, per Agent 3's stack-fidelity finding below). Also
8
+ * grounded in the architecture doc's §18.2 (evidence bundling —
9
+ * screenshot/console/network/backend log, "none of these individually
10
+ * would have been enough"), §17.2 (the observe stream), §9 (the three
11
+ * confidence axes — this file's `confidence` field is the resolution-
12
+ * honesty axis, never conflated with environment fidelity, which lives on
13
+ * Execution/Capability instead) and §25 (redaction before storage).
14
+ *
15
+ * Static facts and runtime observations stay separate. Evidence never
16
+ * embeds a graph node's data — `graphNodeId` is a reference into
17
+ * @descryy/ir's identity scheme, resolved by whoever reads it. This file
18
+ * does not, and must not, redefine graph identity or storage.
19
+ */
20
+ export const EVIDENCE_SOURCES = [
21
+ // Also the source for VIDEO (runtime-event.ts) -- SCREENSHOT's own
22
+ // precedent: a captured-artifact *kind* is a RuntimeEventType, not a
23
+ // watched *domain*, so it reuses this entry rather than adding one.
24
+ "browser-dom",
25
+ "browser-console",
26
+ "browser-network",
27
+ "backend-log",
28
+ "backend-process",
29
+ "process-exit",
30
+ "http-response-payload",
31
+ /** §17 (Test Runner Support, RT-073): TEST_STARTED/PASSED/FAILED, from a runner's own structured reporter output -- never parsed from printed prose (see `packages/test-runner`'s own module doc for why). */
32
+ "test-runner",
33
+ /**
34
+ * RT-219 (runtime self-observability). Every other value in this list
35
+ * names a domain the runtime is *watching* (a browser, a backend
36
+ * process, a test runner). `"harness"` names the opposite direction: the
37
+ * runtime observing **itself** -- a collector/orchestrator/correlator/
38
+ * evidence-store operation that broke on its own terms, not on the
39
+ * observed application's. DEC-273's `automation` fault value (Descry's
40
+ * own harness broke, not the app) had no evidence this repo could point
41
+ * at to positively establish it; this is that evidence's tag.
42
+ *
43
+ * Deliberately a new `source`, not a repurposing of `COLLECTOR_ERROR`
44
+ * alone. `COLLECTOR_ERROR` already existed (`runtime-event.ts`) for "the
45
+ * observer failed, not the observed system," but every existing emitter
46
+ * stamps it with the *domain* source it was observing when it died
47
+ * (`"backend-process"` for a log collector's consume loop, etc.) --
48
+ * correct for a collector's own mid-stream failure, but it means a
49
+ * COLLECTOR_ERROR row is not on its own distinguishable from ordinary
50
+ * domain evidence by `source` alone, only by `eventType`. A harness
51
+ * component with no domain of its own (the orchestrator's own
52
+ * `Promise.all` around `collector.start()`, for instance) has no honest
53
+ * domain source to reuse, and reusing one anyway would make a self-
54
+ * failure look like it came from the thing being watched. `"harness"`
55
+ * is that missing, honestly-named source -- additive, not a
56
+ * retag of any existing emitter.
57
+ */
58
+ "harness",
59
+ /**
60
+ * `DEC-NEXT-fault-layer-empirical-confirmation.md`'s `dependency`
61
+ * mechanism (`@descryy/runtime-controller`'s
62
+ * `checkDependencyVersions`): a structural comparison finding the
63
+ * project's lockfile-declared version of a direct dependency does not
64
+ * match the version actually installed under `node_modules` at
65
+ * execution time. Same standing as `"harness"` -- a fact the runtime
66
+ * establishes about its own execution environment, not an observation of
67
+ * the domain under test, so `signal` stays `null` for records carrying
68
+ * this source (`classifyEvidenceChannel` fails it closed, same as
69
+ * `"harness"`).
70
+ */
71
+ "dependency-check",
72
+ /**
73
+ * The same ruling's `environment` mechanism
74
+ * (`checkEnvironmentVersion`): a structural comparison finding the
75
+ * project's declared runner version (`.nvmrc`/`package.json
76
+ * engines.node`) does not match the runner version actually observed at
77
+ * execution (`process.version`). Same standing as `"dependency-check"`.
78
+ */
79
+ "environment-check",
80
+ ];
81
+ export const REDACTION_STATUSES = ["not-required", "redacted", "pending-redaction"];
82
+ /**
83
+ * Source-location reliability is not one axis with a probabilistic middle —
84
+ * it is three structurally different classes (Agent 3's finding), and
85
+ * conflating them into a single confidence number loses exactly the
86
+ * information a reader needs to judge a location claim:
87
+ *
88
+ * - self-contained: the location came from the process's own captured
89
+ * state (a Python traceback, a Ruby backtrace, a Go `recover()` frame).
90
+ * Accurate when captured; the risk is *capture completeness*, not
91
+ * correctness.
92
+ * - debug-info-present / debug-info-stripped: a binary's own line-number
93
+ * table (Java/Kotlin). A binary outcome — there is no partial case.
94
+ * - side-artifact-resolved / side-artifact-stale / side-artifact-missing:
95
+ * resolution went through a separate file that can drift or vanish
96
+ * (a Node source map, a C# PDB, a Swift dSYM). "We mapped it and it's
97
+ * right" and "we mapped it through an artifact that may be stale" are
98
+ * different confidence claims, and this type is what lets Evidence say
99
+ * which one it is instead of reporting both identically.
100
+ * - self-contained-eval-line: same mechanism as self-contained — the
101
+ * process's own captured backtrace, nothing translated through a side
102
+ * artifact — but the *line* does not index the named file. Ruby's
103
+ * `instance_eval`/`eval` frames print a synthetic path,
104
+ * `(eval at file.rb:12):1`, where `12` is where `eval` was called from
105
+ * but `1` counts lines within the evaluated string, not within
106
+ * `file.rb`. Opening `file.rb` at line `1` shows unrelated code, so this
107
+ * is not a plain self-contained claim; it is not a side-artifact claim
108
+ * either, since nothing was resolved through a separate file. See
109
+ * `packages/adapter-ruby/src/ruby-source-location-resolver.ts` for the
110
+ * one producer of this value.
111
+ */
112
+ export const SOURCE_LOCATION_RELIABILITIES = [
113
+ "self-contained",
114
+ "debug-info-present",
115
+ "debug-info-stripped",
116
+ "side-artifact-resolved",
117
+ "side-artifact-stale",
118
+ "side-artifact-missing",
119
+ "self-contained-eval-line",
120
+ ];
121
+ /**
122
+ * Whether a captured stack reflects the actual logical call chain is a
123
+ * third, orthogonal axis (Agent 3's finding): concurrency models
124
+ * (coroutines, goroutines, async/await, tokio tasks) can capture a stack
125
+ * successfully while structurally breaking the "reflects the logical
126
+ * caller" guarantee. That is not a low-confidence stack — it is a
127
+ * different kind of evidence, and gets its own field rather than a lower
128
+ * number folded into `confidence`.
129
+ */
130
+ export const STACK_FIDELITIES = ["synchronous", "concurrency-fragmented", "unavailable"];
131
+ /**
132
+ * Which `SourceLocation` an `Evidence` carries for a given stack — one rule,
133
+ * in one place, for every collector that turns a trace into evidence.
134
+ *
135
+ * ## Why it lives in the contract rather than in each collector
136
+ *
137
+ * It was written twice. `backend-observation`'s collector was moved onto
138
+ * `primaryFrameIndex` (RT-083); `browser`'s console collector kept its own
139
+ * `frames[0]` copy and nothing failed, because V8 reports
140
+ * `primaryFrameIndex: 0` and the two rules agree there **by coincidence**.
141
+ * A copied rule is a rule that will hold in one of them, and this one held
142
+ * in one of them for exactly as long as one runtime was involved.
143
+ *
144
+ * ## The empty location, which is the part that is not obvious
145
+ *
146
+ * `StackFrame.location` is not nullable, so a frame that resolved nothing
147
+ * still carries a `SourceLocation` — one whose `file`, `line` and
148
+ * `functionName` are all null. Returning it would set
149
+ * `Evidence.sourceLocation` to a non-null object naming nothing, and
150
+ * `evidence-package.ts` censuses located evidence with `sourceLocation !==
151
+ * null`. An unsymbolicated crash would be counted as *located* in the very
152
+ * artifact handed to a model — RT-124's shape (a thing reported as the thing
153
+ * it failed to be), one field over.
154
+ *
155
+ * Measured rather than imagined (Lane C, RT-126): on a CI runner a real
156
+ * Swift crash produced a real three-thread backtrace in which every frame is
157
+ * address-only — no symbol, no `at file:line`.
158
+ *
159
+ * ## The discriminator is `functionName`, not `file`
160
+ *
161
+ * A stripped JVM frame (`at com.example.Thrower.handler(Unknown Source)`)
162
+ * and a Rust release frame both have a null file **and a real symbol**,
163
+ * which `SourceLocation.file`'s own doc calls real evidence that still
164
+ * resolves against the graph by name. `adapter-jvm` and `adapter-rust` each
165
+ * assert exactly that. Keying emptiness on a null file would delete the
166
+ * location for every stripped build in both languages — the case this type
167
+ * was widened to express.
168
+ *
169
+ * ## Nothing is lost by returning null
170
+ *
171
+ * The frames stay on `Evidence.stackTrace` with their raw text and their
172
+ * `reliability`. "There was no stack" and "there was a stack that could name
173
+ * nothing" therefore remain distinguishable **on the same record**, because
174
+ * `stackTrace` separates them. That recoverability is the test for whether
175
+ * nulling a field is honest degradation or information loss; here it is the
176
+ * first.
177
+ */
178
+ export function primaryFrameLocation(stackTrace) {
179
+ if (stackTrace === null || stackTrace.frames.length === 0)
180
+ return null;
181
+ const index = stackTrace.primaryFrameIndex;
182
+ if (!Number.isInteger(index) || index < 0 || index >= stackTrace.frames.length) {
183
+ throw new RangeError(`primaryFrameIndex ${String(index)} is outside the ${stackTrace.frames.length}-frame list it indexes. ` +
184
+ "The adapter that produced this trace declared a failure site that does not exist; reported rather " +
185
+ "than clamped to frames[0], which would silently restore the stdlib-frame defect this index removes.");
186
+ }
187
+ const location = stackTrace.frames[index]?.location ?? null;
188
+ if (location === null)
189
+ return null;
190
+ return locationNamesNothing(location) ? null : location;
191
+ }
192
+ /**
193
+ * True when a location identifies no place in any source.
194
+ *
195
+ * `column` is deliberately not consulted: a column is an offset into a line,
196
+ * so with no line it names no position and cannot make an otherwise-empty
197
+ * location informative. `reliability` and `resolvedVia` are not consulted
198
+ * either — they record *why* nothing resolved, which describes the failure
199
+ * rather than a place.
200
+ */
201
+ export function locationNamesNothing(location) {
202
+ return location.file === null && location.line === null && location.functionName === null;
203
+ }
204
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../src/evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,mEAAmE;IACnE,qEAAqE;IACrE,oEAAoE;IACpE,aAAa;IACb,iBAAiB;IACjB,iBAAiB;IACjB,aAAa;IACb,iBAAiB;IACjB,cAAc;IACd,uBAAuB;IACvB,8MAA8M;IAC9M,aAAa;IACb;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,SAAS;IACT;;;;;;;;;;;OAWG;IACH,kBAAkB;IAClB;;;;;;OAMG;IACH,mBAAmB;CACX,CAAC;AAGX,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,cAAc,EAAE,UAAU,EAAE,mBAAmB,CAAU,CAAC;AAG7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,gBAAgB;IAChB,oBAAoB;IACpB,qBAAqB;IACrB,wBAAwB;IACxB,qBAAqB;IACrB,uBAAuB;IACvB,0BAA0B;CAClB,CAAC;AAgDX;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,aAAa,EAAE,wBAAwB,EAAE,aAAa,CAAU,CAAC;AAqIlG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAA6B;IAChE,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvE,MAAM,KAAK,GAAG,UAAU,CAAC,iBAAiB,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC/E,MAAM,IAAI,UAAU,CAClB,qBAAqB,MAAM,CAAC,KAAK,CAAC,mBAAmB,UAAU,CAAC,MAAM,CAAC,MAAM,0BAA0B;YACrG,oGAAoG;YACpG,qGAAqG,CACxG,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC5D,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC1D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAwB;IAC3D,OAAO,QAAQ,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,YAAY,KAAK,IAAI,CAAC;AAC5F,CAAC"}