@descryy/mcp 0.11.8 → 0.12.1
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/action-handshake.d.ts.map +1 -1
- package/dist/action-handshake.js +5 -1
- package/dist/action-handshake.js.map +1 -1
- package/dist/browser/driver.d.ts +74 -0
- package/dist/browser/driver.d.ts.map +1 -1
- package/dist/browser/driver.js +48 -0
- package/dist/browser/driver.js.map +1 -1
- package/dist/browser/fake-driver.d.ts +39 -0
- package/dist/browser/fake-driver.d.ts.map +1 -1
- package/dist/browser/fake-driver.js +123 -5
- package/dist/browser/fake-driver.js.map +1 -1
- package/dist/browser/fault-attribution.d.ts +75 -39
- package/dist/browser/fault-attribution.d.ts.map +1 -1
- package/dist/browser/fault-attribution.js +100 -89
- package/dist/browser/fault-attribution.js.map +1 -1
- package/dist/browser/graph-write.d.ts +22 -2
- package/dist/browser/graph-write.d.ts.map +1 -1
- package/dist/browser/graph-write.js +60 -2
- package/dist/browser/graph-write.js.map +1 -1
- package/dist/browser/identity-graph-write.d.ts +26 -2
- package/dist/browser/identity-graph-write.d.ts.map +1 -1
- package/dist/browser/identity-graph-write.js +44 -2
- package/dist/browser/identity-graph-write.js.map +1 -1
- package/dist/browser/playwright-driver.d.ts.map +1 -1
- package/dist/browser/playwright-driver.js +63 -8
- package/dist/browser/playwright-driver.js.map +1 -1
- package/dist/browser/provider.d.ts +5 -0
- package/dist/browser/provider.d.ts.map +1 -1
- package/dist/browser/provider.js.map +1 -1
- package/dist/browser/reach-recording-session.d.ts.map +1 -1
- package/dist/browser/reach-recording-session.js +10 -0
- package/dist/browser/reach-recording-session.js.map +1 -1
- package/dist/browser/scenario-runner.d.ts.map +1 -1
- package/dist/browser/scenario-runner.js +2 -0
- package/dist/browser/scenario-runner.js.map +1 -1
- package/dist/browser/tool-support.d.ts.map +1 -1
- package/dist/browser/tool-support.js +6 -1
- package/dist/browser/tool-support.js.map +1 -1
- package/dist/findings/index.d.ts +2 -0
- package/dist/findings/index.d.ts.map +1 -0
- package/dist/findings/index.js +2 -0
- package/dist/findings/index.js.map +1 -0
- package/dist/findings/store.d.ts +81 -0
- package/dist/findings/store.d.ts.map +1 -0
- package/dist/findings/store.js +148 -0
- package/dist/findings/store.js.map +1 -0
- package/dist/fs-gateway.d.ts +57 -0
- package/dist/fs-gateway.d.ts.map +1 -0
- package/dist/fs-gateway.js +86 -0
- package/dist/fs-gateway.js.map +1 -0
- package/dist/scenarios/storage.d.ts.map +1 -1
- package/dist/scenarios/storage.js +3 -3
- package/dist/scenarios/storage.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +8 -13
- package/dist/session.js.map +1 -1
- package/dist/tools/browser-read.d.ts +19 -12
- package/dist/tools/browser-read.d.ts.map +1 -1
- package/dist/tools/browser-read.js +34 -18
- package/dist/tools/browser-read.js.map +1 -1
- package/dist/tools/browser-record-start.d.ts +20 -0
- package/dist/tools/browser-record-start.d.ts.map +1 -0
- package/dist/tools/browser-record-start.js +97 -0
- package/dist/tools/browser-record-start.js.map +1 -0
- package/dist/tools/browser-record-stop.d.ts +25 -0
- package/dist/tools/browser-record-stop.d.ts.map +1 -0
- package/dist/tools/browser-record-stop.js +102 -0
- package/dist/tools/browser-record-stop.js.map +1 -0
- package/dist/tools/browser-start-session.d.ts.map +1 -1
- package/dist/tools/browser-start-session.js +12 -0
- package/dist/tools/browser-start-session.js.map +1 -1
- package/dist/tools/browser.d.ts.map +1 -1
- package/dist/tools/browser.js +6 -0
- package/dist/tools/browser.js.map +1 -1
- package/dist/tools/chain.d.ts +5 -0
- package/dist/tools/chain.d.ts.map +1 -1
- package/dist/tools/chain.js +5 -2
- package/dist/tools/chain.js.map +1 -1
- package/dist/tools/draw-conclusion.d.ts +18 -2
- package/dist/tools/draw-conclusion.d.ts.map +1 -1
- package/dist/tools/draw-conclusion.js +69 -11
- package/dist/tools/draw-conclusion.js.map +1 -1
- package/dist/tools/finding-lookup.d.ts +58 -0
- package/dist/tools/finding-lookup.d.ts.map +1 -0
- package/dist/tools/finding-lookup.js +261 -0
- package/dist/tools/finding-lookup.js.map +1 -0
- package/dist/tools/kit.d.ts +1 -1
- package/dist/tools/link-workspace.d.ts +7 -0
- package/dist/tools/link-workspace.d.ts.map +1 -1
- package/dist/tools/link-workspace.js +20 -0
- package/dist/tools/link-workspace.js.map +1 -1
- package/dist/tools/propagation.d.ts +14 -8
- package/dist/tools/propagation.d.ts.map +1 -1
- package/dist/tools/propagation.js +23 -15
- package/dist/tools/propagation.js.map +1 -1
- package/dist/tools/prove-reach.d.ts +8 -0
- package/dist/tools/prove-reach.d.ts.map +1 -1
- package/dist/tools/prove-reach.js +80 -2
- package/dist/tools/prove-reach.js.map +1 -1
- package/dist/tools/workspace.d.ts.map +1 -1
- package/dist/tools/workspace.js +10 -2
- package/dist/tools/workspace.js.map +1 -1
- package/package.json +21 -21
|
@@ -15,6 +15,22 @@
|
|
|
15
15
|
* like its neighbours — a small closed vocabulary, one function that decides,
|
|
16
16
|
* and an explicit value for "do not know".
|
|
17
17
|
*
|
|
18
|
+
* ## The vocabulary is `@descryy/ir`'s, not this module's own — `DEC-NEXT-fault-layer-vocabulary-merge.md`
|
|
19
|
+
*
|
|
20
|
+
* This module used to carry its own five-value `FaultOwner` type, spelled
|
|
21
|
+
* `application`/`automation`/`environment`/`dependency`/`undetermined`, that
|
|
22
|
+
* disagreed with `@descryy/ir`'s independent `FaultLayer`
|
|
23
|
+
* (`product`/`automation`/`environment`/`dependency`/`unknown`) on the one
|
|
24
|
+
* value that mattered most to get right: the same fact was `application` here
|
|
25
|
+
* and `unknown` there whenever ir's own classifier had no marker for it, and
|
|
26
|
+
* a desktop finding and a browser-drive disclosure could never be compared or
|
|
27
|
+
* merged. `FaultOwner`/`FAULT_OWNERS` are gone; this module now imports
|
|
28
|
+
* `@descryy/ir`'s `FaultLayer` directly, `application` is spelled `product`
|
|
29
|
+
* everywhere below, and `FAULT_OWNER_DISPLAY_LABELS`/`faultOwnerDisplayLabel`
|
|
30
|
+
* are gone too — `@descryy/ir`'s `FAULT_LAYER_DISPLAY_LABELS`/
|
|
31
|
+
* `faultLayerDisplayLabel` are the one copy now, re-exported here for callers
|
|
32
|
+
* that already imported the display helpers from this module.
|
|
33
|
+
*
|
|
18
34
|
* ## The one rule everything else serves
|
|
19
35
|
*
|
|
20
36
|
* **A timeout with nothing corroborating it is never the application's fault.**
|
|
@@ -23,13 +39,23 @@
|
|
|
23
39
|
* consistent with a broken button, a slow one, an overlay, and an animation.
|
|
24
40
|
* Reporting it as the user's bug is the single fastest way to make a testing
|
|
25
41
|
* tool untrusted, and the cost of being wrong is asymmetric — an
|
|
26
|
-
* `undetermined` that was really a bug costs one missed finding, and
|
|
27
|
-
* `
|
|
42
|
+
* `undetermined` that was really a bug costs one missed finding, and a
|
|
43
|
+
* `product` that was really our timeout costs the tool's credibility.
|
|
28
44
|
* That is rule 2 (precision over recall) applied to blame rather than to edges.
|
|
29
45
|
*
|
|
30
|
-
* So `
|
|
31
|
-
* signal** in the same window
|
|
32
|
-
*
|
|
46
|
+
* So `product` is only ever named with a **first-party corroborating
|
|
47
|
+
* signal** in the same window. **The corroboration rule itself moved to
|
|
48
|
+
* `@descryy/ir`** (`hasFirstPartyCorroboration`, `DEC-NEXT-fault-layer-vocabulary-merge.md`)
|
|
49
|
+
* so the desktop's own findings can apply the identical three-form test
|
|
50
|
+
* rather than a second, independently-drifting heuristic. Here, the two forms
|
|
51
|
+
* a browser action failure can actually produce are: a console error whose
|
|
52
|
+
* stack resolved (via `rewriteScriptUrls`) into a file inside the repository
|
|
53
|
+
* under test (`stackFrameInRepo`), or a 5xx response from a request to the
|
|
54
|
+
* application's own origin (`spawnedServiceFiveHundred`). A merely third-party
|
|
55
|
+
* console error, an unmapped stack, or a 4xx/unanswered request is never
|
|
56
|
+
* enough on its own — that tightening (this module used to treat *any*
|
|
57
|
+
* console error in the window as sufficient) is the corroboration rule's own
|
|
58
|
+
* substance, not a side effect of the move.
|
|
33
59
|
*
|
|
34
60
|
* ## Where the corroborating signal comes from (C3)
|
|
35
61
|
*
|
|
@@ -45,17 +71,17 @@
|
|
|
45
71
|
* `observeAndCorrelate` for every evidence-bearing tool call, and the
|
|
46
72
|
* registry's `reap` for the tail no tool call ever returns.
|
|
47
73
|
*/
|
|
74
|
+
import { FAULT_LAYER_DISPLAY_LABELS, faultLayerDisplayLabel } from "@descryy/ir";
|
|
75
|
+
import type { FaultLayer } from "@descryy/ir";
|
|
48
76
|
import { type BrowserObservation } from "./driver.ts";
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
export declare const FAULT_OWNERS: readonly ["application", "automation", "environment", "dependency", "undetermined"];
|
|
56
|
-
export type FaultOwner = (typeof FAULT_OWNERS)[number];
|
|
77
|
+
/** Re-exported so a caller that already imports the vocabulary from this
|
|
78
|
+
* module (rather than from `@descryy/ir` directly) keeps working. The values
|
|
79
|
+
* themselves live in `@descryy/ir`'s `FaultLayer`/`FAULT_LAYER_DISPLAY_LABELS`/
|
|
80
|
+
* `faultLayerDisplayLabel` now — see the module doc. */
|
|
81
|
+
export { FAULT_LAYER_DISPLAY_LABELS, faultLayerDisplayLabel };
|
|
82
|
+
export type { FaultLayer };
|
|
57
83
|
export interface FaultAttribution {
|
|
58
|
-
readonly owner:
|
|
84
|
+
readonly owner: FaultLayer;
|
|
59
85
|
/** What happened, in the report's voice. Never an accusation. */
|
|
60
86
|
readonly reason: string;
|
|
61
87
|
/** What was observed that led here. Deliberately distinct from `reason`: a
|
|
@@ -75,6 +101,17 @@ export interface ActionFailure {
|
|
|
75
101
|
readonly failedRequests: number;
|
|
76
102
|
/** How many of those were to an origin other than the application's own. */
|
|
77
103
|
readonly thirdPartyFailedRequests: number;
|
|
104
|
+
/** Of `pageErrors`, how many carried at least one stack frame that
|
|
105
|
+
* `rewriteScriptUrls` mapped into a file inside the repository under test
|
|
106
|
+
* — `@descryy/ir`'s `hasFirstPartyCorroboration`'s `stackFrameInRepo` form.
|
|
107
|
+
* A console error with no mapped frame (third-party script, or a bundle
|
|
108
|
+
* nothing could rewrite) is not counted here even though it still counts
|
|
109
|
+
* toward `pageErrors`. */
|
|
110
|
+
readonly firstPartyPageErrors: number;
|
|
111
|
+
/** Of `failedRequests`, how many were a 5xx response — never a bare 4xx or
|
|
112
|
+
* an unanswered request — to the application's own origin.
|
|
113
|
+
* `spawnedServiceFiveHundred`'s form. */
|
|
114
|
+
readonly firstPartyFiveHundreds: number;
|
|
78
115
|
}
|
|
79
116
|
export declare function attributeActionFailure(failure: ActionFailure): FaultAttribution;
|
|
80
117
|
/** The bounds of one failed action, in epoch milliseconds: when the verb was
|
|
@@ -83,12 +120,14 @@ export interface ActionWindow {
|
|
|
83
120
|
readonly from: number;
|
|
84
121
|
readonly to: number;
|
|
85
122
|
}
|
|
86
|
-
/** What `evidenceInWindow` found — the
|
|
123
|
+
/** What `evidenceInWindow` found — the five counts `ActionFailure` could not
|
|
87
124
|
* carry at the moment of failure. */
|
|
88
125
|
export interface LaterEvidence {
|
|
89
126
|
readonly pageErrors: number;
|
|
90
127
|
readonly failedRequests: number;
|
|
91
128
|
readonly thirdPartyFailedRequests: number;
|
|
129
|
+
readonly firstPartyPageErrors: number;
|
|
130
|
+
readonly firstPartyFiveHundreds: number;
|
|
92
131
|
}
|
|
93
132
|
/**
|
|
94
133
|
* Counts, out of one drained observation, only what happened **inside a failed
|
|
@@ -107,15 +146,20 @@ export interface LaterEvidence {
|
|
|
107
146
|
* ## What is excluded, and why each exclusion goes the same way
|
|
108
147
|
*
|
|
109
148
|
* A timestamp that will not parse, a request URL that will not parse, and an
|
|
110
|
-
* `unattributed` request all resolve *away* from `
|
|
149
|
+
* `unattributed` request all resolve *away* from `product`. That is not
|
|
111
150
|
* symmetry for its own sake: the asymmetric cost this module was built around
|
|
112
|
-
* says an `undetermined` that was really a bug costs one finding, and
|
|
113
|
-
* `
|
|
151
|
+
* says an `undetermined` that was really a bug costs one finding, and a
|
|
152
|
+
* `product` that was really Descry's own timeout costs the tool. So an
|
|
114
153
|
* unreadable URL is counted as third-party (it cannot name the application), an
|
|
115
154
|
* unreadable timestamp is counted as outside the window, and a request whose
|
|
116
155
|
* terminal event could not be assigned to it is not counted as a failure at
|
|
117
156
|
* all — otherwise C3's own refusal to guess a join would come straight back as
|
|
118
157
|
* a guess about blame.
|
|
158
|
+
*
|
|
159
|
+
* `firstPartyPageErrors`/`firstPartyFiveHundreds` are the two forms of
|
|
160
|
+
* `@descryy/ir`'s corroboration rule this evidence shape can actually produce
|
|
161
|
+
* — see `attributeActionFailure`'s own doc for why a merely-present console
|
|
162
|
+
* error or a bare 4xx no longer qualifies on its own.
|
|
119
163
|
*/
|
|
120
164
|
export declare function evidenceInWindow(observation: Pick<BrowserObservation, "consoleErrors" | "requests">, window: ActionWindow, applicationOrigin: string): LaterEvidence;
|
|
121
165
|
/**
|
|
@@ -130,8 +174,9 @@ export declare function faultNote(attribution: FaultAttribution): string;
|
|
|
130
174
|
/**
|
|
131
175
|
* RG-12(b): the vocabulary reconciliation. The site names three layers to a
|
|
132
176
|
* user — "your product", "your environment", "a dependency" — and this
|
|
133
|
-
* module's
|
|
134
|
-
* `dependency`, `undetermined`. Two real gaps,
|
|
177
|
+
* module's five values (now `@descryy/ir`'s `FaultLayer`) are `product`,
|
|
178
|
+
* `automation`, `environment`, `dependency`, `undetermined`. Two real gaps,
|
|
179
|
+
* not one:
|
|
135
180
|
*
|
|
136
181
|
* 1. `automation` (Descry's *own* fault — a bad ref, a stale handle, a
|
|
137
182
|
* harness bug) has nowhere to go in the site's three layers, and it is
|
|
@@ -141,26 +186,17 @@ export declare function faultNote(attribution: FaultAttribution): string;
|
|
|
141
186
|
* 2. `undetermined` has nowhere to go either, and collapsing it into any of
|
|
142
187
|
* the three would state a layer the evidence did not actually reach.
|
|
143
188
|
*
|
|
144
|
-
* **Recommendation (implemented
|
|
145
|
-
* different lane's to change): the site
|
|
146
|
-
* rather than losing this module's
|
|
147
|
-
* `automation` (visible, not hidden —
|
|
148
|
-
* be named when the tool is the one
|
|
149
|
-
* determined" for `undetermined` (an honest
|
|
150
|
-
* failure). No
|
|
151
|
-
*
|
|
152
|
-
* display text, so a copy change only
|
|
153
|
-
|
|
154
|
-
export declare const FAULT_OWNER_DISPLAY_LABELS: Readonly<Record<FaultOwner, string>>;
|
|
155
|
-
/**
|
|
156
|
-
* RG-12(c): the type-level half of "every failure carries a layer, by
|
|
157
|
-
* construction, not by convention." A `switch` with no `default` fails to
|
|
158
|
-
* compile the moment `FAULT_OWNERS` gains or loses a value without this
|
|
159
|
-
* function being updated to match — the same guarantee `ActionRecord`'s
|
|
160
|
-
* discriminated union (`reachability.ts`) gives the *presence* of an
|
|
161
|
-
* attribution; this is what gives the *display* side the same guarantee.
|
|
189
|
+
* **Recommendation (implemented in `@descryy/ir`'s `FAULT_LAYER_DISPLAY_LABELS`,
|
|
190
|
+
* not on the site — that copy is a different lane's to change): the site
|
|
191
|
+
* gains a fourth and fifth category rather than losing this module's
|
|
192
|
+
* granularity.** "Descry itself" for `automation` (visible, not hidden —
|
|
193
|
+
* this is the layer that most needs to be named when the tool is the one
|
|
194
|
+
* that got it wrong) and "not determined" for `undetermined` (an honest
|
|
195
|
+
* refusal is not a hidden failure). No value is deleted to fit the narrower
|
|
196
|
+
* copy; `faultLayerDisplayLabel` (re-exported above) is the one place that
|
|
197
|
+
* maps the closed five-value set onto display text, so a copy change only
|
|
198
|
+
* ever touches that map — one copy now, not this module's own second one.
|
|
162
199
|
*/
|
|
163
|
-
export declare function faultOwnerDisplayLabel(owner: FaultOwner): string;
|
|
164
200
|
/**
|
|
165
201
|
* RG-12(c): the run-level half. Not a convention check — `ActionRecord`'s
|
|
166
202
|
* discriminated union already makes `{ succeeded: false, attribution: null }`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fault-attribution.d.ts","sourceRoot":"","sources":["../../src/browser/fault-attribution.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fault-attribution.d.ts","sourceRoot":"","sources":["../../src/browser/fault-attribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwEG;AAEH,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EAEvB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAuE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE3H;;;yDAGyD;AACzD,OAAO,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,CAAC;AAC9D,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;wDAEoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAC;IAC1C;;;;;+BAK2B;IAC3B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;;8CAE0C;IAC1C,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC;AAWD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,GAAG,gBAAgB,CAoE/E;AAED;+EAC+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED;sCACsC;AACtC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,eAAe,GAAG,UAAU,CAAC,EACnE,MAAM,EAAE,YAAY,EACpB,iBAAiB,EAAE,MAAM,GACxB,aAAa,CAiCf;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,aAAa,GACnB,gBAAgB,CAYlB;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,gBAAgB,GAAG,MAAM,CAE/D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,SAAS;IAAE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAAE,EAAE,GAAG,IAAI,CAStJ"}
|
|
@@ -15,6 +15,22 @@
|
|
|
15
15
|
* like its neighbours — a small closed vocabulary, one function that decides,
|
|
16
16
|
* and an explicit value for "do not know".
|
|
17
17
|
*
|
|
18
|
+
* ## The vocabulary is `@descryy/ir`'s, not this module's own — `DEC-NEXT-fault-layer-vocabulary-merge.md`
|
|
19
|
+
*
|
|
20
|
+
* This module used to carry its own five-value `FaultOwner` type, spelled
|
|
21
|
+
* `application`/`automation`/`environment`/`dependency`/`undetermined`, that
|
|
22
|
+
* disagreed with `@descryy/ir`'s independent `FaultLayer`
|
|
23
|
+
* (`product`/`automation`/`environment`/`dependency`/`unknown`) on the one
|
|
24
|
+
* value that mattered most to get right: the same fact was `application` here
|
|
25
|
+
* and `unknown` there whenever ir's own classifier had no marker for it, and
|
|
26
|
+
* a desktop finding and a browser-drive disclosure could never be compared or
|
|
27
|
+
* merged. `FaultOwner`/`FAULT_OWNERS` are gone; this module now imports
|
|
28
|
+
* `@descryy/ir`'s `FaultLayer` directly, `application` is spelled `product`
|
|
29
|
+
* everywhere below, and `FAULT_OWNER_DISPLAY_LABELS`/`faultOwnerDisplayLabel`
|
|
30
|
+
* are gone too — `@descryy/ir`'s `FAULT_LAYER_DISPLAY_LABELS`/
|
|
31
|
+
* `faultLayerDisplayLabel` are the one copy now, re-exported here for callers
|
|
32
|
+
* that already imported the display helpers from this module.
|
|
33
|
+
*
|
|
18
34
|
* ## The one rule everything else serves
|
|
19
35
|
*
|
|
20
36
|
* **A timeout with nothing corroborating it is never the application's fault.**
|
|
@@ -23,13 +39,23 @@
|
|
|
23
39
|
* consistent with a broken button, a slow one, an overlay, and an animation.
|
|
24
40
|
* Reporting it as the user's bug is the single fastest way to make a testing
|
|
25
41
|
* tool untrusted, and the cost of being wrong is asymmetric — an
|
|
26
|
-
* `undetermined` that was really a bug costs one missed finding, and
|
|
27
|
-
* `
|
|
42
|
+
* `undetermined` that was really a bug costs one missed finding, and a
|
|
43
|
+
* `product` that was really our timeout costs the tool's credibility.
|
|
28
44
|
* That is rule 2 (precision over recall) applied to blame rather than to edges.
|
|
29
45
|
*
|
|
30
|
-
* So `
|
|
31
|
-
* signal** in the same window
|
|
32
|
-
*
|
|
46
|
+
* So `product` is only ever named with a **first-party corroborating
|
|
47
|
+
* signal** in the same window. **The corroboration rule itself moved to
|
|
48
|
+
* `@descryy/ir`** (`hasFirstPartyCorroboration`, `DEC-NEXT-fault-layer-vocabulary-merge.md`)
|
|
49
|
+
* so the desktop's own findings can apply the identical three-form test
|
|
50
|
+
* rather than a second, independently-drifting heuristic. Here, the two forms
|
|
51
|
+
* a browser action failure can actually produce are: a console error whose
|
|
52
|
+
* stack resolved (via `rewriteScriptUrls`) into a file inside the repository
|
|
53
|
+
* under test (`stackFrameInRepo`), or a 5xx response from a request to the
|
|
54
|
+
* application's own origin (`spawnedServiceFiveHundred`). A merely third-party
|
|
55
|
+
* console error, an unmapped stack, or a 4xx/unanswered request is never
|
|
56
|
+
* enough on its own — that tightening (this module used to treat *any*
|
|
57
|
+
* console error in the window as sufficient) is the corroboration rule's own
|
|
58
|
+
* substance, not a side effect of the move.
|
|
33
59
|
*
|
|
34
60
|
* ## Where the corroborating signal comes from (C3)
|
|
35
61
|
*
|
|
@@ -45,14 +71,13 @@
|
|
|
45
71
|
* `observeAndCorrelate` for every evidence-bearing tool call, and the
|
|
46
72
|
* registry's `reap` for the tail no tool call ever returns.
|
|
47
73
|
*/
|
|
74
|
+
import { FAULT_LAYER_DISPLAY_LABELS, faultLayerDisplayLabel, hasFirstPartyCorroboration, } from "@descryy/ir";
|
|
48
75
|
import { BrowserSessionCrashedError, isFailedRequest, UnknownElementRefError } from "./driver.js";
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
|
|
54
|
-
*/
|
|
55
|
-
export const FAULT_OWNERS = ["application", "automation", "environment", "dependency", "undetermined"];
|
|
76
|
+
/** Re-exported so a caller that already imports the vocabulary from this
|
|
77
|
+
* module (rather than from `@descryy/ir` directly) keeps working. The values
|
|
78
|
+
* themselves live in `@descryy/ir`'s `FaultLayer`/`FAULT_LAYER_DISPLAY_LABELS`/
|
|
79
|
+
* `faultLayerDisplayLabel` now — see the module doc. */
|
|
80
|
+
export { FAULT_LAYER_DISPLAY_LABELS, faultLayerDisplayLabel };
|
|
56
81
|
/** Playwright's expiry reads as a message, not a type, on the far side of the
|
|
57
82
|
* port. Matching it is a heuristic and is treated as one: a false positive
|
|
58
83
|
* only ever routes to `undetermined`, which is where an unrecognised error
|
|
@@ -62,7 +87,7 @@ function looksLikeExpiry(error) {
|
|
|
62
87
|
return /timeout|timed out|exceeded/i.test(text);
|
|
63
88
|
}
|
|
64
89
|
export function attributeActionFailure(failure) {
|
|
65
|
-
const { error, verb, pageErrors, failedRequests, thirdPartyFailedRequests } = failure;
|
|
90
|
+
const { error, verb, pageErrors, failedRequests, thirdPartyFailedRequests, firstPartyPageErrors, firstPartyFiveHundreds } = failure;
|
|
66
91
|
if (error instanceof UnknownElementRefError) {
|
|
67
92
|
return {
|
|
68
93
|
owner: "automation",
|
|
@@ -77,28 +102,30 @@ export function attributeActionFailure(failure) {
|
|
|
77
102
|
evidence: "The session reported itself unusable before the action could complete.",
|
|
78
103
|
};
|
|
79
104
|
}
|
|
80
|
-
// Corroboration first, expiry second.
|
|
81
|
-
// is
|
|
82
|
-
|
|
105
|
+
// Corroboration first, expiry second. `@descryy/ir`'s `hasFirstPartyCorroboration`
|
|
106
|
+
// is the one rule now — a page error only counts here when its own stack
|
|
107
|
+
// resolved into the application's own source, and a failed request only
|
|
108
|
+
// counts when it was a 5xx to the application's own origin. A third-party
|
|
109
|
+
// console error or a bare 4xx is never sufficient on its own.
|
|
110
|
+
if (hasFirstPartyCorroboration({ stackFrameInRepo: firstPartyPageErrors > 0 })) {
|
|
83
111
|
return {
|
|
84
|
-
owner: "
|
|
85
|
-
reason: `The page raised errors of its own while Descry was waiting to ${verb}.`,
|
|
86
|
-
evidence: `${pageErrors} console error${pageErrors === 1 ? "" : "s"} in the same window
|
|
112
|
+
owner: "product",
|
|
113
|
+
reason: `The page raised errors of its own, from its own source, while Descry was waiting to ${verb}.`,
|
|
114
|
+
evidence: `${firstPartyPageErrors} of ${pageErrors} console error${pageErrors === 1 ? "" : "s"} in the same window carried a stack frame inside the application's own source.`,
|
|
87
115
|
};
|
|
88
116
|
}
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const firstParty = failedRequests - thirdPartyFailedRequests;
|
|
117
|
+
if (hasFirstPartyCorroboration({ spawnedServiceFiveHundred: firstPartyFiveHundreds > 0 })) {
|
|
118
|
+
return {
|
|
119
|
+
owner: "product",
|
|
120
|
+
reason: `A request to the application's own origin returned a server error while Descry was waiting to ${verb}.`,
|
|
121
|
+
evidence: `${firstPartyFiveHundreds} of ${failedRequests} failed request${failedRequests === 1 ? "" : "s"} were a 5xx response from the application's own origin.`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (failedRequests > 0 && thirdPartyFailedRequests >= failedRequests) {
|
|
98
125
|
return {
|
|
99
|
-
owner: "
|
|
100
|
-
reason: `
|
|
101
|
-
evidence: `${
|
|
126
|
+
owner: "dependency",
|
|
127
|
+
reason: `Every request that failed while Descry was waiting to ${verb} went to a third-party origin.`,
|
|
128
|
+
evidence: `${failedRequests} failed request${failedRequests === 1 ? "" : "s"}, all of them off the application's own origin.`,
|
|
102
129
|
};
|
|
103
130
|
}
|
|
104
131
|
if (looksLikeExpiry(error)) {
|
|
@@ -106,13 +133,18 @@ export function attributeActionFailure(failure) {
|
|
|
106
133
|
owner: "undetermined",
|
|
107
134
|
reason: `The element did not become actionable within the time Descry waited, and nothing else was observed ` +
|
|
108
135
|
`that would say why. A slow page, a covering overlay and a broken ${verb} target all look like this.`,
|
|
109
|
-
evidence: `The ${verb} expired after ${failure.elapsedMs} ms with no console error
|
|
136
|
+
evidence: `The ${verb} expired after ${failure.elapsedMs} ms with no corroborating console error or failed request alongside it.`,
|
|
110
137
|
};
|
|
111
138
|
}
|
|
139
|
+
// Reached with pageErrors/failedRequests > 0 but none of them first-party
|
|
140
|
+
// corroboration (a third-party console error, an unmapped stack, a 4xx or
|
|
141
|
+
// unanswered request to the application's own origin) — real signal, but
|
|
142
|
+
// not enough to place a layer. Falling here rather than to a fault-domain
|
|
143
|
+
// count keeps the message honest about which case this is.
|
|
112
144
|
return {
|
|
113
145
|
owner: "undetermined",
|
|
114
|
-
reason: `The ${verb} failed for a reason Descry could not place in any
|
|
115
|
-
evidence: `${error instanceof Error ? `${error.name}: ${error.message}` : String(error)} after ${failure.elapsedMs} ms, with nothing
|
|
146
|
+
reason: `The ${verb} failed for a reason Descry could not place in any fault layer.`,
|
|
147
|
+
evidence: `${error instanceof Error ? `${error.name}: ${error.message}` : String(error)} after ${failure.elapsedMs} ms, with nothing first-party observed.`,
|
|
116
148
|
};
|
|
117
149
|
}
|
|
118
150
|
/**
|
|
@@ -132,34 +164,45 @@ export function attributeActionFailure(failure) {
|
|
|
132
164
|
* ## What is excluded, and why each exclusion goes the same way
|
|
133
165
|
*
|
|
134
166
|
* A timestamp that will not parse, a request URL that will not parse, and an
|
|
135
|
-
* `unattributed` request all resolve *away* from `
|
|
167
|
+
* `unattributed` request all resolve *away* from `product`. That is not
|
|
136
168
|
* symmetry for its own sake: the asymmetric cost this module was built around
|
|
137
|
-
* says an `undetermined` that was really a bug costs one finding, and
|
|
138
|
-
* `
|
|
169
|
+
* says an `undetermined` that was really a bug costs one finding, and a
|
|
170
|
+
* `product` that was really Descry's own timeout costs the tool. So an
|
|
139
171
|
* unreadable URL is counted as third-party (it cannot name the application), an
|
|
140
172
|
* unreadable timestamp is counted as outside the window, and a request whose
|
|
141
173
|
* terminal event could not be assigned to it is not counted as a failure at
|
|
142
174
|
* all — otherwise C3's own refusal to guess a join would come straight back as
|
|
143
175
|
* a guess about blame.
|
|
176
|
+
*
|
|
177
|
+
* `firstPartyPageErrors`/`firstPartyFiveHundreds` are the two forms of
|
|
178
|
+
* `@descryy/ir`'s corroboration rule this evidence shape can actually produce
|
|
179
|
+
* — see `attributeActionFailure`'s own doc for why a merely-present console
|
|
180
|
+
* error or a bare 4xx no longer qualifies on its own.
|
|
144
181
|
*/
|
|
145
182
|
export function evidenceInWindow(observation, window, applicationOrigin) {
|
|
146
183
|
const inside = (at) => {
|
|
147
184
|
const ms = Date.parse(at);
|
|
148
185
|
return Number.isFinite(ms) && ms >= window.from && ms <= window.to;
|
|
149
186
|
};
|
|
187
|
+
const consoleErrorsInWindow = observation.consoleErrors.filter((error) => inside(error.at));
|
|
188
|
+
const firstPartyPageErrors = consoleErrorsInWindow.filter((error) => error.scriptUrlMapping.some((outcome) => outcome.mapped !== null)).length;
|
|
150
189
|
const failed = observation.requests.filter((request) => request.outcome !== "unattributed" && isFailedRequest(request) && inside(request.at));
|
|
151
|
-
const
|
|
190
|
+
const sameOrigin = (request) => {
|
|
152
191
|
try {
|
|
153
|
-
return new URL(request.url).origin
|
|
192
|
+
return new URL(request.url).origin === applicationOrigin;
|
|
154
193
|
}
|
|
155
194
|
catch {
|
|
156
|
-
return
|
|
195
|
+
return false;
|
|
157
196
|
}
|
|
158
|
-
}
|
|
197
|
+
};
|
|
198
|
+
const thirdParty = failed.filter((request) => !sameOrigin(request));
|
|
199
|
+
const firstPartyFiveHundreds = failed.filter((request) => request.status !== null && request.status >= 500 && sameOrigin(request)).length;
|
|
159
200
|
return {
|
|
160
|
-
pageErrors:
|
|
201
|
+
pageErrors: consoleErrorsInWindow.length,
|
|
161
202
|
failedRequests: failed.length,
|
|
162
203
|
thirdPartyFailedRequests: thirdParty.length,
|
|
204
|
+
firstPartyPageErrors,
|
|
205
|
+
firstPartyFiveHundreds,
|
|
163
206
|
};
|
|
164
207
|
}
|
|
165
208
|
/**
|
|
@@ -177,6 +220,8 @@ export function refineAttribution(attribution, failure, later) {
|
|
|
177
220
|
pageErrors: failure.pageErrors + later.pageErrors,
|
|
178
221
|
failedRequests: failure.failedRequests + later.failedRequests,
|
|
179
222
|
thirdPartyFailedRequests: failure.thirdPartyFailedRequests + later.thirdPartyFailedRequests,
|
|
223
|
+
firstPartyPageErrors: failure.firstPartyPageErrors + later.firstPartyPageErrors,
|
|
224
|
+
firstPartyFiveHundreds: failure.firstPartyFiveHundreds + later.firstPartyFiveHundreds,
|
|
180
225
|
});
|
|
181
226
|
if (refined.owner === "undetermined")
|
|
182
227
|
return attribution;
|
|
@@ -188,8 +233,9 @@ export function faultNote(attribution) {
|
|
|
188
233
|
/**
|
|
189
234
|
* RG-12(b): the vocabulary reconciliation. The site names three layers to a
|
|
190
235
|
* user — "your product", "your environment", "a dependency" — and this
|
|
191
|
-
* module's
|
|
192
|
-
* `dependency`, `undetermined`. Two real gaps,
|
|
236
|
+
* module's five values (now `@descryy/ir`'s `FaultLayer`) are `product`,
|
|
237
|
+
* `automation`, `environment`, `dependency`, `undetermined`. Two real gaps,
|
|
238
|
+
* not one:
|
|
193
239
|
*
|
|
194
240
|
* 1. `automation` (Descry's *own* fault — a bad ref, a stale handle, a
|
|
195
241
|
* harness bug) has nowhere to go in the site's three layers, and it is
|
|
@@ -199,52 +245,17 @@ export function faultNote(attribution) {
|
|
|
199
245
|
* 2. `undetermined` has nowhere to go either, and collapsing it into any of
|
|
200
246
|
* the three would state a layer the evidence did not actually reach.
|
|
201
247
|
*
|
|
202
|
-
* **Recommendation (implemented
|
|
203
|
-
* different lane's to change): the site
|
|
204
|
-
* rather than losing this module's
|
|
205
|
-
* `automation` (visible, not hidden —
|
|
206
|
-
* be named when the tool is the one
|
|
207
|
-
* determined" for `undetermined` (an honest
|
|
208
|
-
* failure). No
|
|
209
|
-
*
|
|
210
|
-
* display text, so a copy change only
|
|
211
|
-
|
|
212
|
-
export const FAULT_OWNER_DISPLAY_LABELS = {
|
|
213
|
-
application: "your product",
|
|
214
|
-
automation: "Descry itself",
|
|
215
|
-
environment: "your environment",
|
|
216
|
-
dependency: "a dependency",
|
|
217
|
-
undetermined: "not determined",
|
|
218
|
-
};
|
|
219
|
-
/**
|
|
220
|
-
* RG-12(c): the type-level half of "every failure carries a layer, by
|
|
221
|
-
* construction, not by convention." A `switch` with no `default` fails to
|
|
222
|
-
* compile the moment `FAULT_OWNERS` gains or loses a value without this
|
|
223
|
-
* function being updated to match — the same guarantee `ActionRecord`'s
|
|
224
|
-
* discriminated union (`reachability.ts`) gives the *presence* of an
|
|
225
|
-
* attribution; this is what gives the *display* side the same guarantee.
|
|
248
|
+
* **Recommendation (implemented in `@descryy/ir`'s `FAULT_LAYER_DISPLAY_LABELS`,
|
|
249
|
+
* not on the site — that copy is a different lane's to change): the site
|
|
250
|
+
* gains a fourth and fifth category rather than losing this module's
|
|
251
|
+
* granularity.** "Descry itself" for `automation` (visible, not hidden —
|
|
252
|
+
* this is the layer that most needs to be named when the tool is the one
|
|
253
|
+
* that got it wrong) and "not determined" for `undetermined` (an honest
|
|
254
|
+
* refusal is not a hidden failure). No value is deleted to fit the narrower
|
|
255
|
+
* copy; `faultLayerDisplayLabel` (re-exported above) is the one place that
|
|
256
|
+
* maps the closed five-value set onto display text, so a copy change only
|
|
257
|
+
* ever touches that map — one copy now, not this module's own second one.
|
|
226
258
|
*/
|
|
227
|
-
export function faultOwnerDisplayLabel(owner) {
|
|
228
|
-
switch (owner) {
|
|
229
|
-
case "application":
|
|
230
|
-
return FAULT_OWNER_DISPLAY_LABELS.application;
|
|
231
|
-
case "automation":
|
|
232
|
-
return FAULT_OWNER_DISPLAY_LABELS.automation;
|
|
233
|
-
case "environment":
|
|
234
|
-
return FAULT_OWNER_DISPLAY_LABELS.environment;
|
|
235
|
-
case "dependency":
|
|
236
|
-
return FAULT_OWNER_DISPLAY_LABELS.dependency;
|
|
237
|
-
case "undetermined":
|
|
238
|
-
return FAULT_OWNER_DISPLAY_LABELS.undetermined;
|
|
239
|
-
default: {
|
|
240
|
-
// Exhaustiveness check: if FAULT_OWNERS ever gains a member, `owner`
|
|
241
|
-
// stops being `never` here and this file fails to compile — the
|
|
242
|
-
// enforcement is at build time, not at review time.
|
|
243
|
-
const exhaustive = owner;
|
|
244
|
-
throw new Error(`faultOwnerDisplayLabel: unhandled FaultOwner ${String(exhaustive)}`);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
259
|
/**
|
|
249
260
|
* RG-12(c): the run-level half. Not a convention check — `ActionRecord`'s
|
|
250
261
|
* discriminated union already makes `{ succeeded: false, attribution: null }`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fault-attribution.js","sourceRoot":"","sources":["../../src/browser/fault-attribution.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fault-attribution.js","sourceRoot":"","sources":["../../src/browser/fault-attribution.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* R1 string-match `impact`/`propagation` already do. Precision over recall:
|
|
4
4
|
* anything unresolvable (no stack, no endpoint, ambiguous) drops the observation entirely rather than writing a weak edge. Never mints a denial.
|
|
5
5
|
*/
|
|
6
|
-
import type
|
|
7
|
-
import { type ObservedRequest } from "./driver.ts";
|
|
6
|
+
import { type ObservedInteractionAction, type SqlDriver } from "@descryy/core";
|
|
7
|
+
import { type ObservedAction, type ObservedRequest } from "./driver.ts";
|
|
8
8
|
/** A graph node this browser evidence actually reached — §5.3's "any graph node reached, surfaced in the same reply". */
|
|
9
9
|
export interface ReachedNode {
|
|
10
10
|
readonly nodeId: string;
|
|
@@ -17,6 +17,19 @@ export interface ReachedNode {
|
|
|
17
17
|
readonly status: number | null;
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
+
/** A `FUNCTION`/`CLASS`/`COMPONENT` node a real click or input actually reached — B1's graph
|
|
21
|
+
* half. Distinct from `ReachedNode`: that one names an endpoint a *request* hit; this one
|
|
22
|
+
* names the element identity grounding resolved a *DOM action* to. Both are "real evidence
|
|
23
|
+
* reached this graph node", reported the same way for the same reason. */
|
|
24
|
+
export interface WitnessedInteractionNode {
|
|
25
|
+
readonly nodeId: string;
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly type: string;
|
|
28
|
+
readonly via: {
|
|
29
|
+
readonly action: ObservedInteractionAction;
|
|
30
|
+
readonly ref: string | null;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
20
33
|
export interface BrowserGraphWrite {
|
|
21
34
|
/** Endpoints the page's own requests resolved to, whether or not an edge was written. */
|
|
22
35
|
readonly reached: readonly ReachedNode[];
|
|
@@ -28,6 +41,9 @@ export interface BrowserGraphWrite {
|
|
|
28
41
|
readonly refused: readonly string[];
|
|
29
42
|
/** R4-vs-R4 disagreements, passed through untouched — this module does not adjudicate them. */
|
|
30
43
|
readonly contradictions: readonly string[];
|
|
44
|
+
/** Nodes a real click or input reached and witnessed (`observed_interactions`), B1's graph
|
|
45
|
+
* half. Empty when no action carried a grounded identity, or the identity did not join. */
|
|
46
|
+
readonly interactions: readonly WitnessedInteractionNode[];
|
|
31
47
|
}
|
|
32
48
|
export declare const NO_GRAPH_WRITE: BrowserGraphWrite;
|
|
33
49
|
export interface BrowserGraphWriteInput {
|
|
@@ -37,6 +53,10 @@ export interface BrowserGraphWriteInput {
|
|
|
37
53
|
readonly commitSha: string;
|
|
38
54
|
readonly repoRoot: string;
|
|
39
55
|
readonly requests: readonly ObservedRequest[];
|
|
56
|
+
/** Actions this observation drained, so a grounded one can be joined to the graph too —
|
|
57
|
+
* additive to `requests`, and independently non-empty: a page can be clicked with no
|
|
58
|
+
* network effect at all. Defaults to empty for callers that only ever pass requests. */
|
|
59
|
+
readonly actions?: readonly ObservedAction[];
|
|
40
60
|
}
|
|
41
61
|
/** Correlates what the page did against the graph, recording only what was genuinely witnessed. Runs over every request, not just failures — a successful call is what proves the arrow. */
|
|
42
62
|
export declare function writeBrowserObservations(input: BrowserGraphWriteInput): BrowserGraphWrite;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-write.d.ts","sourceRoot":"","sources":["../../src/browser/graph-write.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"graph-write.d.ts","sourceRoot":"","sources":["../../src/browser/graph-write.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAA6B,KAAK,yBAAyB,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAG1G,OAAO,EAAmB,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAGzF,yHAAyH;AACzH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CACjG;AAED;;;2EAG2E;AAC3E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC3F;AAED,MAAM,WAAW,iBAAiB;IAChC,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,oFAAoF;IACpF,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,0HAA0H;IAC1H,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,+FAA+F;IAC/F,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;gGAC4F;IAC5F,QAAQ,CAAC,YAAY,EAAE,SAAS,wBAAwB,EAAE,CAAC;CAC5D;AAED,eAAO,MAAM,cAAc,EAAE,iBAO5B,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C;;6FAEyF;IACzF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CAC9C;AAoBD,4LAA4L;AAC5L,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,sBAAsB,GAAG,iBAAiB,CA4FzF;AAED,uHAAuH;AACvH,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,EAAE,CAqDxG"}
|