@riddledc/riddle-proof 0.8.79 → 0.8.81
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/README.md +48 -0
- package/dist/change-proof.js +2 -2
- package/dist/{chunk-FCSJZBC5.js → chunk-2K3DIK7A.js} +346 -5
- package/dist/{chunk-7N6X54WG.js → chunk-7OAETQU3.js} +1 -1
- package/dist/{chunk-RQPCKRKT.js → chunk-FW7CKARF.js} +1 -1
- package/dist/{chunk-6VFS2JFR.js → chunk-LR4UYJDY.js} +1 -1
- package/dist/{chunk-NEXWITV4.js → chunk-QYZ3GKCP.js} +4 -4
- package/dist/cli/index.js +5 -5
- package/dist/cli.cjs +343 -5
- package/dist/cli.js +5 -5
- package/dist/index.cjs +349 -5
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -4
- package/dist/pr-comment.js +3 -3
- package/dist/profile/index.cjs +349 -5
- package/dist/profile/index.d.cts +1 -1
- package/dist/profile/index.d.ts +1 -1
- package/dist/profile/index.js +7 -1
- package/dist/profile-suggestions.js +2 -2
- package/dist/profile.cjs +349 -5
- package/dist/profile.d.cts +40 -3
- package/dist/profile.d.ts +40 -3
- package/dist/profile.js +7 -1
- package/examples/profiles/ordered-trace.json +58 -0
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -8775,6 +8775,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
8775
8775
|
"selector_text_visible",
|
|
8776
8776
|
"selector_text_absent",
|
|
8777
8777
|
"selector_text_order",
|
|
8778
|
+
"ordered_trace",
|
|
8778
8779
|
"observe_within",
|
|
8779
8780
|
"frame_text_visible",
|
|
8780
8781
|
"frame_url_equals",
|
|
@@ -8838,6 +8839,21 @@ var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
|
8838
8839
|
"timedout",
|
|
8839
8840
|
"failed"
|
|
8840
8841
|
];
|
|
8842
|
+
var RIDDLE_PROOF_ORDERED_TRACE_OPERATORS = [
|
|
8843
|
+
"exists",
|
|
8844
|
+
"equals",
|
|
8845
|
+
"not_equals",
|
|
8846
|
+
"truthy",
|
|
8847
|
+
"falsy",
|
|
8848
|
+
"gt",
|
|
8849
|
+
"gte",
|
|
8850
|
+
"lt",
|
|
8851
|
+
"lte",
|
|
8852
|
+
"abs_gt",
|
|
8853
|
+
"abs_gte",
|
|
8854
|
+
"abs_lt",
|
|
8855
|
+
"abs_lte"
|
|
8856
|
+
];
|
|
8841
8857
|
function uniqueNonEmptyStrings(values) {
|
|
8842
8858
|
const seen = /* @__PURE__ */ new Set();
|
|
8843
8859
|
const result = [];
|
|
@@ -9129,6 +9145,185 @@ function resolveJsonPath(root, path7) {
|
|
|
9129
9145
|
}
|
|
9130
9146
|
return { exists: true, value: current };
|
|
9131
9147
|
}
|
|
9148
|
+
function assessRiddleProofOrderedTrace(trace, events) {
|
|
9149
|
+
const insufficient = (reason, traceLength = Array.isArray(trace) ? trace.length : 0, witnesses2 = [], missingEvent, missingPaths) => ({
|
|
9150
|
+
version: "riddle-proof.ordered-trace-assessment.v1",
|
|
9151
|
+
status: "proof_insufficient",
|
|
9152
|
+
trace_length: traceLength,
|
|
9153
|
+
witnesses: witnesses2,
|
|
9154
|
+
missing_event: missingEvent,
|
|
9155
|
+
missing_paths: missingPaths,
|
|
9156
|
+
reason
|
|
9157
|
+
});
|
|
9158
|
+
const parsePath = (path7) => {
|
|
9159
|
+
const segments = [];
|
|
9160
|
+
let token = "";
|
|
9161
|
+
const pushToken = () => {
|
|
9162
|
+
const value = token.trim();
|
|
9163
|
+
if (value) segments.push(value);
|
|
9164
|
+
token = "";
|
|
9165
|
+
};
|
|
9166
|
+
for (let index = 0; index < path7.length; index += 1) {
|
|
9167
|
+
const char = path7[index];
|
|
9168
|
+
if (char === ".") {
|
|
9169
|
+
pushToken();
|
|
9170
|
+
continue;
|
|
9171
|
+
}
|
|
9172
|
+
if (char !== "[") {
|
|
9173
|
+
token += char;
|
|
9174
|
+
continue;
|
|
9175
|
+
}
|
|
9176
|
+
pushToken();
|
|
9177
|
+
const closeIndex = path7.indexOf("]", index + 1);
|
|
9178
|
+
if (closeIndex === -1) throw new Error(`unterminated bracket at ${index}`);
|
|
9179
|
+
const bracket = path7.slice(index + 1, closeIndex).trim();
|
|
9180
|
+
if (!bracket) throw new Error(`empty bracket at ${index}`);
|
|
9181
|
+
if (/^\d+$/.test(bracket)) {
|
|
9182
|
+
segments.push(Number(bracket));
|
|
9183
|
+
} else {
|
|
9184
|
+
segments.push(bracket.replace(/^['"]|['"]$/g, ""));
|
|
9185
|
+
}
|
|
9186
|
+
index = closeIndex;
|
|
9187
|
+
}
|
|
9188
|
+
pushToken();
|
|
9189
|
+
return segments;
|
|
9190
|
+
};
|
|
9191
|
+
const resolve = (root, path7) => {
|
|
9192
|
+
let segments;
|
|
9193
|
+
try {
|
|
9194
|
+
segments = parsePath(path7);
|
|
9195
|
+
} catch {
|
|
9196
|
+
return { exists: false };
|
|
9197
|
+
}
|
|
9198
|
+
let current = root;
|
|
9199
|
+
for (const segment of segments) {
|
|
9200
|
+
if (Array.isArray(current)) {
|
|
9201
|
+
const index = typeof segment === "number" ? segment : /^\d+$/.test(segment) ? Number(segment) : -1;
|
|
9202
|
+
if (index < 0 || index >= current.length) return { exists: false };
|
|
9203
|
+
current = current[index];
|
|
9204
|
+
continue;
|
|
9205
|
+
}
|
|
9206
|
+
if (typeof segment !== "string" || current === null || typeof current !== "object") return { exists: false };
|
|
9207
|
+
if (!Object.hasOwn(current, segment)) return { exists: false };
|
|
9208
|
+
current = current[segment];
|
|
9209
|
+
}
|
|
9210
|
+
return { exists: true, value: current };
|
|
9211
|
+
};
|
|
9212
|
+
const valuesEqual = (left, right) => {
|
|
9213
|
+
if (Object.is(left, right)) return true;
|
|
9214
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
9215
|
+
return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => valuesEqual(value, right[index]));
|
|
9216
|
+
}
|
|
9217
|
+
if (left === null || right === null || typeof left !== "object" || typeof right !== "object") return false;
|
|
9218
|
+
const leftRecord = left;
|
|
9219
|
+
const rightRecord = right;
|
|
9220
|
+
const leftKeys = Object.keys(leftRecord).sort();
|
|
9221
|
+
const rightKeys = Object.keys(rightRecord).sort();
|
|
9222
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => key === rightKeys[index] && valuesEqual(leftRecord[key], rightRecord[key]));
|
|
9223
|
+
};
|
|
9224
|
+
const numericOperator = (op) => [
|
|
9225
|
+
"gt",
|
|
9226
|
+
"gte",
|
|
9227
|
+
"lt",
|
|
9228
|
+
"lte",
|
|
9229
|
+
"abs_gt",
|
|
9230
|
+
"abs_gte",
|
|
9231
|
+
"abs_lt",
|
|
9232
|
+
"abs_lte"
|
|
9233
|
+
].includes(op);
|
|
9234
|
+
const matches = (value, predicate) => {
|
|
9235
|
+
if (predicate.op === "exists") return true;
|
|
9236
|
+
if (predicate.op === "equals") return valuesEqual(value, predicate.value);
|
|
9237
|
+
if (predicate.op === "not_equals") return !valuesEqual(value, predicate.value);
|
|
9238
|
+
if (predicate.op === "truthy") return Boolean(value);
|
|
9239
|
+
if (predicate.op === "falsy") return !value;
|
|
9240
|
+
const observed = typeof value === "number" ? value : Number.NaN;
|
|
9241
|
+
const expected = typeof predicate.value === "number" ? predicate.value : Number.NaN;
|
|
9242
|
+
if (!Number.isFinite(observed) || !Number.isFinite(expected)) return false;
|
|
9243
|
+
const candidate = predicate.op.startsWith("abs_") ? Math.abs(observed) : observed;
|
|
9244
|
+
if (predicate.op === "gt" || predicate.op === "abs_gt") return candidate > expected;
|
|
9245
|
+
if (predicate.op === "gte" || predicate.op === "abs_gte") return candidate >= expected;
|
|
9246
|
+
if (predicate.op === "lt" || predicate.op === "abs_lt") return candidate < expected;
|
|
9247
|
+
return candidate <= expected;
|
|
9248
|
+
};
|
|
9249
|
+
if (!Array.isArray(trace) || trace.length === 0) return insufficient("trace_missing_or_empty");
|
|
9250
|
+
if (!Array.isArray(events) || events.length === 0) return insufficient("events_missing", trace.length);
|
|
9251
|
+
for (const event of events) {
|
|
9252
|
+
const missingPaths = event.predicates.filter((predicate) => !trace.some((sample) => {
|
|
9253
|
+
const resolved = resolve(sample, predicate.path);
|
|
9254
|
+
return resolved.exists && (!numericOperator(predicate.op) || typeof resolved.value === "number" && Number.isFinite(resolved.value));
|
|
9255
|
+
})).map((predicate) => predicate.path);
|
|
9256
|
+
if (missingPaths.length) {
|
|
9257
|
+
return insufficient("required_trace_field_missing", trace.length, [], event.label, Array.from(new Set(missingPaths)));
|
|
9258
|
+
}
|
|
9259
|
+
}
|
|
9260
|
+
const witnesses = [];
|
|
9261
|
+
let cursor = 0;
|
|
9262
|
+
for (const event of events) {
|
|
9263
|
+
let witnessIndex = -1;
|
|
9264
|
+
for (let index = cursor; index < trace.length; index += 1) {
|
|
9265
|
+
if (event.predicates.every((predicate) => {
|
|
9266
|
+
const resolved = resolve(trace[index], predicate.path);
|
|
9267
|
+
return resolved.exists && matches(resolved.value, predicate);
|
|
9268
|
+
})) {
|
|
9269
|
+
witnessIndex = index;
|
|
9270
|
+
break;
|
|
9271
|
+
}
|
|
9272
|
+
}
|
|
9273
|
+
if (witnessIndex < 0) {
|
|
9274
|
+
return {
|
|
9275
|
+
version: "riddle-proof.ordered-trace-assessment.v1",
|
|
9276
|
+
status: "failed",
|
|
9277
|
+
trace_length: trace.length,
|
|
9278
|
+
witnesses,
|
|
9279
|
+
missing_event: event.label,
|
|
9280
|
+
reason: "ordered_event_not_observed"
|
|
9281
|
+
};
|
|
9282
|
+
}
|
|
9283
|
+
witnesses.push({
|
|
9284
|
+
label: event.label,
|
|
9285
|
+
index: witnessIndex,
|
|
9286
|
+
observations: event.predicates.map((predicate) => {
|
|
9287
|
+
const observed = resolve(trace[witnessIndex], predicate.path).value;
|
|
9288
|
+
return {
|
|
9289
|
+
path: predicate.path,
|
|
9290
|
+
op: predicate.op,
|
|
9291
|
+
expected: predicate.value,
|
|
9292
|
+
observed
|
|
9293
|
+
};
|
|
9294
|
+
})
|
|
9295
|
+
});
|
|
9296
|
+
cursor = witnessIndex + 1;
|
|
9297
|
+
}
|
|
9298
|
+
return {
|
|
9299
|
+
version: "riddle-proof.ordered-trace-assessment.v1",
|
|
9300
|
+
status: "passed",
|
|
9301
|
+
trace_length: trace.length,
|
|
9302
|
+
witnesses
|
|
9303
|
+
};
|
|
9304
|
+
}
|
|
9305
|
+
function assessRiddleProofOrderedTraceSetupResults(results, setupActionLabel, tracePath, events) {
|
|
9306
|
+
const insufficient = (reason) => ({
|
|
9307
|
+
version: "riddle-proof.ordered-trace-assessment.v1",
|
|
9308
|
+
status: "proof_insufficient",
|
|
9309
|
+
trace_length: 0,
|
|
9310
|
+
witnesses: [],
|
|
9311
|
+
reason
|
|
9312
|
+
});
|
|
9313
|
+
if (!Array.isArray(results)) return insufficient("setup_results_missing");
|
|
9314
|
+
const source = results.find((item) => item && typeof item === "object" && !Array.isArray(item) && item.label === setupActionLabel);
|
|
9315
|
+
if (!source) return insufficient("setup_action_result_missing");
|
|
9316
|
+
if (!Object.hasOwn(source, "returned")) return insufficient("setup_action_return_missing");
|
|
9317
|
+
const segments = tracePath.split(".").map((segment) => segment.trim()).filter(Boolean);
|
|
9318
|
+
let trace = source.returned;
|
|
9319
|
+
for (const segment of segments) {
|
|
9320
|
+
if (trace === null || typeof trace !== "object" || Array.isArray(trace) || !Object.hasOwn(trace, segment)) {
|
|
9321
|
+
return insufficient("trace_path_missing");
|
|
9322
|
+
}
|
|
9323
|
+
trace = trace[segment];
|
|
9324
|
+
}
|
|
9325
|
+
return assessRiddleProofOrderedTrace(trace, events);
|
|
9326
|
+
}
|
|
9132
9327
|
function evaluateHttpStatusBodyJsonAssertion(root, assertion) {
|
|
9133
9328
|
const resolved = resolveJsonPath(root, assertion.path);
|
|
9134
9329
|
const errors = [];
|
|
@@ -9235,6 +9430,7 @@ function profileSetupWindowCallReceipts(results) {
|
|
|
9235
9430
|
return results.filter((result) => profileSetupResultAction(result) === "window_call").map((result) => {
|
|
9236
9431
|
const receipt = {
|
|
9237
9432
|
ordinal: result.ordinal ?? null,
|
|
9433
|
+
label: result.label ?? null,
|
|
9238
9434
|
ok: result.ok !== false,
|
|
9239
9435
|
path: result.path ?? null,
|
|
9240
9436
|
return_captured: result.return_captured ?? null,
|
|
@@ -9253,6 +9449,7 @@ function profileSetupWindowEvalReceipts(results) {
|
|
|
9253
9449
|
return results.filter((result) => profileSetupResultAction(result) === "window_eval").map((result) => {
|
|
9254
9450
|
const receipt = {
|
|
9255
9451
|
ordinal: result.ordinal ?? null,
|
|
9452
|
+
label: result.label ?? null,
|
|
9256
9453
|
ok: result.ok !== false,
|
|
9257
9454
|
script_length: result.script_length ?? null,
|
|
9258
9455
|
return_captured: result.return_captured ?? null,
|
|
@@ -9696,10 +9893,14 @@ function normalizeViewport(input, index) {
|
|
|
9696
9893
|
if (!width || !height || width < 100 || height < 100) {
|
|
9697
9894
|
throw new Error(`target.viewports[${index}] requires numeric width and height >= 100.`);
|
|
9698
9895
|
}
|
|
9896
|
+
const hasTouch = booleanValue2(valueFromOwn(input, "hasTouch", "has_touch"));
|
|
9897
|
+
const isMobile = booleanValue2(valueFromOwn(input, "isMobile", "is_mobile"));
|
|
9699
9898
|
return {
|
|
9700
9899
|
name: normalizeName(input.name || input.label, `viewport-${index + 1}`),
|
|
9701
9900
|
width: Math.round(width),
|
|
9702
|
-
height: Math.round(height)
|
|
9901
|
+
height: Math.round(height),
|
|
9902
|
+
...hasTouch === void 0 ? {} : { hasTouch },
|
|
9903
|
+
...isMobile === void 0 ? {} : { isMobile }
|
|
9703
9904
|
};
|
|
9704
9905
|
}
|
|
9705
9906
|
function normalizeViewports(value) {
|
|
@@ -10525,6 +10726,51 @@ function dialogCountFieldForCheckType(type) {
|
|
|
10525
10726
|
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
10526
10727
|
return "dialog_count";
|
|
10527
10728
|
}
|
|
10729
|
+
function normalizeOrderedTraceEvents(value, label) {
|
|
10730
|
+
if (value === void 0) return void 0;
|
|
10731
|
+
if (!Array.isArray(value) || !value.length) throw new Error(`${label} must be a non-empty array.`);
|
|
10732
|
+
const seenLabels = /* @__PURE__ */ new Set();
|
|
10733
|
+
return value.map((item, eventIndex) => {
|
|
10734
|
+
const eventLabel = `${label}[${eventIndex}]`;
|
|
10735
|
+
if (!isRecord2(item)) throw new Error(`${eventLabel} must be an object.`);
|
|
10736
|
+
const name = stringFromOwn(item, "label", "name", "event");
|
|
10737
|
+
if (!name) throw new Error(`${eventLabel}.label is required.`);
|
|
10738
|
+
if (seenLabels.has(name)) throw new Error(`${eventLabel}.label must be unique.`);
|
|
10739
|
+
seenLabels.add(name);
|
|
10740
|
+
const predicatesInput = item.predicates ?? item.all ?? item.where;
|
|
10741
|
+
if (!Array.isArray(predicatesInput) || !predicatesInput.length) {
|
|
10742
|
+
throw new Error(`${eventLabel}.predicates must be a non-empty array.`);
|
|
10743
|
+
}
|
|
10744
|
+
const predicates = predicatesInput.map((predicateInput, predicateIndex) => {
|
|
10745
|
+
const predicateLabel = `${eventLabel}.predicates[${predicateIndex}]`;
|
|
10746
|
+
if (!isRecord2(predicateInput)) throw new Error(`${predicateLabel} must be an object.`);
|
|
10747
|
+
const path7 = stringFromOwn(predicateInput, "path", "field", "key");
|
|
10748
|
+
if (!path7) throw new Error(`${predicateLabel}.path is required.`);
|
|
10749
|
+
const op = stringFromOwn(predicateInput, "op", "operator");
|
|
10750
|
+
if (!op || !RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.includes(op)) {
|
|
10751
|
+
throw new Error(`${predicateLabel}.op must be one of ${RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.join(", ")}.`);
|
|
10752
|
+
}
|
|
10753
|
+
const requiresValue = !["exists", "truthy", "falsy"].includes(op);
|
|
10754
|
+
const hasValue = hasOwn(predicateInput, "value") || hasOwn(predicateInput, "expected");
|
|
10755
|
+
if (requiresValue && !hasValue) throw new Error(`${predicateLabel}.value is required for ${op}.`);
|
|
10756
|
+
const value2 = hasOwn(predicateInput, "value") ? predicateInput.value : predicateInput.expected;
|
|
10757
|
+
if (["gt", "gte", "lt", "lte", "abs_gt", "abs_gte", "abs_lt", "abs_lte"].includes(op)) {
|
|
10758
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) {
|
|
10759
|
+
throw new Error(`${predicateLabel}.value must be a finite number for ${op}.`);
|
|
10760
|
+
}
|
|
10761
|
+
if (op.startsWith("abs_") && value2 < 0) {
|
|
10762
|
+
throw new Error(`${predicateLabel}.value must be non-negative for ${op}.`);
|
|
10763
|
+
}
|
|
10764
|
+
}
|
|
10765
|
+
return {
|
|
10766
|
+
path: path7,
|
|
10767
|
+
op,
|
|
10768
|
+
value: requiresValue ? toJsonValue(value2) : void 0
|
|
10769
|
+
};
|
|
10770
|
+
});
|
|
10771
|
+
return { label: name, predicates };
|
|
10772
|
+
});
|
|
10773
|
+
}
|
|
10528
10774
|
function normalizeCheck(input, index) {
|
|
10529
10775
|
if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
|
|
10530
10776
|
const type = stringValue3(input.type);
|
|
@@ -10575,6 +10821,17 @@ function normalizeCheck(input, index) {
|
|
|
10575
10821
|
if (!stringValue3(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
|
|
10576
10822
|
if (!expectedTexts?.length) throw new Error(`checks[${index}] selector_text_order requires expected_texts.`);
|
|
10577
10823
|
}
|
|
10824
|
+
const setupActionLabel = stringFromOwn(input, "setup_action_label", "setupActionLabel", "source_action_label", "sourceActionLabel");
|
|
10825
|
+
const tracePath = stringFromOwn(input, "trace_path", "tracePath", "path");
|
|
10826
|
+
const orderedTraceEvents = normalizeOrderedTraceEvents(
|
|
10827
|
+
input.events ?? input.sequence ?? input.ordered_events ?? input.orderedEvents,
|
|
10828
|
+
`checks[${index}].events`
|
|
10829
|
+
);
|
|
10830
|
+
if (type === "ordered_trace") {
|
|
10831
|
+
if (!setupActionLabel) throw new Error(`checks[${index}] ordered_trace requires setup_action_label.`);
|
|
10832
|
+
if (!tracePath) throw new Error(`checks[${index}] ordered_trace requires trace_path.`);
|
|
10833
|
+
if (!orderedTraceEvents?.length) throw new Error(`checks[${index}] ordered_trace requires events.`);
|
|
10834
|
+
}
|
|
10578
10835
|
const expectedRoutes = normalizeRouteInventoryRoutes(input.expected_routes ?? input.expectedRoutes, index);
|
|
10579
10836
|
if (type === "route_inventory" && !expectedRoutes?.length) {
|
|
10580
10837
|
throw new Error(`checks[${index}] route_inventory requires expected_routes.`);
|
|
@@ -10647,6 +10904,9 @@ function normalizeCheck(input, index) {
|
|
|
10647
10904
|
body_not_patterns: bodyNotPatterns,
|
|
10648
10905
|
body_json_assertions: bodyJsonAssertions,
|
|
10649
10906
|
expected_texts: expectedTexts,
|
|
10907
|
+
setup_action_label: type === "ordered_trace" ? setupActionLabel : void 0,
|
|
10908
|
+
trace_path: type === "ordered_trace" ? tracePath : void 0,
|
|
10909
|
+
events: type === "ordered_trace" ? orderedTraceEvents : void 0,
|
|
10650
10910
|
link_selector: stringValue3(input.link_selector) || stringValue3(input.linkSelector),
|
|
10651
10911
|
source_selector: stringValue3(input.source_selector) || stringValue3(input.sourceSelector),
|
|
10652
10912
|
route_path_prefix: stringValue3(input.route_path_prefix) || stringValue3(input.routePathPrefix),
|
|
@@ -10713,6 +10973,20 @@ function normalizeRiddleProofProfile(input, options = {}) {
|
|
|
10713
10973
|
const targetUrl = stringValue3(options.url) || stringValue3(targetInput.url);
|
|
10714
10974
|
const route = stringValue3(options.route) || stringValue3(targetInput.route);
|
|
10715
10975
|
if (!targetUrl && !route) throw new Error("profile.target requires url or route, or pass --url.");
|
|
10976
|
+
const setupActions = normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions);
|
|
10977
|
+
for (const [index, check] of checks.entries()) {
|
|
10978
|
+
if (check.type !== "ordered_trace") continue;
|
|
10979
|
+
const matches = (setupActions || []).filter((action) => action.label === check.setup_action_label);
|
|
10980
|
+
if (matches.length !== 1) {
|
|
10981
|
+
throw new Error(`checks[${index}] ordered_trace setup_action_label must match exactly one target.setup_actions label.`);
|
|
10982
|
+
}
|
|
10983
|
+
if (!["window_eval", "window_call", "window_call_until"].includes(matches[0].type)) {
|
|
10984
|
+
throw new Error(`checks[${index}] ordered_trace source action must capture a window_eval, window_call, or window_call_until return.`);
|
|
10985
|
+
}
|
|
10986
|
+
if (matches[0].capture_return === false) {
|
|
10987
|
+
throw new Error(`checks[${index}] ordered_trace source action must not set capture_return to false.`);
|
|
10988
|
+
}
|
|
10989
|
+
}
|
|
10716
10990
|
return {
|
|
10717
10991
|
version: RIDDLE_PROOF_PROFILE_VERSION,
|
|
10718
10992
|
name: normalizeName(input.name, "riddle-proof-profile"),
|
|
@@ -10725,7 +10999,7 @@ function normalizeRiddleProofProfile(input, options = {}) {
|
|
|
10725
10999
|
wait_for_selector: stringValue3(targetInput.wait_for_selector) || stringValue3(targetInput.waitForSelector),
|
|
10726
11000
|
wait_ms: numberValue2(targetInput.wait_ms) ?? numberValue2(targetInput.waitMs),
|
|
10727
11001
|
screenshot_full_page: normalizeTargetScreenshotFullPage(targetInput),
|
|
10728
|
-
setup_actions:
|
|
11002
|
+
setup_actions: setupActions,
|
|
10729
11003
|
network_mocks: normalizeNetworkMocks(targetInput.network_mocks ?? targetInput.networkMocks)
|
|
10730
11004
|
},
|
|
10731
11005
|
checks,
|
|
@@ -11738,6 +12012,32 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
11738
12012
|
message: failed ? `Selector ${key} text order failed in ${failed} viewport(s).` : void 0
|
|
11739
12013
|
};
|
|
11740
12014
|
}
|
|
12015
|
+
if (check.type === "ordered_trace") {
|
|
12016
|
+
const assessments = viewports.map((viewport) => ({
|
|
12017
|
+
viewport: viewport.name,
|
|
12018
|
+
assessment: assessRiddleProofOrderedTraceSetupResults(
|
|
12019
|
+
viewport.setup_action_results,
|
|
12020
|
+
check.setup_action_label || "",
|
|
12021
|
+
check.trace_path || "",
|
|
12022
|
+
check.events || []
|
|
12023
|
+
)
|
|
12024
|
+
}));
|
|
12025
|
+
const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
|
|
12026
|
+
const failed = assessments.filter((item) => item.assessment.status === "failed");
|
|
12027
|
+
const status = insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed";
|
|
12028
|
+
return {
|
|
12029
|
+
type: check.type,
|
|
12030
|
+
label: checkLabel(check),
|
|
12031
|
+
status,
|
|
12032
|
+
evidence: {
|
|
12033
|
+
setup_action_label: check.setup_action_label || "",
|
|
12034
|
+
trace_path: check.trace_path || "",
|
|
12035
|
+
events: toJsonValue((check.events || []).map((event) => event.label)),
|
|
12036
|
+
viewports: toJsonValue(assessments)
|
|
12037
|
+
},
|
|
12038
|
+
message: insufficient.length ? `Ordered trace evidence was insufficient in ${insufficient.length} viewport(s).` : failed.length ? `Ordered trace did not contain the required event sequence in ${failed.length} viewport(s).` : void 0
|
|
12039
|
+
};
|
|
12040
|
+
}
|
|
11741
12041
|
if (check.type === "observe_within") {
|
|
11742
12042
|
const key = observeWithinKey(check);
|
|
11743
12043
|
const timeoutMs = observeWithinTimeoutMs(check);
|
|
@@ -12237,6 +12537,7 @@ function profileStatusFromEvidence(profile, evidence, checks) {
|
|
|
12237
12537
|
if (!viewports.length || !checks.length) return "proof_insufficient";
|
|
12238
12538
|
if (viewports.some((viewport) => viewport.navigation_error)) return "environment_blocked";
|
|
12239
12539
|
if (expectedViewportCount && viewports.length < expectedViewportCount) return "proof_insufficient";
|
|
12540
|
+
if (checks.some((check) => check.status === "proof_insufficient")) return "proof_insufficient";
|
|
12240
12541
|
if (checks.some((check) => check.status === "needs_human_review")) return "needs_human_review";
|
|
12241
12542
|
if (checks.some((check) => check.status === "failed")) return "product_regression";
|
|
12242
12543
|
return "passed";
|
|
@@ -12566,8 +12867,12 @@ function createRiddleProofProfileInsufficientResult(input) {
|
|
|
12566
12867
|
error: message
|
|
12567
12868
|
};
|
|
12568
12869
|
}
|
|
12569
|
-
function runtimeScriptAssessmentSource() {
|
|
12870
|
+
function runtimeScriptAssessmentSource(includeOrderedTrace = false) {
|
|
12871
|
+
const orderedTraceSource = includeOrderedTrace ? String.raw`
|
|
12872
|
+
const assessRiddleProofOrderedTrace = ${assessRiddleProofOrderedTrace.toString()};
|
|
12873
|
+
const assessRiddleProofOrderedTraceSetupResults = ${assessRiddleProofOrderedTraceSetupResults.toString()};` : "";
|
|
12570
12874
|
return String.raw`
|
|
12875
|
+
${orderedTraceSource}
|
|
12571
12876
|
function normalizeRoutePath(path) {
|
|
12572
12877
|
const value = path || "/";
|
|
12573
12878
|
if (value === "/") return "/";
|
|
@@ -13397,6 +13702,7 @@ function profileSetupWindowCallReceipts(results) {
|
|
|
13397
13702
|
.map((result) => {
|
|
13398
13703
|
const receipt = {
|
|
13399
13704
|
ordinal: result.ordinal ?? null,
|
|
13705
|
+
label: result.label ?? null,
|
|
13400
13706
|
ok: result.ok !== false,
|
|
13401
13707
|
path: result.path ?? null,
|
|
13402
13708
|
return_captured: result.return_captured ?? null,
|
|
@@ -13417,6 +13723,7 @@ function profileSetupWindowEvalReceipts(results) {
|
|
|
13417
13723
|
.map((result) => {
|
|
13418
13724
|
const receipt = {
|
|
13419
13725
|
ordinal: result.ordinal ?? null,
|
|
13726
|
+
label: result.label ?? null,
|
|
13420
13727
|
ok: result.ok !== false,
|
|
13421
13728
|
script_length: result.script_length ?? null,
|
|
13422
13729
|
return_captured: result.return_captured ?? null,
|
|
@@ -14232,6 +14539,36 @@ function assessProfile(profile, evidence) {
|
|
|
14232
14539
|
});
|
|
14233
14540
|
continue;
|
|
14234
14541
|
}
|
|
14542
|
+
if (check.type === "ordered_trace") {
|
|
14543
|
+
const assessments = checkViewports.map((viewport) => ({
|
|
14544
|
+
viewport: viewport.name,
|
|
14545
|
+
assessment: assessRiddleProofOrderedTraceSetupResults(
|
|
14546
|
+
viewport.setup_action_results,
|
|
14547
|
+
check.setup_action_label || "",
|
|
14548
|
+
check.trace_path || "",
|
|
14549
|
+
check.events || [],
|
|
14550
|
+
),
|
|
14551
|
+
}));
|
|
14552
|
+
const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
|
|
14553
|
+
const failed = assessments.filter((item) => item.assessment.status === "failed");
|
|
14554
|
+
checks.push({
|
|
14555
|
+
type: check.type,
|
|
14556
|
+
label: check.label || check.type,
|
|
14557
|
+
status: insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed",
|
|
14558
|
+
evidence: {
|
|
14559
|
+
setup_action_label: check.setup_action_label || "",
|
|
14560
|
+
trace_path: check.trace_path || "",
|
|
14561
|
+
events: (check.events || []).map((event) => event.label),
|
|
14562
|
+
viewports: assessments,
|
|
14563
|
+
},
|
|
14564
|
+
message: insufficient.length
|
|
14565
|
+
? "Ordered trace evidence was insufficient in " + insufficient.length + " viewport(s)."
|
|
14566
|
+
: failed.length
|
|
14567
|
+
? "Ordered trace did not contain the required event sequence in " + failed.length + " viewport(s)."
|
|
14568
|
+
: undefined,
|
|
14569
|
+
});
|
|
14570
|
+
continue;
|
|
14571
|
+
}
|
|
14235
14572
|
if (check.type === "observe_within") {
|
|
14236
14573
|
const key = observeWithinKey(check);
|
|
14237
14574
|
const timeoutMs = observeWithinTimeoutMs(check);
|
|
@@ -14588,6 +14925,7 @@ function assessProfile(profile, evidence) {
|
|
|
14588
14925
|
if (!viewports.length || !checks.length) status = "proof_insufficient";
|
|
14589
14926
|
else if (viewports.some((viewport) => viewport.navigation_error)) status = "environment_blocked";
|
|
14590
14927
|
else if (expectedViewportCount && viewports.length < expectedViewportCount) status = "proof_insufficient";
|
|
14928
|
+
else if (checks.some((check) => check.status === "proof_insufficient")) status = "proof_insufficient";
|
|
14591
14929
|
else if (checks.some((check) => check.status === "needs_human_review")) status = "needs_human_review";
|
|
14592
14930
|
else if (checks.some((check) => check.status === "failed")) status = "product_regression";
|
|
14593
14931
|
const screenshotLabels = profileScreenshotLabels(viewports);
|
|
@@ -15519,7 +15857,7 @@ let activeViewportName = null;
|
|
|
15519
15857
|
async function executeSetupAction(action, ordinal, viewport) {
|
|
15520
15858
|
const type = setupActionType(action);
|
|
15521
15859
|
const frameSelector = setupFrameSelector(action);
|
|
15522
|
-
const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null, frame_selector: frameSelector || null, optional: action.optional === true };
|
|
15860
|
+
const base = { ok: false, action: type || "unknown", ordinal, label: action.label || null, selector: action.selector || null, frame_selector: frameSelector || null, optional: action.optional === true };
|
|
15523
15861
|
const timeout = setupNumber(action.timeout_ms, 5000);
|
|
15524
15862
|
try {
|
|
15525
15863
|
if (type === "wait") {
|
|
@@ -18171,7 +18509,7 @@ async function captureViewport(viewport) {
|
|
|
18171
18509
|
wait_error: waitError,
|
|
18172
18510
|
};
|
|
18173
18511
|
}
|
|
18174
|
-
${runtimeScriptAssessmentSource()}
|
|
18512
|
+
${runtimeScriptAssessmentSource(profile.checks.some((check) => check.type === "ordered_trace"))}
|
|
18175
18513
|
const viewports = [];
|
|
18176
18514
|
function buildProfileEvidence(currentViewports) {
|
|
18177
18515
|
const expectedViewportCount = (profile.target.viewports || []).length;
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-QYZ3GKCP.js";
|
|
3
3
|
import "./chunk-5IFZSUPF.js";
|
|
4
4
|
import "./chunk-JFQXAJH2.js";
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-7OAETQU3.js";
|
|
6
|
+
import "./chunk-FW7CKARF.js";
|
|
7
|
+
import "./chunk-LR4UYJDY.js";
|
|
8
8
|
import "./chunk-MEVVL4TI.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-2K3DIK7A.js";
|
|
10
10
|
import "./chunk-KXLEN4SA.js";
|
|
11
11
|
import "./chunk-WLUMLHII.js";
|
|
12
12
|
import "./chunk-CGJX7LJO.js";
|