@dreamdata_io/verify-tracking 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +756 -0
- package/dist/ai/checker.js +222 -0
- package/dist/ai/checker.js.map +1 -0
- package/dist/ai/checklist.js +190 -0
- package/dist/ai/checklist.js.map +1 -0
- package/dist/ai/cli-presets.js +27 -0
- package/dist/ai/cli-presets.js.map +1 -0
- package/dist/ai/evidence-view.js +143 -0
- package/dist/ai/evidence-view.js.map +1 -0
- package/dist/ai/local-cli.js +58 -0
- package/dist/ai/local-cli.js.map +1 -0
- package/dist/ai/openai-compatible.js +78 -0
- package/dist/ai/openai-compatible.js.map +1 -0
- package/dist/ai/response-parser.js +105 -0
- package/dist/ai/response-parser.js.map +1 -0
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/analysis/consent-mode.js +225 -0
- package/dist/analysis/consent-mode.js.map +1 -0
- package/dist/analysis/deployment.js +2658 -0
- package/dist/analysis/deployment.js.map +1 -0
- package/dist/analysis/diagnosis/copy.en.js +303 -0
- package/dist/analysis/diagnosis/copy.en.js.map +1 -0
- package/dist/analysis/diagnosis/diagnose.js +172 -0
- package/dist/analysis/diagnosis/diagnose.js.map +1 -0
- package/dist/analysis/diagnosis/docs.js +118 -0
- package/dist/analysis/diagnosis/docs.js.map +1 -0
- package/dist/analysis/diagnosis/index.js +5 -0
- package/dist/analysis/diagnosis/index.js.map +1 -0
- package/dist/analysis/diagnosis/rules.js +656 -0
- package/dist/analysis/diagnosis/rules.js.map +1 -0
- package/dist/analysis/diagnosis/types.js +2 -0
- package/dist/analysis/diagnosis/types.js.map +1 -0
- package/dist/cli.js +344 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/env.js +100 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/preflight.js +167 -0
- package/dist/config/preflight.js.map +1 -0
- package/dist/config/user-config.js +79 -0
- package/dist/config/user-config.js.map +1 -0
- package/dist/evidence/collect.js +527 -0
- package/dist/evidence/collect.js.map +1 -0
- package/dist/evidence/consent-accept.js +377 -0
- package/dist/evidence/consent-accept.js.map +1 -0
- package/dist/evidence/consent.js +340 -0
- package/dist/evidence/consent.js.map +1 -0
- package/dist/evidence/constants.js +615 -0
- package/dist/evidence/constants.js.map +1 -0
- package/dist/evidence/globals.js +132 -0
- package/dist/evidence/globals.js.map +1 -0
- package/dist/evidence/gtm-container.js +432 -0
- package/dist/evidence/gtm-container.js.map +1 -0
- package/dist/evidence/heuristic-banner.js +107 -0
- package/dist/evidence/heuristic-banner.js.map +1 -0
- package/dist/evidence/http-probe.js +139 -0
- package/dist/evidence/http-probe.js.map +1 -0
- package/dist/evidence/init-script.js +112 -0
- package/dist/evidence/init-script.js.map +1 -0
- package/dist/evidence/network.js +365 -0
- package/dist/evidence/network.js.map +1 -0
- package/dist/evidence/preference-center.js +368 -0
- package/dist/evidence/preference-center.js.map +1 -0
- package/dist/evidence/script.js +425 -0
- package/dist/evidence/script.js.map +1 -0
- package/dist/evidence/second-page.js +332 -0
- package/dist/evidence/second-page.js.map +1 -0
- package/dist/evidence/selector-probe.js +53 -0
- package/dist/evidence/selector-probe.js.map +1 -0
- package/dist/evidence/stealth.js +21 -0
- package/dist/evidence/stealth.js.map +1 -0
- package/dist/evidence/types.js +14 -0
- package/dist/evidence/types.js.map +1 -0
- package/dist/interactive/prompt.js +31 -0
- package/dist/interactive/prompt.js.map +1 -0
- package/dist/mcp/server.js +308 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/summary.js +41 -0
- package/dist/mcp/summary.js.map +1 -0
- package/dist/report/context.js +184 -0
- package/dist/report/context.js.map +1 -0
- package/dist/report/projection.js +125 -0
- package/dist/report/projection.js.map +1 -0
- package/dist/report/quote-check.js +90 -0
- package/dist/report/quote-check.js.map +1 -0
- package/dist/report/render.js +178 -0
- package/dist/report/render.js.map +1 -0
- package/dist/report/serializers.js +124 -0
- package/dist/report/serializers.js.map +1 -0
- package/dist/report/store.js +139 -0
- package/dist/report/store.js.map +1 -0
- package/dist/run/verify.js +77 -0
- package/dist/run/verify.js.map +1 -0
- package/dist/utils/duration.js +10 -0
- package/dist/utils/duration.js.map +1 -0
- package/dist/utils/errors.js +17 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/runTimingsLog.js +27 -0
- package/dist/utils/runTimingsLog.js.map +1 -0
- package/dist/utils/slug.js +27 -0
- package/dist/utils/slug.js.map +1 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/package.json +57 -0
- package/scripts/install.sh +314 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The verification CLI as an MCP server.
|
|
4
|
+
*
|
|
5
|
+
* The point of running it this way is pairing it with chrome-devtools-mcp in
|
|
6
|
+
* one agent: this server measures (three consent states, each in its own
|
|
7
|
+
* fresh browser context, which is the only reason a consent verdict means
|
|
8
|
+
* anything), and DevTools is for following up on what the report said. The
|
|
9
|
+
* division matters — an agent that "re-checks" a consent verdict by driving
|
|
10
|
+
* one shared browser tab through accept and reject is measuring a page that
|
|
11
|
+
* already carries the previous answer's cookie, and will contradict a correct
|
|
12
|
+
* report with a confident wrong one.
|
|
13
|
+
*
|
|
14
|
+
* Run it directly (`bun run src/mcp/server.ts`) or via the `verify-tracking-mcp`
|
|
15
|
+
* bin. It speaks JSON-RPC over stdio, so nothing may write to stdout except
|
|
16
|
+
* the transport: see sendLogsToStderr below.
|
|
17
|
+
*/
|
|
18
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
19
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
import { ALL_PHASES } from "../evidence/types.js";
|
|
22
|
+
import { DEFAULT_TIMEOUT_MS, resolveAiTimeoutMs, resolveApiKey, resolveBackendType, resolveBaseUrl, resolveCliCmd, resolveCliPreset, resolveModel, } from "../config/env.js";
|
|
23
|
+
import { CHECKS_BEARING_ON } from "../ai/checklist.js";
|
|
24
|
+
import { checkQuote, resolveCitations } from "../report/quote-check.js";
|
|
25
|
+
import { findReportPath, listReports, readReport, valueAtPath } from "../report/store.js";
|
|
26
|
+
import { runVerification, writeDefaultArtifacts } from "../run/verify.js";
|
|
27
|
+
import { loadUserConfig } from "../config/user-config.js";
|
|
28
|
+
import { logger, sendLogsToStderr } from "../utils/logger.js";
|
|
29
|
+
import { isSafeSlug, slugFromUrl } from "../utils/slug.js";
|
|
30
|
+
import { summarizeRun } from "./summary.js";
|
|
31
|
+
import { VERSION } from "../version.js";
|
|
32
|
+
sendLogsToStderr();
|
|
33
|
+
// Same settings file the CLI reads, and read before anything resolves a
|
|
34
|
+
// backend or an output root from the environment: an operator who configured
|
|
35
|
+
// verify-tracking would otherwise find verify-tracking-mcp ignoring it.
|
|
36
|
+
const userConfigPath = loadUserConfig();
|
|
37
|
+
if (userConfigPath)
|
|
38
|
+
logger.debug(`Loaded settings from ${userConfigPath}`);
|
|
39
|
+
/**
|
|
40
|
+
* How often a long-running tool says it is still alive.
|
|
41
|
+
*
|
|
42
|
+
* A full run is minutes — three consent states, then a model that may be
|
|
43
|
+
* running on the same laptop — and a client that hears nothing for that long
|
|
44
|
+
* gives up on the call. The MCP spec has clients reset their timeout when a
|
|
45
|
+
* progress notification arrives, so the run reports in on this interval
|
|
46
|
+
* rather than asking every operator to raise a timeout by hand.
|
|
47
|
+
*/
|
|
48
|
+
const PROGRESS_HEARTBEAT_MS = 10_000;
|
|
49
|
+
/** Tool results are JSON — an agent reads them, and a model reasons better over structure than prose. */
|
|
50
|
+
function jsonResult(payload) {
|
|
51
|
+
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
52
|
+
}
|
|
53
|
+
function errorResult(message) {
|
|
54
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The backend comes from the environment, never from a tool argument.
|
|
58
|
+
*
|
|
59
|
+
* A tool call is model-authored text; letting it name a base URL would let
|
|
60
|
+
* anything the agent read on a page redirect this run's evidence — the whole
|
|
61
|
+
* payload, cookies and requests included — to a host of its choosing. The
|
|
62
|
+
* operator picks the backend in .env, the same way `bun run src/cli.ts` does.
|
|
63
|
+
*/
|
|
64
|
+
function backendFromEnv() {
|
|
65
|
+
const flags = { headed: false };
|
|
66
|
+
return {
|
|
67
|
+
type: resolveBackendType(flags),
|
|
68
|
+
baseUrl: resolveBaseUrl(flags),
|
|
69
|
+
apiKey: resolveApiKey(flags),
|
|
70
|
+
model: resolveModel(flags),
|
|
71
|
+
cliPreset: resolveCliPreset(flags),
|
|
72
|
+
cliCmd: resolveCliCmd(flags),
|
|
73
|
+
timeoutMs: resolveAiTimeoutMs(flags),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function loadReport(slug) {
|
|
77
|
+
if (!isSafeSlug(slug)) {
|
|
78
|
+
return { error: `Not a valid slug: "${slug}". Slugs are letters, digits, "_" and "-" (e.g. clio_com).` };
|
|
79
|
+
}
|
|
80
|
+
const path = findReportPath(slug);
|
|
81
|
+
if (!path) {
|
|
82
|
+
return { error: `No report for "${slug}" under verification/reports/. Call list_reports to see what is there.` };
|
|
83
|
+
}
|
|
84
|
+
return { report: (await readReport(path)), path };
|
|
85
|
+
}
|
|
86
|
+
const server = new McpServer({ name: "verify-tracking", version: VERSION });
|
|
87
|
+
server.registerTool("verify_tracking", {
|
|
88
|
+
title: "Verify a Dreamdata Analytics Script install",
|
|
89
|
+
description: "Walk a site in a headless browser across three consent states (clean, grant, reject — each in its own fresh " +
|
|
90
|
+
"browser context), analyse the install deterministically, and score it against the installation checklist. " +
|
|
91
|
+
"Writes verification/reports/<slug>_report.json and returns a summary plus that path — not the full evidence, " +
|
|
92
|
+
"which runs 40-50KB. Takes minutes: three states, each loading two pages. Use read_report/explain_verdict " +
|
|
93
|
+
"to dig into the result, and browser tools only to follow up on what it says — never to re-measure a consent verdict, " +
|
|
94
|
+
"which needs the per-state context isolation only this tool has.",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
url: z.string().url().describe("Page to check, e.g. https://www.example.com/"),
|
|
97
|
+
slug: z
|
|
98
|
+
.string()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("Account this run is filed under; names the report file. Defaults to the URL's hostname with dots as " +
|
|
101
|
+
"underscores — pass it when the page under test is not on the account's own domain (a login host, a " +
|
|
102
|
+
"marketing subdomain), or that run files under the wrong account."),
|
|
103
|
+
phases: z
|
|
104
|
+
.array(z.enum(ALL_PHASES))
|
|
105
|
+
.optional()
|
|
106
|
+
.describe("Consent states to observe (default: all three). A consent verdict is a comparison between them — one " +
|
|
107
|
+
"state alone cannot tell a correctly gated bundle from a broken one, since both look like silence. " +
|
|
108
|
+
"Narrow this only when the consent behaviour is not what is being asked about."),
|
|
109
|
+
scanTagManager: z
|
|
110
|
+
.boolean()
|
|
111
|
+
.optional()
|
|
112
|
+
.describe("Read the page's GTM container(s) (default: true). Off, a tag-manager-injected bundle looks absent."),
|
|
113
|
+
probeSecondPage: z
|
|
114
|
+
.boolean()
|
|
115
|
+
.optional()
|
|
116
|
+
.describe("Follow one internal link per phase (default: true). Off, a bundle that stops after the entry page looks healthy."),
|
|
117
|
+
probeOverHttp: z
|
|
118
|
+
.boolean()
|
|
119
|
+
.optional()
|
|
120
|
+
.describe("Fetch the served markup over plain HTTP first (default: true). Off, a bot wall is indistinguishable from an empty site."),
|
|
121
|
+
headed: z.boolean().optional().describe("Show the browser window (default: false)."),
|
|
122
|
+
trackingHosts: z
|
|
123
|
+
.array(z.string())
|
|
124
|
+
.optional()
|
|
125
|
+
.describe("Hosts receiving event requests, for installs fronted by a first-party CNAME (default: cdn.dreamdata.cloud)."),
|
|
126
|
+
timeoutMs: z.number().int().positive().optional().describe(`Navigation timeout (default: ${DEFAULT_TIMEOUT_MS}).`),
|
|
127
|
+
},
|
|
128
|
+
}, async (args, extra) => {
|
|
129
|
+
const slug = args.slug ?? slugFromUrl(args.url);
|
|
130
|
+
if (!isSafeSlug(slug)) {
|
|
131
|
+
return errorResult(`Cannot file a report under "${slug}" (derived from ${args.url}). Pass an explicit slug of letters, digits, "_" and "-".`);
|
|
132
|
+
}
|
|
133
|
+
const phases = args.phases?.length
|
|
134
|
+
? ALL_PHASES.filter((phase) => args.phases.includes(phase))
|
|
135
|
+
: [...ALL_PHASES];
|
|
136
|
+
logger.info(`verify_tracking: ${args.url} (${slug}), phases ${phases.join(",")}`);
|
|
137
|
+
// Progress is only sent when the caller asked for it by including a
|
|
138
|
+
// token; without one there is nothing to attach a notification to.
|
|
139
|
+
const progressToken = extra._meta?.progressToken;
|
|
140
|
+
const startedAt = Date.now();
|
|
141
|
+
let ticks = 0;
|
|
142
|
+
let step = "starting";
|
|
143
|
+
const report = (message) => {
|
|
144
|
+
if (progressToken === undefined)
|
|
145
|
+
return;
|
|
146
|
+
void extra
|
|
147
|
+
.sendNotification({
|
|
148
|
+
method: "notifications/progress",
|
|
149
|
+
// progress must increase on every notification, and a run cannot
|
|
150
|
+
// know its own length in advance (a phase takes as long as the site
|
|
151
|
+
// takes), so it counts notifications and sends no total.
|
|
152
|
+
params: { progressToken, progress: ++ticks, message },
|
|
153
|
+
})
|
|
154
|
+
.catch((err) => logger.debug("Could not send progress", err));
|
|
155
|
+
};
|
|
156
|
+
// The steps announce themselves, and a heartbeat covers the gaps between
|
|
157
|
+
// them — the AI check is one call that can run for minutes with nothing
|
|
158
|
+
// to report until it returns, which is exactly the stretch a client would
|
|
159
|
+
// otherwise time out in.
|
|
160
|
+
const heartbeat = setInterval(() => report(`${step} — ${Math.round((Date.now() - startedAt) / 1000)}s elapsed`), PROGRESS_HEARTBEAT_MS);
|
|
161
|
+
let run;
|
|
162
|
+
try {
|
|
163
|
+
run = await runVerification({
|
|
164
|
+
url: args.url,
|
|
165
|
+
slug,
|
|
166
|
+
phases,
|
|
167
|
+
backend: backendFromEnv(),
|
|
168
|
+
headless: args.headed !== true,
|
|
169
|
+
timeoutMs: args.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
170
|
+
trackingHosts: args.trackingHosts,
|
|
171
|
+
scanTagManager: args.scanTagManager !== false,
|
|
172
|
+
probeSecondPage: args.probeSecondPage !== false,
|
|
173
|
+
probeOverHttp: args.probeOverHttp !== false,
|
|
174
|
+
}, (event) => {
|
|
175
|
+
step =
|
|
176
|
+
event.step === "collect"
|
|
177
|
+
? `collecting the ${event.phase} state (${event.index + 1}/${event.total})`
|
|
178
|
+
: event.step === "analyze"
|
|
179
|
+
? "analysing the deployment"
|
|
180
|
+
: "checking the evidence with the AI model";
|
|
181
|
+
report(step);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
clearInterval(heartbeat);
|
|
186
|
+
}
|
|
187
|
+
const written = await writeDefaultArtifacts(run, slug);
|
|
188
|
+
return jsonResult({
|
|
189
|
+
...summarizeRun(slug, args.url, run.analysis, run.result),
|
|
190
|
+
timings: run.timings,
|
|
191
|
+
...written,
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
server.registerTool("list_reports", {
|
|
195
|
+
title: "List saved verification reports",
|
|
196
|
+
description: "Every report under verification/reports/ (subfolders included), newest first, with each run's shape and " +
|
|
197
|
+
"verdict. Use it to find the slug for read_report or explain_verdict.",
|
|
198
|
+
inputSchema: {
|
|
199
|
+
limit: z.number().int().positive().max(200).optional().describe("How many to return (default: 50)."),
|
|
200
|
+
},
|
|
201
|
+
}, async (args) => {
|
|
202
|
+
const reports = listReports().slice(0, args.limit ?? 50);
|
|
203
|
+
const rows = await Promise.all(reports.map(async (entry) => {
|
|
204
|
+
try {
|
|
205
|
+
const report = (await readReport(entry.path));
|
|
206
|
+
return {
|
|
207
|
+
...entry,
|
|
208
|
+
url: report.url ?? null,
|
|
209
|
+
slugRecordedAs: report.slug ?? null,
|
|
210
|
+
shape: report.deployment?.shape ?? null,
|
|
211
|
+
overallPass: report.result?.overallPass ?? null,
|
|
212
|
+
// The one field that makes "which cause is most common across
|
|
213
|
+
// accounts" answerable from a single tool call — the reason the
|
|
214
|
+
// cause ids and sentences are kept byte-stable. Null on a report
|
|
215
|
+
// written before the diagnosis layer existed.
|
|
216
|
+
topCause: report.deployment?.diagnosis?.causes?.[0]?.id ?? null,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
return { ...entry, error: `Unreadable: ${err.message}` };
|
|
221
|
+
}
|
|
222
|
+
}));
|
|
223
|
+
return jsonResult({ count: rows.length, reports: rows });
|
|
224
|
+
});
|
|
225
|
+
server.registerTool("read_report", {
|
|
226
|
+
title: "Read a saved verification report",
|
|
227
|
+
description: "One report by slug. A whole report is 40-50KB, so pass `path` to take only the part you need — e.g. " +
|
|
228
|
+
'"deployment.checks", "result.verdicts", "phases.1.network.requests". Omit it only when you really want ' +
|
|
229
|
+
"the whole file.",
|
|
230
|
+
inputSchema: {
|
|
231
|
+
slug: z.string().describe("Account slug, e.g. clio_com. See list_reports."),
|
|
232
|
+
path: z
|
|
233
|
+
.string()
|
|
234
|
+
.optional()
|
|
235
|
+
.describe('Dotted path into the report, e.g. "deployment.shape" or "phases[0].script". Omit for the whole file.'),
|
|
236
|
+
},
|
|
237
|
+
}, async (args) => {
|
|
238
|
+
const loaded = await loadReport(args.slug);
|
|
239
|
+
if ("error" in loaded)
|
|
240
|
+
return errorResult(loaded.error);
|
|
241
|
+
if (!args.path)
|
|
242
|
+
return jsonResult({ path: loaded.path, report: loaded.report });
|
|
243
|
+
const value = valueAtPath(loaded.report, args.path);
|
|
244
|
+
if (value === undefined) {
|
|
245
|
+
return errorResult(`No such field: "${args.path}" in ${loaded.path}. Top-level keys: ${Object.keys(loaded.report).join(", ")}.`);
|
|
246
|
+
}
|
|
247
|
+
return jsonResult({ path: loaded.path, field: args.path, value });
|
|
248
|
+
});
|
|
249
|
+
server.registerTool("explain_verdict", {
|
|
250
|
+
title: "Explain one checklist verdict",
|
|
251
|
+
description: "One checklist item from a saved report, with the evidence behind it resolved: the value at the field path " +
|
|
252
|
+
"the model quoted (so a quote naming a field that does not exist is visible as such), and the cross-phase " +
|
|
253
|
+
"consent checks, which outrank the model on consent behaviour. Start here before reading raw evidence.",
|
|
254
|
+
inputSchema: {
|
|
255
|
+
slug: z.string().describe("Account slug, e.g. clio_com."),
|
|
256
|
+
id: z
|
|
257
|
+
.string()
|
|
258
|
+
.describe('Checklist item id, e.g. "consent-mode". Omit-and-list is not supported; read_report "result.verdicts" shows them all.'),
|
|
259
|
+
},
|
|
260
|
+
}, async (args) => {
|
|
261
|
+
const loaded = await loadReport(args.slug);
|
|
262
|
+
if ("error" in loaded)
|
|
263
|
+
return errorResult(loaded.error);
|
|
264
|
+
const verdicts = loaded.report.result?.verdicts ?? [];
|
|
265
|
+
const verdict = verdicts.find((entry) => entry.id === args.id);
|
|
266
|
+
if (!verdict) {
|
|
267
|
+
return errorResult(`No verdict "${args.id}" in ${loaded.path}. This report has: ${verdicts.map((entry) => entry.id).join(", ")}.`);
|
|
268
|
+
}
|
|
269
|
+
// Resolving the quote is the cheapest hallucination check there is — but
|
|
270
|
+
// only if it is done the way replay does it. A quote is usually prose with
|
|
271
|
+
// paths embedded in it ("deployment.shape: 'nothing-installed',
|
|
272
|
+
// deployment.install.detail: '...'"), so resolving the whole string as one
|
|
273
|
+
// path reports a perfectly good citation as unsupported, which is worse
|
|
274
|
+
// than not checking: an agent told the evidence is missing will go looking
|
|
275
|
+
// for a problem that is not there. Shared with replay's checker so the two
|
|
276
|
+
// cannot disagree about the same quote.
|
|
277
|
+
const subject = { phases: loaded.report.phases, deployment: loaded.report.deployment };
|
|
278
|
+
const citations = resolveCitations(subject, verdict.evidenceQuote);
|
|
279
|
+
const quoteVerdict = checkQuote(subject, verdict.evidenceQuote);
|
|
280
|
+
const bearing = new Set(CHECKS_BEARING_ON[verdict.id] ?? []);
|
|
281
|
+
const checks = loaded.report.deployment?.checks ?? [];
|
|
282
|
+
return jsonResult({
|
|
283
|
+
path: loaded.path,
|
|
284
|
+
verdict,
|
|
285
|
+
quote: {
|
|
286
|
+
text: verdict.evidenceQuote,
|
|
287
|
+
// "resolved" — every path it names exists. "unverifiable" — it names
|
|
288
|
+
// none, so it is prose, or check ids cited by name; not a claim about
|
|
289
|
+
// a field and not evidence of fabrication. "invented" — it names paths
|
|
290
|
+
// and none of them exist, so treat the verdict as unsupported.
|
|
291
|
+
status: quoteVerdict,
|
|
292
|
+
citations,
|
|
293
|
+
},
|
|
294
|
+
deployment: {
|
|
295
|
+
shape: loaded.report.deployment?.shape ?? null,
|
|
296
|
+
shapeReason: loaded.report.deployment?.shapeReason ?? null,
|
|
297
|
+
pageReadability: loaded.report.deployment?.pageReadability ?? null,
|
|
298
|
+
},
|
|
299
|
+
// The checks that decide this item, named from the same map
|
|
300
|
+
// applyDeterministicChecks enforces — so what is shown here as
|
|
301
|
+
// authoritative is exactly what overruled the model.
|
|
302
|
+
checksBearingOnThisItem: checks.filter((check) => bearing.has(check.id)),
|
|
303
|
+
otherCrossPhaseChecks: checks.filter((check) => !bearing.has(check.id)),
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
await server.connect(new StdioServerTransport());
|
|
307
|
+
logger.info("verify-tracking MCP server ready on stdio.");
|
|
308
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function summarizeRun(slug, url, analysis, result) {
|
|
2
|
+
return {
|
|
3
|
+
slug,
|
|
4
|
+
url,
|
|
5
|
+
overallPass: result.overallPass,
|
|
6
|
+
verdictIsInconclusive: result.verdicts.every((verdict) => verdict.passed === "inconclusive"),
|
|
7
|
+
shape: analysis.shape,
|
|
8
|
+
shapeReason: analysis.shapeReason,
|
|
9
|
+
pageUnreadable: analysis.pageReadability.unreadable,
|
|
10
|
+
routing: {
|
|
11
|
+
mode: analysis.routing.mode,
|
|
12
|
+
observed: analysis.routing.observed,
|
|
13
|
+
reason: analysis.routing.reason,
|
|
14
|
+
},
|
|
15
|
+
phasesObserved: analysis.phasesObserved,
|
|
16
|
+
phasesMissing: analysis.phasesMissing,
|
|
17
|
+
checks: analysis.checks.map((check) => ({
|
|
18
|
+
id: check.id,
|
|
19
|
+
status: check.status,
|
|
20
|
+
title: check.title,
|
|
21
|
+
detail: check.detail,
|
|
22
|
+
})),
|
|
23
|
+
diagnosis: analysis.diagnosis.causes.map((cause) => ({
|
|
24
|
+
id: cause.id,
|
|
25
|
+
kind: cause.kind,
|
|
26
|
+
problem: cause.problem,
|
|
27
|
+
fix: cause.fix,
|
|
28
|
+
docUrl: cause.docUrl,
|
|
29
|
+
explains: cause.explains,
|
|
30
|
+
})),
|
|
31
|
+
unexplainedChecks: analysis.diagnosis.unexplainedChecks,
|
|
32
|
+
verdicts: result.verdicts.map((verdict) => ({
|
|
33
|
+
id: verdict.id,
|
|
34
|
+
title: verdict.title,
|
|
35
|
+
passed: verdict.passed,
|
|
36
|
+
feedback: verdict.feedback,
|
|
37
|
+
})),
|
|
38
|
+
remediationAdvice: result.remediationAdvice,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/mcp/summary.ts"],"names":[],"mappings":"AAyDA,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,GAAW,EACX,QAA4B,EAC5B,MAAqB;IAErB,OAAO;QACL,IAAI;QACJ,GAAG;QACH,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,qBAAqB,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,cAAc,CAAC;QAC5F,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,cAAc,EAAE,QAAQ,CAAC,eAAe,CAAC,UAAU;QACnD,OAAO,EAAE;YACP,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI;YAC3B,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ;YACnC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM;SAChC;QACD,cAAc,EAAE,QAAQ,CAAC,cAAc;QACvC,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACtC,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;QACH,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACnD,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;QACH,iBAAiB,EAAE,QAAQ,CAAC,SAAS,CAAC,iBAAiB;QACvD,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC1C,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;QACH,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;KAC5C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const PHASE_LABELS = {
|
|
2
|
+
clean: "clean (banner untouched)",
|
|
3
|
+
grant: "grant (consent accepted, reloaded)",
|
|
4
|
+
reject: "reject (consent refused, reloaded)",
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The conditions one phase's evidence was gathered under. Without these, a
|
|
8
|
+
* pass that observed a pre-consent page reads identically to one that
|
|
9
|
+
* observed a broken install.
|
|
10
|
+
*/
|
|
11
|
+
export function buildContextLines(evidence) {
|
|
12
|
+
const { consent, consentAcceptance, network, globals, secondPage } = evidence;
|
|
13
|
+
const lines = [];
|
|
14
|
+
lines.push(`Phase: ${PHASE_LABELS[evidence.phase]}`);
|
|
15
|
+
const shape = [];
|
|
16
|
+
if (globals.cookielessInitialized)
|
|
17
|
+
shape.push("cookieless");
|
|
18
|
+
if (globals.initialized)
|
|
19
|
+
shape.push("normal");
|
|
20
|
+
if (globals.segmentCompatInitialized)
|
|
21
|
+
shape.push("segment-compat");
|
|
22
|
+
lines.push(`Bundles initialized: ${shape.length > 0 ? shape.join(" + ") : "none"}`);
|
|
23
|
+
const seenHosts = [
|
|
24
|
+
...new Set(network.requests.map((r) => {
|
|
25
|
+
try {
|
|
26
|
+
return new URL(r.url).hostname;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return r.url;
|
|
30
|
+
}
|
|
31
|
+
})),
|
|
32
|
+
];
|
|
33
|
+
const watching = seenHosts.length > 0
|
|
34
|
+
? `from ${seenHosts.join(", ")}`
|
|
35
|
+
: `Dreamdata-owned hosts auto-detected${network.trackingHosts.length > 0 ? `, plus ${network.trackingHosts.join(", ")}` : ""}`;
|
|
36
|
+
lines.push(`Requests captured: ${network.cookielessRequestCount} cookieless, ${network.normalRequestCount} normal (${watching})`);
|
|
37
|
+
if (consent.cmpDetected) {
|
|
38
|
+
const answered = consent.cmpHasResponse === null ? "response state unreadable" : consent.cmpHasResponse ? "answered" : "not answered";
|
|
39
|
+
const provenance = consent.analyticsStorageSource === "update"
|
|
40
|
+
? "set explicitly by the CMP"
|
|
41
|
+
: consent.analyticsStorageSource === "default"
|
|
42
|
+
? "a configured default, not a user decision"
|
|
43
|
+
: consent.analyticsStorageSource === "implicit-default"
|
|
44
|
+
? "gtag.js's own fallback — no declared default applies to this visitor, so this is not a user decision"
|
|
45
|
+
: "not readable";
|
|
46
|
+
const vendorLabel = consent.cmpVendorConfirmed
|
|
47
|
+
? (consent.cmpVendor ?? "unrecognised")
|
|
48
|
+
: `${consent.cmpVendor ?? "unrecognised"} (heuristically detected — no known vendor/global matched, text-matched instead)`;
|
|
49
|
+
lines.push(`CMP: ${vendorLabel}, banner ${answered}`);
|
|
50
|
+
lines.push(`analytics_storage: ${consent.analyticsStorageState ?? "unknown"} — ${provenance}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
lines.push("CMP: none detected");
|
|
54
|
+
}
|
|
55
|
+
if (secondPage === null) {
|
|
56
|
+
lines.push("Second page: not probed, so only the first page view was observed");
|
|
57
|
+
}
|
|
58
|
+
else if (secondPage.urlChanged) {
|
|
59
|
+
const mechanism = secondPage.kind === "soft"
|
|
60
|
+
? "in-app route change, no document load"
|
|
61
|
+
: secondPage.kind === "hard"
|
|
62
|
+
? "new document loaded"
|
|
63
|
+
: "navigation mechanism unclear";
|
|
64
|
+
lines.push(`Second page: ${secondPage.toUrl} via "${secondPage.linkText ?? "a link"}" (${mechanism}) — ${secondPage.network.cookielessRequestCount} cookieless, ${secondPage.network.normalRequestCount} normal`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
lines.push(`Second page: not reached — ${secondPage.skippedReason ?? "no navigation observed"}`);
|
|
68
|
+
}
|
|
69
|
+
if (consentAcceptance.attempted) {
|
|
70
|
+
const verb = consentAcceptance.direction === "deny" ? "denial" : "grant";
|
|
71
|
+
lines.push(consentAcceptance.succeeded
|
|
72
|
+
? `Consent ${verb} driven by this run (${consentAcceptance.detail}); evidence is post-${verb}`
|
|
73
|
+
// "evidence is pre-consent" presumes a consent decision the evidence
|
|
74
|
+
// precedes. With no banner anywhere there is none: this phase is the
|
|
75
|
+
// untouched load again, and reading it as a failed drive sends the
|
|
76
|
+
// reader after a banner that does not exist.
|
|
77
|
+
: consent.cmpDetected
|
|
78
|
+
? `Consent ${verb} requested but failed (${consentAcceptance.detail}); evidence is pre-consent`
|
|
79
|
+
: `No banner was found to answer, so no ${verb} happened and this phase is the untouched load again (${consentAcceptance.detail})`);
|
|
80
|
+
// consentSignalConfirmed is read on the answered page, before the
|
|
81
|
+
// post-consent reload. A CMP that emits the update and then fails to
|
|
82
|
+
// restore it on the next load passes that check and still leaves every
|
|
83
|
+
// gated tag frozen, so the phase's own end state is stated too.
|
|
84
|
+
const expected = consentAcceptance.direction === "deny" ? "denied" : "granted";
|
|
85
|
+
if (consentAcceptance.consentSignalConfirmed === false) {
|
|
86
|
+
lines.push("Consent Mode never reflected that choice — analytics_storage did not move");
|
|
87
|
+
}
|
|
88
|
+
else if (consentAcceptance.succeeded && consent.analyticsStorageState !== null) {
|
|
89
|
+
if (consent.analyticsStorageState !== expected) {
|
|
90
|
+
lines.push(`Consent Mode reached ${expected} while the banner was being answered but reads ${consent.analyticsStorageState} after the post-consent reload — the decision does not survive a page load, so gated tags stay ${consent.analyticsStorageState} for the rest of the visit`);
|
|
91
|
+
}
|
|
92
|
+
else if (consent.analyticsStorageSource === "implicit-default") {
|
|
93
|
+
lines.push(`analytics_storage is ${expected} after the reload only as gtag.js's implicit default — nothing declared applies to this visitor, so it matches the choice by coincidence, not because the choice was carried into Consent Mode`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
/** What the run as a whole established, before any per-phase detail. */
|
|
100
|
+
export function buildRunContextLines(evidence, analysis) {
|
|
101
|
+
const lines = [];
|
|
102
|
+
// First, and on its own, because it is the only line that changes what the
|
|
103
|
+
// rest of the report means: if the browser was never served the page, every
|
|
104
|
+
// observation below describes some other document.
|
|
105
|
+
if (analysis.pageReadability.unreadable) {
|
|
106
|
+
lines.push("BLOCKED RUN: the browser was never served this site's page, so nothing below is a finding about this site.");
|
|
107
|
+
lines.push(` ${analysis.pageReadability.reason}`);
|
|
108
|
+
for (const signal of analysis.pageReadability.signals)
|
|
109
|
+
lines.push(` · ${signal}`);
|
|
110
|
+
}
|
|
111
|
+
lines.push(`Deployment: ${analysis.shape} — ${analysis.shapeReason}`);
|
|
112
|
+
if (analysis.consentGateUndetermined) {
|
|
113
|
+
lines.push("WARNING: a consent banner was detected but no grant/reject was certified in any phase — conclusions that depend on the post-consent state are not reliable this run. Read each phase's drive cell before blaming the site: 'not-submitted' and 'did-not-survive-reload' mean that phase's numbers came from a page with the banner still unanswered, while 'not-persisted' means the answer was submitted and the page reloaded afterwards, and only our read-back of the CMP's own record is missing.");
|
|
114
|
+
}
|
|
115
|
+
if (analysis.normalBundleSignals.length > 0) {
|
|
116
|
+
lines.push("Normal bundle is part of this install because:");
|
|
117
|
+
for (const signal of analysis.normalBundleSignals)
|
|
118
|
+
lines.push(` · ${signal.source}: ${signal.detail}`);
|
|
119
|
+
}
|
|
120
|
+
if (analysis.thirdPartySegmentSignals.length > 0) {
|
|
121
|
+
lines.push("Real Segment install detected (not a Dreamdata bundle):");
|
|
122
|
+
for (const signal of analysis.thirdPartySegmentSignals)
|
|
123
|
+
lines.push(` · ${signal}`);
|
|
124
|
+
}
|
|
125
|
+
lines.push(`CMP: ${analysis.cmpVendor ?? "none detected"}`);
|
|
126
|
+
// The mode name carries whether this was observed or merely suspected, and
|
|
127
|
+
// the reason says off what — a reader must never have to guess which.
|
|
128
|
+
lines.push(`Routing: ${analysis.routing.mode} — ${analysis.routing.reason}`);
|
|
129
|
+
const probe = evidence.httpProbe;
|
|
130
|
+
if (probe !== null && probe.attempted) {
|
|
131
|
+
lines.push(probe.failedReason !== null
|
|
132
|
+
? `Served markup (plain HTTP GET, no browser): could not be fetched — ${probe.failedReason}`
|
|
133
|
+
: `Served markup (plain HTTP GET, no browser): HTTP ${probe.status}, ${probe.bytes} bytes, ${probe.sameOriginLinkCount} same-origin link(s)${probe.tagManagerContainerIds.length > 0 ? `, GTM ${probe.tagManagerContainerIds.join(", ")}` : ""}${probe.cmpMarkers.length > 0 ? `, CMP ${probe.cmpMarkers.join(", ")}` : ""}`);
|
|
134
|
+
}
|
|
135
|
+
lines.push(`Phases observed: ${analysis.phasesObserved.join(", ")}${analysis.phasesMissing.length > 0 ? ` (not run: ${analysis.phasesMissing.join(", ")})` : ""}`);
|
|
136
|
+
if (analysis.segmentCompat)
|
|
137
|
+
lines.push("Segment-compatible install (window.analytics / ajs_* storage)");
|
|
138
|
+
return lines;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The second page's requests in the same normal/cookieless shorthand as the
|
|
142
|
+
* first page's columns, so a bundle that stops after one page view reads as an
|
|
143
|
+
* obvious drop across the row rather than needing the checks to spell it out.
|
|
144
|
+
*/
|
|
145
|
+
function secondPageCell(row) {
|
|
146
|
+
const second = row.secondPage;
|
|
147
|
+
if (second === null)
|
|
148
|
+
return "not probed";
|
|
149
|
+
if (!second.observed)
|
|
150
|
+
return "not reached";
|
|
151
|
+
return `${second.kind}: ${second.normalRequests}n/${second.cookielessRequests}c`;
|
|
152
|
+
}
|
|
153
|
+
/** The per-phase comparison, as aligned rows. */
|
|
154
|
+
export function buildPhaseMatrixRows(analysis) {
|
|
155
|
+
const header = [
|
|
156
|
+
"phase",
|
|
157
|
+
"normal",
|
|
158
|
+
"cookieless",
|
|
159
|
+
"2nd page",
|
|
160
|
+
"identity storage",
|
|
161
|
+
"analytics_storage",
|
|
162
|
+
"consent driven",
|
|
163
|
+
];
|
|
164
|
+
const rows = analysis.matrix.map((row) => [
|
|
165
|
+
row.phase,
|
|
166
|
+
String(row.normalRequests),
|
|
167
|
+
String(row.cookielessRequests),
|
|
168
|
+
secondPageCell(row),
|
|
169
|
+
row.identityCookiesSet.length > 0 ? row.identityCookiesSet.join(" ") : "—",
|
|
170
|
+
`${row.analyticsStorage} (${row.analyticsStorageSource})`,
|
|
171
|
+
row.consentDriven
|
|
172
|
+
? (row.consentDriveDetail ?? "yes")
|
|
173
|
+
: row.phase === "clean"
|
|
174
|
+
? "—"
|
|
175
|
+
// "not certified" reads as a shortfall of this run. With no banner
|
|
176
|
+
// anywhere there was nothing to drive, and the row is the clean load
|
|
177
|
+
// repeated rather than a gap in coverage.
|
|
178
|
+
: row.cmpDetected === false
|
|
179
|
+
? "no banner to answer"
|
|
180
|
+
: `not certified (${row.consentUndrivenReason ?? "unknown"})`,
|
|
181
|
+
]);
|
|
182
|
+
return [header, ...rows];
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/report/context.ts"],"names":[],"mappings":"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"}
|