@riddledc/riddle-proof 0.7.183 → 0.7.184

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 CHANGED
@@ -245,9 +245,13 @@ The package includes generic starter profiles:
245
245
  - `examples/profiles/handled-recovery-action-malformed-success.json` for action recovery profiles where the request succeeds at HTTP level but returns an unusable body.
246
246
  - `examples/profiles/terminal-result-partial-evidence.json` for API-console terminal error or timeout receipts that preserve partial screenshot, console, and HAR evidence.
247
247
  - `examples/profiles/gameplay-window-call-until.json` for gameplay profiles that wait on a runtime state contract instead of a fixed sleep.
248
+ - `examples/profiles/spa-route-exit-state-hygiene.json` for SPA routes that must clean up short-lived proof helpers, receipts, timers, input state, or touch state after visible UI navigation exits the route.
248
249
 
249
250
  Copy one of those shapes into a repository profile directory and replace the
250
251
  routes, selectors, mock URLs, and text checks with app-specific invariants.
252
+ For route-exit hygiene profiles, replace the watched global names with state
253
+ that is expected to exist while the route is active and expected to disappear
254
+ after navigation returns to the owning app shell.
251
255
 
252
256
  For handled recovery profiles, prefer proving the whole boundary instead of
253
257
  only checking that an error message appears. Mock one dependent endpoint into a
@@ -3460,6 +3460,7 @@ function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
3460
3460
  checks,
3461
3461
  summary: summarizeRiddleProofProfileResult({ profile_name: profile.name, status, checks, viewports: evidence?.viewports || [] }),
3462
3462
  captured_at: capturedAt,
3463
+ metadata: profile.metadata,
3463
3464
  warnings: warnings.length ? warnings : void 0,
3464
3465
  evidence,
3465
3466
  riddle: options.riddle
@@ -3521,6 +3522,7 @@ function createRiddleProofProfileEnvironmentBlockedResult(input) {
3521
3522
  checks: [],
3522
3523
  summary: summarizeEnvironmentBlockedRunner(input.profile.name, environmentBlocker),
3523
3524
  captured_at: (/* @__PURE__ */ new Date()).toISOString(),
3525
+ metadata: input.profile.metadata,
3524
3526
  warnings: warnings.length ? warnings : void 0,
3525
3527
  riddle: input.riddle,
3526
3528
  environment_blocker: environmentBlocker,
@@ -3597,6 +3599,7 @@ function createRiddleProofProfileInsufficientResult(input) {
3597
3599
  checks: [],
3598
3600
  summary: `${input.profile.name} did not produce enough evidence for a profile judgment.`,
3599
3601
  captured_at: (/* @__PURE__ */ new Date()).toISOString(),
3602
+ metadata: input.profile.metadata,
3600
3603
  warnings: warnings.length ? warnings : void 0,
3601
3604
  riddle: input.riddle,
3602
3605
  error: message
@@ -5523,6 +5526,7 @@ function assessProfile(profile, evidence) {
5523
5526
  checks,
5524
5527
  summary,
5525
5528
  captured_at: evidence.captured_at,
5529
+ metadata: profile.metadata,
5526
5530
  warnings: profileWarnings.length ? profileWarnings : undefined,
5527
5531
  evidence,
5528
5532
  };
package/dist/cli.cjs CHANGED
@@ -10417,6 +10417,7 @@ function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
10417
10417
  checks,
10418
10418
  summary: summarizeRiddleProofProfileResult({ profile_name: profile.name, status, checks, viewports: evidence?.viewports || [] }),
10419
10419
  captured_at: capturedAt,
10420
+ metadata: profile.metadata,
10420
10421
  warnings: warnings.length ? warnings : void 0,
10421
10422
  evidence,
10422
10423
  riddle: options.riddle
@@ -10462,6 +10463,7 @@ function createRiddleProofProfileEnvironmentBlockedResult(input) {
10462
10463
  checks: [],
10463
10464
  summary: summarizeEnvironmentBlockedRunner(input.profile.name, environmentBlocker),
10464
10465
  captured_at: (/* @__PURE__ */ new Date()).toISOString(),
10466
+ metadata: input.profile.metadata,
10465
10467
  warnings: warnings.length ? warnings : void 0,
10466
10468
  riddle: input.riddle,
10467
10469
  environment_blocker: environmentBlocker,
@@ -10538,6 +10540,7 @@ function createRiddleProofProfileInsufficientResult(input) {
10538
10540
  checks: [],
10539
10541
  summary: `${input.profile.name} did not produce enough evidence for a profile judgment.`,
10540
10542
  captured_at: (/* @__PURE__ */ new Date()).toISOString(),
10543
+ metadata: input.profile.metadata,
10541
10544
  warnings: warnings.length ? warnings : void 0,
10542
10545
  riddle: input.riddle,
10543
10546
  error: message
@@ -12464,6 +12467,7 @@ function assessProfile(profile, evidence) {
12464
12467
  checks,
12465
12468
  summary,
12466
12469
  captured_at: evidence.captured_at,
12470
+ metadata: profile.metadata,
12467
12471
  warnings: profileWarnings.length ? profileWarnings : undefined,
12468
12472
  evidence,
12469
12473
  };
@@ -16179,6 +16183,10 @@ function profileResultMarkdown(result) {
16179
16183
  if (result.warnings.length > 12) lines.push(`- ${result.warnings.length - 12} additional warning(s) omitted.`);
16180
16184
  lines.push("");
16181
16185
  }
16186
+ const packMetadataLines = profilePackMetadataMarkdown(result);
16187
+ if (packMetadataLines.length) {
16188
+ lines.push("## Proof Pack", "", ...packMetadataLines, "");
16189
+ }
16182
16190
  lines.push("## Checks", "");
16183
16191
  for (const check of result.checks) {
16184
16192
  lines.push(`- ${check.status}: ${profileCheckMarkdownLabel(check)}`);
@@ -16188,6 +16196,18 @@ function profileResultMarkdown(result) {
16188
16196
  if (setupSummaryLines.length) {
16189
16197
  lines.push("", "## Setup Summary", "", ...setupSummaryLines);
16190
16198
  }
16199
+ const reachabilitySummaryLines = profileReachabilitySummaryMarkdown(result);
16200
+ if (reachabilitySummaryLines.length) {
16201
+ lines.push("", "## Reachability", "", ...reachabilitySummaryLines);
16202
+ }
16203
+ const stateContractSummaryLines = profileStateContractSummaryMarkdown(result);
16204
+ if (stateContractSummaryLines.length) {
16205
+ lines.push("", "## State Contract", "", ...stateContractSummaryLines);
16206
+ }
16207
+ const sideCaveatSummaryLines = profileSideCaveatSummaryMarkdown(result);
16208
+ if (sideCaveatSummaryLines.length) {
16209
+ lines.push("", "## Side Caveats", "", ...sideCaveatSummaryLines);
16210
+ }
16191
16211
  const networkMockSummaryLines = profileNetworkMockSummaryMarkdown(result);
16192
16212
  if (networkMockSummaryLines.length) {
16193
16213
  lines.push("", "## Network Mocks", "", ...networkMockSummaryLines);
@@ -16286,6 +16306,222 @@ function profileRiddleJobMarkdown(result) {
16286
16306
  if (splitJobs.length > 12) lines.push(`- ${splitJobs.length - 12} additional split job(s) omitted.`);
16287
16307
  return lines;
16288
16308
  }
16309
+ function profileMetadataStringArray(value) {
16310
+ return Array.isArray(value) ? value.map((item) => typeof item === "string" ? item.trim() : "").filter((item) => Boolean(item)) : [];
16311
+ }
16312
+ function profileSetupSummaryRecord(result) {
16313
+ const setupCheck = result.checks.find((check) => check.type === "setup_actions_succeeded");
16314
+ return cliRecord(setupCheck?.evidence?.setup_summary);
16315
+ }
16316
+ function profileSetupSummaryViewports(result) {
16317
+ const setupSummary = profileSetupSummaryRecord(result);
16318
+ return Array.isArray(setupSummary?.viewports) ? setupSummary.viewports.map(cliRecord).filter((viewport) => Boolean(viewport)) : [];
16319
+ }
16320
+ function profileHasPassedCheck(result, types) {
16321
+ return result.checks.some((check) => types.includes(check.type) && check.status === "passed");
16322
+ }
16323
+ function profileHasCheck(result, types) {
16324
+ return result.checks.some((check) => types.includes(check.type));
16325
+ }
16326
+ function profileSetupScreenshotCount(viewports) {
16327
+ return viewports.reduce((sum, viewport) => {
16328
+ const setupScreenshots = Array.isArray(viewport.setup_screenshots) ? viewport.setup_screenshots.filter((label) => typeof label === "string" && label.trim()).length : 0;
16329
+ const finalScreenshot = cliString(viewport.final_screenshot) || cliString(viewport.screenshot_label) ? 1 : 0;
16330
+ return sum + setupScreenshots + finalScreenshot;
16331
+ }, 0);
16332
+ }
16333
+ function profileSetupReceiptTotal(viewports, key) {
16334
+ return viewports.reduce((sum, viewport) => sum + setupReceiptArray(viewport, key).filter((receipt) => receipt.ok !== false).length, 0);
16335
+ }
16336
+ function profileSetupFailureCount(viewports) {
16337
+ return viewports.reduce((sum, viewport) => {
16338
+ const failed = Array.isArray(viewport.failed) ? viewport.failed : [];
16339
+ return sum + failed.filter((failure) => Boolean(cliRecord(failure))).length;
16340
+ }, 0);
16341
+ }
16342
+ function profileSetupObstructionCount(viewports) {
16343
+ return viewports.reduce((sum, viewport) => {
16344
+ const failed = Array.isArray(viewport.failed) ? viewport.failed.map(cliRecord).filter((failure) => Boolean(failure)) : [];
16345
+ return sum + failed.filter((failure) => Boolean(setupFailureObstructionSnippet(cliString(failure.reason)))).length;
16346
+ }, 0);
16347
+ }
16348
+ function profileResultHasArtifact(result) {
16349
+ return Boolean(
16350
+ result.artifacts.proof_json || result.artifacts.console || result.artifacts.dom_summary || result.artifacts.screenshots?.length || result.artifacts.riddle_artifacts?.some((artifact) => artifact.url || artifact.path || artifact.name)
16351
+ );
16352
+ }
16353
+ function profileReceiptSignalStatus(hasSignal, presentReason, missingReason) {
16354
+ return hasSignal ? { status: "present", reason: presentReason } : { status: "missing", reason: missingReason };
16355
+ }
16356
+ function profilePackReceiptStatus(result, metadata, receipt) {
16357
+ const text = receipt.toLowerCase();
16358
+ const setupSummary = profileSetupSummaryRecord(result);
16359
+ const setupViewports = profileSetupSummaryViewports(result);
16360
+ const evidenceViewports = Array.isArray(result.evidence?.viewports) ? result.evidence.viewports : [];
16361
+ const setupResultCount = setupViewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.result_count) || 0), 0);
16362
+ const setupScreenshotCount = profileSetupScreenshotCount(setupViewports);
16363
+ const screenshotCount = (result.artifacts.screenshots?.length || 0) + evidenceViewports.filter((viewport) => cliString(viewport.screenshot_label)).length + setupScreenshotCount;
16364
+ const windowEvalCount = profileSetupReceiptTotal(setupViewports, "window_eval");
16365
+ const valueReceipts = [
16366
+ ...setupViewports.flatMap((viewport) => setupReceiptArray(viewport, "window_eval")),
16367
+ ...setupViewports.flatMap((viewport) => setupReceiptArray(viewport, "window_call"))
16368
+ ].filter((item) => item.ok !== false);
16369
+ const clickCount = setupViewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.clicked_total) || 0), 0) + profileSetupReceiptTotal(setupViewports, "click") + profileSetupReceiptTotal(setupViewports, "click_count");
16370
+ const setupFailureCount = profileSetupFailureCount(setupViewports);
16371
+ const setupObstructionCount = profileSetupObstructionCount(setupViewports);
16372
+ const inputDispatchCount = profileSetupReceiptTotal(setupViewports, "drag") + profileSetupReceiptTotal(setupViewports, "tap") + profileSetupReceiptTotal(setupViewports, "press") + profileSetupReceiptTotal(setupViewports, "keyboard_sequence");
16373
+ const canvasReceipts = setupViewports.flatMap((viewport) => setupReceiptArray(viewport, "canvas_signature"));
16374
+ const hasCanvasChange = canvasReceipts.some((item) => item.ok !== false && item.changed === true);
16375
+ const canvasSignatureHashes = canvasReceipts.filter((item) => item.ok !== false).map((item) => cliString(item.hash)).filter(Boolean);
16376
+ const hasCanvasSignatureChange = hasCanvasChange || new Set(canvasSignatureHashes).size >= 2;
16377
+ const hasNaturalInput = setupNaturalInputSummaryMarkdown(setupViewports).length > 0;
16378
+ const hasStateContract = profileStateContractSummaryMarkdown(result).length > 0 || Boolean(cliRecord(metadata.declared_state_contract));
16379
+ const hasInvalidStateReceipt = valueReceipts.some((item) => {
16380
+ const state = setupReturnSummaryValue(item, ["state", "nextState"]);
16381
+ return typeof state === "string" && state.toLowerCase().includes("invalid");
16382
+ });
16383
+ const hasErrorDetailReceipt = valueReceipts.some((item) => setupReturnSummaryValue(item, ["hasErrorDetail", "errorDetail", "error_detail"]) === true);
16384
+ const hasGridEvidence = valueReceipts.some((item) => setupReturnSummaryValue(item, ["itemCount", "grid.width", "gridWidth", "visibleGridCount"]) !== void 0);
16385
+ const hasVisibleControlReceipt = valueReceipts.some((item) => setupReturnSummaryValue(item, ["visibleButtonCount", "visibleControlCount"]) !== void 0 || setupReturnSummaryValue(item, ["buttonStillVisible", "controlStillVisible"]) === true);
16386
+ const hasToolSelectionReceipt = valueReceipts.some((item) => setupReturnSummaryValue(item, ["rectangleChecked", "toolSelected", "toolChecked", "selected"]) === true);
16387
+ const hasStateGrowthReceipt = valueReceipts.some((item) => {
16388
+ const delta = cliFiniteNumber(setupReturnSummaryValue(item, ["delta", "countDelta", "itemDelta", "stateDelta"]));
16389
+ if (delta !== void 0 && delta > 0) return true;
16390
+ const before = cliFiniteNumber(setupReturnSummaryValue(item, ["before", "beforeCount", "previousCount"]));
16391
+ const after = cliFiniteNumber(setupReturnSummaryValue(item, ["after", "afterCount", "itemCount", "count"]));
16392
+ return before !== void 0 && after !== void 0 && after > before;
16393
+ });
16394
+ const hasReachability = profileReachabilitySummaryMarkdown(result).length > 0 || result.checks.some((check) => check.type === "selector_visible" && Boolean(cliRecord(check.evidence)?.selector));
16395
+ const hasOverflowEvidence = result.checks.some((check) => check.type === "no_horizontal_overflow" || check.type === "no_mobile_horizontal_overflow" || check.type === "frame_no_horizontal_overflow") || evidenceViewports.some((viewport) => (cliFiniteNumber(viewport.overflow_px) || 0) > 0 || (cliFiniteNumber(viewport.bounds_overflow_px) || 0) > 0 || Boolean(viewport.overflow_offenders?.length));
16396
+ const hasConsoleAccounting = profileHasCheck(result, ["no_console_warnings", "no_fatal_console_errors"]) || Boolean(result.evidence?.console || result.evidence?.page_errors);
16397
+ const hasDomSummary = Boolean(result.artifacts.dom_summary || result.evidence?.dom_summary);
16398
+ const hasProofJson = Boolean(result.artifacts.proof_json || result.version === "riddle-proof.profile-result.v1");
16399
+ const hasRouteViewport = Boolean(result.route?.requested || result.route?.observed) && Boolean(evidenceViewports.length || result.route?.matched !== void 0);
16400
+ const hasSetupReceipts = setupResultCount > 0 || Boolean(setupSummary);
16401
+ const hasTextVisibility = profileHasPassedCheck(result, ["text_visible", "selector_text_visible", "selector_visible"]);
16402
+ const hasTextAbsence = profileHasPassedCheck(result, ["text_absent", "selector_text_absent"]);
16403
+ const hasMeasuredStateChange = hasNaturalInput || hasCanvasChange || valueReceipts.some((item) => setupReturnSummaryValue(item, ["changed"]) === true || setupReturnSummaryValue(item, ["nonWhiteDelta", "darkDelta", "pixelDelta", "movementDelta"]) !== void 0);
16404
+ if (text.includes("artifact link") || text.includes("artifact path")) {
16405
+ return profileReceiptSignalStatus(profileResultHasArtifact(result), "artifact references listed", "no artifact references found");
16406
+ }
16407
+ if (text.includes("proof json")) return profileReceiptSignalStatus(hasProofJson, "proof JSON artifact named", "proof JSON artifact missing");
16408
+ if (text.includes("dom summary")) return profileReceiptSignalStatus(hasDomSummary, "DOM summary evidence present", "DOM summary evidence missing");
16409
+ if (text.includes("console") || text.includes("warning") || text.includes("fatal") || text.includes("browser warning") || text.includes("graphics")) {
16410
+ return profileReceiptSignalStatus(hasConsoleAccounting, "console checks or evidence present", "console accounting evidence missing");
16411
+ }
16412
+ if (text.includes("route") && text.includes("viewport")) {
16413
+ return profileReceiptSignalStatus(hasRouteViewport, "route and viewport evidence present", "route or viewport evidence missing");
16414
+ }
16415
+ if (text.includes("setup action")) {
16416
+ return profileReceiptSignalStatus(hasSetupReceipts, "setup receipts present", "setup receipts missing");
16417
+ }
16418
+ if (text.includes("declared state contract")) {
16419
+ return profileReceiptSignalStatus(hasStateContract, "state contract metadata or receipts present", "state contract evidence missing");
16420
+ }
16421
+ if (text.includes("stale") || text.includes("absence")) {
16422
+ return profileReceiptSignalStatus(hasTextAbsence, "absence check passed", "absence check missing");
16423
+ }
16424
+ if (text.includes("recovered") || text.includes("final state")) {
16425
+ return profileReceiptSignalStatus(hasStateContract || hasTextVisibility, "final state receipt present", "final state receipt missing");
16426
+ }
16427
+ if (text.includes("error detail")) {
16428
+ const hasRequiredState = !text.includes("invalid") || hasInvalidStateReceipt;
16429
+ return profileReceiptSignalStatus(
16430
+ hasRequiredState && hasErrorDetailReceipt,
16431
+ "error-detail state receipt present",
16432
+ "error-detail state receipt missing"
16433
+ );
16434
+ }
16435
+ if (text.includes("invalid state")) {
16436
+ return profileReceiptSignalStatus(hasStateContract || hasInvalidStateReceipt, "invalid-state receipt present", "invalid-state receipt missing");
16437
+ }
16438
+ if (text.includes("retry") || text.includes("repair") || text.includes("reset") || text.includes("affordance")) {
16439
+ return profileReceiptSignalStatus(hasStateContract || clickCount > 0, "affordance or transition receipt present", "affordance receipt missing");
16440
+ }
16441
+ if (text.includes("failure") || text.includes("mutation")) {
16442
+ return profileReceiptSignalStatus(hasStateContract || windowEvalCount > 0 || clickCount > 0, "failure or mutation receipt present", "failure or mutation receipt missing");
16443
+ }
16444
+ if (text.includes("initial") && (text.includes("visible") || text.includes("state"))) {
16445
+ return profileReceiptSignalStatus(hasTextVisibility || screenshotCount > 0, "initial visible-state evidence present", "initial state evidence missing");
16446
+ }
16447
+ if (text.includes("state-growth") || text.includes("state growth") || text.includes("growth receipt") || text.includes("grid grows") || text.includes("state") && text.includes("after the click")) {
16448
+ return profileReceiptSignalStatus(hasStateGrowthReceipt, "state-growth receipt present", "state-growth receipt missing");
16449
+ }
16450
+ if (text.includes("visible grid") || text.includes("control evidence") || text.includes("grid") && text.includes("control")) {
16451
+ return profileReceiptSignalStatus(
16452
+ hasGridEvidence && (hasVisibleControlReceipt || hasReachability),
16453
+ "visible grid/control evidence present",
16454
+ "visible grid/control evidence missing"
16455
+ );
16456
+ }
16457
+ if (text.includes("tool") && text.includes("selected") || text.includes("rectangle tool")) {
16458
+ return profileReceiptSignalStatus(hasToolSelectionReceipt, "tool-selection receipt present", "tool-selection receipt missing");
16459
+ }
16460
+ if (text.includes("canvas signature")) {
16461
+ return profileReceiptSignalStatus(hasCanvasSignatureChange, "canvas signature change evidence present", "canvas signature evidence missing");
16462
+ }
16463
+ if (text.includes("selector count") || text.includes("visible count") || text.includes("control visibility") || text.includes("reachability gate") || text.includes("visible control")) {
16464
+ return profileReceiptSignalStatus(hasReachability, "selector visibility or reachability evidence present", "reachability evidence missing");
16465
+ }
16466
+ if (text.includes("overflow") || text.includes("clipped") || text.includes("fit")) {
16467
+ return profileReceiptSignalStatus(hasOverflowEvidence, "overflow evidence present", "overflow evidence missing");
16468
+ }
16469
+ if (text.includes("click receipt") || text.includes("obstruction receipt") || text.includes("state mutation")) {
16470
+ return profileReceiptSignalStatus(clickCount > 0 || setupObstructionCount > 0, "click or obstruction receipt present", "click or obstruction receipt missing");
16471
+ }
16472
+ if (text.includes("target selector") || text.includes("target selector/text")) {
16473
+ return profileReceiptSignalStatus(hasReachability || hasTextVisibility, "selector or text check evidence present", "selector/text evidence missing");
16474
+ }
16475
+ if (text.includes("intercepting element")) {
16476
+ if (setupObstructionCount > 0) return { status: "present", reason: "obstruction receipt present" };
16477
+ return setupFailureCount > 0 ? { status: "missing", reason: "setup failed without intercepting element evidence" } : { status: "manual", reason: "only applies when blocked" };
16478
+ }
16479
+ if (text.includes("before and after state")) {
16480
+ return profileReceiptSignalStatus(
16481
+ hasStateContract || valueReceipts.length >= 2 || screenshotCount >= 2,
16482
+ "before/after state evidence present",
16483
+ "before/after state evidence missing"
16484
+ );
16485
+ }
16486
+ if (text.includes("screenshot")) {
16487
+ const needsBoundaryScreenshots = text.includes("each") || text.includes("before and after") || text.includes("state boundary");
16488
+ return profileReceiptSignalStatus(
16489
+ needsBoundaryScreenshots ? screenshotCount >= 2 : screenshotCount > 0,
16490
+ needsBoundaryScreenshots ? "multiple screenshots present" : "screenshot evidence present",
16491
+ needsBoundaryScreenshots ? "multiple screenshots missing" : "screenshot evidence missing"
16492
+ );
16493
+ }
16494
+ if (text.includes("input dispatch") || text.includes("pointer") || text.includes("touch") || text.includes("key event") || text.includes("trusted-event")) {
16495
+ return profileReceiptSignalStatus(inputDispatchCount > 0 || hasNaturalInput, "input dispatch evidence present", "input dispatch evidence missing");
16496
+ }
16497
+ if (text.includes("measured") || text.includes("state-change") || text.includes("pixel delta") || text.includes("movement receipt") || text.includes("canvas hash")) {
16498
+ return profileReceiptSignalStatus(hasMeasuredStateChange, "measured-change evidence present", "measured-change evidence missing");
16499
+ }
16500
+ return { status: "manual", reason: "semantic receipt requires audit review" };
16501
+ }
16502
+ function profilePackMetadataMarkdown(result) {
16503
+ const metadata = cliRecord(result.metadata);
16504
+ if (!metadata) return [];
16505
+ const packId = cliString(metadata.pack_id);
16506
+ const packPublicName = cliString(metadata.pack_public_name);
16507
+ const requiredReceipts = profileMetadataStringArray(metadata.required_receipts);
16508
+ if (!packId && !packPublicName && !requiredReceipts.length) return [];
16509
+ const lines = [];
16510
+ const packParts = [
16511
+ packId ? markdownInlineCode(packId) : "",
16512
+ packPublicName ? packPublicName : ""
16513
+ ].filter(Boolean);
16514
+ if (packParts.length) lines.push(`- pack: ${packParts.join(" - ")}`);
16515
+ if (requiredReceipts.length) {
16516
+ lines.push(`- required receipts: ${requiredReceipts.length}`);
16517
+ for (const receipt of requiredReceipts.slice(0, 20)) {
16518
+ const item = profilePackReceiptStatus(result, metadata, receipt);
16519
+ lines.push(` - ${item.status}: ${receipt} (${item.reason})`);
16520
+ }
16521
+ if (requiredReceipts.length > 20) lines.push(` - ${requiredReceipts.length - 20} additional required receipt(s) omitted.`);
16522
+ }
16523
+ return lines;
16524
+ }
16289
16525
  function markdownInlineCode(value, maxLength = 80) {
16290
16526
  const normalized = value.replace(/\s+/g, " ").trim();
16291
16527
  const clipped = normalized.length > maxLength ? `${normalized.slice(0, Math.max(0, maxLength - 3))}...` : normalized;
@@ -16547,6 +16783,221 @@ function setupNaturalInputSummaryMarkdown(viewports) {
16547
16783
  }
16548
16784
  return lines;
16549
16785
  }
16786
+ function reachabilityFailureReason(reason) {
16787
+ if (!reason) return void 0;
16788
+ const noVisibleMatch = /No visible match for selector [\s\S]*?:\s*([^\n]+)/.exec(reason);
16789
+ if (noVisibleMatch?.[1]) return noVisibleMatch[1].trim().slice(0, 120);
16790
+ if (/no_visible_match/.test(reason)) return "no_visible_match";
16791
+ if (/not visible/i.test(reason)) return "not_visible";
16792
+ return void 0;
16793
+ }
16794
+ function viewportTopBoundsOverflowPx(viewport) {
16795
+ const direct = cliFiniteNumber(viewport.bounds_overflow_px);
16796
+ if (direct !== void 0 && direct > 0) return direct;
16797
+ const offenders = Array.isArray(viewport.overflow_offenders) ? viewport.overflow_offenders.map(cliRecord).filter((item) => Boolean(item)) : [];
16798
+ for (const offender of offenders) {
16799
+ const overflow = cliFiniteNumber(offender.bounds_overflow_px) ?? cliFiniteNumber(offender.overflow_px) ?? cliFiniteNumber(offender.overflow);
16800
+ if (overflow !== void 0 && overflow > 0) return overflow;
16801
+ }
16802
+ const scrollOverflow = cliFiniteNumber(viewport.overflow_px);
16803
+ return scrollOverflow !== void 0 && scrollOverflow > 0 ? scrollOverflow : void 0;
16804
+ }
16805
+ function profileReachabilitySummaryMarkdown(result) {
16806
+ const evidenceViewports = Array.isArray(result.evidence?.viewports) ? result.evidence.viewports.map((viewport) => cliRecord(viewport)).filter((viewport) => Boolean(viewport)) : [];
16807
+ if (!evidenceViewports.length) return [];
16808
+ const evidenceByName = /* @__PURE__ */ new Map();
16809
+ for (const viewport of evidenceViewports) {
16810
+ const name = cliString(viewport.name);
16811
+ if (name) evidenceByName.set(name, viewport);
16812
+ }
16813
+ const receipts = [];
16814
+ const seen = /* @__PURE__ */ new Set();
16815
+ const addReceipt = (viewportName, selector, reason) => {
16816
+ const viewport = evidenceByName.get(viewportName);
16817
+ if (!viewport) return;
16818
+ const selectors = cliRecord(viewport.selectors);
16819
+ const selectorEvidence = cliRecord(selectors?.[selector]);
16820
+ const count = cliFiniteNumber(selectorEvidence?.count);
16821
+ const visibleCount = cliFiniteNumber(selectorEvidence?.visible_count);
16822
+ if (count === void 0 || count <= 0 || visibleCount === void 0 || visibleCount > 0) return;
16823
+ const key = `${viewportName}\0${selector}`;
16824
+ if (seen.has(key)) return;
16825
+ seen.add(key);
16826
+ const reasonText = reason || "no_visible_match";
16827
+ const boundsOverflow = viewportTopBoundsOverflowPx(viewport);
16828
+ receipts.push(`- reachability ${viewportName}: ${markdownInlineCode(selector, 120)} exists ${count}, visible ${visibleCount}, reason ${markdownInlineCode(reasonText, 80)}${boundsOverflow === void 0 ? "" : `, top bounds overflow ${boundsOverflow}px`}`);
16829
+ };
16830
+ const setupCheck = result.checks.find((check) => check.type === "setup_actions_succeeded");
16831
+ const setupSummary = cliRecord(setupCheck?.evidence?.setup_summary);
16832
+ const setupViewports = Array.isArray(setupSummary?.viewports) ? setupSummary.viewports.map(cliRecord).filter((viewport) => Boolean(viewport)) : [];
16833
+ for (const viewport of setupViewports) {
16834
+ const viewportName = cliString(viewport.name) || "viewport";
16835
+ const failed = [
16836
+ ...Array.isArray(viewport.failed) ? viewport.failed : [],
16837
+ ...Array.isArray(viewport.optional_failed) ? viewport.optional_failed : []
16838
+ ].map(cliRecord).filter((failure) => Boolean(failure));
16839
+ for (const failure of failed) {
16840
+ const selector = cliString(failure.selector);
16841
+ const reason = reachabilityFailureReason(cliString(failure.reason));
16842
+ if (selector && reason) addReceipt(viewportName, selector, reason);
16843
+ }
16844
+ }
16845
+ for (const check of result.checks) {
16846
+ if (check.type !== "selector_visible" || check.status !== "failed") continue;
16847
+ const evidence = cliRecord(check.evidence);
16848
+ const selector = cliString(evidence?.selector);
16849
+ if (!selector) continue;
16850
+ for (const viewport of evidenceViewports) {
16851
+ const viewportName = cliString(viewport.name) || "viewport";
16852
+ addReceipt(viewportName, selector, "no_visible_match");
16853
+ }
16854
+ }
16855
+ if (receipts.length > 8) {
16856
+ return [...receipts.slice(0, 8), `- ${receipts.length - 8} additional reachability receipt(s) omitted.`];
16857
+ }
16858
+ return receipts;
16859
+ }
16860
+ function stateContractReceiptName(receipt, fallbackIndex) {
16861
+ const storedTo = cliString(receipt.return_stored_to);
16862
+ if (!storedTo) return `receipt-${fallbackIndex + 1}`;
16863
+ const parts = storedTo.split(".").map((part) => part.trim()).filter(Boolean);
16864
+ return parts[parts.length - 1] || storedTo;
16865
+ }
16866
+ function stateContractReceiptValue(receipt) {
16867
+ const value = setupReturnSummaryValue(receipt, [
16868
+ "state",
16869
+ "nextState",
16870
+ "terminalState",
16871
+ "finalState",
16872
+ "status",
16873
+ "phase"
16874
+ ]);
16875
+ return cliValueLabel(value);
16876
+ }
16877
+ function stateContractSignalParts(receipts) {
16878
+ const names = [
16879
+ "hasValidate",
16880
+ "hasTryFix",
16881
+ "hasErrorDetail",
16882
+ "hasValid",
16883
+ "hasInvalid",
16884
+ "invalidGone",
16885
+ "staleGone",
16886
+ "staleCopyGone",
16887
+ "repairedTrailingCommaGone",
16888
+ "hasSuccess",
16889
+ "hasFailure",
16890
+ "hasRetry",
16891
+ "hasError",
16892
+ "success",
16893
+ "recovered"
16894
+ ];
16895
+ const seen = /* @__PURE__ */ new Set();
16896
+ const parts = [];
16897
+ for (const receipt of receipts) {
16898
+ for (const name of names) {
16899
+ const value = setupReturnSummaryValue(receipt, [name]);
16900
+ if (value === void 0) continue;
16901
+ const label = cliValueLabel(value);
16902
+ if (label === void 0) continue;
16903
+ const part = `${name}=${label}`;
16904
+ if (seen.has(part)) continue;
16905
+ seen.add(part);
16906
+ parts.push(part);
16907
+ if (parts.length >= 8) return parts;
16908
+ }
16909
+ }
16910
+ return parts;
16911
+ }
16912
+ function profileStateContractSummaryMarkdown(result) {
16913
+ const setupCheck = result.checks.find((check) => check.type === "setup_actions_succeeded");
16914
+ const setupSummary = cliRecord(setupCheck?.evidence?.setup_summary);
16915
+ const viewports = Array.isArray(setupSummary?.viewports) ? setupSummary.viewports.map(cliRecord).filter((viewport) => Boolean(viewport)) : [];
16916
+ const lines = [];
16917
+ for (const viewport of viewports.slice(0, 8)) {
16918
+ const name = cliString(viewport.name) || "viewport";
16919
+ const receipts = [
16920
+ ...setupReceiptArray(viewport, "window_eval"),
16921
+ ...setupReceiptArray(viewport, "window_call"),
16922
+ ...setupReceiptArray(viewport, "window_call_until")
16923
+ ].filter((receipt) => receipt.ok !== false);
16924
+ const states = receipts.map((receipt, index) => ({
16925
+ name: stateContractReceiptName(receipt, index),
16926
+ state: stateContractReceiptValue(receipt)
16927
+ })).filter((receipt) => Boolean(receipt.state));
16928
+ if (states.length < 2) continue;
16929
+ const stateChain = states.slice(0, 6).map((receipt) => `${markdownInlineCode(receipt.name, 60)}=${markdownInlineCode(receipt.state, 80)}`).join(" -> ");
16930
+ const omitted = states.length > 6 ? ` (+${states.length - 6} more)` : "";
16931
+ const signals = stateContractSignalParts(receipts);
16932
+ lines.push(`- state contract ${name}: ${stateChain}${omitted}${signals.length ? `; signals ${signals.map((part) => markdownInlineCode(part, 80)).join(", ")}` : ""}`);
16933
+ }
16934
+ return lines;
16935
+ }
16936
+ function sideCaveatAllowlistPart(evidence, totalKey, allowedKey) {
16937
+ const total = cliFiniteNumber(evidence[totalKey]);
16938
+ const allowed = cliFiniteNumber(evidence[allowedKey]);
16939
+ if (total === void 0 || allowed === void 0 || allowed <= 0) return void 0;
16940
+ return `${allowed}/${total} allowed`;
16941
+ }
16942
+ function sideCaveatAllowlistCounts(evidence) {
16943
+ const textCount = Array.isArray(evidence.allowed_console_texts) ? evidence.allowed_console_texts.filter((value) => typeof value === "string" && value.trim()).length : 0;
16944
+ const patternCount = Array.isArray(evidence.allowed_console_patterns) ? evidence.allowed_console_patterns.filter((value) => typeof value === "string" && value.trim()).length : 0;
16945
+ return textCount || patternCount ? `allowlist ${textCount} text${textCount === 1 ? "" : "s"}, ${patternCount} pattern${patternCount === 1 ? "" : "s"}` : void 0;
16946
+ }
16947
+ function overflowCheckFailed(result) {
16948
+ return result.checks.some((check) => check.status === "failed" && (check.type === "no_horizontal_overflow" || check.type === "no_mobile_horizontal_overflow" || check.type === "frame_no_horizontal_overflow"));
16949
+ }
16950
+ function sideCaveatOverflowLine(viewport) {
16951
+ const name = cliString(viewport.name) || "viewport";
16952
+ const scrollOverflow = cliFiniteNumber(viewport.overflow_px);
16953
+ const boundsOverflow = cliFiniteNumber(viewport.bounds_overflow_px);
16954
+ if ((scrollOverflow === void 0 || scrollOverflow <= 0) && (boundsOverflow === void 0 || boundsOverflow <= 0)) return void 0;
16955
+ const parts = [
16956
+ scrollOverflow !== void 0 && scrollOverflow > 0 ? `scroll overflow ${scrollOverflow}px` : "",
16957
+ boundsOverflow !== void 0 && boundsOverflow > 0 ? `bounds overflow ${boundsOverflow}px` : ""
16958
+ ].filter(Boolean);
16959
+ const offenders = Array.isArray(viewport.overflow_offenders) ? viewport.overflow_offenders.map(cliRecord).filter((item) => Boolean(item)) : [];
16960
+ const offender = offenders.find((item) => {
16961
+ const overflow = cliFiniteNumber(item.bounds_overflow_px) ?? cliFiniteNumber(item.overflow_px) ?? cliFiniteNumber(item.overflow);
16962
+ return overflow !== void 0 && overflow > 0;
16963
+ });
16964
+ const offenderSelector = cliString(offender?.selector);
16965
+ const offenderOverflow = offender ? cliFiniteNumber(offender.bounds_overflow_px) ?? cliFiniteNumber(offender.overflow_px) ?? cliFiniteNumber(offender.overflow) : void 0;
16966
+ return `- side caveat layout ${name}: ${parts.join(", ")}${offenderSelector && offenderOverflow !== void 0 ? `; top offender ${markdownInlineCode(offenderSelector, 100)} ${offenderOverflow}px` : ""}`;
16967
+ }
16968
+ function profileSideCaveatSummaryMarkdown(result) {
16969
+ const lines = [];
16970
+ for (const check of result.checks) {
16971
+ if (check.status !== "passed") continue;
16972
+ const evidence = cliRecord(check.evidence);
16973
+ if (!evidence) continue;
16974
+ if (check.type === "no_console_warnings") {
16975
+ const allowed = sideCaveatAllowlistPart(evidence, "total_console_warning_count", "allowed_console_warning_count");
16976
+ if (allowed) {
16977
+ const allowlist = sideCaveatAllowlistCounts(evidence);
16978
+ lines.push(`- side caveat console warnings: ${allowed}${allowlist ? `; ${allowlist}` : ""}`);
16979
+ }
16980
+ }
16981
+ if (check.type === "no_fatal_console_errors") {
16982
+ const consoleAllowed = sideCaveatAllowlistPart(evidence, "total_console_fatal_count", "allowed_console_fatal_count");
16983
+ const pageAllowed = sideCaveatAllowlistPart(evidence, "total_page_error_count", "allowed_page_error_count");
16984
+ const parts = [
16985
+ consoleAllowed ? `console fatal ${consoleAllowed}` : "",
16986
+ pageAllowed ? `page errors ${pageAllowed}` : "",
16987
+ sideCaveatAllowlistCounts(evidence)
16988
+ ].filter(Boolean);
16989
+ if (parts.length) lines.push(`- side caveat fatal errors: ${parts.join("; ")}`);
16990
+ }
16991
+ }
16992
+ if (!overflowCheckFailed(result) && Array.isArray(result.evidence?.viewports)) {
16993
+ for (const viewport of result.evidence.viewports.slice(0, 8)) {
16994
+ const line = sideCaveatOverflowLine(cliRecord(viewport) || {});
16995
+ if (line) lines.push(line);
16996
+ }
16997
+ if (result.evidence.viewports.length > 8) lines.push(`- ${result.evidence.viewports.length - 8} additional viewport side caveat(s) omitted.`);
16998
+ }
16999
+ return lines.slice(0, 12);
17000
+ }
16550
17001
  function balancedSetupReceiptDetails(groups, limit) {
16551
17002
  if (limit <= 0) return [];
16552
17003
  const total = groups.reduce((sum, group) => sum + group.length, 0);
@@ -17264,7 +17715,7 @@ async function readArtifactJson(artifact) {
17264
17715
  async function profileResultFromRiddleArtifacts(profile, artifacts, fallbackInputs) {
17265
17716
  for (const input of fallbackInputs) {
17266
17717
  const result = extractRiddleProofProfileResult(input);
17267
- if (result) return result;
17718
+ if (result) return withProfileMetadata(profile, result);
17268
17719
  }
17269
17720
  const proofArtifacts = artifacts.filter((artifact) => /(^|\/)proof\.json(?:\.json)?$/i.test(artifact.name || artifact.url || artifact.path || "")).sort((left, right) => {
17270
17721
  const leftName = left.name || left.url || left.path || "";
@@ -17274,7 +17725,7 @@ async function profileResultFromRiddleArtifacts(profile, artifacts, fallbackInpu
17274
17725
  for (const artifact of proofArtifacts) {
17275
17726
  const parsed = await readArtifactJson(artifact);
17276
17727
  const result = extractRiddleProofProfileResult(parsed);
17277
- if (result) return result;
17728
+ if (result) return withProfileMetadata(profile, result);
17278
17729
  }
17279
17730
  const evidenceArtifacts = artifacts.filter((artifact) => /profile-evidence|evidence\.json/i.test(artifact.name || artifact.url || artifact.path || ""));
17280
17731
  for (const artifact of evidenceArtifacts) {
@@ -17285,6 +17736,16 @@ async function profileResultFromRiddleArtifacts(profile, artifacts, fallbackInpu
17285
17736
  }
17286
17737
  return void 0;
17287
17738
  }
17739
+ function withProfileMetadata(profile, result) {
17740
+ if (!profile.metadata || !Object.keys(profile.metadata).length) return result;
17741
+ return {
17742
+ ...result,
17743
+ metadata: {
17744
+ ...profile.metadata,
17745
+ ...result.metadata || {}
17746
+ }
17747
+ };
17748
+ }
17288
17749
  function withRiddleMetadata(result, input) {
17289
17750
  const poll = input.poll;
17290
17751
  const staleJobIds = input.staleJobIds?.filter(Boolean);
@@ -17628,7 +18089,7 @@ async function runSingleRiddleProfileForCli(profile, options, input) {
17628
18089
  jobId = typeof created.job_id === "string" ? created.job_id : typeof created.id === "string" ? created.id : "";
17629
18090
  if (!jobId) {
17630
18091
  const directResult = extractRiddleProofProfileResult(created);
17631
- return directResult ? withRiddleMetadata(directResult, { artifacts: collectRiddleProfileArtifactRefs(created) }) : createRiddleProofProfileInsufficientResult({ profile, runner, error: "Riddle run response was missing job_id.", artifacts: collectRiddleProfileArtifactRefs(created) });
18092
+ return directResult ? withRiddleMetadata(withProfileMetadata(profile, directResult), { artifacts: collectRiddleProfileArtifactRefs(created) }) : createRiddleProofProfileInsufficientResult({ profile, runner, error: "Riddle run response was missing job_id.", artifacts: collectRiddleProfileArtifactRefs(created) });
17632
18093
  }
17633
18094
  poll = await client.pollJob(jobId, pollOptions);
17634
18095
  if (attempt < retryLimit && shouldRetryUnsubmittedRiddleJob(poll)) {