@riddledc/riddle-proof 0.7.8 → 0.7.10

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/profile.cjs CHANGED
@@ -23,6 +23,7 @@ __export(profile_exports, {
23
23
  RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
24
24
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: () => RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
25
25
  RIDDLE_PROOF_PROFILE_RESULT_VERSION: () => RIDDLE_PROOF_PROFILE_RESULT_VERSION,
26
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: () => RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
26
27
  RIDDLE_PROOF_PROFILE_STATUSES: () => RIDDLE_PROOF_PROFILE_STATUSES,
27
28
  RIDDLE_PROOF_PROFILE_VERSION: () => RIDDLE_PROOF_PROFILE_VERSION,
28
29
  assessRiddleProofProfileEvidence: () => assessRiddleProofProfileEvidence,
@@ -60,6 +61,12 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
60
61
  "no_mobile_horizontal_overflow",
61
62
  "no_fatal_console_errors"
62
63
  ];
64
+ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
65
+ "click",
66
+ "wait",
67
+ "wait_for_selector",
68
+ "wait_for_text"
69
+ ];
63
70
  var DEFAULT_VIEWPORTS = [
64
71
  { name: "desktop", width: 1280, height: 800 }
65
72
  ];
@@ -112,6 +119,41 @@ function normalizeViewports(value) {
112
119
  function isSupportedCheckType(value) {
113
120
  return RIDDLE_PROOF_PROFILE_CHECK_TYPES.includes(value);
114
121
  }
122
+ function normalizeSetupActionType(value, index) {
123
+ const normalized = String(value || "").trim().replace(/-/g, "_");
124
+ if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
125
+ return normalized;
126
+ }
127
+ throw new Error(`target.setup_actions[${index}].type ${value || "(missing)"} is not supported. Supported actions: ${RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.join(", ")}`);
128
+ }
129
+ function normalizeSetupAction(input, index) {
130
+ if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
131
+ const type = normalizeSetupActionType(stringValue(input.type), index);
132
+ const selector = stringValue(input.selector);
133
+ if ((type === "click" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
134
+ throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
135
+ }
136
+ if (type === "wait_for_text" && !stringValue(input.text) && !stringValue(input.pattern)) {
137
+ throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
138
+ }
139
+ return {
140
+ type,
141
+ selector,
142
+ text: stringValue(input.text),
143
+ pattern: stringValue(input.pattern),
144
+ flags: stringValue(input.flags),
145
+ index: numberValue(input.index),
146
+ ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
147
+ timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
148
+ after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
149
+ continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
150
+ };
151
+ }
152
+ function normalizeSetupActions(value) {
153
+ if (value === void 0) return void 0;
154
+ if (!Array.isArray(value)) throw new Error("target.setup_actions must be an array.");
155
+ return value.map(normalizeSetupAction);
156
+ }
115
157
  function normalizeCheck(input, index) {
116
158
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
117
159
  const type = stringValue(input.type);
@@ -179,7 +221,8 @@ function normalizeRiddleProofProfile(input, options = {}) {
179
221
  viewports: options.viewports?.length ? options.viewports : normalizeViewports(targetInput.viewports),
180
222
  auth: stringValue(targetInput.auth) || "none",
181
223
  wait_for_selector: stringValue(targetInput.wait_for_selector) || stringValue(targetInput.waitForSelector),
182
- wait_ms: numberValue(targetInput.wait_ms) ?? numberValue(targetInput.waitMs)
224
+ wait_ms: numberValue(targetInput.wait_ms) ?? numberValue(targetInput.waitMs),
225
+ setup_actions: normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions)
183
226
  },
184
227
  checks,
185
228
  artifacts: Array.isArray(input.artifacts) ? input.artifacts.map((item) => String(item)).filter(Boolean) : ["screenshot", "console", "dom_summary", "proof_json"],
@@ -197,7 +240,13 @@ function resolveRiddleProofProfileTargetUrl(profile) {
197
240
  throw new Error("profile target URL could not be resolved.");
198
241
  }
199
242
  function routeForViewport(viewport) {
200
- return viewport?.route || {
243
+ if (viewport?.route) {
244
+ return {
245
+ ...viewport.route,
246
+ matched: viewport.route.matched || routePathMatches(viewport.route.observed, viewport.route.expected_path)
247
+ };
248
+ }
249
+ return {
201
250
  requested: "",
202
251
  observed: "",
203
252
  matched: false,
@@ -223,8 +272,17 @@ function matchText(sample, check) {
223
272
  }
224
273
  return sample.includes(check.text || "");
225
274
  }
275
+ function normalizeRoutePath(path) {
276
+ const value = path || "/";
277
+ if (value === "/") return "/";
278
+ return value.replace(/\/+$/, "") || "/";
279
+ }
280
+ function routePathMatches(observed, expected) {
281
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
282
+ }
226
283
  function successfulRoute(route) {
227
- return route.matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
284
+ const matched = route.matched || routePathMatches(route.observed, route.expected_path);
285
+ return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
228
286
  }
229
287
  function assessCheckFromEvidence(check, evidence) {
230
288
  const viewports = evidence.viewports || [];
@@ -242,7 +300,7 @@ function assessCheckFromEvidence(check, evidence) {
242
300
  const failed = viewports.filter((viewport) => !successfulRoute({
243
301
  ...viewport.route,
244
302
  expected_path: expectedPath,
245
- matched: viewport.route.observed === expectedPath || viewport.route.matched
303
+ matched: routePathMatches(viewport.route.observed, expectedPath) || viewport.route.matched
246
304
  }));
247
305
  return {
248
306
  type: check.type,
@@ -352,6 +410,48 @@ function assessCheckFromEvidence(check, evidence) {
352
410
  message: "Unsupported check type."
353
411
  };
354
412
  }
413
+ function assessSetupActionsFromEvidence(profile, evidence) {
414
+ if (!profile.target.setup_actions?.length) return void 0;
415
+ const actionCount = profile.target.setup_actions.length;
416
+ const failed = [];
417
+ const viewports = evidence.viewports || [];
418
+ for (const viewport of viewports) {
419
+ const results = viewport.setup_action_results || [];
420
+ for (const result of results) {
421
+ if (result.ok === false) {
422
+ failed.push({
423
+ viewport: viewport.name,
424
+ action: result.action ?? result.type ?? null,
425
+ selector: result.selector ?? null,
426
+ reason: result.reason ?? result.error ?? null
427
+ });
428
+ }
429
+ }
430
+ if (results.length < actionCount && results.every((result) => result.ok !== false)) {
431
+ failed.push({
432
+ viewport: viewport.name,
433
+ action: "setup_actions",
434
+ selector: null,
435
+ reason: `missing setup action results: ${results.length}/${actionCount}`
436
+ });
437
+ }
438
+ }
439
+ return {
440
+ type: "setup_actions_succeeded",
441
+ label: "setup actions succeeded",
442
+ status: failed.length ? "failed" : "passed",
443
+ evidence: {
444
+ action_count: actionCount,
445
+ viewports: viewports.map((viewport) => ({
446
+ name: viewport.name,
447
+ ok: (viewport.setup_action_results || []).length >= actionCount && (viewport.setup_action_results || []).every((result) => result.ok !== false),
448
+ result_count: (viewport.setup_action_results || []).length
449
+ })),
450
+ failed
451
+ },
452
+ message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
453
+ };
454
+ }
355
455
  function profileStatusFromEvidence(evidence, checks) {
356
456
  if (!evidence) return "proof_insufficient";
357
457
  const viewports = evidence.viewports || [];
@@ -363,7 +463,10 @@ function profileStatusFromEvidence(evidence, checks) {
363
463
  }
364
464
  function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
365
465
  const capturedAt = evidence?.captured_at || (/* @__PURE__ */ new Date()).toISOString();
366
- const checks = evidence ? profile.checks.map((check) => assessCheckFromEvidence(check, evidence)) : [];
466
+ const checks = evidence ? [
467
+ assessSetupActionsFromEvidence(profile, evidence),
468
+ ...profile.checks.map((check) => assessCheckFromEvidence(check, evidence))
469
+ ].filter((check) => Boolean(check)) : [];
367
470
  const status = profileStatusFromEvidence(evidence, checks);
368
471
  const firstViewport = evidence?.viewports?.[0];
369
472
  const screenshots = (evidence?.viewports || []).map((viewport) => viewport.screenshot_label).filter((label) => Boolean(label));
@@ -465,8 +568,16 @@ function createRiddleProofProfileInsufficientResult(input) {
465
568
  }
466
569
  function runtimeScriptAssessmentSource() {
467
570
  return String.raw`
571
+ function normalizeRoutePath(path) {
572
+ const value = path || "/";
573
+ if (value === "/") return "/";
574
+ return value.replace(/\/+$/, "") || "/";
575
+ }
576
+ function routePathMatches(observed, expected) {
577
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
578
+ }
468
579
  function routeOk(route) {
469
- return Boolean(route && route.matched && !route.error && (route.http_status == null || route.http_status < 400));
580
+ return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path)) && !route.error && (route.http_status == null || route.http_status < 400));
470
581
  }
471
582
  function textMatches(sample, check) {
472
583
  if (check.pattern) {
@@ -477,12 +588,53 @@ function textMatches(sample, check) {
477
588
  function assessProfile(profile, evidence) {
478
589
  const checks = [];
479
590
  const viewports = evidence.viewports || [];
591
+ if (profile.target && Array.isArray(profile.target.setup_actions) && profile.target.setup_actions.length) {
592
+ const actionCount = profile.target.setup_actions.length;
593
+ const failed = [];
594
+ for (const viewport of viewports) {
595
+ const results = viewport.setup_action_results || [];
596
+ for (const result of results) {
597
+ if (result && result.ok === false) {
598
+ failed.push({
599
+ viewport: viewport.name,
600
+ action: result.action || result.type || null,
601
+ selector: result.selector || null,
602
+ reason: result.reason || result.error || null,
603
+ });
604
+ }
605
+ }
606
+ if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
607
+ failed.push({
608
+ viewport: viewport.name,
609
+ action: "setup_actions",
610
+ selector: null,
611
+ reason: "missing setup action results: " + results.length + "/" + actionCount,
612
+ });
613
+ }
614
+ }
615
+ checks.push({
616
+ type: "setup_actions_succeeded",
617
+ label: "setup actions succeeded",
618
+ status: failed.length ? "failed" : "passed",
619
+ evidence: {
620
+ action_count: actionCount,
621
+ viewports: viewports.map((viewport) => ({
622
+ name: viewport.name,
623
+ ok: (viewport.setup_action_results || []).length >= actionCount
624
+ && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false),
625
+ result_count: (viewport.setup_action_results || []).length,
626
+ })),
627
+ failed,
628
+ },
629
+ message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
630
+ });
631
+ }
480
632
  for (const check of profile.checks || []) {
481
633
  if (check.type === "route_loaded") {
482
634
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
483
635
  const failed = viewports.filter((viewport) => {
484
636
  const route = { ...(viewport.route || {}), expected_path: expectedPath };
485
- route.matched = route.observed === expectedPath || route.matched;
637
+ route.matched = routePathMatches(route.observed, expectedPath) || route.matched;
486
638
  return !routeOk(route);
487
639
  });
488
640
  checks.push({
@@ -639,6 +791,105 @@ function textMatches(sample, check) {
639
791
  }
640
792
  return String(sample || "").includes(check.text || "");
641
793
  }
794
+ function setupActionType(action) {
795
+ return String(action && action.type ? action.type : "").replace(/-/g, "_");
796
+ }
797
+ function setupNumber(value, fallback) {
798
+ const number = Number(value);
799
+ return Number.isFinite(number) && number >= 0 ? number : fallback;
800
+ }
801
+ function setupTextMatches(sample, action) {
802
+ if (action.pattern) {
803
+ try { return new RegExp(action.pattern, action.flags || "").test(sample || ""); } catch { return false; }
804
+ }
805
+ return String(sample || "").includes(action.text || "");
806
+ }
807
+ async function setupLocatorText(locator, index) {
808
+ return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
809
+ }
810
+ async function setupLocatorVisible(locator, index) {
811
+ return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
812
+ }
813
+ async function executeSetupAction(action, ordinal) {
814
+ const type = setupActionType(action);
815
+ const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
816
+ const timeout = setupNumber(action.timeout_ms, 5000);
817
+ try {
818
+ if (type === "wait") {
819
+ const ms = setupNumber(action.ms, 500);
820
+ await page.waitForTimeout(ms);
821
+ return { ...base, ok: true, ms };
822
+ }
823
+ if (type === "wait_for_selector") {
824
+ await page.waitForSelector(action.selector, { state: "visible", timeout });
825
+ return { ...base, ok: true, timeout_ms: timeout };
826
+ }
827
+ if (type === "click") {
828
+ const locator = page.locator(action.selector);
829
+ const count = await locator.count();
830
+ if (!count) return { ...base, reason: "selector_not_found", count };
831
+ let targetIndex = Number.isInteger(action.index) ? action.index : 0;
832
+ let matchedText = null;
833
+ let hiddenMatchIndex = -1;
834
+ let hiddenMatchedText = null;
835
+ if (action.text || action.pattern) {
836
+ targetIndex = -1;
837
+ for (let index = 0; index < count; index += 1) {
838
+ const text = await setupLocatorText(locator, index);
839
+ if (setupTextMatches(text, action)) {
840
+ const visible = await setupLocatorVisible(locator, index);
841
+ if (visible) {
842
+ targetIndex = index;
843
+ matchedText = text;
844
+ break;
845
+ }
846
+ if (hiddenMatchIndex < 0) {
847
+ hiddenMatchIndex = index;
848
+ hiddenMatchedText = text;
849
+ }
850
+ }
851
+ }
852
+ if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
853
+ if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
854
+ }
855
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
856
+ await locator.nth(targetIndex).click({ timeout });
857
+ return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
858
+ }
859
+ if (type === "wait_for_text") {
860
+ const locator = page.locator(action.selector);
861
+ const startedAt = Date.now();
862
+ let lastText = "";
863
+ while (Date.now() - startedAt <= timeout) {
864
+ const count = await locator.count().catch(() => 0);
865
+ for (let index = 0; index < count; index += 1) {
866
+ const text = await setupLocatorText(locator, index);
867
+ lastText = text || lastText;
868
+ if (setupTextMatches(text, action)) {
869
+ return { ...base, ok: true, text, target_index: index, timeout_ms: timeout };
870
+ }
871
+ }
872
+ await page.waitForTimeout(100);
873
+ }
874
+ return { ...base, reason: "text_not_found", text: lastText, timeout_ms: timeout };
875
+ }
876
+ return { ...base, reason: "unsupported_action" };
877
+ } catch (error) {
878
+ return { ...base, error: String(error && error.message ? error.message : error).slice(0, 1000) };
879
+ }
880
+ }
881
+ async function executeSetupActions(actions) {
882
+ const results = [];
883
+ for (let index = 0; index < (actions || []).length; index += 1) {
884
+ const action = actions[index] || {};
885
+ const result = await executeSetupAction(action, index);
886
+ results.push(result);
887
+ const afterMs = setupNumber(action.after_ms, 0);
888
+ if (afterMs) await page.waitForTimeout(afterMs);
889
+ if (result.ok === false && action.continue_on_failure !== true) break;
890
+ }
891
+ return results;
892
+ }
642
893
  function expectedPathFor(check) {
643
894
  return check.expected_path || new URL(targetUrl).pathname || "/";
644
895
  }
@@ -673,6 +924,9 @@ async function captureViewport(viewport) {
673
924
  if (!navigationError && profile.target.wait_ms) {
674
925
  await page.waitForTimeout(profile.target.wait_ms);
675
926
  }
927
+ const setupActionResults = (!navigationError && !waitError)
928
+ ? await executeSetupActions(profile.target.setup_actions || [])
929
+ : [];
676
930
  const dom = await page.evaluate(() => {
677
931
  const body = document.body;
678
932
  const documentElement = document.documentElement;
@@ -722,7 +976,7 @@ async function captureViewport(viewport) {
722
976
  requested: targetUrl,
723
977
  observed: dom.pathname,
724
978
  expected_path: expectedPath,
725
- matched: dom.pathname === expectedPath,
979
+ matched: routePathMatches(dom.pathname, expectedPath),
726
980
  http_status: httpStatus,
727
981
  error: navigationError || waitError || undefined,
728
982
  },
@@ -734,6 +988,7 @@ async function captureViewport(viewport) {
734
988
  overflow_px: Math.max(0, (dom.scroll_width || 0) - (dom.client_width || viewport.width)),
735
989
  selectors,
736
990
  text_matches,
991
+ setup_action_results: setupActionResults,
737
992
  screenshot_label: screenshotLabel,
738
993
  navigation_error: navigationError,
739
994
  wait_error: waitError,
@@ -831,6 +1086,7 @@ function extractRiddleProofProfileResult(input) {
831
1086
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
832
1087
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
833
1088
  RIDDLE_PROOF_PROFILE_RESULT_VERSION,
1089
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
834
1090
  RIDDLE_PROOF_PROFILE_STATUSES,
835
1091
  RIDDLE_PROOF_PROFILE_VERSION,
836
1092
  assessRiddleProofProfileEvidence,
@@ -5,8 +5,10 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "selector_visible", "selector_count_at_least", "text_visible", "text_absent", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "wait", "wait_for_selector", "wait_for_text"];
8
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
9
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
+ type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
10
12
  type RiddleProofProfileRunner = "riddle" | "local-playwright" | "browserless" | "github-actions" | (string & {});
11
13
  type RiddleProofProfileFailureAction = "fail" | "neutral" | "review";
12
14
  type RiddleProofProfileBaselinePolicy = "invariant_only" | "production_comparison" | "last_accepted_artifact" | "golden_reference_artifact" | (string & {});
@@ -15,6 +17,18 @@ interface RiddleProofProfileViewport {
15
17
  width: number;
16
18
  height: number;
17
19
  }
20
+ interface RiddleProofProfileSetupAction {
21
+ type: RiddleProofProfileSetupActionType;
22
+ selector?: string;
23
+ text?: string;
24
+ pattern?: string;
25
+ flags?: string;
26
+ index?: number;
27
+ ms?: number;
28
+ timeout_ms?: number;
29
+ after_ms?: number;
30
+ continue_on_failure?: boolean;
31
+ }
18
32
  interface RiddleProofProfileTarget {
19
33
  url?: string;
20
34
  route?: string;
@@ -22,6 +36,7 @@ interface RiddleProofProfileTarget {
22
36
  auth?: "none" | (string & {});
23
37
  wait_for_selector?: string;
24
38
  wait_ms?: number;
39
+ setup_actions?: RiddleProofProfileSetupAction[];
25
40
  }
26
41
  interface RiddleProofProfileCheck {
27
42
  type: RiddleProofProfileCheckType;
@@ -69,6 +84,7 @@ interface RiddleProofProfileViewportEvidence {
69
84
  visible_count: number;
70
85
  }>;
71
86
  text_matches?: Record<string, boolean>;
87
+ setup_action_results?: Array<Record<string, JsonValue>>;
72
88
  screenshot_label?: string;
73
89
  navigation_error?: string;
74
90
  wait_error?: string;
@@ -172,4 +188,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
172
188
  declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
173
189
  declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
174
190
 
175
- export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRunner, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
191
+ export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
package/dist/profile.d.ts CHANGED
@@ -5,8 +5,10 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "selector_visible", "selector_count_at_least", "text_visible", "text_absent", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "wait", "wait_for_selector", "wait_for_text"];
8
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
9
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
+ type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
10
12
  type RiddleProofProfileRunner = "riddle" | "local-playwright" | "browserless" | "github-actions" | (string & {});
11
13
  type RiddleProofProfileFailureAction = "fail" | "neutral" | "review";
12
14
  type RiddleProofProfileBaselinePolicy = "invariant_only" | "production_comparison" | "last_accepted_artifact" | "golden_reference_artifact" | (string & {});
@@ -15,6 +17,18 @@ interface RiddleProofProfileViewport {
15
17
  width: number;
16
18
  height: number;
17
19
  }
20
+ interface RiddleProofProfileSetupAction {
21
+ type: RiddleProofProfileSetupActionType;
22
+ selector?: string;
23
+ text?: string;
24
+ pattern?: string;
25
+ flags?: string;
26
+ index?: number;
27
+ ms?: number;
28
+ timeout_ms?: number;
29
+ after_ms?: number;
30
+ continue_on_failure?: boolean;
31
+ }
18
32
  interface RiddleProofProfileTarget {
19
33
  url?: string;
20
34
  route?: string;
@@ -22,6 +36,7 @@ interface RiddleProofProfileTarget {
22
36
  auth?: "none" | (string & {});
23
37
  wait_for_selector?: string;
24
38
  wait_ms?: number;
39
+ setup_actions?: RiddleProofProfileSetupAction[];
25
40
  }
26
41
  interface RiddleProofProfileCheck {
27
42
  type: RiddleProofProfileCheckType;
@@ -69,6 +84,7 @@ interface RiddleProofProfileViewportEvidence {
69
84
  visible_count: number;
70
85
  }>;
71
86
  text_matches?: Record<string, boolean>;
87
+ setup_action_results?: Array<Record<string, JsonValue>>;
72
88
  screenshot_label?: string;
73
89
  navigation_error?: string;
74
90
  wait_error?: string;
@@ -172,4 +188,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
172
188
  declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
173
189
  declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
174
190
 
175
- export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRunner, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
191
+ export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
package/dist/profile.js CHANGED
@@ -2,6 +2,7 @@ import {
2
2
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
3
3
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
4
4
  RIDDLE_PROOF_PROFILE_RESULT_VERSION,
5
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
5
6
  RIDDLE_PROOF_PROFILE_STATUSES,
6
7
  RIDDLE_PROOF_PROFILE_VERSION,
7
8
  assessRiddleProofProfileEvidence,
@@ -16,11 +17,12 @@ import {
16
17
  resolveRiddleProofProfileTargetUrl,
17
18
  slugifyRiddleProofProfileName,
18
19
  summarizeRiddleProofProfileResult
19
- } from "./chunk-7NMAU4DP.js";
20
+ } from "./chunk-A7RJZD4I.js";
20
21
  export {
21
22
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
22
23
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
23
24
  RIDDLE_PROOF_PROFILE_RESULT_VERSION,
25
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
24
26
  RIDDLE_PROOF_PROFILE_STATUSES,
25
27
  RIDDLE_PROOF_PROFILE_VERSION,
26
28
  assessRiddleProofProfileEvidence,
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
295
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
385
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
662
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
295
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
385
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
662
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -8,7 +8,10 @@
8
8
  { "name": "desktop", "width": 1440, "height": 1000 }
9
9
  ],
10
10
  "auth": "none",
11
- "wait_for_selector": "body"
11
+ "wait_for_selector": "body",
12
+ "setup_actions": [
13
+ { "type": "wait", "ms": 250 }
14
+ ]
12
15
  },
13
16
  "checks": [
14
17
  { "type": "route_loaded", "expected_path": "/" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.8",
3
+ "version": "0.7.10",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",