@riddledc/riddle-proof 0.8.76 → 0.8.78
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 +74 -5
- package/dist/advanced/index.d.cts +1 -1
- package/dist/advanced/index.d.ts +1 -1
- package/dist/advanced/proof-run-engine.d.cts +1 -1
- package/dist/advanced/proof-run-engine.d.ts +1 -1
- package/dist/change-proof.cjs +991 -7
- package/dist/change-proof.d.cts +157 -1
- package/dist/change-proof.d.ts +157 -1
- package/dist/change-proof.js +25 -3
- package/dist/{chunk-B2DP2LET.js → chunk-5IFZSUPF.js} +52 -13
- package/dist/chunk-6VFS2JFR.js +886 -0
- package/dist/{chunk-CWRIXP5H.js → chunk-7N6X54WG.js} +181 -17
- package/dist/{chunk-GG2D3MFZ.js → chunk-FCSJZBC5.js} +26 -1
- package/dist/{chunk-AK2EPEVO.js → chunk-HSGZV2NK.js} +221 -63
- package/dist/chunk-MEVVL4TI.js +258 -0
- package/dist/{chunk-UE4I7RTI.js → chunk-RQPCKRKT.js} +1 -1
- package/dist/cli/index.js +7 -6
- package/dist/cli.cjs +1678 -361
- package/dist/cli.js +7 -6
- package/dist/index.cjs +1242 -42
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +46 -10
- package/dist/pr-comment.cjs +481 -17
- package/dist/pr-comment.d.cts +6 -1
- package/dist/pr-comment.d.ts +6 -1
- package/dist/pr-comment.js +6 -1
- package/dist/profile/index.cjs +26 -1
- package/dist/profile/index.js +1 -1
- package/dist/profile-suggestions.js +2 -2
- package/dist/profile.cjs +26 -1
- package/dist/profile.d.cts +7 -0
- package/dist/profile.d.ts +7 -0
- package/dist/profile.js +1 -1
- package/dist/{proof-run-engine-MiKZt9oY.d.ts → proof-run-engine-CsQshTUX.d.ts} +3 -3
- package/dist/{proof-run-engine-Baiv6l3A.d.cts → proof-run-engine-DmUqh7Cw.d.cts} +3 -3
- package/dist/proof-run-engine.d.cts +1 -1
- package/dist/proof-run-engine.d.ts +1 -1
- package/dist/receipts.cjs +286 -0
- package/dist/receipts.d.cts +115 -0
- package/dist/receipts.d.ts +115 -0
- package/dist/receipts.js +15 -0
- package/dist/riddle-client.cjs +98 -13
- package/dist/riddle-client.d.cts +18 -5
- package/dist/riddle-client.d.ts +18 -5
- package/dist/riddle-client.js +4 -1
- package/dist/runtime/index.cjs +98 -13
- package/dist/runtime/index.d.cts +5 -1
- package/dist/runtime/index.d.ts +5 -1
- package/dist/runtime/index.js +4 -1
- package/dist/runtime/riddle-client.cjs +98 -13
- package/dist/runtime/riddle-client.d.cts +5 -1
- package/dist/runtime/riddle-client.d.ts +5 -1
- package/dist/runtime/riddle-client.js +4 -1
- package/package.json +7 -2
- package/dist/chunk-6S7DZWVC.js +0 -167
package/dist/index.cjs
CHANGED
|
@@ -3414,15 +3414,20 @@ __export(index_exports, {
|
|
|
3414
3414
|
DEFAULT_DIAGNOSTIC_STRING_LIMIT: () => DEFAULT_DIAGNOSTIC_STRING_LIMIT,
|
|
3415
3415
|
DEFAULT_RIDDLE_API_BASE_URL: () => DEFAULT_RIDDLE_API_BASE_URL,
|
|
3416
3416
|
DEFAULT_RIDDLE_API_KEY_FILE: () => DEFAULT_RIDDLE_API_KEY_FILE,
|
|
3417
|
+
RIDDLE_PREVIEW_RECEIPT_VERSION: () => RIDDLE_PREVIEW_RECEIPT_VERSION,
|
|
3417
3418
|
RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION: () => RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
|
|
3418
3419
|
RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION: () => RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
|
|
3419
3420
|
RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION: () => RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
|
|
3420
3421
|
RIDDLE_PROOF_CAPTURE_DIAGNOSTIC_VERSION: () => RIDDLE_PROOF_CAPTURE_DIAGNOSTIC_VERSION,
|
|
3421
3422
|
RIDDLE_PROOF_CHANGE_CONTRACT_VERSION: () => RIDDLE_PROOF_CHANGE_CONTRACT_VERSION,
|
|
3423
|
+
RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION: () => RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION,
|
|
3424
|
+
RIDDLE_PROOF_CHANGE_RECEIPT_VERSION: () => RIDDLE_PROOF_CHANGE_RECEIPT_VERSION,
|
|
3422
3425
|
RIDDLE_PROOF_CHANGE_RESULT_VERSION: () => RIDDLE_PROOF_CHANGE_RESULT_VERSION,
|
|
3423
3426
|
RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION: () => RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
|
|
3424
3427
|
RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION: () => RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
|
|
3428
|
+
RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION: () => RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION,
|
|
3425
3429
|
RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS: () => RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
|
|
3430
|
+
RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION: () => RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
|
|
3426
3431
|
RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION: () => RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION,
|
|
3427
3432
|
RIDDLE_PROOF_PLAYABILITY_VERSION: () => RIDDLE_PROOF_PLAYABILITY_VERSION,
|
|
3428
3433
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
@@ -3461,6 +3466,7 @@ __export(index_exports, {
|
|
|
3461
3466
|
buildAuthorCheckpointPacket: () => buildAuthorCheckpointPacket,
|
|
3462
3467
|
buildCheckpointPacketForEngineResult: () => buildCheckpointPacketForEngineResult,
|
|
3463
3468
|
buildProofAssessmentCheckpointPacket: () => buildProofAssessmentCheckpointPacket,
|
|
3469
|
+
buildRiddleProofHandoffPrCommentMarkdown: () => buildRiddleProofHandoffPrCommentMarkdown,
|
|
3464
3470
|
buildRiddleProofPrCommentMarkdown: () => buildRiddleProofPrCommentMarkdown,
|
|
3465
3471
|
buildRiddleProofProfileScript: () => buildRiddleProofProfileScript,
|
|
3466
3472
|
buildStageCheckpointPacket: () => buildStageCheckpointPacket,
|
|
@@ -3484,6 +3490,9 @@ __export(index_exports, {
|
|
|
3484
3490
|
createLocalAgentAdapter: () => createCodexExecAgentAdapter,
|
|
3485
3491
|
createLocalAgentJsonRunner: () => createCodexExecJsonRunner,
|
|
3486
3492
|
createRiddleApiClient: () => createRiddleApiClient,
|
|
3493
|
+
createRiddleProofChangeReceipt: () => createRiddleProofChangeReceipt,
|
|
3494
|
+
createRiddleProofHandoffReceipt: () => createRiddleProofHandoffReceipt,
|
|
3495
|
+
createRiddleProofObservationReceipt: () => createRiddleProofObservationReceipt,
|
|
3487
3496
|
createRiddleProofProfileConfigurationError: () => createRiddleProofProfileConfigurationError,
|
|
3488
3497
|
createRiddleProofProfileEnvironmentBlockedResult: () => createRiddleProofProfileEnvironmentBlockedResult,
|
|
3489
3498
|
createRiddleProofProfileInsufficientResult: () => createRiddleProofProfileInsufficientResult,
|
|
@@ -3494,6 +3503,7 @@ __export(index_exports, {
|
|
|
3494
3503
|
deployRiddlePreview: () => deployRiddlePreview,
|
|
3495
3504
|
deployRiddleStaticPreview: () => deployRiddleStaticPreview,
|
|
3496
3505
|
deriveRiddleProofArtifactBodyAssertions: () => deriveRiddleProofArtifactBodyAssertions,
|
|
3506
|
+
detectRiddlePreviewSource: () => detectRiddlePreviewSource,
|
|
3497
3507
|
extractBasicGameplayEvidence: () => extractBasicGameplayEvidence,
|
|
3498
3508
|
extractPlayabilityEvidence: () => extractPlayabilityEvidence,
|
|
3499
3509
|
extractRiddleProofProfileResult: () => extractRiddleProofProfileResult,
|
|
@@ -3504,6 +3514,7 @@ __export(index_exports, {
|
|
|
3504
3514
|
isSuccessfulStatus: () => isSuccessfulStatus,
|
|
3505
3515
|
isTerminalRiddleJobStatus: () => isTerminalRiddleJobStatus,
|
|
3506
3516
|
isTerminalStatus: () => isTerminalStatus,
|
|
3517
|
+
migrateRiddleProofChangeReceipt: () => migrateRiddleProofChangeReceipt,
|
|
3507
3518
|
nonEmptyString: () => nonEmptyString,
|
|
3508
3519
|
normalizeCheckpointResponse: () => normalizeCheckpointResponse,
|
|
3509
3520
|
normalizeIntegrationContext: () => normalizeIntegrationContext,
|
|
@@ -3511,6 +3522,10 @@ __export(index_exports, {
|
|
|
3511
3522
|
normalizeRiddleProofProfile: () => normalizeRiddleProofProfile,
|
|
3512
3523
|
normalizeRunParams: () => normalizeRunParams,
|
|
3513
3524
|
normalizeTerminalMetadata: () => normalizeTerminalMetadata,
|
|
3525
|
+
parseRiddlePreviewReceipt: () => parseRiddlePreviewReceipt,
|
|
3526
|
+
parseRiddleProofChangeReceipt: () => parseRiddleProofChangeReceipt,
|
|
3527
|
+
parseRiddleProofHandoffReceipt: () => parseRiddleProofHandoffReceipt,
|
|
3528
|
+
parseRiddleProofObservationReceipt: () => parseRiddleProofObservationReceipt,
|
|
3514
3529
|
parseRiddleViewport: () => parseRiddleViewport,
|
|
3515
3530
|
parseVisualProofSession: () => parseVisualProofSession,
|
|
3516
3531
|
pollRiddleJob: () => pollRiddleJob,
|
|
@@ -3529,6 +3544,8 @@ __export(index_exports, {
|
|
|
3529
3544
|
resolveRiddleProofProfileRouteUrl: () => resolveRiddleProofProfileRouteUrl,
|
|
3530
3545
|
resolveRiddleProofProfileTargetUrl: () => resolveRiddleProofProfileTargetUrl,
|
|
3531
3546
|
resolveRiddleProofProfileTimeoutSec: () => resolveRiddleProofProfileTimeoutSec,
|
|
3547
|
+
riddleProofChangeReceiptHtml: () => riddleProofChangeReceiptHtml,
|
|
3548
|
+
riddleProofChangeReceiptMarkdown: () => riddleProofChangeReceiptMarkdown,
|
|
3532
3549
|
riddleProofPublicStateAllowsClaim: () => riddleProofPublicStateAllowsClaim,
|
|
3533
3550
|
riddleProofPublicStateAllowsMergeRecommendation: () => riddleProofPublicStateAllowsMergeRecommendation,
|
|
3534
3551
|
riddleProofPublicStateMergeRecommendation: () => riddleProofPublicStateMergeRecommendation,
|
|
@@ -10943,6 +10960,12 @@ function profileScreenshotLabels(viewports) {
|
|
|
10943
10960
|
}
|
|
10944
10961
|
return labels;
|
|
10945
10962
|
}
|
|
10963
|
+
function profileFinalScreenshotLabels(viewports) {
|
|
10964
|
+
return (viewports || []).map((viewport) => viewport.screenshot_label).filter((label) => typeof label === "string" && Boolean(label.trim()));
|
|
10965
|
+
}
|
|
10966
|
+
function profileAllSetupScreenshotLabels(viewports) {
|
|
10967
|
+
return (viewports || []).flatMap((viewport) => profileSetupScreenshotLabels(viewport.setup_action_results || []));
|
|
10968
|
+
}
|
|
10946
10969
|
function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport, finalScreenshotFullPage) {
|
|
10947
10970
|
const normalizedFinalScreenshotFullPage = finalScreenshotFullPage === void 0 ? void 0 : finalScreenshotFullPage !== false;
|
|
10948
10971
|
const finalScreenshotCount = viewports.filter((viewport) => typeof viewport.screenshot_label === "string" && viewport.screenshot_label.trim()).length;
|
|
@@ -13793,6 +13816,8 @@ function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
|
|
|
13793
13816
|
const status = profileStatusFromEvidence(profile, evidence, checks);
|
|
13794
13817
|
const firstViewport = evidence?.viewports?.[0];
|
|
13795
13818
|
const screenshots = profileScreenshotLabels(evidence?.viewports);
|
|
13819
|
+
const canonicalScreenshots = profileFinalScreenshotLabels(evidence?.viewports);
|
|
13820
|
+
const setupScreenshots = profileAllSetupScreenshotLabels(evidence?.viewports);
|
|
13796
13821
|
const result = {
|
|
13797
13822
|
version: RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
13798
13823
|
profile_name: profile.name,
|
|
@@ -13802,6 +13827,8 @@ function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
|
|
|
13802
13827
|
route: routeForViewport(firstViewport, evidence?.target_url),
|
|
13803
13828
|
artifacts: {
|
|
13804
13829
|
screenshots,
|
|
13830
|
+
canonical_screenshots: canonicalScreenshots,
|
|
13831
|
+
setup_screenshots: setupScreenshots,
|
|
13805
13832
|
console: "console.json",
|
|
13806
13833
|
proof_json: "proof.json",
|
|
13807
13834
|
dom_summary: "dom-summary.json",
|
|
@@ -15120,6 +15147,12 @@ function profileScreenshotLabels(viewports) {
|
|
|
15120
15147
|
}
|
|
15121
15148
|
return labels;
|
|
15122
15149
|
}
|
|
15150
|
+
function profileFinalScreenshotLabels(viewports) {
|
|
15151
|
+
return (viewports || []).map((viewport) => viewport && viewport.screenshot_label).filter(Boolean);
|
|
15152
|
+
}
|
|
15153
|
+
function profileAllSetupScreenshotLabels(viewports) {
|
|
15154
|
+
return (viewports || []).flatMap((viewport) => profileSetupScreenshotLabels(viewport && viewport.setup_action_results || []));
|
|
15155
|
+
}
|
|
15123
15156
|
function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport, finalScreenshotFullPage) {
|
|
15124
15157
|
const normalizedFinalScreenshotFullPage = finalScreenshotFullPage === undefined
|
|
15125
15158
|
? undefined
|
|
@@ -15988,6 +16021,8 @@ function assessProfile(profile, evidence) {
|
|
|
15988
16021
|
else if (checks.some((check) => check.status === "needs_human_review")) status = "needs_human_review";
|
|
15989
16022
|
else if (checks.some((check) => check.status === "failed")) status = "product_regression";
|
|
15990
16023
|
const screenshotLabels = profileScreenshotLabels(viewports);
|
|
16024
|
+
const canonicalScreenshotLabels = profileFinalScreenshotLabels(viewports);
|
|
16025
|
+
const setupScreenshotLabels = profileAllSetupScreenshotLabels(viewports);
|
|
15991
16026
|
const route = viewports[0] && viewports[0].route ? viewports[0].route : { requested: evidence.target_url, observed: "", matched: false, error: "missing viewport evidence" };
|
|
15992
16027
|
const passedChecks = checks.filter((check) => check.status === "passed").length;
|
|
15993
16028
|
const failedChecks = checks.filter((check) => check.status === "failed").length;
|
|
@@ -16004,7 +16039,14 @@ function assessProfile(profile, evidence) {
|
|
|
16004
16039
|
status,
|
|
16005
16040
|
baseline_policy: profile.baseline_policy || "invariant_only",
|
|
16006
16041
|
route,
|
|
16007
|
-
artifacts: {
|
|
16042
|
+
artifacts: {
|
|
16043
|
+
screenshots: screenshotLabels,
|
|
16044
|
+
canonical_screenshots: canonicalScreenshotLabels,
|
|
16045
|
+
setup_screenshots: setupScreenshotLabels,
|
|
16046
|
+
console: "console.json",
|
|
16047
|
+
proof_json: "proof.json",
|
|
16048
|
+
dom_summary: "dom-summary.json"
|
|
16049
|
+
},
|
|
16008
16050
|
checks,
|
|
16009
16051
|
summary,
|
|
16010
16052
|
captured_at: evidence.captured_at,
|
|
@@ -19932,9 +19974,263 @@ function suggestRiddleProofProfileChecks(input) {
|
|
|
19932
19974
|
};
|
|
19933
19975
|
}
|
|
19934
19976
|
|
|
19977
|
+
// src/receipts.ts
|
|
19978
|
+
var RIDDLE_PREVIEW_RECEIPT_VERSION = "riddle.preview-receipt.v1";
|
|
19979
|
+
var RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION = "riddle-proof.observation-receipt.v1";
|
|
19980
|
+
function isRecord3(value) {
|
|
19981
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
19982
|
+
}
|
|
19983
|
+
function requiredString(record, key, context) {
|
|
19984
|
+
const value = record[key];
|
|
19985
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
19986
|
+
throw new Error(`${context}.${key} must be a non-empty string.`);
|
|
19987
|
+
}
|
|
19988
|
+
return value.trim();
|
|
19989
|
+
}
|
|
19990
|
+
function normalizedSourceIdentity(value) {
|
|
19991
|
+
if (!isRecord3(value)) return {};
|
|
19992
|
+
return {
|
|
19993
|
+
git_revision: typeof value.git_revision === "string" && value.git_revision.trim() ? value.git_revision.trim() : void 0,
|
|
19994
|
+
repository: typeof value.repository === "string" && value.repository.trim() ? value.repository.trim() : void 0,
|
|
19995
|
+
dirty: typeof value.dirty === "boolean" ? value.dirty : void 0,
|
|
19996
|
+
label: typeof value.label === "string" && value.label.trim() ? value.label.trim() : void 0
|
|
19997
|
+
};
|
|
19998
|
+
}
|
|
19999
|
+
function parseRiddlePreviewReceipt(value) {
|
|
20000
|
+
if (!isRecord3(value)) throw new Error("Preview receipt must be an object.");
|
|
20001
|
+
if (value.version !== RIDDLE_PREVIEW_RECEIPT_VERSION) {
|
|
20002
|
+
throw new Error(`Unsupported Preview receipt version ${String(value.version || "missing")}.`);
|
|
20003
|
+
}
|
|
20004
|
+
if (!isRecord3(value.source)) throw new Error("Preview receipt source must be an object.");
|
|
20005
|
+
const expiresAt = requiredString(value, "expires_at", "preview receipt");
|
|
20006
|
+
const publishedAt = requiredString(value, "published_at", "preview receipt");
|
|
20007
|
+
const contentDigest = requiredString(value, "content_digest", "preview receipt");
|
|
20008
|
+
if (!contentDigest.startsWith("sha256:") || contentDigest.length <= "sha256:".length) {
|
|
20009
|
+
throw new Error("preview receipt.content_digest must be a sha256 digest.");
|
|
20010
|
+
}
|
|
20011
|
+
if (!Number.isFinite(Date.parse(expiresAt)) || !Number.isFinite(Date.parse(publishedAt))) {
|
|
20012
|
+
throw new Error("Preview receipt timestamps must be valid ISO date strings.");
|
|
20013
|
+
}
|
|
20014
|
+
return {
|
|
20015
|
+
version: RIDDLE_PREVIEW_RECEIPT_VERSION,
|
|
20016
|
+
preview_id: requiredString(value, "preview_id", "preview receipt"),
|
|
20017
|
+
url: requiredString(value, "url", "preview receipt"),
|
|
20018
|
+
expires_at: expiresAt,
|
|
20019
|
+
content_digest: contentDigest,
|
|
20020
|
+
source: normalizedSourceIdentity(value.source),
|
|
20021
|
+
published_at: publishedAt
|
|
20022
|
+
};
|
|
20023
|
+
}
|
|
20024
|
+
function comparableArtifactName(value) {
|
|
20025
|
+
return (value || "").split(/[/?#]/).pop()?.toLowerCase().replace(/\.(png|jpe?g|gif|webp|avif|svg)$/u, "").replace(/[^a-z0-9_-]+/gu, "-").replace(/^-+|-+$/g, "") || "";
|
|
20026
|
+
}
|
|
20027
|
+
function artifactMatchesLabel(artifact, label) {
|
|
20028
|
+
const expected = comparableArtifactName(label);
|
|
20029
|
+
if (!expected) return false;
|
|
20030
|
+
return [artifact.name, artifact.url, artifact.path].map(comparableArtifactName).some((name) => name === expected || name.endsWith(`-${expected}`));
|
|
20031
|
+
}
|
|
20032
|
+
function artifactLooksLikeScreenshot(ref) {
|
|
20033
|
+
const text = [ref.name, ref.url, ref.path, ref.kind, ref.content_type].filter(Boolean).join(" ").toLowerCase();
|
|
20034
|
+
return /screenshot|\bimage\b/.test(text) || /\.(png|jpe?g|gif|webp|avif|svg)(\?|#|$)/.test(text);
|
|
20035
|
+
}
|
|
20036
|
+
function finalScreenshotLabels(result) {
|
|
20037
|
+
const explicit = result.artifacts.canonical_screenshots || [];
|
|
20038
|
+
if (explicit.length) return explicit;
|
|
20039
|
+
const fromEvidence = (result.evidence?.viewports || []).map((viewport) => viewport.screenshot_label).filter((label) => typeof label === "string" && Boolean(label.trim()));
|
|
20040
|
+
if (fromEvidence.length) return fromEvidence;
|
|
20041
|
+
return (result.artifacts.screenshots || []).slice(0, 1);
|
|
20042
|
+
}
|
|
20043
|
+
function setupScreenshotLabels(result) {
|
|
20044
|
+
const explicit = result.artifacts.setup_screenshots || [];
|
|
20045
|
+
if (explicit.length) return explicit;
|
|
20046
|
+
return (result.evidence?.viewports || []).flatMap(
|
|
20047
|
+
(viewport) => (viewport.setup_action_results || []).filter((action) => action.action === "screenshot" && action.ok !== false && typeof action.screenshot_label === "string").map((action) => String(action.screenshot_label))
|
|
20048
|
+
);
|
|
20049
|
+
}
|
|
20050
|
+
function observationArtifactFromRef(ref, canonicalLabels, setupLabels) {
|
|
20051
|
+
const base = {
|
|
20052
|
+
name: ref.name,
|
|
20053
|
+
role: ref.role || "artifact",
|
|
20054
|
+
url: ref.url,
|
|
20055
|
+
path: ref.path,
|
|
20056
|
+
kind: ref.kind,
|
|
20057
|
+
content_type: ref.content_type,
|
|
20058
|
+
source: ref.source
|
|
20059
|
+
};
|
|
20060
|
+
if (!artifactLooksLikeScreenshot(ref)) return base;
|
|
20061
|
+
if (canonicalLabels.some((label) => artifactMatchesLabel(base, label))) {
|
|
20062
|
+
return { ...base, role: "canonical_screenshot" };
|
|
20063
|
+
}
|
|
20064
|
+
if (setupLabels.some((label) => artifactMatchesLabel(base, label))) {
|
|
20065
|
+
return { ...base, role: "setup_screenshot" };
|
|
20066
|
+
}
|
|
20067
|
+
return { ...base, role: "diagnostic" };
|
|
20068
|
+
}
|
|
20069
|
+
function profileObservationArtifacts(result) {
|
|
20070
|
+
const canonicalLabels = finalScreenshotLabels(result);
|
|
20071
|
+
const setupLabels = setupScreenshotLabels(result);
|
|
20072
|
+
const artifacts = [];
|
|
20073
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20074
|
+
const add = (artifact) => {
|
|
20075
|
+
const key = artifact.url || artifact.path || `${artifact.role}:${artifact.name}`;
|
|
20076
|
+
if (!artifact.name || seen.has(key)) return;
|
|
20077
|
+
seen.add(key);
|
|
20078
|
+
artifacts.push(artifact);
|
|
20079
|
+
};
|
|
20080
|
+
for (const ref of result.artifacts.riddle_artifacts || []) {
|
|
20081
|
+
add(observationArtifactFromRef(ref, canonicalLabels, setupLabels));
|
|
20082
|
+
}
|
|
20083
|
+
for (const label of canonicalLabels) {
|
|
20084
|
+
if (!artifacts.some((artifact) => artifactMatchesLabel(artifact, label))) {
|
|
20085
|
+
add({ name: label, path: label, role: "canonical_screenshot", kind: "image" });
|
|
20086
|
+
}
|
|
20087
|
+
}
|
|
20088
|
+
for (const label of setupLabels) {
|
|
20089
|
+
if (!artifacts.some((artifact) => artifactMatchesLabel(artifact, label))) {
|
|
20090
|
+
add({ name: label, path: label, role: "setup_screenshot", kind: "image" });
|
|
20091
|
+
}
|
|
20092
|
+
}
|
|
20093
|
+
for (const label of result.artifacts.screenshots || []) {
|
|
20094
|
+
if (!artifacts.some((artifact) => artifactMatchesLabel(artifact, label))) {
|
|
20095
|
+
add({ name: label, path: label, role: "diagnostic", kind: "image" });
|
|
20096
|
+
}
|
|
20097
|
+
}
|
|
20098
|
+
return artifacts;
|
|
20099
|
+
}
|
|
20100
|
+
function mergeObservationArtifacts(profileArtifacts, suppliedArtifacts) {
|
|
20101
|
+
const artifacts = [...profileArtifacts];
|
|
20102
|
+
for (const supplied of suppliedArtifacts) {
|
|
20103
|
+
const suppliedNames = [supplied.name, supplied.url, supplied.path].map(comparableArtifactName).filter(Boolean);
|
|
20104
|
+
const existingIndex = artifacts.findIndex((artifact) => {
|
|
20105
|
+
if (supplied.url && artifact.url === supplied.url) return true;
|
|
20106
|
+
if (supplied.path && artifact.path === supplied.path) return true;
|
|
20107
|
+
return [artifact.name, artifact.url, artifact.path].map(comparableArtifactName).some((name) => name && suppliedNames.includes(name));
|
|
20108
|
+
});
|
|
20109
|
+
if (existingIndex < 0) {
|
|
20110
|
+
artifacts.push(supplied);
|
|
20111
|
+
continue;
|
|
20112
|
+
}
|
|
20113
|
+
const existing = artifacts[existingIndex];
|
|
20114
|
+
const role = supplied.role === "canonical_screenshot" || supplied.role === "setup_screenshot" ? supplied.role : existing.role === "canonical_screenshot" || existing.role === "setup_screenshot" ? existing.role : supplied.role === "artifact" ? existing.role : supplied.role;
|
|
20115
|
+
artifacts[existingIndex] = {
|
|
20116
|
+
...existing,
|
|
20117
|
+
...supplied,
|
|
20118
|
+
role
|
|
20119
|
+
};
|
|
20120
|
+
}
|
|
20121
|
+
return artifacts;
|
|
20122
|
+
}
|
|
20123
|
+
function defaultObservationId(role, capturedAt) {
|
|
20124
|
+
return `obs_${role}_${capturedAt.replace(/[^0-9]/g, "").slice(0, 17) || "unknown"}`;
|
|
20125
|
+
}
|
|
20126
|
+
function profileCheckCounts(result) {
|
|
20127
|
+
const counts = { total: result.checks.length, passed: 0, failed: 0, skipped: 0, needs_human_review: 0 };
|
|
20128
|
+
for (const check of result.checks) {
|
|
20129
|
+
if (check.status === "passed") counts.passed += 1;
|
|
20130
|
+
if (check.status === "failed") counts.failed += 1;
|
|
20131
|
+
if (check.status === "skipped") counts.skipped += 1;
|
|
20132
|
+
if (check.status === "needs_human_review") counts.needs_human_review += 1;
|
|
20133
|
+
}
|
|
20134
|
+
return counts;
|
|
20135
|
+
}
|
|
20136
|
+
function createRiddleProofObservationReceipt(input) {
|
|
20137
|
+
const capturedAt = input.captured_at || input.profile_result?.captured_at || (/* @__PURE__ */ new Date()).toISOString();
|
|
20138
|
+
const profileArtifacts = input.profile_result ? profileObservationArtifacts(input.profile_result) : [];
|
|
20139
|
+
const requestedCanonical = input.canonical_screenshot ? { ...input.canonical_screenshot, role: "canonical_screenshot" } : void 0;
|
|
20140
|
+
const artifacts = mergeObservationArtifacts(
|
|
20141
|
+
profileArtifacts,
|
|
20142
|
+
[...input.artifacts || [], ...requestedCanonical ? [requestedCanonical] : []]
|
|
20143
|
+
);
|
|
20144
|
+
const canonicalScreenshot = requestedCanonical ? artifacts.find((artifact) => artifact.role === "canonical_screenshot" && artifactMatchesLabel(artifact, requestedCanonical.name)) || requestedCanonical : artifacts.find((artifact) => artifact.role === "canonical_screenshot");
|
|
20145
|
+
const target = input.target.kind === "preview" && input.target.preview ? { ...input.target, preview: parseRiddlePreviewReceipt(input.target.preview) } : input.target;
|
|
20146
|
+
return {
|
|
20147
|
+
version: RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
|
|
20148
|
+
observation_id: input.observation_id || defaultObservationId(input.comparison_role, capturedAt),
|
|
20149
|
+
comparison_role: input.comparison_role,
|
|
20150
|
+
executor: input.executor,
|
|
20151
|
+
target,
|
|
20152
|
+
source: normalizedSourceIdentity(input.source || input.target.preview?.source),
|
|
20153
|
+
captured_at: capturedAt,
|
|
20154
|
+
artifacts,
|
|
20155
|
+
canonical_screenshot: canonicalScreenshot,
|
|
20156
|
+
profile_summary: input.profile_result ? {
|
|
20157
|
+
profile_name: input.profile_result.profile_name,
|
|
20158
|
+
status: input.profile_result.status,
|
|
20159
|
+
summary: input.profile_result.summary,
|
|
20160
|
+
route: input.profile_result.route,
|
|
20161
|
+
checks: profileCheckCounts(input.profile_result)
|
|
20162
|
+
} : void 0,
|
|
20163
|
+
proof: input.profile_result ? {
|
|
20164
|
+
profile_name: input.profile_result.profile_name,
|
|
20165
|
+
result: input.profile_result
|
|
20166
|
+
} : void 0,
|
|
20167
|
+
publication: input.publication,
|
|
20168
|
+
execution: input.execution,
|
|
20169
|
+
metadata: input.metadata
|
|
20170
|
+
};
|
|
20171
|
+
}
|
|
20172
|
+
function parseRiddleProofObservationReceipt(value) {
|
|
20173
|
+
if (!isRecord3(value)) throw new Error("Observation receipt must be an object.");
|
|
20174
|
+
if (value.version !== RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION) {
|
|
20175
|
+
throw new Error(`Unsupported Observation receipt version ${String(value.version || "missing")}.`);
|
|
20176
|
+
}
|
|
20177
|
+
if (!isRecord3(value.executor)) throw new Error("Observation receipt executor must be an object.");
|
|
20178
|
+
if (!isRecord3(value.target)) throw new Error("Observation receipt target must be an object.");
|
|
20179
|
+
if (!isRecord3(value.source)) throw new Error("Observation receipt source must be an object.");
|
|
20180
|
+
requiredString(value, "observation_id", "observation receipt");
|
|
20181
|
+
requiredString(value, "captured_at", "observation receipt");
|
|
20182
|
+
const executorKind = requiredString(value.executor, "kind", "observation receipt executor");
|
|
20183
|
+
if (!"local_playwright,riddle_hosted,browser_api,other".split(",").includes(executorKind)) {
|
|
20184
|
+
throw new Error(`Unsupported observation executor kind ${executorKind}.`);
|
|
20185
|
+
}
|
|
20186
|
+
if (value.executor.runner !== void 0) {
|
|
20187
|
+
requiredString(value.executor, "runner", "observation receipt executor");
|
|
20188
|
+
}
|
|
20189
|
+
const role = requiredString(value, "comparison_role", "observation receipt");
|
|
20190
|
+
if (!["before", "after", "standalone"].includes(role)) {
|
|
20191
|
+
throw new Error(`Unsupported observation comparison role ${role}.`);
|
|
20192
|
+
}
|
|
20193
|
+
const targetKind = requiredString(value.target, "kind", "observation receipt target");
|
|
20194
|
+
if (targetKind !== "url" && targetKind !== "preview") {
|
|
20195
|
+
throw new Error(`Unsupported observation target kind ${targetKind}.`);
|
|
20196
|
+
}
|
|
20197
|
+
requiredString(value.target, "url", "observation receipt target");
|
|
20198
|
+
if (targetKind === "preview") {
|
|
20199
|
+
if (value.target.preview === void 0) {
|
|
20200
|
+
throw new Error("Preview Observation target must include its Preview receipt.");
|
|
20201
|
+
}
|
|
20202
|
+
parseRiddlePreviewReceipt(value.target.preview);
|
|
20203
|
+
}
|
|
20204
|
+
if (!Array.isArray(value.artifacts)) throw new Error("Observation receipt artifacts must be an array.");
|
|
20205
|
+
const artifactRoles = /* @__PURE__ */ new Set(["canonical_screenshot", "setup_screenshot", "data", "diagnostic", "artifact"]);
|
|
20206
|
+
const artifacts = value.artifacts.map((artifact, index) => {
|
|
20207
|
+
if (!isRecord3(artifact)) throw new Error(`Observation receipt artifact ${index} must be an object.`);
|
|
20208
|
+
requiredString(artifact, "name", `observation receipt artifact ${index}`);
|
|
20209
|
+
const artifactRole = requiredString(artifact, "role", `observation receipt artifact ${index}`);
|
|
20210
|
+
if (!artifactRoles.has(artifactRole)) {
|
|
20211
|
+
throw new Error(`Unsupported observation artifact role ${artifactRole}.`);
|
|
20212
|
+
}
|
|
20213
|
+
return artifact;
|
|
20214
|
+
});
|
|
20215
|
+
if (value.canonical_screenshot !== void 0) {
|
|
20216
|
+
if (!isRecord3(value.canonical_screenshot) || value.canonical_screenshot.role !== "canonical_screenshot") {
|
|
20217
|
+
throw new Error("Observation canonical_screenshot must have the canonical_screenshot role.");
|
|
20218
|
+
}
|
|
20219
|
+
const canonical = value.canonical_screenshot;
|
|
20220
|
+
const included = artifacts.some((artifact) => artifact.role === "canonical_screenshot" && artifact.name === canonical.name && artifact.url === canonical.url && artifact.path === canonical.path);
|
|
20221
|
+
if (!included) {
|
|
20222
|
+
throw new Error("Observation canonical_screenshot must reference an artifact in the receipt.");
|
|
20223
|
+
}
|
|
20224
|
+
}
|
|
20225
|
+
return value;
|
|
20226
|
+
}
|
|
20227
|
+
|
|
19935
20228
|
// src/change-proof.ts
|
|
19936
20229
|
var RIDDLE_PROOF_CHANGE_CONTRACT_VERSION = "riddle-proof.change-contract.v1";
|
|
19937
20230
|
var RIDDLE_PROOF_CHANGE_RESULT_VERSION = "riddle-proof.change-result.v1";
|
|
20231
|
+
var RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION = "riddle-proof.change-receipt.v1";
|
|
20232
|
+
var RIDDLE_PROOF_CHANGE_RECEIPT_VERSION = "riddle-proof.change-receipt.v2";
|
|
20233
|
+
var RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION = "riddle-proof.handoff-receipt.v1";
|
|
19938
20234
|
var DEFAULT_BEFORE_STATUSES = ["passed", "product_regression"];
|
|
19939
20235
|
var DEFAULT_AFTER_STATUSES = ["passed"];
|
|
19940
20236
|
var DEFAULT_PROFILE_STATUS_TRANSITION_BEFORE = ["product_regression"];
|
|
@@ -20056,13 +20352,163 @@ function assessDelta(delta, before, after) {
|
|
|
20056
20352
|
}
|
|
20057
20353
|
return checkStatusTransitionResult(delta, before, after);
|
|
20058
20354
|
}
|
|
20059
|
-
function
|
|
20355
|
+
function profileResultFromObservation(observation) {
|
|
20356
|
+
return observation?.proof?.result;
|
|
20357
|
+
}
|
|
20358
|
+
function previewReceiptCoversTarget(previewUrl, targetUrl) {
|
|
20359
|
+
try {
|
|
20360
|
+
const preview = new URL(previewUrl);
|
|
20361
|
+
const target = new URL(targetUrl);
|
|
20362
|
+
const previewPath = preview.pathname.replace(/\/+$/u, "");
|
|
20363
|
+
return preview.origin === target.origin && (target.pathname === previewPath || target.pathname.startsWith(`${previewPath}/`));
|
|
20364
|
+
} catch {
|
|
20365
|
+
return false;
|
|
20366
|
+
}
|
|
20367
|
+
}
|
|
20368
|
+
function sourceBindingResult(side, requirement, observation, expectedRevision, evaluatedAt) {
|
|
20369
|
+
const expected = expectedRevision || requirement?.expected_git_revision;
|
|
20370
|
+
const required = Boolean(
|
|
20371
|
+
requirement?.preview_receipt_required || requirement?.require_clean_source || requirement?.require_content_digest || requirement?.expected_git_revision || expected
|
|
20372
|
+
);
|
|
20373
|
+
if (!required) return { side, required: false, ok: true, status: "not_required" };
|
|
20374
|
+
if (!observation) {
|
|
20375
|
+
return {
|
|
20376
|
+
side,
|
|
20377
|
+
required: true,
|
|
20378
|
+
ok: false,
|
|
20379
|
+
status: "missing",
|
|
20380
|
+
expected_git_revision: expected,
|
|
20381
|
+
message: `${side} source binding requires an Observation receipt.`
|
|
20382
|
+
};
|
|
20383
|
+
}
|
|
20384
|
+
const preview = observation.target.preview;
|
|
20385
|
+
if (requirement?.preview_receipt_required && !preview) {
|
|
20386
|
+
return {
|
|
20387
|
+
side,
|
|
20388
|
+
required: true,
|
|
20389
|
+
ok: false,
|
|
20390
|
+
status: "missing",
|
|
20391
|
+
expected_git_revision: expected,
|
|
20392
|
+
message: `${side} source binding requires a Preview receipt.`
|
|
20393
|
+
};
|
|
20394
|
+
}
|
|
20395
|
+
if (preview && !previewReceiptCoversTarget(preview.url, observation.target.url)) {
|
|
20396
|
+
return {
|
|
20397
|
+
side,
|
|
20398
|
+
required: true,
|
|
20399
|
+
ok: false,
|
|
20400
|
+
status: "mismatched",
|
|
20401
|
+
expected_git_revision: expected,
|
|
20402
|
+
observed_git_revision: preview.source.git_revision || observation.source.git_revision,
|
|
20403
|
+
content_digest: preview.content_digest,
|
|
20404
|
+
preview_id: preview.preview_id,
|
|
20405
|
+
preview_url: preview.url,
|
|
20406
|
+
target_url: observation.target.url,
|
|
20407
|
+
message: `${side} observation target is not contained by Preview ${preview.preview_id}.`
|
|
20408
|
+
};
|
|
20409
|
+
}
|
|
20410
|
+
const observed = preview?.source.git_revision || observation.source.git_revision;
|
|
20411
|
+
const digestRequired = requirement?.require_content_digest === true || requirement?.preview_receipt_required === true;
|
|
20412
|
+
if (digestRequired && !preview?.content_digest) {
|
|
20413
|
+
return {
|
|
20414
|
+
side,
|
|
20415
|
+
required: true,
|
|
20416
|
+
ok: false,
|
|
20417
|
+
status: "missing",
|
|
20418
|
+
expected_git_revision: expected,
|
|
20419
|
+
observed_git_revision: observed,
|
|
20420
|
+
preview_id: preview?.preview_id,
|
|
20421
|
+
preview_url: preview?.url,
|
|
20422
|
+
target_url: observation.target.url,
|
|
20423
|
+
message: `${side} Preview receipt is missing a content digest.`
|
|
20424
|
+
};
|
|
20425
|
+
}
|
|
20426
|
+
if (expected && !observed) {
|
|
20427
|
+
return {
|
|
20428
|
+
side,
|
|
20429
|
+
required: true,
|
|
20430
|
+
ok: false,
|
|
20431
|
+
status: "missing",
|
|
20432
|
+
expected_git_revision: expected,
|
|
20433
|
+
content_digest: preview?.content_digest,
|
|
20434
|
+
preview_id: preview?.preview_id,
|
|
20435
|
+
preview_url: preview?.url,
|
|
20436
|
+
target_url: observation.target.url,
|
|
20437
|
+
message: `${side} evidence is missing its source Git revision.`
|
|
20438
|
+
};
|
|
20439
|
+
}
|
|
20440
|
+
if (expected && observed !== expected) {
|
|
20441
|
+
return {
|
|
20442
|
+
side,
|
|
20443
|
+
required: true,
|
|
20444
|
+
ok: false,
|
|
20445
|
+
status: "mismatched",
|
|
20446
|
+
expected_git_revision: expected,
|
|
20447
|
+
observed_git_revision: observed,
|
|
20448
|
+
content_digest: preview?.content_digest,
|
|
20449
|
+
preview_id: preview?.preview_id,
|
|
20450
|
+
preview_url: preview?.url,
|
|
20451
|
+
target_url: observation.target.url,
|
|
20452
|
+
message: `${side} evidence came from Git revision ${observed}, not expected revision ${expected}.`
|
|
20453
|
+
};
|
|
20454
|
+
}
|
|
20455
|
+
const cleanRequired = requirement?.require_clean_source === true || requirement?.preview_receipt_required === true;
|
|
20456
|
+
const dirty = preview?.source.dirty ?? observation.source.dirty;
|
|
20457
|
+
if (cleanRequired && dirty !== false) {
|
|
20458
|
+
return {
|
|
20459
|
+
side,
|
|
20460
|
+
required: true,
|
|
20461
|
+
ok: false,
|
|
20462
|
+
status: dirty === true ? "mismatched" : "missing",
|
|
20463
|
+
expected_git_revision: expected,
|
|
20464
|
+
observed_git_revision: observed,
|
|
20465
|
+
content_digest: preview?.content_digest,
|
|
20466
|
+
preview_id: preview?.preview_id,
|
|
20467
|
+
preview_url: preview?.url,
|
|
20468
|
+
target_url: observation.target.url,
|
|
20469
|
+
message: dirty === true ? `${side} evidence was built from a dirty worktree and is not bound only to its Git revision.` : `${side} evidence does not record whether its source worktree was clean.`
|
|
20470
|
+
};
|
|
20471
|
+
}
|
|
20472
|
+
const evaluatedMs = Date.parse(evaluatedAt);
|
|
20473
|
+
const expiresMs = preview?.expires_at ? Date.parse(preview.expires_at) : Number.NaN;
|
|
20474
|
+
if (preview && Number.isFinite(evaluatedMs) && Number.isFinite(expiresMs) && expiresMs <= evaluatedMs) {
|
|
20475
|
+
return {
|
|
20476
|
+
side,
|
|
20477
|
+
required: true,
|
|
20478
|
+
ok: false,
|
|
20479
|
+
status: "stale",
|
|
20480
|
+
expected_git_revision: expected,
|
|
20481
|
+
observed_git_revision: observed,
|
|
20482
|
+
content_digest: preview.content_digest,
|
|
20483
|
+
preview_id: preview.preview_id,
|
|
20484
|
+
preview_url: preview.url,
|
|
20485
|
+
target_url: observation.target.url,
|
|
20486
|
+
expires_at: preview.expires_at,
|
|
20487
|
+
message: `${side} Preview receipt expired at ${preview.expires_at}.`
|
|
20488
|
+
};
|
|
20489
|
+
}
|
|
20490
|
+
return {
|
|
20491
|
+
side,
|
|
20492
|
+
required: true,
|
|
20493
|
+
ok: true,
|
|
20494
|
+
status: "matched",
|
|
20495
|
+
expected_git_revision: expected,
|
|
20496
|
+
observed_git_revision: observed,
|
|
20497
|
+
content_digest: preview?.content_digest,
|
|
20498
|
+
preview_id: preview?.preview_id,
|
|
20499
|
+
preview_url: preview?.url,
|
|
20500
|
+
target_url: observation.target.url,
|
|
20501
|
+
expires_at: preview?.expires_at
|
|
20502
|
+
};
|
|
20503
|
+
}
|
|
20504
|
+
function collapsedChangeStatus(groups, deltas, sourceBindings) {
|
|
20060
20505
|
const groupResults = [groups.before, groups.after];
|
|
20061
20506
|
if (groupResults.some((group) => group.status === "environment_blocked")) return "environment_blocked";
|
|
20062
20507
|
if (groupResults.some((group) => group.status === "configuration_error")) return "configuration_error";
|
|
20063
20508
|
if (deltas.some((delta) => delta.status === "configuration_error")) return "configuration_error";
|
|
20064
20509
|
if (groupResults.some((group) => group.status === "needs_human_review")) return "needs_human_review";
|
|
20065
20510
|
if (groupResults.some((group) => group.status === "missing" || group.status === "proof_insufficient")) return "proof_insufficient";
|
|
20511
|
+
if ([sourceBindings.before, sourceBindings.after].some((binding) => binding.required && !binding.ok)) return "proof_insufficient";
|
|
20066
20512
|
if (!deltas.length || deltas.some((delta) => delta.status === "proof_insufficient")) return "proof_insufficient";
|
|
20067
20513
|
if (groupResults.some((group) => !group.ok)) return "product_regression";
|
|
20068
20514
|
if (deltas.some((delta) => delta.status === "failed")) return "product_regression";
|
|
@@ -20077,22 +20523,570 @@ function changeSummary(name, status, deltas) {
|
|
|
20077
20523
|
return `${name} failed ${deltas.filter((delta) => delta.status === "failed").length} change delta(s).`;
|
|
20078
20524
|
}
|
|
20079
20525
|
function assessRiddleProofChange(contract, input) {
|
|
20526
|
+
const beforeResult = input.before_result || profileResultFromObservation(input.before_observation);
|
|
20527
|
+
const afterResult = input.after_result || profileResultFromObservation(input.after_observation);
|
|
20080
20528
|
const groups = {
|
|
20081
|
-
before: groupResult("before", contract.before,
|
|
20082
|
-
after: groupResult("after", contract.after,
|
|
20529
|
+
before: groupResult("before", contract.before, beforeResult),
|
|
20530
|
+
after: groupResult("after", contract.after, afterResult)
|
|
20083
20531
|
};
|
|
20084
|
-
const deltas = (contract.deltas || []).map((delta) => assessDelta(delta,
|
|
20085
|
-
const
|
|
20532
|
+
const deltas = (contract.deltas || []).map((delta) => assessDelta(delta, beforeResult, afterResult));
|
|
20533
|
+
const evaluatedAt = input.evaluated_at || (/* @__PURE__ */ new Date()).toISOString();
|
|
20534
|
+
const sourceBindings = {
|
|
20535
|
+
before: sourceBindingResult(
|
|
20536
|
+
"before",
|
|
20537
|
+
contract.source_binding?.before,
|
|
20538
|
+
input.before_observation,
|
|
20539
|
+
input.expected_source_revisions?.before,
|
|
20540
|
+
evaluatedAt
|
|
20541
|
+
),
|
|
20542
|
+
after: sourceBindingResult(
|
|
20543
|
+
"after",
|
|
20544
|
+
contract.source_binding?.after,
|
|
20545
|
+
input.after_observation,
|
|
20546
|
+
input.expected_source_revisions?.after,
|
|
20547
|
+
evaluatedAt
|
|
20548
|
+
)
|
|
20549
|
+
};
|
|
20550
|
+
const status = collapsedChangeStatus(groups, deltas, sourceBindings);
|
|
20086
20551
|
return {
|
|
20087
20552
|
version: RIDDLE_PROOF_CHANGE_RESULT_VERSION,
|
|
20088
20553
|
contract_name: contract.name,
|
|
20089
20554
|
status,
|
|
20090
20555
|
groups,
|
|
20091
20556
|
deltas,
|
|
20557
|
+
source_bindings: sourceBindings,
|
|
20092
20558
|
summary: changeSummary(contract.name, status, deltas),
|
|
20093
20559
|
metadata: contract.metadata
|
|
20094
20560
|
};
|
|
20095
20561
|
}
|
|
20562
|
+
function changeReceiptVerdict(status) {
|
|
20563
|
+
if (status === "passed") return "mergeable";
|
|
20564
|
+
if (status === "environment_blocked") return "environment_blocked";
|
|
20565
|
+
if (status === "configuration_error") return "configuration_error";
|
|
20566
|
+
if (status === "needs_human_review") return "needs_human_review";
|
|
20567
|
+
if (status === "proof_insufficient") return "proof_insufficient";
|
|
20568
|
+
return "not_mergeable";
|
|
20569
|
+
}
|
|
20570
|
+
function profileCheckCounts2(result) {
|
|
20571
|
+
const counts = {
|
|
20572
|
+
total: result.checks.length,
|
|
20573
|
+
passed: 0,
|
|
20574
|
+
failed: 0,
|
|
20575
|
+
skipped: 0,
|
|
20576
|
+
needs_human_review: 0
|
|
20577
|
+
};
|
|
20578
|
+
for (const check of result.checks) {
|
|
20579
|
+
if (check.status === "passed") counts.passed += 1;
|
|
20580
|
+
if (check.status === "failed") counts.failed += 1;
|
|
20581
|
+
if (check.status === "skipped") counts.skipped += 1;
|
|
20582
|
+
if (check.status === "needs_human_review") counts.needs_human_review += 1;
|
|
20583
|
+
}
|
|
20584
|
+
return counts;
|
|
20585
|
+
}
|
|
20586
|
+
function artifactIsScreenshot(artifact) {
|
|
20587
|
+
if (artifact.kind !== "image") return false;
|
|
20588
|
+
return /screenshot|\.png|\.jpe?g|\.webp|\.gif|\.avif|\.svg/i.test([artifact.name, artifact.url, artifact.path].filter(Boolean).join(" "));
|
|
20589
|
+
}
|
|
20590
|
+
function metadataStringList(metadata, key) {
|
|
20591
|
+
const value = metadata?.[key];
|
|
20592
|
+
if (!Array.isArray(value)) return [];
|
|
20593
|
+
return value.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim());
|
|
20594
|
+
}
|
|
20595
|
+
function changeRecommendation(verdict) {
|
|
20596
|
+
if (verdict === "mergeable") {
|
|
20597
|
+
return {
|
|
20598
|
+
merge_recommended: true,
|
|
20599
|
+
verdict,
|
|
20600
|
+
label: "Merge recommended",
|
|
20601
|
+
reason: "The declared before/after delta contract passed with sufficient bound evidence."
|
|
20602
|
+
};
|
|
20603
|
+
}
|
|
20604
|
+
const reason = verdict === "not_mergeable" ? "The declared change delta did not pass." : verdict === "environment_blocked" ? "The environment blocked reliable evidence collection." : verdict === "needs_human_review" ? "The evidence requires human review." : verdict === "configuration_error" ? "The change contract is invalid." : "The change proof did not produce sufficient bound evidence.";
|
|
20605
|
+
return { merge_recommended: false, verdict, label: "Merge not recommended", reason };
|
|
20606
|
+
}
|
|
20607
|
+
function noShippingAuthorization() {
|
|
20608
|
+
return { status: "not_granted", authorized: false, source: "none" };
|
|
20609
|
+
}
|
|
20610
|
+
function recommendationMatches(actual, expected) {
|
|
20611
|
+
return actual?.merge_recommended === expected.merge_recommended && actual.verdict === expected.verdict && actual.label === expected.label && actual.reason === expected.reason;
|
|
20612
|
+
}
|
|
20613
|
+
function assertShippingAuthorizationConsistent(authorization, receiptName) {
|
|
20614
|
+
if (!authorization) throw new Error(`${receiptName} shipping authorization is required.`);
|
|
20615
|
+
if (authorization.status !== "not_granted" && authorization.status !== "granted") {
|
|
20616
|
+
throw new Error(`${receiptName} shipping authorization status is invalid.`);
|
|
20617
|
+
}
|
|
20618
|
+
if (authorization.source !== "none" && authorization.source !== "human" && authorization.source !== "automation") {
|
|
20619
|
+
throw new Error(`${receiptName} shipping authorization source is invalid.`);
|
|
20620
|
+
}
|
|
20621
|
+
const granted = authorization.status === "granted";
|
|
20622
|
+
if (authorization.authorized !== granted) {
|
|
20623
|
+
throw new Error(`${receiptName} shipping authorization status and authorized flag must agree.`);
|
|
20624
|
+
}
|
|
20625
|
+
if (authorization.source === "none" === granted) {
|
|
20626
|
+
throw new Error(`${receiptName} shipping authorization source must identify an authorizer only when granted.`);
|
|
20627
|
+
}
|
|
20628
|
+
}
|
|
20629
|
+
function observationArtifactMatches(actual, expected) {
|
|
20630
|
+
if (!actual || !expected) return actual === expected;
|
|
20631
|
+
return actual.name === expected.name && actual.role === expected.role && actual.url === expected.url && actual.path === expected.path && actual.kind === expected.kind && actual.content_type === expected.content_type && actual.source === expected.source;
|
|
20632
|
+
}
|
|
20633
|
+
function observationExecutor(result) {
|
|
20634
|
+
return result.runner === "local-playwright" ? { kind: "local_playwright", runner: result.runner } : {
|
|
20635
|
+
kind: "riddle_hosted",
|
|
20636
|
+
runner: result.runner,
|
|
20637
|
+
job_id: result.riddle?.job_id
|
|
20638
|
+
};
|
|
20639
|
+
}
|
|
20640
|
+
function observationForReceiptSide(side, result, source, sourceIdentity) {
|
|
20641
|
+
if (!result) throw new Error(`${side}_result or ${side}_observation is required.`);
|
|
20642
|
+
if (!source) throw new Error(`${side}_source or ${side}_observation is required.`);
|
|
20643
|
+
return createRiddleProofObservationReceipt({
|
|
20644
|
+
comparison_role: side,
|
|
20645
|
+
executor: observationExecutor(result),
|
|
20646
|
+
target: { kind: "url", url: source },
|
|
20647
|
+
source: sourceIdentity,
|
|
20648
|
+
profile_result: result,
|
|
20649
|
+
execution: result.riddle?.execution,
|
|
20650
|
+
publication: source.startsWith("http") ? { kind: result.runner === "local-playwright" ? "other" : "riddle_cdn", url: source } : { kind: "local", path: source }
|
|
20651
|
+
});
|
|
20652
|
+
}
|
|
20653
|
+
function createRiddleProofChangeReceipt(input) {
|
|
20654
|
+
const before = input.before_observation ? parseRiddleProofObservationReceipt(input.before_observation) : observationForReceiptSide("before", input.before_result, input.before_source, input.before_source_identity);
|
|
20655
|
+
const after = input.after_observation ? parseRiddleProofObservationReceipt(input.after_observation) : observationForReceiptSide("after", input.after_result, input.after_source, input.after_source_identity);
|
|
20656
|
+
const verdict = changeReceiptVerdict(input.result.status);
|
|
20657
|
+
const shippingAuthorization = input.shipping_authorization || noShippingAuthorization();
|
|
20658
|
+
assertShippingAuthorizationConsistent(shippingAuthorization, "Change receipt");
|
|
20659
|
+
return {
|
|
20660
|
+
version: RIDDLE_PROOF_CHANGE_RECEIPT_VERSION,
|
|
20661
|
+
contract_name: input.result.contract_name,
|
|
20662
|
+
profile_name: input.profile_name,
|
|
20663
|
+
status: input.result.status,
|
|
20664
|
+
verdict,
|
|
20665
|
+
summary: input.result.summary,
|
|
20666
|
+
before,
|
|
20667
|
+
after,
|
|
20668
|
+
groups: input.result.groups,
|
|
20669
|
+
source_bindings: input.result.source_bindings,
|
|
20670
|
+
deltas: input.result.deltas.map((delta) => ({
|
|
20671
|
+
type: delta.type,
|
|
20672
|
+
label: delta.label,
|
|
20673
|
+
status: delta.status,
|
|
20674
|
+
before_observed: delta.before_observed,
|
|
20675
|
+
after_observed: delta.after_observed,
|
|
20676
|
+
message: delta.message
|
|
20677
|
+
})),
|
|
20678
|
+
recommendation: changeRecommendation(verdict),
|
|
20679
|
+
shipping_authorization: shippingAuthorization,
|
|
20680
|
+
proves: metadataStringList(input.contract.metadata, "required_receipts"),
|
|
20681
|
+
does_not_prove: metadataStringList(input.contract.metadata, "does_not_prove"),
|
|
20682
|
+
metadata: input.result.metadata
|
|
20683
|
+
};
|
|
20684
|
+
}
|
|
20685
|
+
function isRecord4(value) {
|
|
20686
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
20687
|
+
}
|
|
20688
|
+
function migratedObservationFromLegacySide(side, legacy) {
|
|
20689
|
+
const legacyArtifacts = legacy.artifacts.map((artifact) => ({
|
|
20690
|
+
name: artifact.name,
|
|
20691
|
+
url: artifact.url,
|
|
20692
|
+
path: artifact.path,
|
|
20693
|
+
source: artifact.source,
|
|
20694
|
+
kind: artifact.kind,
|
|
20695
|
+
role: legacy.screenshots[0] && artifactTarget(artifact) === artifactTarget(legacy.screenshots[0]) ? "canonical_screenshot" : artifact.kind === "image" ? "diagnostic" : artifact.kind === "data" ? "data" : "artifact"
|
|
20696
|
+
}));
|
|
20697
|
+
const canonicalScreenshot = legacyArtifacts.find((artifact) => artifact.role === "canonical_screenshot");
|
|
20698
|
+
return {
|
|
20699
|
+
version: "riddle-proof.observation-receipt.v1",
|
|
20700
|
+
observation_id: `obs_${side}_migrated`,
|
|
20701
|
+
comparison_role: side,
|
|
20702
|
+
executor: { kind: "other", runner: "legacy-change-receipt" },
|
|
20703
|
+
target: { kind: "url", url: legacy.source },
|
|
20704
|
+
source: {},
|
|
20705
|
+
captured_at: legacy.captured_at || (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
20706
|
+
artifacts: legacyArtifacts,
|
|
20707
|
+
canonical_screenshot: canonicalScreenshot,
|
|
20708
|
+
profile_summary: {
|
|
20709
|
+
profile_name: legacy.profile_name,
|
|
20710
|
+
status: legacy.status,
|
|
20711
|
+
summary: legacy.summary,
|
|
20712
|
+
route: legacy.route,
|
|
20713
|
+
checks: legacy.checks
|
|
20714
|
+
},
|
|
20715
|
+
metadata: { migrated_from: RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION }
|
|
20716
|
+
};
|
|
20717
|
+
}
|
|
20718
|
+
function migrateRiddleProofChangeReceipt(legacy) {
|
|
20719
|
+
const recommendation = changeRecommendation(legacy.verdict);
|
|
20720
|
+
return {
|
|
20721
|
+
version: RIDDLE_PROOF_CHANGE_RECEIPT_VERSION,
|
|
20722
|
+
contract_name: legacy.contract_name,
|
|
20723
|
+
profile_name: legacy.profile_name,
|
|
20724
|
+
status: legacy.status,
|
|
20725
|
+
verdict: legacy.verdict,
|
|
20726
|
+
summary: legacy.summary,
|
|
20727
|
+
before: migratedObservationFromLegacySide("before", legacy.before),
|
|
20728
|
+
after: migratedObservationFromLegacySide("after", legacy.after),
|
|
20729
|
+
groups: {
|
|
20730
|
+
before: {
|
|
20731
|
+
side: "before",
|
|
20732
|
+
label: "before",
|
|
20733
|
+
ok: legacy.before.status === "passed" || legacy.before.status === "product_regression",
|
|
20734
|
+
profile_name: legacy.before.profile_name,
|
|
20735
|
+
status: legacy.before.status,
|
|
20736
|
+
required_status: DEFAULT_BEFORE_STATUSES,
|
|
20737
|
+
summary: legacy.before.summary
|
|
20738
|
+
},
|
|
20739
|
+
after: {
|
|
20740
|
+
side: "after",
|
|
20741
|
+
label: "after",
|
|
20742
|
+
ok: legacy.after.status === "passed",
|
|
20743
|
+
profile_name: legacy.after.profile_name,
|
|
20744
|
+
status: legacy.after.status,
|
|
20745
|
+
required_status: DEFAULT_AFTER_STATUSES,
|
|
20746
|
+
summary: legacy.after.summary
|
|
20747
|
+
}
|
|
20748
|
+
},
|
|
20749
|
+
source_bindings: {
|
|
20750
|
+
before: { side: "before", required: false, ok: true, status: "not_required" },
|
|
20751
|
+
after: { side: "after", required: false, ok: true, status: "not_required" }
|
|
20752
|
+
},
|
|
20753
|
+
deltas: legacy.deltas,
|
|
20754
|
+
recommendation,
|
|
20755
|
+
shipping_authorization: noShippingAuthorization(),
|
|
20756
|
+
proves: legacy.proves,
|
|
20757
|
+
does_not_prove: legacy.does_not_prove,
|
|
20758
|
+
metadata: legacy.metadata
|
|
20759
|
+
};
|
|
20760
|
+
}
|
|
20761
|
+
function parseRiddleProofChangeReceipt(value) {
|
|
20762
|
+
if (!isRecord4(value)) throw new Error("Change receipt must be an object.");
|
|
20763
|
+
if (value.version === RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION) {
|
|
20764
|
+
return migrateRiddleProofChangeReceipt(value);
|
|
20765
|
+
}
|
|
20766
|
+
if (value.version !== RIDDLE_PROOF_CHANGE_RECEIPT_VERSION) {
|
|
20767
|
+
throw new Error(`Unsupported Change receipt version ${String(value.version || "missing")}.`);
|
|
20768
|
+
}
|
|
20769
|
+
const receipt = value;
|
|
20770
|
+
if (!RIDDLE_PROOF_PROFILE_STATUSES.includes(receipt.status)) {
|
|
20771
|
+
throw new Error(`Unsupported Change receipt status ${String(receipt.status || "missing")}.`);
|
|
20772
|
+
}
|
|
20773
|
+
parseRiddleProofObservationReceipt(receipt.before);
|
|
20774
|
+
parseRiddleProofObservationReceipt(receipt.after);
|
|
20775
|
+
if (receipt.before.comparison_role !== "before" || receipt.after.comparison_role !== "after") {
|
|
20776
|
+
throw new Error("Change receipt observations must preserve their before and after comparison roles.");
|
|
20777
|
+
}
|
|
20778
|
+
const expectedVerdict = changeReceiptVerdict(receipt.status);
|
|
20779
|
+
if (receipt.verdict !== expectedVerdict) {
|
|
20780
|
+
throw new Error("Change receipt verdict must match its evaluated status.");
|
|
20781
|
+
}
|
|
20782
|
+
if (!recommendationMatches(receipt.recommendation, changeRecommendation(expectedVerdict))) {
|
|
20783
|
+
throw new Error("Change receipt recommendation must be derived from the Change receipt verdict.");
|
|
20784
|
+
}
|
|
20785
|
+
assertShippingAuthorizationConsistent(receipt.shipping_authorization, "Change receipt");
|
|
20786
|
+
return receipt;
|
|
20787
|
+
}
|
|
20788
|
+
function createRiddleProofHandoffReceipt(changeReceipt, options = {}) {
|
|
20789
|
+
const change = parseRiddleProofChangeReceipt(changeReceipt);
|
|
20790
|
+
const authorization = options.shipping_authorization || change.shipping_authorization;
|
|
20791
|
+
assertShippingAuthorizationConsistent(authorization, "Handoff receipt");
|
|
20792
|
+
return {
|
|
20793
|
+
version: RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION,
|
|
20794
|
+
change,
|
|
20795
|
+
verdict: change.verdict,
|
|
20796
|
+
recommendation: change.recommendation,
|
|
20797
|
+
shipping_authorization: authorization,
|
|
20798
|
+
canonical_pair: {
|
|
20799
|
+
before: change.before.canonical_screenshot,
|
|
20800
|
+
after: change.after.canonical_screenshot
|
|
20801
|
+
},
|
|
20802
|
+
created_at: options.created_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
20803
|
+
};
|
|
20804
|
+
}
|
|
20805
|
+
function parseRiddleProofHandoffReceipt(value) {
|
|
20806
|
+
if (!isRecord4(value) || value.version !== RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION) {
|
|
20807
|
+
throw new Error(`Unsupported Handoff receipt version ${String(isRecord4(value) ? value.version || "missing" : "missing")}.`);
|
|
20808
|
+
}
|
|
20809
|
+
const receipt = value;
|
|
20810
|
+
if (!Number.isFinite(Date.parse(receipt.created_at))) {
|
|
20811
|
+
throw new Error("Handoff receipt created_at must be a valid timestamp.");
|
|
20812
|
+
}
|
|
20813
|
+
const change = parseRiddleProofChangeReceipt(receipt.change);
|
|
20814
|
+
if (receipt.verdict !== change.verdict || !recommendationMatches(receipt.recommendation, change.recommendation)) {
|
|
20815
|
+
throw new Error("Handoff receipt must preserve the Change receipt verdict and recommendation.");
|
|
20816
|
+
}
|
|
20817
|
+
if (!observationArtifactMatches(receipt.canonical_pair?.before, change.before.canonical_screenshot) || !observationArtifactMatches(receipt.canonical_pair?.after, change.after.canonical_screenshot)) {
|
|
20818
|
+
throw new Error("Handoff receipt canonical pair must project the Change receipt observations.");
|
|
20819
|
+
}
|
|
20820
|
+
assertShippingAuthorizationConsistent(receipt.shipping_authorization, "Handoff receipt");
|
|
20821
|
+
return receipt;
|
|
20822
|
+
}
|
|
20823
|
+
function markdownTableCell(value) {
|
|
20824
|
+
return String(value ?? "").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
20825
|
+
}
|
|
20826
|
+
function artifactTarget(artifact) {
|
|
20827
|
+
return artifact.url || artifact.path;
|
|
20828
|
+
}
|
|
20829
|
+
function observationArtifactKind(artifact) {
|
|
20830
|
+
if (artifact.role === "canonical_screenshot" || artifact.role === "setup_screenshot" || artifact.kind === "image") return "image";
|
|
20831
|
+
if (artifact.role === "data" || /\.(json|md|txt|html|log|har)(\?|#|$)/i.test(artifact.name)) return "data";
|
|
20832
|
+
return "artifact";
|
|
20833
|
+
}
|
|
20834
|
+
function receiptSideView(side, observation) {
|
|
20835
|
+
const artifacts = observation.artifacts.map((artifact) => ({
|
|
20836
|
+
side,
|
|
20837
|
+
name: artifact.name,
|
|
20838
|
+
kind: observationArtifactKind(artifact),
|
|
20839
|
+
url: artifact.url,
|
|
20840
|
+
path: artifact.path,
|
|
20841
|
+
source: artifact.source
|
|
20842
|
+
}));
|
|
20843
|
+
const summary = observation.profile_summary;
|
|
20844
|
+
const canonical = observation.canonical_screenshot;
|
|
20845
|
+
const screenshots = artifacts.filter(artifactIsScreenshot);
|
|
20846
|
+
if (canonical) {
|
|
20847
|
+
const canonicalTarget = canonical.url || canonical.path;
|
|
20848
|
+
screenshots.sort((left, right) => {
|
|
20849
|
+
const leftCanonical = (left.url || left.path) === canonicalTarget || left.name === canonical.name;
|
|
20850
|
+
const rightCanonical = (right.url || right.path) === canonicalTarget || right.name === canonical.name;
|
|
20851
|
+
return Number(rightCanonical) - Number(leftCanonical);
|
|
20852
|
+
});
|
|
20853
|
+
}
|
|
20854
|
+
return {
|
|
20855
|
+
side,
|
|
20856
|
+
source: observation.target.url,
|
|
20857
|
+
profile_name: summary?.profile_name || observation.proof?.profile_name || "profile",
|
|
20858
|
+
status: summary?.status || observation.proof?.result.status || "proof_insufficient",
|
|
20859
|
+
summary: summary?.summary || observation.proof?.result.summary || "No profile summary recorded.",
|
|
20860
|
+
route: summary?.route,
|
|
20861
|
+
captured_at: observation.captured_at,
|
|
20862
|
+
checks: summary?.checks || (observation.proof ? profileCheckCounts2(observation.proof.result) : {
|
|
20863
|
+
total: 0,
|
|
20864
|
+
passed: 0,
|
|
20865
|
+
failed: 0,
|
|
20866
|
+
skipped: 0,
|
|
20867
|
+
needs_human_review: 0
|
|
20868
|
+
}),
|
|
20869
|
+
screenshots,
|
|
20870
|
+
artifacts
|
|
20871
|
+
};
|
|
20872
|
+
}
|
|
20873
|
+
function markdownLink(label, target) {
|
|
20874
|
+
return `[${label.replace(/\]/g, "\\]")}](${target})`;
|
|
20875
|
+
}
|
|
20876
|
+
function appendMarkdownArtifacts(lines, title, artifacts) {
|
|
20877
|
+
lines.push(`### ${title}`, "");
|
|
20878
|
+
if (!artifacts.length) {
|
|
20879
|
+
lines.push("- No screenshot artifacts recorded.", "");
|
|
20880
|
+
return;
|
|
20881
|
+
}
|
|
20882
|
+
for (const artifact of artifacts.slice(0, 6)) {
|
|
20883
|
+
const target = artifactTarget(artifact);
|
|
20884
|
+
if (target && artifact.kind === "image") {
|
|
20885
|
+
lines.push(`![${artifact.name.replace(/\]/g, "\\]")}](${target})`);
|
|
20886
|
+
} else if (target) {
|
|
20887
|
+
lines.push(`- ${markdownLink(artifact.name, target)}`);
|
|
20888
|
+
} else {
|
|
20889
|
+
lines.push(`- ${artifact.name}`);
|
|
20890
|
+
}
|
|
20891
|
+
}
|
|
20892
|
+
if (artifacts.length > 6) lines.push(`- ${artifacts.length - 6} more artifact(s) omitted`);
|
|
20893
|
+
lines.push("");
|
|
20894
|
+
}
|
|
20895
|
+
function riddleProofChangeReceiptMarkdown(receipt) {
|
|
20896
|
+
const before = receiptSideView("before", receipt.before);
|
|
20897
|
+
const after = receiptSideView("after", receipt.after);
|
|
20898
|
+
const lines = [
|
|
20899
|
+
"# Riddle Proof Change Receipt",
|
|
20900
|
+
"",
|
|
20901
|
+
`**Verdict:** ${receipt.verdict}`,
|
|
20902
|
+
`**Status:** ${receipt.status}`,
|
|
20903
|
+
`**Contract:** ${receipt.contract_name}`,
|
|
20904
|
+
receipt.profile_name ? `**Profile:** ${receipt.profile_name}` : "",
|
|
20905
|
+
`**Recommendation:** ${receipt.recommendation.label}`,
|
|
20906
|
+
`**Shipping authorization:** ${receipt.shipping_authorization.status}`,
|
|
20907
|
+
"",
|
|
20908
|
+
receipt.summary,
|
|
20909
|
+
"",
|
|
20910
|
+
"## Evidence Pair",
|
|
20911
|
+
"",
|
|
20912
|
+
"| Side | Source | Status | Checks |",
|
|
20913
|
+
"| --- | --- | --- | --- |",
|
|
20914
|
+
`| Before | ${markdownTableCell(before.source)} | ${before.status}${receipt.groups.before.ok ? " (matched baseline)" : " (baseline mismatch)"} | ${before.checks.passed} passed / ${before.checks.failed} failed |`,
|
|
20915
|
+
`| After | ${markdownTableCell(after.source)} | ${after.status} | ${after.checks.passed} passed / ${after.checks.failed} failed |`,
|
|
20916
|
+
"",
|
|
20917
|
+
"## Source Binding",
|
|
20918
|
+
"",
|
|
20919
|
+
"| Side | Status | Git revision | Preview | Digest |",
|
|
20920
|
+
"| --- | --- | --- | --- | --- |",
|
|
20921
|
+
`| Before | ${receipt.source_bindings.before.status} | ${markdownTableCell(receipt.source_bindings.before.observed_git_revision || "not recorded")} | ${markdownTableCell(receipt.source_bindings.before.preview_id || "not required")} | ${markdownTableCell(receipt.source_bindings.before.content_digest || "not required")} |`,
|
|
20922
|
+
`| After | ${receipt.source_bindings.after.status} | ${markdownTableCell(receipt.source_bindings.after.observed_git_revision || "not recorded")} | ${markdownTableCell(receipt.source_bindings.after.preview_id || "not required")} | ${markdownTableCell(receipt.source_bindings.after.content_digest || "not required")} |`,
|
|
20923
|
+
"",
|
|
20924
|
+
"## Delta Checks",
|
|
20925
|
+
"",
|
|
20926
|
+
"| Delta | Status | Before | After |",
|
|
20927
|
+
"| --- | --- | --- | --- |"
|
|
20928
|
+
].filter(Boolean);
|
|
20929
|
+
for (const delta of receipt.deltas) {
|
|
20930
|
+
lines.push(`| ${markdownTableCell(delta.label)} | ${delta.status} | ${markdownTableCell(delta.before_observed)} | ${markdownTableCell(delta.after_observed)} |`);
|
|
20931
|
+
if (delta.message) lines.push(`| ${markdownTableCell(`${delta.label} message`)} | ${markdownTableCell(delta.message)} | | |`);
|
|
20932
|
+
}
|
|
20933
|
+
lines.push("");
|
|
20934
|
+
appendMarkdownArtifacts(lines, "Before Canonical Screenshot", before.screenshots.slice(0, 1));
|
|
20935
|
+
appendMarkdownArtifacts(lines, "After Canonical Screenshot", after.screenshots.slice(0, 1));
|
|
20936
|
+
if (receipt.proves.length) {
|
|
20937
|
+
lines.push("## What This Proves", "");
|
|
20938
|
+
for (const claim of receipt.proves) lines.push(`- ${claim}`);
|
|
20939
|
+
lines.push("");
|
|
20940
|
+
}
|
|
20941
|
+
if (receipt.does_not_prove.length) {
|
|
20942
|
+
lines.push("## What This Does Not Prove", "");
|
|
20943
|
+
for (const claim of receipt.does_not_prove) lines.push(`- ${claim}`);
|
|
20944
|
+
lines.push("");
|
|
20945
|
+
}
|
|
20946
|
+
const linkedArtifacts = [...before.artifacts, ...after.artifacts].filter((artifact) => artifactTarget(artifact)).slice(0, 24);
|
|
20947
|
+
if (linkedArtifacts.length) {
|
|
20948
|
+
lines.push("## Artifacts", "");
|
|
20949
|
+
for (const artifact of linkedArtifacts) {
|
|
20950
|
+
lines.push(`- ${artifact.side}: ${markdownLink(artifact.name, artifactTarget(artifact) || "")}`);
|
|
20951
|
+
}
|
|
20952
|
+
lines.push("");
|
|
20953
|
+
}
|
|
20954
|
+
return `${lines.join("\n").trim()}
|
|
20955
|
+
`;
|
|
20956
|
+
}
|
|
20957
|
+
function escapeHtml(value) {
|
|
20958
|
+
return String(value ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
20959
|
+
}
|
|
20960
|
+
function htmlArtifactCard(artifact) {
|
|
20961
|
+
const target = artifactTarget(artifact);
|
|
20962
|
+
if (!target) return `<p>${escapeHtml(artifact.name)}</p>`;
|
|
20963
|
+
if (artifact.kind === "image") {
|
|
20964
|
+
return `<figure><img src="${escapeHtml(target)}" alt="${escapeHtml(artifact.name)}"><figcaption>${escapeHtml(artifact.name)}</figcaption></figure>`;
|
|
20965
|
+
}
|
|
20966
|
+
return `<p><a href="${escapeHtml(target)}">${escapeHtml(artifact.name)}</a></p>`;
|
|
20967
|
+
}
|
|
20968
|
+
function htmlArtifactLink(artifact) {
|
|
20969
|
+
const target = artifactTarget(artifact);
|
|
20970
|
+
if (!target) return escapeHtml(artifact.name);
|
|
20971
|
+
return `<a href="${escapeHtml(target)}">${escapeHtml(artifact.name)}</a>`;
|
|
20972
|
+
}
|
|
20973
|
+
function htmlList(items, emptyText) {
|
|
20974
|
+
if (!items.length) return `<p class="muted">${escapeHtml(emptyText)}</p>`;
|
|
20975
|
+
return `<ul>${items.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>`;
|
|
20976
|
+
}
|
|
20977
|
+
function riddleProofChangeReceiptHtml(receipt) {
|
|
20978
|
+
const before = receiptSideView("before", receipt.before);
|
|
20979
|
+
const after = receiptSideView("after", receipt.after);
|
|
20980
|
+
const artifactLinks = [...before.artifacts, ...after.artifacts].filter((artifact) => artifactTarget(artifact)).slice(0, 32);
|
|
20981
|
+
const deltaRows = receipt.deltas.map((delta) => `
|
|
20982
|
+
<tr>
|
|
20983
|
+
<td>${escapeHtml(delta.label)}</td>
|
|
20984
|
+
<td><span class="status ${escapeHtml(delta.status)}">${escapeHtml(delta.status)}</span></td>
|
|
20985
|
+
<td>${escapeHtml(delta.before_observed)}</td>
|
|
20986
|
+
<td>${escapeHtml(delta.after_observed)}</td>
|
|
20987
|
+
</tr>
|
|
20988
|
+
${delta.message ? `<tr><td class="muted">${escapeHtml(delta.label)} message</td><td colspan="3">${escapeHtml(delta.message)}</td></tr>` : ""}`).join("");
|
|
20989
|
+
return `<!doctype html>
|
|
20990
|
+
<html lang="en">
|
|
20991
|
+
<head>
|
|
20992
|
+
<meta charset="utf-8">
|
|
20993
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
20994
|
+
<title>${escapeHtml(receipt.contract_name)} - Riddle Proof Change Receipt</title>
|
|
20995
|
+
<style>
|
|
20996
|
+
:root { color-scheme: light dark; --bg: #0f141b; --panel: #171f29; --text: #eef4f8; --muted: #aebbc8; --border: #314152; --ok: #69d089; --bad: #ff7a7a; --warn: #ffd166; }
|
|
20997
|
+
body { margin: 0; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: var(--bg); color: var(--text); }
|
|
20998
|
+
main { max-width: 1120px; margin: 0 auto; padding: 32px 20px 48px; }
|
|
20999
|
+
header, section { border: 1px solid var(--border); background: var(--panel); border-radius: 8px; padding: 20px; margin: 0 0 18px; }
|
|
21000
|
+
h1, h2, h3, p { margin-top: 0; }
|
|
21001
|
+
h1 { font-size: clamp(1.6rem, 3vw, 2.4rem); }
|
|
21002
|
+
h2 { font-size: 1.1rem; margin-bottom: 14px; }
|
|
21003
|
+
.muted { color: var(--muted); }
|
|
21004
|
+
.verdict { display: inline-flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 999px; border: 1px solid var(--border); font-weight: 700; }
|
|
21005
|
+
.mergeable, .passed { color: var(--ok); }
|
|
21006
|
+
.not_mergeable, .failed, .product_regression { color: var(--bad); }
|
|
21007
|
+
.proof_insufficient, .environment_blocked, .needs_human_review, .configuration_error { color: var(--warn); }
|
|
21008
|
+
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
|
|
21009
|
+
.side { border: 1px solid var(--border); border-radius: 8px; padding: 14px; min-width: 0; }
|
|
21010
|
+
code { overflow-wrap: anywhere; color: var(--muted); }
|
|
21011
|
+
table { width: 100%; border-collapse: collapse; }
|
|
21012
|
+
th, td { border-bottom: 1px solid var(--border); padding: 10px 8px; text-align: left; vertical-align: top; }
|
|
21013
|
+
figure { margin: 0; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: #0b1017; }
|
|
21014
|
+
img { display: block; width: 100%; height: auto; }
|
|
21015
|
+
figcaption { padding: 8px 10px; color: var(--muted); font-size: 0.9rem; }
|
|
21016
|
+
ul { margin-bottom: 0; }
|
|
21017
|
+
a { color: #8bc7ff; }
|
|
21018
|
+
@media (max-width: 760px) { .grid { grid-template-columns: 1fr; } main { padding: 18px 12px 32px; } }
|
|
21019
|
+
</style>
|
|
21020
|
+
</head>
|
|
21021
|
+
<body>
|
|
21022
|
+
<main>
|
|
21023
|
+
<header>
|
|
21024
|
+
<p class="verdict ${escapeHtml(receipt.verdict)}">${escapeHtml(receipt.verdict)}</p>
|
|
21025
|
+
<h1>${escapeHtml(receipt.contract_name)}</h1>
|
|
21026
|
+
<p>${escapeHtml(receipt.summary)}</p>
|
|
21027
|
+
<p class="muted">Status: ${escapeHtml(receipt.status)}${receipt.profile_name ? ` | Profile: ${escapeHtml(receipt.profile_name)}` : ""}</p>
|
|
21028
|
+
<p>${escapeHtml(receipt.recommendation.label)}. Shipping authorization: ${escapeHtml(receipt.shipping_authorization.status)}.</p>
|
|
21029
|
+
</header>
|
|
21030
|
+
<section>
|
|
21031
|
+
<h2>Evidence Pair</h2>
|
|
21032
|
+
<div class="grid">
|
|
21033
|
+
<div class="side">
|
|
21034
|
+
<h3>Before</h3>
|
|
21035
|
+
<p><code>${escapeHtml(before.source)}</code></p>
|
|
21036
|
+
<p>Status: <strong class="${escapeHtml(before.status)}">${escapeHtml(before.status)}</strong>${receipt.groups.before.ok ? " (matched baseline)" : " (baseline mismatch)"}</p>
|
|
21037
|
+
<p>${escapeHtml(before.summary)}</p>
|
|
21038
|
+
<p class="muted">${before.checks.passed} passed / ${before.checks.failed} failed checks</p>
|
|
21039
|
+
</div>
|
|
21040
|
+
<div class="side">
|
|
21041
|
+
<h3>After</h3>
|
|
21042
|
+
<p><code>${escapeHtml(after.source)}</code></p>
|
|
21043
|
+
<p>Status: <strong class="${escapeHtml(after.status)}">${escapeHtml(after.status)}</strong></p>
|
|
21044
|
+
<p>${escapeHtml(after.summary)}</p>
|
|
21045
|
+
<p class="muted">${after.checks.passed} passed / ${after.checks.failed} failed checks</p>
|
|
21046
|
+
</div>
|
|
21047
|
+
</div>
|
|
21048
|
+
</section>
|
|
21049
|
+
<section>
|
|
21050
|
+
<h2>Source Binding</h2>
|
|
21051
|
+
<table>
|
|
21052
|
+
<thead><tr><th>Side</th><th>Status</th><th>Git revision</th><th>Preview</th><th>Digest</th></tr></thead>
|
|
21053
|
+
<tbody>
|
|
21054
|
+
<tr><td>Before</td><td>${escapeHtml(receipt.source_bindings.before.status)}</td><td>${escapeHtml(receipt.source_bindings.before.observed_git_revision || "not recorded")}</td><td>${escapeHtml(receipt.source_bindings.before.preview_id || "not required")}</td><td>${escapeHtml(receipt.source_bindings.before.content_digest || "not required")}</td></tr>
|
|
21055
|
+
<tr><td>After</td><td>${escapeHtml(receipt.source_bindings.after.status)}</td><td>${escapeHtml(receipt.source_bindings.after.observed_git_revision || "not recorded")}</td><td>${escapeHtml(receipt.source_bindings.after.preview_id || "not required")}</td><td>${escapeHtml(receipt.source_bindings.after.content_digest || "not required")}</td></tr>
|
|
21056
|
+
</tbody>
|
|
21057
|
+
</table>
|
|
21058
|
+
</section>
|
|
21059
|
+
<section>
|
|
21060
|
+
<h2>Delta Checks</h2>
|
|
21061
|
+
<table>
|
|
21062
|
+
<thead><tr><th>Delta</th><th>Status</th><th>Before</th><th>After</th></tr></thead>
|
|
21063
|
+
<tbody>${deltaRows}</tbody>
|
|
21064
|
+
</table>
|
|
21065
|
+
</section>
|
|
21066
|
+
<section>
|
|
21067
|
+
<h2>Screenshots</h2>
|
|
21068
|
+
<div class="grid">
|
|
21069
|
+
<div>${before.screenshots.slice(0, 1).map(htmlArtifactCard).join("") || `<p class="muted">No canonical before screenshot recorded.</p>`}</div>
|
|
21070
|
+
<div>${after.screenshots.slice(0, 1).map(htmlArtifactCard).join("") || `<p class="muted">No canonical after screenshot recorded.</p>`}</div>
|
|
21071
|
+
</div>
|
|
21072
|
+
</section>
|
|
21073
|
+
<section>
|
|
21074
|
+
<h2>What This Proves</h2>
|
|
21075
|
+
${htmlList(receipt.proves, "No explicit proof claims were recorded in contract metadata.")}
|
|
21076
|
+
</section>
|
|
21077
|
+
<section>
|
|
21078
|
+
<h2>What This Does Not Prove</h2>
|
|
21079
|
+
${htmlList(receipt.does_not_prove, "No explicit limits were recorded in contract metadata.")}
|
|
21080
|
+
</section>
|
|
21081
|
+
<section>
|
|
21082
|
+
<h2>Artifacts</h2>
|
|
21083
|
+
${artifactLinks.length ? `<ul>${artifactLinks.map((artifact) => `<li>${escapeHtml(artifact.side)}: ${htmlArtifactLink(artifact)}</li>`).join("")}</ul>` : `<p class="muted">No linked artifacts recorded.</p>`}
|
|
21084
|
+
</section>
|
|
21085
|
+
</main>
|
|
21086
|
+
</body>
|
|
21087
|
+
</html>
|
|
21088
|
+
`;
|
|
21089
|
+
}
|
|
20096
21090
|
|
|
20097
21091
|
// src/riddle-client.ts
|
|
20098
21092
|
var import_node_child_process4 = require("child_process");
|
|
@@ -20160,6 +21154,7 @@ async function getRiddleBalance(config = {}) {
|
|
|
20160
21154
|
}
|
|
20161
21155
|
function previewDeployResultFromRecord(input) {
|
|
20162
21156
|
const { record, id, label, framework, expiresAt, publishRecovered, publishError } = input;
|
|
21157
|
+
const receipt = record.receipt && typeof record.receipt === "object" ? parseRiddlePreviewReceipt(record.receipt) : void 0;
|
|
20163
21158
|
return {
|
|
20164
21159
|
ok: true,
|
|
20165
21160
|
id: String(record.id || record.preview_id || id),
|
|
@@ -20168,13 +21163,32 @@ function previewDeployResultFromRecord(input) {
|
|
|
20168
21163
|
preview_url: String(record.preview_url || ""),
|
|
20169
21164
|
file_count: typeof record.file_count === "number" ? record.file_count : void 0,
|
|
20170
21165
|
total_bytes: typeof record.total_bytes === "number" ? record.total_bytes : void 0,
|
|
20171
|
-
expires_at: expiresAt,
|
|
21166
|
+
expires_at: receipt?.expires_at || expiresAt,
|
|
21167
|
+
receipt,
|
|
20172
21168
|
publish_recovered: publishRecovered || void 0,
|
|
20173
21169
|
publish_error: publishError,
|
|
20174
21170
|
warnings: input.warnings?.length ? input.warnings : void 0,
|
|
20175
21171
|
raw: record
|
|
20176
21172
|
};
|
|
20177
21173
|
}
|
|
21174
|
+
function gitOutput(directory, args) {
|
|
21175
|
+
try {
|
|
21176
|
+
return (0, import_node_child_process4.execFileSync)("git", ["-C", directory, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
21177
|
+
} catch {
|
|
21178
|
+
return "";
|
|
21179
|
+
}
|
|
21180
|
+
}
|
|
21181
|
+
function detectRiddlePreviewSource(directory) {
|
|
21182
|
+
const gitRevision = gitOutput(directory, ["rev-parse", "HEAD"]);
|
|
21183
|
+
if (!gitRevision) return {};
|
|
21184
|
+
const repository = gitOutput(directory, ["config", "--get", "remote.origin.url"]);
|
|
21185
|
+
const status = gitOutput(directory, ["status", "--porcelain", "--untracked-files=normal"]);
|
|
21186
|
+
return {
|
|
21187
|
+
git_revision: gitRevision,
|
|
21188
|
+
repository: repository || void 0,
|
|
21189
|
+
dirty: Boolean(status)
|
|
21190
|
+
};
|
|
21191
|
+
}
|
|
20178
21192
|
function canRecoverPreviewPublish(error) {
|
|
20179
21193
|
return error instanceof RiddleApiError && PREVIEW_PUBLISH_RECOVERY_STATUSES.has(error.status);
|
|
20180
21194
|
}
|
|
@@ -20257,12 +21271,13 @@ async function waitForPublishedPreview(config, input) {
|
|
|
20257
21271
|
}
|
|
20258
21272
|
throw input.publishError;
|
|
20259
21273
|
}
|
|
20260
|
-
async function deployRiddlePreview(config, directory, label, framework = "static") {
|
|
21274
|
+
async function deployRiddlePreview(config, directory, label, framework = "static", options = {}) {
|
|
20261
21275
|
if (!directory?.trim()) throw new Error("directory is required");
|
|
20262
21276
|
if (!label?.trim()) throw new Error("label is required");
|
|
20263
21277
|
if (framework !== "spa" && framework !== "static") throw new Error("framework must be spa or static");
|
|
20264
21278
|
const startedAt = Date.now();
|
|
20265
21279
|
const warnings = collectRiddlePreviewDeployWarnings(directory, framework);
|
|
21280
|
+
const source = options.source || detectRiddlePreviewSource(directory);
|
|
20266
21281
|
const emitProgress = previewProgressEmitter(config, { label, framework, directory, startedAt, warnings });
|
|
20267
21282
|
await emitProgress({ stage: "validating", message: "checking preview input directory" });
|
|
20268
21283
|
const localSummary = summarizePreviewDirectory(directory);
|
|
@@ -20274,7 +21289,7 @@ async function deployRiddlePreview(config, directory, label, framework = "static
|
|
|
20274
21289
|
});
|
|
20275
21290
|
const created = await riddleRequestJson(config, "/v1/preview", {
|
|
20276
21291
|
method: "POST",
|
|
20277
|
-
body: JSON.stringify({ framework, label })
|
|
21292
|
+
body: JSON.stringify({ framework, label, source })
|
|
20278
21293
|
});
|
|
20279
21294
|
const id = String(created.id || "");
|
|
20280
21295
|
const uploadUrl = String(created.upload_url || "");
|
|
@@ -20416,8 +21431,8 @@ function collectRiddlePreviewDeployWarnings(directory, framework = "static") {
|
|
|
20416
21431
|
return [];
|
|
20417
21432
|
}
|
|
20418
21433
|
}
|
|
20419
|
-
async function deployRiddleStaticPreview(config, directory, label) {
|
|
20420
|
-
return deployRiddlePreview(config, directory, label, "static");
|
|
21434
|
+
async function deployRiddleStaticPreview(config, directory, label, options = {}) {
|
|
21435
|
+
return deployRiddlePreview(config, directory, label, "static", options);
|
|
20421
21436
|
}
|
|
20422
21437
|
function createTarball(directory, label, exclude = []) {
|
|
20423
21438
|
const scratch = (0, import_node_fs5.mkdtempSync)(import_node_path5.default.join((0, import_node_os2.tmpdir)(), "riddle-upload-"));
|
|
@@ -20539,21 +21554,31 @@ function parseTimestampMs(value) {
|
|
|
20539
21554
|
}
|
|
20540
21555
|
function buildPollSnapshot(jobId, job, input) {
|
|
20541
21556
|
const status = job?.status ? String(job.status) : null;
|
|
21557
|
+
const phase = job?.phase ? String(job.phase) : null;
|
|
20542
21558
|
const terminal = isTerminalRiddleJobStatus(status);
|
|
20543
21559
|
const createdAt = stringField(job, "created_at");
|
|
20544
21560
|
const submittedAt = stringField(job, "submitted_at");
|
|
20545
21561
|
const completedAt = stringField(job, "completed_at");
|
|
20546
21562
|
const createdMs = parseTimestampMs(createdAt);
|
|
20547
21563
|
const submittedMs = parseTimestampMs(submittedAt);
|
|
21564
|
+
const rawExecution = job?.execution && typeof job.execution === "object" && !Array.isArray(job.execution) ? job.execution : null;
|
|
21565
|
+
const enqueuedAt = rawExecution ? stringField(rawExecution, "enqueued_at") : null;
|
|
21566
|
+
const enqueuedMs = parseTimestampMs(enqueuedAt);
|
|
21567
|
+
const queueStartedMs = enqueuedMs ?? createdMs;
|
|
21568
|
+
const claimedAt = rawExecution ? stringField(rawExecution, "claimed_at") : null;
|
|
21569
|
+
const claimedMs = parseTimestampMs(claimedAt);
|
|
20548
21570
|
let queueElapsedMs = null;
|
|
20549
|
-
if (
|
|
20550
|
-
queueElapsedMs = Math.max(0,
|
|
20551
|
-
} else if (
|
|
20552
|
-
queueElapsedMs = Math.max(0,
|
|
21571
|
+
if (queueStartedMs !== null && claimedMs !== null) {
|
|
21572
|
+
queueElapsedMs = Math.max(0, claimedMs - queueStartedMs);
|
|
21573
|
+
} else if (queueStartedMs !== null && submittedMs !== null) {
|
|
21574
|
+
queueElapsedMs = Math.max(0, submittedMs - queueStartedMs);
|
|
21575
|
+
} else if (queueStartedMs !== null && !submittedAt && !terminal) {
|
|
21576
|
+
queueElapsedMs = Math.max(0, input.observedAt - queueStartedMs);
|
|
20553
21577
|
}
|
|
20554
21578
|
return {
|
|
20555
21579
|
job_id: jobId,
|
|
20556
21580
|
status,
|
|
21581
|
+
phase,
|
|
20557
21582
|
terminal,
|
|
20558
21583
|
attempt: input.attempt,
|
|
20559
21584
|
attempts: input.attempts,
|
|
@@ -20563,7 +21588,9 @@ function buildPollSnapshot(jobId, job, input) {
|
|
|
20563
21588
|
completed_at: completedAt,
|
|
20564
21589
|
queue_elapsed_ms: queueElapsedMs,
|
|
20565
21590
|
pre_submission_elapsed_ms: Math.max(0, Math.floor(input.preSubmissionElapsedMs ?? 0)),
|
|
20566
|
-
running_without_submission: Boolean(status && !terminal && !submittedAt)
|
|
21591
|
+
running_without_submission: Boolean(status && !terminal && !submittedAt),
|
|
21592
|
+
active_execution: Boolean(status === "running" && phase && phase !== "queued"),
|
|
21593
|
+
execution: rawExecution ? rawExecution : void 0
|
|
20567
21594
|
};
|
|
20568
21595
|
}
|
|
20569
21596
|
function pollMessage(snapshot, timedOut) {
|
|
@@ -20572,7 +21599,7 @@ function pollMessage(snapshot, timedOut) {
|
|
|
20572
21599
|
const wakeHint = snapshot.running_without_submission && !snapshot.created_at && !snapshot.submitted_at ? ` ${RIDDLE_UNSUBMITTED_WAKE_HINT}.` : "";
|
|
20573
21600
|
const queue = snapshot.queue_elapsed_ms !== null ? ` queue_elapsed_ms=${snapshot.queue_elapsed_ms}` : "";
|
|
20574
21601
|
const preSubmit = snapshot.pre_submission_elapsed_ms > 0 ? ` pre_submission_elapsed_ms=${snapshot.pre_submission_elapsed_ms}` : "";
|
|
20575
|
-
return `Riddle job ${snapshot.job_id} did not reach a terminal status after ${snapshot.attempt} poll attempts; status=${snapshot.status || "unknown"} submitted_at=${submitted}.${wakeHint}${queue}${preSubmit}`;
|
|
21602
|
+
return `Riddle job ${snapshot.job_id} did not reach a terminal status after ${snapshot.attempt} poll attempts; status=${snapshot.status || "unknown"} phase=${snapshot.phase || "unknown"} submitted_at=${submitted}.${wakeHint}${queue}${preSubmit}`;
|
|
20576
21603
|
}
|
|
20577
21604
|
async function pollRiddleJob(config, jobId, options = {}) {
|
|
20578
21605
|
if (!jobId?.trim()) throw new Error("jobId is required");
|
|
@@ -20606,6 +21633,7 @@ async function pollRiddleJob(config, jobId, options = {}) {
|
|
|
20606
21633
|
};
|
|
20607
21634
|
const progressKey = [
|
|
20608
21635
|
lastSnapshot.status || "unknown",
|
|
21636
|
+
lastSnapshot.phase || "unknown",
|
|
20609
21637
|
lastSnapshot.terminal ? "terminal" : "nonterminal",
|
|
20610
21638
|
lastSnapshot.submitted_at ? "submitted" : "unsubmitted"
|
|
20611
21639
|
].join(":");
|
|
@@ -20672,8 +21700,8 @@ function createRiddleApiClient(config = {}) {
|
|
|
20672
21700
|
apiKeySource: () => resolveRiddleApiKeySource(config),
|
|
20673
21701
|
requestJson: (pathname, init) => riddleRequestJson(config, pathname, init),
|
|
20674
21702
|
getBalance: () => getRiddleBalance(config),
|
|
20675
|
-
deployPreview: (directory, label, framework = "static") => deployRiddlePreview(config, directory, label, framework),
|
|
20676
|
-
deployStaticPreview: (directory, label) => deployRiddleStaticPreview(config, directory, label),
|
|
21703
|
+
deployPreview: (directory, label, framework = "static", options) => deployRiddlePreview(config, directory, label, framework, options),
|
|
21704
|
+
deployStaticPreview: (directory, label, options) => deployRiddleStaticPreview(config, directory, label, options),
|
|
20677
21705
|
runScript: (input) => runRiddleScript(config, input),
|
|
20678
21706
|
runServerPreview: (input) => runRiddleServerPreview(config, input),
|
|
20679
21707
|
pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
|
|
@@ -20755,6 +21783,34 @@ function collectProfileArtifacts(result) {
|
|
|
20755
21783
|
}
|
|
20756
21784
|
return artifacts;
|
|
20757
21785
|
}
|
|
21786
|
+
function collectChangeReceiptArtifacts(result) {
|
|
21787
|
+
const artifacts = [];
|
|
21788
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21789
|
+
const collectSide = (sideName, side) => {
|
|
21790
|
+
const candidates = [
|
|
21791
|
+
side.canonical_screenshot,
|
|
21792
|
+
...asArray(side.screenshots),
|
|
21793
|
+
...asArray(side.artifacts)
|
|
21794
|
+
].filter(Boolean);
|
|
21795
|
+
for (const [index, item] of candidates.entries()) {
|
|
21796
|
+
const artifact = asRecord2(item);
|
|
21797
|
+
const url = stringValue7(artifact.url) || stringValue7(artifact.path);
|
|
21798
|
+
if (!url || seen.has(url)) continue;
|
|
21799
|
+
seen.add(url);
|
|
21800
|
+
const fallbackName = `${sideName}-artifact-${index + 1}`;
|
|
21801
|
+
const name = `${sideName}/${artifactDisplayName(artifact.name, fallbackName)}`;
|
|
21802
|
+
artifacts.push({
|
|
21803
|
+
name,
|
|
21804
|
+
url,
|
|
21805
|
+
kind: artifactKind(name, url),
|
|
21806
|
+
size_bytes: numberValue5(artifact.size_bytes) ?? numberValue5(artifact.size)
|
|
21807
|
+
});
|
|
21808
|
+
}
|
|
21809
|
+
};
|
|
21810
|
+
collectSide("before", asRecord2(result.before));
|
|
21811
|
+
collectSide("after", asRecord2(result.after));
|
|
21812
|
+
return artifacts;
|
|
21813
|
+
}
|
|
20758
21814
|
function mergeArtifacts(...artifactLists) {
|
|
20759
21815
|
const artifacts = [];
|
|
20760
21816
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -20781,7 +21837,7 @@ function pageSummaries(result) {
|
|
|
20781
21837
|
}
|
|
20782
21838
|
return pages;
|
|
20783
21839
|
}
|
|
20784
|
-
function
|
|
21840
|
+
function profileCheckCounts3(result) {
|
|
20785
21841
|
const checks = asArray(result.checks);
|
|
20786
21842
|
if (checks.length) {
|
|
20787
21843
|
let passed2 = 0;
|
|
@@ -20810,6 +21866,33 @@ function profilePageSummaries(result, counts) {
|
|
|
20810
21866
|
failed: counts.failed
|
|
20811
21867
|
}];
|
|
20812
21868
|
}
|
|
21869
|
+
function changeReceiptCheckCounts(result) {
|
|
21870
|
+
const deltas = asArray(result.deltas);
|
|
21871
|
+
if (!deltas.length) return void 0;
|
|
21872
|
+
let passed = 0;
|
|
21873
|
+
let failed = 0;
|
|
21874
|
+
for (const item of deltas) {
|
|
21875
|
+
const status = stringValue7(asRecord2(item).status);
|
|
21876
|
+
if (status === "passed") passed += 1;
|
|
21877
|
+
if (status === "failed" || status === "proof_insufficient" || status === "configuration_error") failed += 1;
|
|
21878
|
+
}
|
|
21879
|
+
return { passed, failed };
|
|
21880
|
+
}
|
|
21881
|
+
function changeReceiptPageSummaries(result) {
|
|
21882
|
+
const pages = [];
|
|
21883
|
+
for (const sideName of ["before", "after"]) {
|
|
21884
|
+
const side = asRecord2(result[sideName]);
|
|
21885
|
+
if (!Object.keys(side).length) continue;
|
|
21886
|
+
const profileSummary = asRecord2(side.profile_summary);
|
|
21887
|
+
const checks = Object.keys(asRecord2(side.checks)).length ? asRecord2(side.checks) : asRecord2(profileSummary.checks);
|
|
21888
|
+
pages.push({
|
|
21889
|
+
route: firstStringValue2(asRecord2(side.target).url, side.source, profileSummary.profile_name, side.profile_name) || sideName,
|
|
21890
|
+
passed: numberValue5(checks.passed) ?? 0,
|
|
21891
|
+
failed: numberValue5(checks.failed) ?? 0
|
|
21892
|
+
});
|
|
21893
|
+
}
|
|
21894
|
+
return pages;
|
|
21895
|
+
}
|
|
20813
21896
|
function summarizeExplicitChecks(value) {
|
|
20814
21897
|
let passed = 0;
|
|
20815
21898
|
let failed = 0;
|
|
@@ -20865,11 +21948,27 @@ function isProfileResult(result) {
|
|
|
20865
21948
|
const version = stringValue7(result.version);
|
|
20866
21949
|
return version === "riddle-proof.profile-result.v1" || version === "riddle-proof.profile-compact-result.v1";
|
|
20867
21950
|
}
|
|
21951
|
+
function isChangeReceiptResult(result) {
|
|
21952
|
+
const version = stringValue7(result.version);
|
|
21953
|
+
return version === RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION || version === RIDDLE_PROOF_CHANGE_RECEIPT_VERSION;
|
|
21954
|
+
}
|
|
21955
|
+
function isHandoffReceiptResult(result) {
|
|
21956
|
+
return stringValue7(result.version) === RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION;
|
|
21957
|
+
}
|
|
21958
|
+
function isChangeResult(result) {
|
|
21959
|
+
const version = stringValue7(result.version);
|
|
21960
|
+
return version === "riddle-proof.change-result.v1" || version === "riddle-proof.change-compact-result.v1";
|
|
21961
|
+
}
|
|
20868
21962
|
function summarizeRiddleProofPrComment(input) {
|
|
20869
21963
|
const runResponse = asRecord2(input.runResponse);
|
|
20870
|
-
const
|
|
21964
|
+
const inputResult = asRecord2(input.result);
|
|
21965
|
+
const handoffReceipt = isHandoffReceiptResult(inputResult) ? parseRiddleProofHandoffReceipt(inputResult) : void 0;
|
|
21966
|
+
const parsedChangeReceipt = handoffReceipt?.change || (isChangeReceiptResult(inputResult) ? parseRiddleProofChangeReceipt(inputResult) : void 0);
|
|
21967
|
+
const result = parsedChangeReceipt ? asRecord2(parsedChangeReceipt) : inputResult;
|
|
20871
21968
|
const proofResult = asRecord2(runResponse.proofResult);
|
|
20872
21969
|
const profileResult = isProfileResult(result);
|
|
21970
|
+
const changeReceiptResult = Boolean(parsedChangeReceipt);
|
|
21971
|
+
const changeResult = changeReceiptResult || isChangeResult(result);
|
|
20873
21972
|
const profileRiddle = asRecord2(result.riddle);
|
|
20874
21973
|
const preview = asRecord2(runResponse.preview);
|
|
20875
21974
|
const resultRunCard = asRecord2(result.run_card);
|
|
@@ -20877,16 +21976,19 @@ function summarizeRiddleProofPrComment(input) {
|
|
|
20877
21976
|
const resultDetails = asRecord2(result.details);
|
|
20878
21977
|
const resultRaw = asRecord2(result.raw);
|
|
20879
21978
|
const rawDetails = asRecord2(resultRaw.details);
|
|
20880
|
-
const profileChecks = profileResult ?
|
|
21979
|
+
const profileChecks = profileResult ? profileCheckCounts3(result) : void 0;
|
|
21980
|
+
const changeChecks = changeResult ? changeReceiptCheckCounts(result) : void 0;
|
|
20881
21981
|
const artifacts = mergeArtifacts(
|
|
20882
21982
|
collectArtifacts(runResponse),
|
|
20883
|
-
profileResult ? collectProfileArtifacts(result) : []
|
|
21983
|
+
profileResult ? collectProfileArtifacts(result) : [],
|
|
21984
|
+
changeReceiptResult ? collectChangeReceiptArtifacts(result) : []
|
|
20884
21985
|
);
|
|
20885
|
-
const pages = profileResult ? profilePageSummaries(result, profileChecks) : pageSummaries(result);
|
|
21986
|
+
const pages = changeReceiptResult ? changeReceiptPageSummaries(result) : profileResult ? profilePageSummaries(result, profileChecks) : pageSummaries(result);
|
|
20886
21987
|
const checkSource = { ...result };
|
|
20887
21988
|
delete checkSource.ok;
|
|
20888
21989
|
const nestedChecks = summarizeExplicitChecks(checkSource);
|
|
20889
|
-
const
|
|
21990
|
+
const resultStatus = firstStringValue2(result.status, stopCondition.status);
|
|
21991
|
+
const ok = changeReceiptResult ? parsedChangeReceipt?.recommendation.merge_recommended ?? false : changeResult ? resultStatus === "passed" : booleanValue3(result.ok) ?? booleanValue3(runResponse.ok) ?? null;
|
|
20890
21992
|
const checkpointSummary = checkpointSummaryFrom2(
|
|
20891
21993
|
result.checkpoint_summary,
|
|
20892
21994
|
stopCondition.checkpoint_summary,
|
|
@@ -20894,19 +21996,19 @@ function summarizeRiddleProofPrComment(input) {
|
|
|
20894
21996
|
rawDetails.checkpoint_summary,
|
|
20895
21997
|
proofResult.checkpoint_summary
|
|
20896
21998
|
);
|
|
20897
|
-
const publicState = summarizeRiddleProofPublicState({
|
|
21999
|
+
const publicState = changeReceiptResult ? void 0 : summarizeRiddleProofPublicState({
|
|
20898
22000
|
...result,
|
|
20899
|
-
status:
|
|
22001
|
+
status: resultStatus,
|
|
20900
22002
|
checkpoint_summary: checkpointSummary || result.checkpoint_summary
|
|
20901
22003
|
});
|
|
20902
|
-
const mergeRecommendation = riddleProofPublicStateMergeRecommendation(
|
|
22004
|
+
const mergeRecommendation = publicState ? riddleProofPublicStateMergeRecommendation(
|
|
20903
22005
|
publicState,
|
|
20904
22006
|
firstStringValue2(result.merge_recommendation, stopCondition.merge_recommendation, resultRaw.merge_recommendation)
|
|
20905
|
-
);
|
|
22007
|
+
) : void 0;
|
|
20906
22008
|
return {
|
|
20907
22009
|
ok,
|
|
20908
22010
|
status: firstStringValue2(proofResult.status, profileRiddle.status),
|
|
20909
|
-
result_status: publicState
|
|
22011
|
+
result_status: changeResult ? resultStatus : publicState?.status,
|
|
20910
22012
|
job_id: firstStringValue2(proofResult.job_id, profileRiddle.job_id),
|
|
20911
22013
|
duration_ms: numberValue5(proofResult.duration_ms) ?? numberValue5(profileRiddle.elapsed_ms),
|
|
20912
22014
|
proof_url: stringValue7(runResponse.proofUrl),
|
|
@@ -20914,17 +22016,17 @@ function summarizeRiddleProofPrComment(input) {
|
|
|
20914
22016
|
preview_url: stringValue7(preview.preview_url) || stringValue7(preview.url),
|
|
20915
22017
|
preview_publish_recovered: booleanValue3(preview.publish_recovered),
|
|
20916
22018
|
preview_publish_error: stringValue7(preview.publish_error),
|
|
20917
|
-
ship_held: publicState
|
|
20918
|
-
shipping_disabled: publicState
|
|
20919
|
-
ship_authorized: publicState
|
|
20920
|
-
merge_ready: publicState
|
|
20921
|
-
sync_allowed: publicState
|
|
22019
|
+
ship_held: publicState?.ship_held,
|
|
22020
|
+
shipping_disabled: publicState?.shipping_disabled,
|
|
22021
|
+
ship_authorized: changeReceiptResult ? parsedChangeReceipt?.shipping_authorization.authorized : publicState?.ship_authorized,
|
|
22022
|
+
merge_ready: publicState?.merge_ready,
|
|
22023
|
+
sync_allowed: publicState?.sync_allowed,
|
|
20922
22024
|
proof_decision: firstStringValue2(result.proof_decision, stopCondition.proof_decision, resultRaw.proof_decision),
|
|
20923
|
-
merge_recommendation: mergeRecommendation,
|
|
22025
|
+
merge_recommendation: changeReceiptResult ? parsedChangeReceipt?.recommendation.label : mergeRecommendation,
|
|
20924
22026
|
checkpoint_summary: checkpointSummary,
|
|
20925
22027
|
public_state: publicState,
|
|
20926
|
-
passed_checks: profileChecks?.passed ?? nestedChecks.passed,
|
|
20927
|
-
failed_checks: profileChecks?.failed ?? nestedChecks.failed,
|
|
22028
|
+
passed_checks: changeChecks?.passed ?? profileChecks?.passed ?? nestedChecks.passed,
|
|
22029
|
+
failed_checks: changeChecks?.failed ?? profileChecks?.failed ?? nestedChecks.failed,
|
|
20928
22030
|
pages,
|
|
20929
22031
|
artifacts,
|
|
20930
22032
|
primary_image: selectPrimaryImage(artifacts)
|
|
@@ -20937,7 +22039,7 @@ function formatDuration(ms) {
|
|
|
20937
22039
|
const remainder = seconds % 60;
|
|
20938
22040
|
return minutes > 0 ? `${minutes}m${String(remainder).padStart(2, "0")}s` : `${seconds}s`;
|
|
20939
22041
|
}
|
|
20940
|
-
function
|
|
22042
|
+
function markdownLink2(label, url) {
|
|
20941
22043
|
return `[${label.replace(/\]/g, "\\]")}](${url})`;
|
|
20942
22044
|
}
|
|
20943
22045
|
function resultLabel(summary) {
|
|
@@ -20988,7 +22090,88 @@ function checkpointSummaryLine(summary) {
|
|
|
20988
22090
|
summary.latest_decision ? `latest decision \`${summary.latest_decision}\`` : ""
|
|
20989
22091
|
].filter(Boolean).join("; ");
|
|
20990
22092
|
}
|
|
22093
|
+
function markdownTableValue(value) {
|
|
22094
|
+
return String(value ?? "").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
22095
|
+
}
|
|
22096
|
+
function observationArtifactTarget(artifact) {
|
|
22097
|
+
return artifact?.url || artifact?.path;
|
|
22098
|
+
}
|
|
22099
|
+
function canonicalScreenshotCell(artifact, fallback) {
|
|
22100
|
+
const target = observationArtifactTarget(artifact);
|
|
22101
|
+
if (!artifact || !target) return fallback;
|
|
22102
|
+
if (artifact.url) return `![${artifact.name.replace(/\]/g, "\\]")}](${artifact.url})`;
|
|
22103
|
+
return markdownTableValue(artifact.path || artifact.name);
|
|
22104
|
+
}
|
|
22105
|
+
function shortRevision(value) {
|
|
22106
|
+
return value ? value.slice(0, 12) : "not recorded";
|
|
22107
|
+
}
|
|
22108
|
+
function buildRiddleProofHandoffPrCommentMarkdown(handoff, input = {}) {
|
|
22109
|
+
const receipt = parseRiddleProofHandoffReceipt(handoff);
|
|
22110
|
+
const change = receipt.change;
|
|
22111
|
+
const beforeStatus = change.before.profile_summary?.status || "not recorded";
|
|
22112
|
+
const afterStatus = change.after.profile_summary?.status || "not recorded";
|
|
22113
|
+
const beforeBaseline = change.groups.before.ok ? "matched baseline" : "baseline mismatch";
|
|
22114
|
+
const lines = [
|
|
22115
|
+
RIDDLE_PROOF_PR_COMMENT_MARKER,
|
|
22116
|
+
`## ${input.title?.trim() || "Riddle Change Proof"}`,
|
|
22117
|
+
"",
|
|
22118
|
+
`**Result:** ${receipt.recommendation.label}`,
|
|
22119
|
+
`**Evidence verdict:** \`${receipt.verdict}\``,
|
|
22120
|
+
`**Shipping authorization:** ${receipt.shipping_authorization.status}`,
|
|
22121
|
+
`**Contract:** ${change.contract_name}`
|
|
22122
|
+
];
|
|
22123
|
+
if (input.goal?.trim()) lines.push(`**Goal:** ${input.goal.trim()}`);
|
|
22124
|
+
if (input.successCriteria?.trim()) lines.push(`**Success criteria:** ${input.successCriteria.trim()}`);
|
|
22125
|
+
lines.push("", change.summary, "", "### Canonical Before / After", "");
|
|
22126
|
+
lines.push("| Before | After |");
|
|
22127
|
+
lines.push("| --- | --- |");
|
|
22128
|
+
lines.push(`| ${beforeBaseline}: \`${markdownTableValue(beforeStatus)}\` | \`${markdownTableValue(afterStatus)}\` |`);
|
|
22129
|
+
lines.push(`| ${canonicalScreenshotCell(receipt.canonical_pair.before, "No canonical before screenshot")} | ${canonicalScreenshotCell(receipt.canonical_pair.after, "No canonical after screenshot")} |`);
|
|
22130
|
+
lines.push("", "### Source Binding", "");
|
|
22131
|
+
lines.push("| Side | Target | Git revision | Binding | Preview | Digest |");
|
|
22132
|
+
lines.push("| --- | --- | --- | --- | --- | --- |");
|
|
22133
|
+
for (const side of ["before", "after"]) {
|
|
22134
|
+
const observation = change[side];
|
|
22135
|
+
const binding = change.source_bindings[side];
|
|
22136
|
+
lines.push(`| ${side} | ${markdownTableValue(observation.target.url)} | \`${shortRevision(binding.observed_git_revision || observation.source.git_revision)}\` | ${binding.status} | ${markdownTableValue(binding.preview_id || observation.target.preview?.preview_id || "not required")} | \`${markdownTableValue(binding.content_digest || observation.target.preview?.content_digest || "not required")}\` |`);
|
|
22137
|
+
}
|
|
22138
|
+
lines.push("", "### Declared Delta", "");
|
|
22139
|
+
lines.push("| Measurement | Status | Before | After |");
|
|
22140
|
+
lines.push("| --- | --- | --- | --- |");
|
|
22141
|
+
for (const delta of change.deltas) {
|
|
22142
|
+
lines.push(`| ${markdownTableValue(delta.label)} | ${delta.status} | ${markdownTableValue(delta.before_observed)} | ${markdownTableValue(delta.after_observed)} |`);
|
|
22143
|
+
}
|
|
22144
|
+
if (change.proves.length) {
|
|
22145
|
+
lines.push("", "### What This Proves", "");
|
|
22146
|
+
for (const claim of change.proves) lines.push(`- ${claim}`);
|
|
22147
|
+
}
|
|
22148
|
+
if (change.does_not_prove.length) {
|
|
22149
|
+
lines.push("", "### Limits", "");
|
|
22150
|
+
for (const claim of change.does_not_prove) lines.push(`- ${claim}`);
|
|
22151
|
+
}
|
|
22152
|
+
const linkedArtifacts = [
|
|
22153
|
+
...change.before.artifacts.map((artifact) => ({ side: "before", artifact })),
|
|
22154
|
+
...change.after.artifacts.map((artifact) => ({ side: "after", artifact }))
|
|
22155
|
+
].filter(({ artifact }) => Boolean(artifact.url));
|
|
22156
|
+
if (linkedArtifacts.length) {
|
|
22157
|
+
lines.push("", "### Artifacts", "");
|
|
22158
|
+
for (const { side, artifact } of linkedArtifacts.slice(0, 24)) {
|
|
22159
|
+
lines.push(`- ${side}: ${markdownLink2(artifact.name, artifact.url || "")}`);
|
|
22160
|
+
}
|
|
22161
|
+
}
|
|
22162
|
+
lines.push("", input.source?.trim() ? `_Source: ${input.source.trim()}_` : "_Rendered from the Handoff receipt without recomputing its verdict._");
|
|
22163
|
+
return `${lines.join("\n").trim()}
|
|
22164
|
+
`;
|
|
22165
|
+
}
|
|
20991
22166
|
function buildRiddleProofPrCommentMarkdown(input) {
|
|
22167
|
+
const result = asRecord2(input.result);
|
|
22168
|
+
if (isHandoffReceiptResult(result)) {
|
|
22169
|
+
return buildRiddleProofHandoffPrCommentMarkdown(parseRiddleProofHandoffReceipt(result), input);
|
|
22170
|
+
}
|
|
22171
|
+
if (isChangeReceiptResult(result)) {
|
|
22172
|
+
const handoff = createRiddleProofHandoffReceipt(parseRiddleProofChangeReceipt(result));
|
|
22173
|
+
return buildRiddleProofHandoffPrCommentMarkdown(handoff, input);
|
|
22174
|
+
}
|
|
20992
22175
|
const summary = summarizeRiddleProofPrComment(input);
|
|
20993
22176
|
const title = input.title?.trim() || "Riddle Proof Evidence";
|
|
20994
22177
|
const lines = [
|
|
@@ -21012,10 +22195,10 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21012
22195
|
if (summary.proof_decision) lines.push(`**Proof decision:** \`${summary.proof_decision}\``);
|
|
21013
22196
|
if (shouldRenderMergeRecommendation(summary)) lines.push(`**Merge recommendation:** ${summary.merge_recommendation}`);
|
|
21014
22197
|
if (summary.checkpoint_summary) lines.push(`**Checkpoints:** ${checkpointSummaryLine(summary.checkpoint_summary)}`);
|
|
21015
|
-
if (summary.proof_url) lines.push(`**Proof URL:** ${
|
|
22198
|
+
if (summary.proof_url) lines.push(`**Proof URL:** ${markdownLink2(summary.proof_url, summary.proof_url)}`);
|
|
21016
22199
|
if (summary.preview_id || summary.preview_url) {
|
|
21017
22200
|
const previewLabel = summary.preview_id ? `\`${summary.preview_id}\`` : "preview";
|
|
21018
|
-
lines.push(`**Preview:** ${summary.preview_url ?
|
|
22201
|
+
lines.push(`**Preview:** ${summary.preview_url ? markdownLink2(previewLabel, summary.preview_url) : previewLabel}`);
|
|
21019
22202
|
}
|
|
21020
22203
|
if (summary.preview_publish_recovered) {
|
|
21021
22204
|
const detail = summary.preview_publish_error ? `: ${summary.preview_publish_error}` : "";
|
|
@@ -21040,7 +22223,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21040
22223
|
if (linkedArtifacts.length) {
|
|
21041
22224
|
lines.push("### Artifacts");
|
|
21042
22225
|
for (const artifact of linkedArtifacts) {
|
|
21043
|
-
lines.push(`- ${
|
|
22226
|
+
lines.push(`- ${markdownLink2(artifact.name, artifact.url)}`);
|
|
21044
22227
|
}
|
|
21045
22228
|
if (summary.artifacts.length - (summary.primary_image ? 1 : 0) > linkedArtifacts.length) {
|
|
21046
22229
|
lines.push(`- ${summary.artifacts.length - (summary.primary_image ? 1 : 0) - linkedArtifacts.length} more artifact(s) omitted`);
|
|
@@ -21064,15 +22247,20 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21064
22247
|
DEFAULT_DIAGNOSTIC_STRING_LIMIT,
|
|
21065
22248
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
21066
22249
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
|
22250
|
+
RIDDLE_PREVIEW_RECEIPT_VERSION,
|
|
21067
22251
|
RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
|
|
21068
22252
|
RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
|
|
21069
22253
|
RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
|
|
21070
22254
|
RIDDLE_PROOF_CAPTURE_DIAGNOSTIC_VERSION,
|
|
21071
22255
|
RIDDLE_PROOF_CHANGE_CONTRACT_VERSION,
|
|
22256
|
+
RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION,
|
|
22257
|
+
RIDDLE_PROOF_CHANGE_RECEIPT_VERSION,
|
|
21072
22258
|
RIDDLE_PROOF_CHANGE_RESULT_VERSION,
|
|
21073
22259
|
RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
|
|
21074
22260
|
RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
|
|
22261
|
+
RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION,
|
|
21075
22262
|
RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
|
|
22263
|
+
RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
|
|
21076
22264
|
RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION,
|
|
21077
22265
|
RIDDLE_PROOF_PLAYABILITY_VERSION,
|
|
21078
22266
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
@@ -21111,6 +22299,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21111
22299
|
buildAuthorCheckpointPacket,
|
|
21112
22300
|
buildCheckpointPacketForEngineResult,
|
|
21113
22301
|
buildProofAssessmentCheckpointPacket,
|
|
22302
|
+
buildRiddleProofHandoffPrCommentMarkdown,
|
|
21114
22303
|
buildRiddleProofPrCommentMarkdown,
|
|
21115
22304
|
buildRiddleProofProfileScript,
|
|
21116
22305
|
buildStageCheckpointPacket,
|
|
@@ -21134,6 +22323,9 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21134
22323
|
createLocalAgentAdapter,
|
|
21135
22324
|
createLocalAgentJsonRunner,
|
|
21136
22325
|
createRiddleApiClient,
|
|
22326
|
+
createRiddleProofChangeReceipt,
|
|
22327
|
+
createRiddleProofHandoffReceipt,
|
|
22328
|
+
createRiddleProofObservationReceipt,
|
|
21137
22329
|
createRiddleProofProfileConfigurationError,
|
|
21138
22330
|
createRiddleProofProfileEnvironmentBlockedResult,
|
|
21139
22331
|
createRiddleProofProfileInsufficientResult,
|
|
@@ -21144,6 +22336,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21144
22336
|
deployRiddlePreview,
|
|
21145
22337
|
deployRiddleStaticPreview,
|
|
21146
22338
|
deriveRiddleProofArtifactBodyAssertions,
|
|
22339
|
+
detectRiddlePreviewSource,
|
|
21147
22340
|
extractBasicGameplayEvidence,
|
|
21148
22341
|
extractPlayabilityEvidence,
|
|
21149
22342
|
extractRiddleProofProfileResult,
|
|
@@ -21154,6 +22347,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21154
22347
|
isSuccessfulStatus,
|
|
21155
22348
|
isTerminalRiddleJobStatus,
|
|
21156
22349
|
isTerminalStatus,
|
|
22350
|
+
migrateRiddleProofChangeReceipt,
|
|
21157
22351
|
nonEmptyString,
|
|
21158
22352
|
normalizeCheckpointResponse,
|
|
21159
22353
|
normalizeIntegrationContext,
|
|
@@ -21161,6 +22355,10 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21161
22355
|
normalizeRiddleProofProfile,
|
|
21162
22356
|
normalizeRunParams,
|
|
21163
22357
|
normalizeTerminalMetadata,
|
|
22358
|
+
parseRiddlePreviewReceipt,
|
|
22359
|
+
parseRiddleProofChangeReceipt,
|
|
22360
|
+
parseRiddleProofHandoffReceipt,
|
|
22361
|
+
parseRiddleProofObservationReceipt,
|
|
21164
22362
|
parseRiddleViewport,
|
|
21165
22363
|
parseVisualProofSession,
|
|
21166
22364
|
pollRiddleJob,
|
|
@@ -21179,6 +22377,8 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21179
22377
|
resolveRiddleProofProfileRouteUrl,
|
|
21180
22378
|
resolveRiddleProofProfileTargetUrl,
|
|
21181
22379
|
resolveRiddleProofProfileTimeoutSec,
|
|
22380
|
+
riddleProofChangeReceiptHtml,
|
|
22381
|
+
riddleProofChangeReceiptMarkdown,
|
|
21182
22382
|
riddleProofPublicStateAllowsClaim,
|
|
21183
22383
|
riddleProofPublicStateAllowsMergeRecommendation,
|
|
21184
22384
|
riddleProofPublicStateMergeRecommendation,
|