@descryy/mcp 0.2.0 → 0.4.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/bin/descry-mcp.js +6 -1
- package/dist/bin/descry-mcp.js.map +1 -1
- package/dist/browser/driver.d.ts +236 -0
- package/dist/browser/driver.d.ts.map +1 -0
- package/dist/browser/driver.js +70 -0
- package/dist/browser/driver.js.map +1 -0
- package/dist/browser/evidence.d.ts +47 -0
- package/dist/browser/evidence.d.ts.map +1 -0
- package/dist/browser/evidence.js +55 -0
- package/dist/browser/evidence.js.map +1 -0
- package/dist/browser/fake-driver.d.ts +58 -0
- package/dist/browser/fake-driver.d.ts.map +1 -0
- package/dist/browser/fake-driver.js +161 -0
- package/dist/browser/fake-driver.js.map +1 -0
- package/dist/browser/graph-write.d.ts +86 -0
- package/dist/browser/graph-write.d.ts.map +1 -0
- package/dist/browser/graph-write.js +135 -0
- package/dist/browser/graph-write.js.map +1 -0
- package/dist/browser/playwright-driver.d.ts +65 -0
- package/dist/browser/playwright-driver.d.ts.map +1 -0
- package/dist/browser/playwright-driver.js +359 -0
- package/dist/browser/playwright-driver.js.map +1 -0
- package/dist/browser/provider.d.ts +49 -0
- package/dist/browser/provider.d.ts.map +1 -0
- package/dist/browser/provider.js +28 -0
- package/dist/browser/provider.js.map +1 -0
- package/dist/browser/registry.d.ts +182 -0
- package/dist/browser/registry.d.ts.map +1 -0
- package/dist/browser/registry.js +215 -0
- package/dist/browser/registry.js.map +1 -0
- package/dist/browser/scenario-resolve.d.ts +62 -0
- package/dist/browser/scenario-resolve.d.ts.map +1 -0
- package/dist/browser/scenario-resolve.js +127 -0
- package/dist/browser/scenario-resolve.js.map +1 -0
- package/dist/browser/scenario-runner.d.ts +113 -0
- package/dist/browser/scenario-runner.d.ts.map +1 -0
- package/dist/browser/scenario-runner.js +315 -0
- package/dist/browser/scenario-runner.js.map +1 -0
- package/dist/browser/stack-parser.d.ts +43 -0
- package/dist/browser/stack-parser.d.ts.map +1 -0
- package/dist/browser/stack-parser.js +112 -0
- package/dist/browser/stack-parser.js.map +1 -0
- package/dist/browser/tool-support.d.ts +113 -0
- package/dist/browser/tool-support.d.ts.map +1 -0
- package/dist/browser/tool-support.js +181 -0
- package/dist/browser/tool-support.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/render.d.ts +112 -10
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +79 -13
- package/dist/render.js.map +1 -1
- package/dist/scenarios/index.d.ts +4 -0
- package/dist/scenarios/index.d.ts.map +1 -0
- package/dist/scenarios/index.js +4 -0
- package/dist/scenarios/index.js.map +1 -0
- package/dist/scenarios/parse.d.ts +32 -0
- package/dist/scenarios/parse.d.ts.map +1 -0
- package/dist/scenarios/parse.js +199 -0
- package/dist/scenarios/parse.js.map +1 -0
- package/dist/scenarios/scenario.d.ts +115 -0
- package/dist/scenarios/scenario.d.ts.map +1 -0
- package/dist/scenarios/scenario.js +41 -0
- package/dist/scenarios/scenario.js.map +1 -0
- package/dist/scenarios/storage.d.ts +51 -0
- package/dist/scenarios/storage.d.ts.map +1 -0
- package/dist/scenarios/storage.js +93 -0
- package/dist/scenarios/storage.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +6 -3
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +68 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +89 -0
- package/dist/session.js.map +1 -1
- package/dist/tools/analyze.d.ts +41 -1
- package/dist/tools/analyze.d.ts.map +1 -1
- package/dist/tools/analyze.js +81 -8
- package/dist/tools/analyze.js.map +1 -1
- package/dist/tools/browser-click.d.ts +36 -0
- package/dist/tools/browser-click.d.ts.map +1 -0
- package/dist/tools/browser-click.js +117 -0
- package/dist/tools/browser-click.js.map +1 -0
- package/dist/tools/browser-close-session.d.ts +24 -0
- package/dist/tools/browser-close-session.d.ts.map +1 -0
- package/dist/tools/browser-close-session.js +63 -0
- package/dist/tools/browser-close-session.js.map +1 -0
- package/dist/tools/browser-fill.d.ts +49 -0
- package/dist/tools/browser-fill.d.ts.map +1 -0
- package/dist/tools/browser-fill.js +138 -0
- package/dist/tools/browser-fill.js.map +1 -0
- package/dist/tools/browser-navigate.d.ts +32 -0
- package/dist/tools/browser-navigate.d.ts.map +1 -0
- package/dist/tools/browser-navigate.js +103 -0
- package/dist/tools/browser-navigate.js.map +1 -0
- package/dist/tools/browser-run-scenario.d.ts +54 -0
- package/dist/tools/browser-run-scenario.d.ts.map +1 -0
- package/dist/tools/browser-run-scenario.js +228 -0
- package/dist/tools/browser-run-scenario.js.map +1 -0
- package/dist/tools/browser-save-scenario.d.ts +44 -0
- package/dist/tools/browser-save-scenario.d.ts.map +1 -0
- package/dist/tools/browser-save-scenario.js +298 -0
- package/dist/tools/browser-save-scenario.js.map +1 -0
- package/dist/tools/browser-snapshot.d.ts +60 -0
- package/dist/tools/browser-snapshot.d.ts.map +1 -0
- package/dist/tools/browser-snapshot.js +139 -0
- package/dist/tools/browser-snapshot.js.map +1 -0
- package/dist/tools/browser-start-session.d.ts +43 -0
- package/dist/tools/browser-start-session.d.ts.map +1 -0
- package/dist/tools/browser-start-session.js +272 -0
- package/dist/tools/browser-start-session.js.map +1 -0
- package/dist/tools/browser-type.d.ts +48 -0
- package/dist/tools/browser-type.d.ts.map +1 -0
- package/dist/tools/browser-type.js +136 -0
- package/dist/tools/browser-type.js.map +1 -0
- package/dist/tools/contracts.d.ts +15 -0
- package/dist/tools/contracts.d.ts.map +1 -1
- package/dist/tools/contracts.js +14 -3
- package/dist/tools/contracts.js.map +1 -1
- package/dist/tools/git-diff.d.ts.map +1 -1
- package/dist/tools/git-diff.js +85 -6
- package/dist/tools/git-diff.js.map +1 -1
- package/dist/tools/impact.d.ts +9 -0
- package/dist/tools/impact.d.ts.map +1 -1
- package/dist/tools/impact.js +3 -3
- package/dist/tools/impact.js.map +1 -1
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +27 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/kit.d.ts +10 -1
- package/dist/tools/kit.d.ts.map +1 -1
- package/dist/tools/kit.js +2 -0
- package/dist/tools/kit.js.map +1 -1
- package/dist/tools/observe-runtime.d.ts +113 -19
- package/dist/tools/observe-runtime.d.ts.map +1 -1
- package/dist/tools/observe-runtime.js +324 -53
- package/dist/tools/observe-runtime.js.map +1 -1
- package/dist/tools/observe-tests.d.ts +125 -0
- package/dist/tools/observe-tests.d.ts.map +1 -0
- package/dist/tools/observe-tests.js +313 -0
- package/dist/tools/observe-tests.js.map +1 -0
- package/dist/tools/pr-analysis.d.ts +11 -0
- package/dist/tools/pr-analysis.d.ts.map +1 -1
- package/dist/tools/pr-analysis.js +3 -3
- package/dist/tools/pr-analysis.js.map +1 -1
- package/dist/tools/pre-push.d.ts +77 -0
- package/dist/tools/pre-push.d.ts.map +1 -0
- package/dist/tools/pre-push.js +250 -0
- package/dist/tools/pre-push.js.map +1 -0
- package/dist/tools/questions.d.ts.map +1 -1
- package/dist/tools/questions.js +41 -16
- package/dist/tools/questions.js.map +1 -1
- package/dist/tools/verification-status.d.ts +22 -0
- package/dist/tools/verification-status.d.ts.map +1 -1
- package/dist/tools/verification-status.js +51 -5
- package/dist/tools/verification-status.js.map +1 -1
- package/package.json +14 -13
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `BrowserDriver` with no browser behind it.
|
|
3
|
+
*
|
|
4
|
+
* Not a stub. It implements every rule the port states — ref issuance and
|
|
5
|
+
* invalidation, drain-not-peek, crash invalidation, idempotent close that
|
|
6
|
+
* still flushes — and `browser-driver-contract.test.ts` runs the same
|
|
7
|
+
* assertions against it that the real driver will have to pass. Its purpose
|
|
8
|
+
* is to make those rules *checkable in milliseconds*, so the session
|
|
9
|
+
* lifecycle in §4 is tested against timeouts, disconnects and crashes that
|
|
10
|
+
* would otherwise each need a real Chromium.
|
|
11
|
+
*
|
|
12
|
+
* Two deliberate non-goals. It does not simulate a page — pages are declared
|
|
13
|
+
* with `setPage`, because a fake DOM would be a second, wrong browser. And it
|
|
14
|
+
* does not classify anything, for the same structural reason the port does
|
|
15
|
+
* not: there is nowhere to put a verdict.
|
|
16
|
+
*/
|
|
17
|
+
import { randomUUID } from "node:crypto";
|
|
18
|
+
import { BrowserSessionCrashedError, UnknownElementRefError, } from "./driver.js";
|
|
19
|
+
const EMPTY_PAGE = (url) => ({ url, title: "", elements: [] });
|
|
20
|
+
export function createFakeBrowserDriver() {
|
|
21
|
+
const pages = new Map();
|
|
22
|
+
const states = new Map();
|
|
23
|
+
let chromiumMissing = null;
|
|
24
|
+
// Monotonic across the driver, so a ref from one session can never resolve
|
|
25
|
+
// in another — the same property real refs have by being page-scoped.
|
|
26
|
+
let snapshotGeneration = 0;
|
|
27
|
+
function stateOf(sessionId) {
|
|
28
|
+
const state = states.get(sessionId);
|
|
29
|
+
if (state === undefined)
|
|
30
|
+
throw new Error(`no such fake session: ${sessionId}`);
|
|
31
|
+
return state;
|
|
32
|
+
}
|
|
33
|
+
function drain(state) {
|
|
34
|
+
const observation = {
|
|
35
|
+
actions: state.buffer.actions,
|
|
36
|
+
consoleErrors: state.buffer.consoleErrors,
|
|
37
|
+
requests: state.buffer.requests,
|
|
38
|
+
};
|
|
39
|
+
state.buffer.actions = [];
|
|
40
|
+
state.buffer.consoleErrors = [];
|
|
41
|
+
state.buffer.requests = [];
|
|
42
|
+
return observation;
|
|
43
|
+
}
|
|
44
|
+
function openSession(targetUrl) {
|
|
45
|
+
const sessionId = randomUUID();
|
|
46
|
+
let url = targetUrl;
|
|
47
|
+
// Refs live here, keyed by the generation that issued them. Navigation
|
|
48
|
+
// replaces the map wholesale, which is what makes a stale ref refuse
|
|
49
|
+
// rather than resolve against a page nobody inspected.
|
|
50
|
+
let refs = new Map();
|
|
51
|
+
const buffer = { actions: [], consoleErrors: [], requests: [] };
|
|
52
|
+
function assertUsable() {
|
|
53
|
+
const state = states.get(sessionId);
|
|
54
|
+
if (state !== undefined && (state.crashed || state.closed))
|
|
55
|
+
throw new BrowserSessionCrashedError(sessionId);
|
|
56
|
+
}
|
|
57
|
+
function resolve(ref) {
|
|
58
|
+
const element = refs.get(ref);
|
|
59
|
+
if (element === undefined)
|
|
60
|
+
throw new UnknownElementRefError(ref);
|
|
61
|
+
return element;
|
|
62
|
+
}
|
|
63
|
+
function record(action, ref, mode = null) {
|
|
64
|
+
buffer.actions.push({ action, ref, mode, url, at: new Date().toISOString() });
|
|
65
|
+
}
|
|
66
|
+
const session = {
|
|
67
|
+
sessionId,
|
|
68
|
+
startedAt: new Date().toISOString(),
|
|
69
|
+
isUsable() {
|
|
70
|
+
const state = states.get(sessionId);
|
|
71
|
+
return state !== undefined && !state.crashed && !state.closed;
|
|
72
|
+
},
|
|
73
|
+
currentUrl: () => url,
|
|
74
|
+
async navigate(to) {
|
|
75
|
+
assertUsable();
|
|
76
|
+
url = to;
|
|
77
|
+
refs = new Map();
|
|
78
|
+
record("navigate", null);
|
|
79
|
+
},
|
|
80
|
+
async snapshot() {
|
|
81
|
+
assertUsable();
|
|
82
|
+
const page = pages.get(url) ?? EMPTY_PAGE(url);
|
|
83
|
+
snapshotGeneration += 1;
|
|
84
|
+
refs = new Map(page.elements.map((element, index) => {
|
|
85
|
+
const ref = `ref-${snapshotGeneration}-${index}`;
|
|
86
|
+
return [ref, { ref, role: element.role, name: element.name, selector: element.selector }];
|
|
87
|
+
}));
|
|
88
|
+
const elements = [...refs.values()];
|
|
89
|
+
return { url, title: page.title, elements, totalElements: elements.length };
|
|
90
|
+
},
|
|
91
|
+
async click(ref) {
|
|
92
|
+
assertUsable();
|
|
93
|
+
resolve(ref);
|
|
94
|
+
record("click", ref);
|
|
95
|
+
},
|
|
96
|
+
async type(ref, _text) {
|
|
97
|
+
assertUsable();
|
|
98
|
+
resolve(ref);
|
|
99
|
+
record("type", ref, "append");
|
|
100
|
+
},
|
|
101
|
+
async fill(ref, _text) {
|
|
102
|
+
assertUsable();
|
|
103
|
+
resolve(ref);
|
|
104
|
+
record("fill", ref, "replace");
|
|
105
|
+
},
|
|
106
|
+
async drainEvidence() {
|
|
107
|
+
// Deliberately usable on a crashed session: the whole point of the
|
|
108
|
+
// flush-on-every-path rule is that a crash must not take the evidence
|
|
109
|
+
// that preceded it.
|
|
110
|
+
return drain(stateOf(sessionId));
|
|
111
|
+
},
|
|
112
|
+
async close() {
|
|
113
|
+
const state = stateOf(sessionId);
|
|
114
|
+
state.closed = true;
|
|
115
|
+
return drain(state);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
states.set(sessionId, { session, buffer, crashed: false, closed: false });
|
|
119
|
+
return session;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
async launch(options) {
|
|
123
|
+
if (chromiumMissing !== null) {
|
|
124
|
+
return {
|
|
125
|
+
launched: false,
|
|
126
|
+
refusal: "chromiumNotInstalled",
|
|
127
|
+
message: "No Chromium executable at /fake/path/chrome. This package depends on playwright-core, which does " +
|
|
128
|
+
"not download a browser on install, so one has to be installed once before a browser session can launch.",
|
|
129
|
+
remedy: chromiumMissing.remedy,
|
|
130
|
+
expectedExecutablePath: "/fake/path/chrome",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return { launched: true, session: openSession(options.targetUrl) };
|
|
134
|
+
},
|
|
135
|
+
setPage(url, page) {
|
|
136
|
+
pages.set(url, page);
|
|
137
|
+
},
|
|
138
|
+
setChromiumMissing(remedy = "npx playwright install chromium") {
|
|
139
|
+
// A remedy string is required rather than defaulted to empty: the
|
|
140
|
+
// contract test asserts one is present, and a fake that could refuse
|
|
141
|
+
// without one would let the real driver ship without one too.
|
|
142
|
+
chromiumMissing = { remedy };
|
|
143
|
+
},
|
|
144
|
+
emitConsoleError(sessionId, error) {
|
|
145
|
+
stateOf(sessionId).buffer.consoleErrors.push({ ...error, at: new Date().toISOString() });
|
|
146
|
+
},
|
|
147
|
+
emitRequest(sessionId, request) {
|
|
148
|
+
stateOf(sessionId).buffer.requests.push({ stackTrace: null, ...request, at: new Date().toISOString() });
|
|
149
|
+
},
|
|
150
|
+
emitFailedRequest(sessionId, request) {
|
|
151
|
+
stateOf(sessionId).buffer.requests.push({ ...request, stackTrace: null, at: new Date().toISOString() });
|
|
152
|
+
},
|
|
153
|
+
crash(sessionId) {
|
|
154
|
+
stateOf(sessionId).crashed = true;
|
|
155
|
+
},
|
|
156
|
+
openSessionIds() {
|
|
157
|
+
return [...states.entries()].filter(([, state]) => !state.closed).map(([id]) => id);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=fake-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-driver.js","sourceRoot":"","sources":["../../src/browser/fake-driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §5.4 — the payoff. A real browser action becomes a real R4 edge.
|
|
3
|
+
*
|
|
4
|
+
* ## What this closes
|
|
5
|
+
*
|
|
6
|
+
* The UAT's verdict on runtime evidence was that it proves *"this line
|
|
7
|
+
* touched this function"* and never *"this frontend action reached this
|
|
8
|
+
* backend route"* — the cross-boundary confirmation the product's own
|
|
9
|
+
* description leads with. Everything needed for the second claim was built
|
|
10
|
+
* and none of it was joined: the browser package captures a real `fetch()`
|
|
11
|
+
* call-site stack, `confirmObservedFrontendCaller` writes R4 from one, and
|
|
12
|
+
* `applyRuntimeObservations` is the write path. This module is the join,
|
|
13
|
+
* reached from an MCP tool call.
|
|
14
|
+
*
|
|
15
|
+
* ## Why the edge matters more than the reply
|
|
16
|
+
*
|
|
17
|
+
* `impact` and `propagation` already join a frontend caller to a backend
|
|
18
|
+
* route by **comparing `"GET /business-info"` as a string on both sides**.
|
|
19
|
+
* That is an R1 name match: it is right often and it cannot know when it is
|
|
20
|
+
* wrong. What this writes is the same edge *witnessed* — a real click, a real
|
|
21
|
+
* request, a real call-site stack resolved to a real file — at `resolution:
|
|
22
|
+
* 4` carrying the run that saw it. No new query tool is needed and none is
|
|
23
|
+
* added: `impact` and the rest already read `resolution` and pick these up.
|
|
24
|
+
*
|
|
25
|
+
* ## Precision over recall, enforced by omission
|
|
26
|
+
*
|
|
27
|
+
* Every step that cannot be established drops the observation entirely rather
|
|
28
|
+
* than weakening it. No parsed stack, no endpoint resolved, an ambiguous
|
|
29
|
+
* match — each produces **no edge**, not a low-confidence one. A wrong edge
|
|
30
|
+
* corrupts diff scoping, impact scores and root-cause traversal on every
|
|
31
|
+
* later run; a missing one is a disclosed gap, and the disclosures below are
|
|
32
|
+
* how it gets disclosed.
|
|
33
|
+
*
|
|
34
|
+
* Note also what is *not* here: no denial. A run establishes that a call
|
|
35
|
+
* happened and can never establish that one did not — a page visit exercises
|
|
36
|
+
* one path, and the absence of a stack for some other function is absence of
|
|
37
|
+
* evidence. `confirmObservedFrontendCaller` refuses to mint denials for the
|
|
38
|
+
* same reason; this caller must not reintroduce one by another route.
|
|
39
|
+
*/
|
|
40
|
+
import type { SqlDriver } from "@descryy/core";
|
|
41
|
+
import { type ObservedRequest } from "./driver.ts";
|
|
42
|
+
/** A graph node this browser evidence actually reached — §5.3's "any graph node reached, surfaced in the same reply". */
|
|
43
|
+
export interface ReachedNode {
|
|
44
|
+
readonly nodeId: string;
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly type: string;
|
|
47
|
+
/** The request that reached it, so a reader can see which action this was. */
|
|
48
|
+
readonly via: {
|
|
49
|
+
readonly method: string;
|
|
50
|
+
readonly url: string;
|
|
51
|
+
readonly status: number | null;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export interface BrowserGraphWrite {
|
|
55
|
+
/** Endpoints the page's own requests resolved to, whether or not an edge was written. */
|
|
56
|
+
readonly reached: readonly ReachedNode[];
|
|
57
|
+
/** Existing edges promoted to R4 by this observation. */
|
|
58
|
+
readonly promoted: readonly string[];
|
|
59
|
+
/** Edges the structural side never named, minted at R4 — the recall gap closing. */
|
|
60
|
+
readonly created: readonly string[];
|
|
61
|
+
/** Reasons an observation was declined. Kept, because a silent drop is indistinguishable from nothing having happened. */
|
|
62
|
+
readonly refused: readonly string[];
|
|
63
|
+
/** R4-vs-R4 disagreements, passed through untouched — this module does not adjudicate them. */
|
|
64
|
+
readonly contradictions: readonly string[];
|
|
65
|
+
}
|
|
66
|
+
export declare const NO_GRAPH_WRITE: BrowserGraphWrite;
|
|
67
|
+
export interface BrowserGraphWriteInput {
|
|
68
|
+
readonly driver: SqlDriver;
|
|
69
|
+
readonly repo: string;
|
|
70
|
+
readonly runId: string;
|
|
71
|
+
readonly commitSha: string;
|
|
72
|
+
readonly repoRoot: string;
|
|
73
|
+
readonly requests: readonly ObservedRequest[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Correlate what the page did against the graph, and record what was
|
|
77
|
+
* genuinely witnessed.
|
|
78
|
+
*
|
|
79
|
+
* Runs over **every** request, not only the failures. A successful call is
|
|
80
|
+
* the thing that proves the arrow; narrowing to failures here would mean the
|
|
81
|
+
* feature only ever confirmed edges on broken pages.
|
|
82
|
+
*/
|
|
83
|
+
export declare function writeBrowserObservations(input: BrowserGraphWriteInput): BrowserGraphWrite;
|
|
84
|
+
/** What a reply says about a write. Empty when nothing was reached — silence about nothing is not a disclosure gap. */
|
|
85
|
+
export declare function graphWriteNotes(write: BrowserGraphWrite, requests: readonly ObservedRequest[]): string[];
|
|
86
|
+
//# sourceMappingURL=graph-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-write.d.ts","sourceRoot":"","sources":["../../src/browser/graph-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpE,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,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;CAC5C;AAED,eAAO,MAAM,cAAc,EAAE,iBAA+F,CAAC;AAE7H,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;CAC/C;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,sBAAsB,GAAG,iBAAiB,CAiEzF;AAED,uHAAuH;AACvH,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,EAAE,CAiCxG"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §5.4 — the payoff. A real browser action becomes a real R4 edge.
|
|
3
|
+
*
|
|
4
|
+
* ## What this closes
|
|
5
|
+
*
|
|
6
|
+
* The UAT's verdict on runtime evidence was that it proves *"this line
|
|
7
|
+
* touched this function"* and never *"this frontend action reached this
|
|
8
|
+
* backend route"* — the cross-boundary confirmation the product's own
|
|
9
|
+
* description leads with. Everything needed for the second claim was built
|
|
10
|
+
* and none of it was joined: the browser package captures a real `fetch()`
|
|
11
|
+
* call-site stack, `confirmObservedFrontendCaller` writes R4 from one, and
|
|
12
|
+
* `applyRuntimeObservations` is the write path. This module is the join,
|
|
13
|
+
* reached from an MCP tool call.
|
|
14
|
+
*
|
|
15
|
+
* ## Why the edge matters more than the reply
|
|
16
|
+
*
|
|
17
|
+
* `impact` and `propagation` already join a frontend caller to a backend
|
|
18
|
+
* route by **comparing `"GET /business-info"` as a string on both sides**.
|
|
19
|
+
* That is an R1 name match: it is right often and it cannot know when it is
|
|
20
|
+
* wrong. What this writes is the same edge *witnessed* — a real click, a real
|
|
21
|
+
* request, a real call-site stack resolved to a real file — at `resolution:
|
|
22
|
+
* 4` carrying the run that saw it. No new query tool is needed and none is
|
|
23
|
+
* added: `impact` and the rest already read `resolution` and pick these up.
|
|
24
|
+
*
|
|
25
|
+
* ## Precision over recall, enforced by omission
|
|
26
|
+
*
|
|
27
|
+
* Every step that cannot be established drops the observation entirely rather
|
|
28
|
+
* than weakening it. No parsed stack, no endpoint resolved, an ambiguous
|
|
29
|
+
* match — each produces **no edge**, not a low-confidence one. A wrong edge
|
|
30
|
+
* corrupts diff scoping, impact scores and root-cause traversal on every
|
|
31
|
+
* later run; a missing one is a disclosed gap, and the disclosures below are
|
|
32
|
+
* how it gets disclosed.
|
|
33
|
+
*
|
|
34
|
+
* Note also what is *not* here: no denial. A run establishes that a call
|
|
35
|
+
* happened and can never establish that one did not — a page visit exercises
|
|
36
|
+
* one path, and the absence of a stack for some other function is absence of
|
|
37
|
+
* evidence. `confirmObservedFrontendCaller` refuses to mint denials for the
|
|
38
|
+
* same reason; this caller must not reintroduce one by another route.
|
|
39
|
+
*/
|
|
40
|
+
import { confirmObservedFrontendCaller, resolveEndpointNode } from "@descryy/runtime-graph-correlator";
|
|
41
|
+
import { isFailedRequest } from "./driver.js";
|
|
42
|
+
export const NO_GRAPH_WRITE = { reached: [], promoted: [], created: [], refused: [], contradictions: [] };
|
|
43
|
+
/**
|
|
44
|
+
* Correlate what the page did against the graph, and record what was
|
|
45
|
+
* genuinely witnessed.
|
|
46
|
+
*
|
|
47
|
+
* Runs over **every** request, not only the failures. A successful call is
|
|
48
|
+
* the thing that proves the arrow; narrowing to failures here would mean the
|
|
49
|
+
* feature only ever confirmed edges on broken pages.
|
|
50
|
+
*/
|
|
51
|
+
export function writeBrowserObservations(input) {
|
|
52
|
+
const reached = [];
|
|
53
|
+
const promoted = [];
|
|
54
|
+
const created = [];
|
|
55
|
+
const refused = [];
|
|
56
|
+
const contradictions = [];
|
|
57
|
+
const seen = new Set();
|
|
58
|
+
for (const request of input.requests) {
|
|
59
|
+
let path;
|
|
60
|
+
try {
|
|
61
|
+
path = new URL(request.url).pathname;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const resolution = resolveEndpointNode(input.driver, request.method, path);
|
|
67
|
+
if (resolution.outcome !== "resolved") {
|
|
68
|
+
// Not a refusal worth reporting per request: a page issues requests for
|
|
69
|
+
// stylesheets, images and third-party origins, and none of them is
|
|
70
|
+
// meant to be an endpoint in this graph. Reporting each as a miss would
|
|
71
|
+
// bury the real ones.
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const endpoint = resolution.node;
|
|
75
|
+
const key = `${endpoint.id}::${request.method}::${path}`;
|
|
76
|
+
if (!seen.has(key)) {
|
|
77
|
+
seen.add(key);
|
|
78
|
+
reached.push({
|
|
79
|
+
nodeId: endpoint.id,
|
|
80
|
+
name: endpoint.name,
|
|
81
|
+
type: endpoint.type,
|
|
82
|
+
via: { method: request.method, url: request.url, status: request.status },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (request.stackTrace === null) {
|
|
86
|
+
// The endpoint was reached and we can say so; the *caller* half needs a
|
|
87
|
+
// parsed stack and there is none. Disclosed rather than dropped,
|
|
88
|
+
// because "we saw this route get hit but could not tell you from where"
|
|
89
|
+
// is a real, useful, incomplete answer.
|
|
90
|
+
refused.push(`${request.method} ${path} reached ${endpoint.name}, but no parsed call-site stack was captured, so no ` +
|
|
91
|
+
"caller edge was written. Name a stackParser on browser_start_session to capture one.");
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const outcome = confirmObservedFrontendCaller(input.driver, {
|
|
95
|
+
endpointNodeId: endpoint.id,
|
|
96
|
+
stackTrace: request.stackTrace,
|
|
97
|
+
repo: input.repo,
|
|
98
|
+
runId: input.runId,
|
|
99
|
+
commitSha: input.commitSha,
|
|
100
|
+
repoRoot: input.repoRoot,
|
|
101
|
+
});
|
|
102
|
+
promoted.push(...outcome.confirmation.promoted);
|
|
103
|
+
created.push(...outcome.confirmation.created);
|
|
104
|
+
refused.push(...outcome.confirmation.refused.map((r) => r.reason));
|
|
105
|
+
contradictions.push(...outcome.confirmation.contradictions.map((c) => c.detail));
|
|
106
|
+
}
|
|
107
|
+
return { reached, promoted, created, refused, contradictions };
|
|
108
|
+
}
|
|
109
|
+
/** What a reply says about a write. Empty when nothing was reached — silence about nothing is not a disclosure gap. */
|
|
110
|
+
export function graphWriteNotes(write, requests) {
|
|
111
|
+
const notes = [];
|
|
112
|
+
const confirmed = write.promoted.length + write.created.length;
|
|
113
|
+
if (confirmed > 0) {
|
|
114
|
+
notes.push(`${confirmed} frontend→backend edge(s) were confirmed at resolution 4 from this run — ` +
|
|
115
|
+
`${write.promoted.length} existing edge(s) promoted, ${write.created.length} minted that static ` +
|
|
116
|
+
"analysis had not found. These are witnessed, not name-matched: a real request carrying a real " +
|
|
117
|
+
"call-site stack. impact and propagation read them with no further action.");
|
|
118
|
+
}
|
|
119
|
+
if (write.reached.length > 0 && confirmed === 0) {
|
|
120
|
+
notes.push(`${write.reached.length} endpoint(s) in the graph were reached by this page, but no caller edge was ` +
|
|
121
|
+
"written — see the refusals for why. The endpoints are named so the gap is visible rather than absent.");
|
|
122
|
+
}
|
|
123
|
+
if (write.contradictions.length > 0) {
|
|
124
|
+
notes.push(`${write.contradictions.length} observation(s) disagree with an existing R4 edge. Reported, not resolved: ` +
|
|
125
|
+
"adjudicating two runtime observations against each other is not this call's job.");
|
|
126
|
+
}
|
|
127
|
+
const unexplained = requests.filter((r) => r.stackTrace === null && !isFailedRequest(r)).length;
|
|
128
|
+
if (unexplained > 0 && confirmed === 0 && write.reached.length === 0) {
|
|
129
|
+
notes.push(`${requests.length} request(s) were observed and none resolved to an endpoint in the graph. If this ` +
|
|
130
|
+
"repository has not been analysed, run analyze first — nothing here can be related to code the graph " +
|
|
131
|
+
"does not hold.");
|
|
132
|
+
}
|
|
133
|
+
return notes;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=graph-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-write.js","sourceRoot":"","sources":["../../src/browser/graph-write.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The real `BrowserDriver`, over `@descryy/runtime-browser`.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the import is dynamic
|
|
5
|
+
*
|
|
6
|
+
* `@descryy/runtime-browser` is not on the npm registry yet
|
|
7
|
+
* (`mcp-browser-tools.md` §3.1 — the publish returns 429 on new-scoped-package
|
|
8
|
+
* creation). Declaring it in `package.json` today would break `npm install`
|
|
9
|
+
* for everyone, including the lanes that never touch a browser. So it is
|
|
10
|
+
* imported by specifier at call time and its absence is a **named refusal
|
|
11
|
+
* with a remedy**, exactly as a missing Chromium is.
|
|
12
|
+
*
|
|
13
|
+
* That is a temporary shape and it is written down as one: the final swap
|
|
14
|
+
* (§8's tool-count item) declares the dependency and makes this a static
|
|
15
|
+
* import. What must *not* happen in the meantime is the tools quietly
|
|
16
|
+
* appearing to work — see `provider.ts`.
|
|
17
|
+
*
|
|
18
|
+
* ## What this adds over the runtime package, and what it deliberately does not
|
|
19
|
+
*
|
|
20
|
+
* It adds exactly one thing the runtime has no API for: **element refs.** The
|
|
21
|
+
* port's contract is that an action names an element the agent has seen, and
|
|
22
|
+
* `BrowserActionCollector` acts on raw selectors. So this module enumerates
|
|
23
|
+
* the page's interactive elements, holds a Playwright `ElementHandle` per ref,
|
|
24
|
+
* and drops the whole map on navigation. Handles rather than injected `data-`
|
|
25
|
+
* attributes on purpose: stamping the DOM would make the act of observing
|
|
26
|
+
* change the page being observed, and a detached element then fails naturally
|
|
27
|
+
* instead of resolving to whatever took its place.
|
|
28
|
+
*
|
|
29
|
+
* Everything else is composition. Launch, click, type, fill, console capture,
|
|
30
|
+
* network capture, the `fetch()` initiator stack and its source-map rewrite
|
|
31
|
+
* are all the runtime package's, called rather than reimplemented.
|
|
32
|
+
*
|
|
33
|
+
* ## Rule 1
|
|
34
|
+
*
|
|
35
|
+
* No language is named here. The stack-trace parser that turns a raw browser
|
|
36
|
+
* stack into resolved frames is handed in by the caller as a module specifier
|
|
37
|
+
* — the same mechanism `runtime-registry.ts` uses for runtime adapters, for
|
|
38
|
+
* the same reason. Without one, requests are still observed and no caller
|
|
39
|
+
* edge is written; the reply says so.
|
|
40
|
+
*/
|
|
41
|
+
import type { ServiceRootLookup } from "@descryy/runtime-contracts";
|
|
42
|
+
import type { StackTraceParser } from "@descryy/runtime-backend-observation";
|
|
43
|
+
import type { BrowserDriver } from "./driver.ts";
|
|
44
|
+
export interface PlaywrightDriverOptions {
|
|
45
|
+
/**
|
|
46
|
+
* Turns a raw browser stack into resolved frames. Supplied by the caller;
|
|
47
|
+
* this package cannot construct one without naming a language.
|
|
48
|
+
*
|
|
49
|
+
* Absent, the initiator capture is not installed at all — the runtime's own
|
|
50
|
+
* two-halves-or-neither rule — so no request carries a call site and no R4
|
|
51
|
+
* caller edge can be written.
|
|
52
|
+
*/
|
|
53
|
+
readonly stackParser?: StackTraceParser;
|
|
54
|
+
/** Maps a page origin to the on-disk root that served it. Absent means script URLs stay unresolved. */
|
|
55
|
+
readonly resolveSourceRoot?: SourceRootResolver;
|
|
56
|
+
/** Which service the evidence is attributed to. */
|
|
57
|
+
readonly service?: string;
|
|
58
|
+
}
|
|
59
|
+
type SourceRootResolver = (origin: string) => ServiceRootLookup;
|
|
60
|
+
export declare class BrowserBackendMissingError extends Error {
|
|
61
|
+
constructor(cause: unknown);
|
|
62
|
+
}
|
|
63
|
+
export declare function createPlaywrightBrowserDriver(options?: PlaywrightDriverOptions): Promise<BrowserDriver>;
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=playwright-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-driver.d.ts","sourceRoot":"","sources":["../../src/browser/playwright-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,KAAK,EAAc,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAmB7E,OAAO,KAAK,EACV,aAAa,EAUd,MAAM,aAAa,CAAC;AAgBrB,MAAM,WAAW,uBAAuB;IACtC;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IACxC,uGAAuG;IACvG,QAAQ,CAAC,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;IAChD,mDAAmD;IACnD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,KAAK,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,iBAAiB,CAAC;AA+ChE,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,KAAK,EAAE,OAAO;CAO3B;AAgBD,wBAAsB,6BAA6B,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAAC,aAAa,CAAC,CAmBjH"}
|