@riddledc/riddle-proof 0.8.77 → 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 +65 -3
- 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 +744 -85
- package/dist/change-proof.d.cts +100 -8
- package/dist/change-proof.d.ts +100 -8
- package/dist/change-proof.js +15 -1
- package/dist/{chunk-B2DP2LET.js → chunk-5IFZSUPF.js} +52 -13
- package/dist/chunk-6VFS2JFR.js +886 -0
- package/dist/{chunk-IY4W6STC.js → chunk-7N6X54WG.js} +116 -17
- package/dist/{chunk-GG2D3MFZ.js → chunk-FCSJZBC5.js} +26 -1
- package/dist/{chunk-H25IDX76.js → chunk-HSGZV2NK.js} +206 -35
- 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 +2009 -1058
- package/dist/cli.js +7 -6
- package/dist/index.cjs +932 -122
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +42 -14
- package/dist/pr-comment.cjs +416 -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-BILL3UC2.js +0 -488
package/dist/index.cjs
CHANGED
|
@@ -3414,16 +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,
|
|
3422
3424
|
RIDDLE_PROOF_CHANGE_RECEIPT_VERSION: () => RIDDLE_PROOF_CHANGE_RECEIPT_VERSION,
|
|
3423
3425
|
RIDDLE_PROOF_CHANGE_RESULT_VERSION: () => RIDDLE_PROOF_CHANGE_RESULT_VERSION,
|
|
3424
3426
|
RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION: () => RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
|
|
3425
3427
|
RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION: () => RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
|
|
3428
|
+
RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION: () => RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION,
|
|
3426
3429
|
RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS: () => RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
|
|
3430
|
+
RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION: () => RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
|
|
3427
3431
|
RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION: () => RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION,
|
|
3428
3432
|
RIDDLE_PROOF_PLAYABILITY_VERSION: () => RIDDLE_PROOF_PLAYABILITY_VERSION,
|
|
3429
3433
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
@@ -3462,6 +3466,7 @@ __export(index_exports, {
|
|
|
3462
3466
|
buildAuthorCheckpointPacket: () => buildAuthorCheckpointPacket,
|
|
3463
3467
|
buildCheckpointPacketForEngineResult: () => buildCheckpointPacketForEngineResult,
|
|
3464
3468
|
buildProofAssessmentCheckpointPacket: () => buildProofAssessmentCheckpointPacket,
|
|
3469
|
+
buildRiddleProofHandoffPrCommentMarkdown: () => buildRiddleProofHandoffPrCommentMarkdown,
|
|
3465
3470
|
buildRiddleProofPrCommentMarkdown: () => buildRiddleProofPrCommentMarkdown,
|
|
3466
3471
|
buildRiddleProofProfileScript: () => buildRiddleProofProfileScript,
|
|
3467
3472
|
buildStageCheckpointPacket: () => buildStageCheckpointPacket,
|
|
@@ -3486,6 +3491,8 @@ __export(index_exports, {
|
|
|
3486
3491
|
createLocalAgentJsonRunner: () => createCodexExecJsonRunner,
|
|
3487
3492
|
createRiddleApiClient: () => createRiddleApiClient,
|
|
3488
3493
|
createRiddleProofChangeReceipt: () => createRiddleProofChangeReceipt,
|
|
3494
|
+
createRiddleProofHandoffReceipt: () => createRiddleProofHandoffReceipt,
|
|
3495
|
+
createRiddleProofObservationReceipt: () => createRiddleProofObservationReceipt,
|
|
3489
3496
|
createRiddleProofProfileConfigurationError: () => createRiddleProofProfileConfigurationError,
|
|
3490
3497
|
createRiddleProofProfileEnvironmentBlockedResult: () => createRiddleProofProfileEnvironmentBlockedResult,
|
|
3491
3498
|
createRiddleProofProfileInsufficientResult: () => createRiddleProofProfileInsufficientResult,
|
|
@@ -3496,6 +3503,7 @@ __export(index_exports, {
|
|
|
3496
3503
|
deployRiddlePreview: () => deployRiddlePreview,
|
|
3497
3504
|
deployRiddleStaticPreview: () => deployRiddleStaticPreview,
|
|
3498
3505
|
deriveRiddleProofArtifactBodyAssertions: () => deriveRiddleProofArtifactBodyAssertions,
|
|
3506
|
+
detectRiddlePreviewSource: () => detectRiddlePreviewSource,
|
|
3499
3507
|
extractBasicGameplayEvidence: () => extractBasicGameplayEvidence,
|
|
3500
3508
|
extractPlayabilityEvidence: () => extractPlayabilityEvidence,
|
|
3501
3509
|
extractRiddleProofProfileResult: () => extractRiddleProofProfileResult,
|
|
@@ -3506,6 +3514,7 @@ __export(index_exports, {
|
|
|
3506
3514
|
isSuccessfulStatus: () => isSuccessfulStatus,
|
|
3507
3515
|
isTerminalRiddleJobStatus: () => isTerminalRiddleJobStatus,
|
|
3508
3516
|
isTerminalStatus: () => isTerminalStatus,
|
|
3517
|
+
migrateRiddleProofChangeReceipt: () => migrateRiddleProofChangeReceipt,
|
|
3509
3518
|
nonEmptyString: () => nonEmptyString,
|
|
3510
3519
|
normalizeCheckpointResponse: () => normalizeCheckpointResponse,
|
|
3511
3520
|
normalizeIntegrationContext: () => normalizeIntegrationContext,
|
|
@@ -3513,6 +3522,10 @@ __export(index_exports, {
|
|
|
3513
3522
|
normalizeRiddleProofProfile: () => normalizeRiddleProofProfile,
|
|
3514
3523
|
normalizeRunParams: () => normalizeRunParams,
|
|
3515
3524
|
normalizeTerminalMetadata: () => normalizeTerminalMetadata,
|
|
3525
|
+
parseRiddlePreviewReceipt: () => parseRiddlePreviewReceipt,
|
|
3526
|
+
parseRiddleProofChangeReceipt: () => parseRiddleProofChangeReceipt,
|
|
3527
|
+
parseRiddleProofHandoffReceipt: () => parseRiddleProofHandoffReceipt,
|
|
3528
|
+
parseRiddleProofObservationReceipt: () => parseRiddleProofObservationReceipt,
|
|
3516
3529
|
parseRiddleViewport: () => parseRiddleViewport,
|
|
3517
3530
|
parseVisualProofSession: () => parseVisualProofSession,
|
|
3518
3531
|
pollRiddleJob: () => pollRiddleJob,
|
|
@@ -10947,6 +10960,12 @@ function profileScreenshotLabels(viewports) {
|
|
|
10947
10960
|
}
|
|
10948
10961
|
return labels;
|
|
10949
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
|
+
}
|
|
10950
10969
|
function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport, finalScreenshotFullPage) {
|
|
10951
10970
|
const normalizedFinalScreenshotFullPage = finalScreenshotFullPage === void 0 ? void 0 : finalScreenshotFullPage !== false;
|
|
10952
10971
|
const finalScreenshotCount = viewports.filter((viewport) => typeof viewport.screenshot_label === "string" && viewport.screenshot_label.trim()).length;
|
|
@@ -13797,6 +13816,8 @@ function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
|
|
|
13797
13816
|
const status = profileStatusFromEvidence(profile, evidence, checks);
|
|
13798
13817
|
const firstViewport = evidence?.viewports?.[0];
|
|
13799
13818
|
const screenshots = profileScreenshotLabels(evidence?.viewports);
|
|
13819
|
+
const canonicalScreenshots = profileFinalScreenshotLabels(evidence?.viewports);
|
|
13820
|
+
const setupScreenshots = profileAllSetupScreenshotLabels(evidence?.viewports);
|
|
13800
13821
|
const result = {
|
|
13801
13822
|
version: RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
13802
13823
|
profile_name: profile.name,
|
|
@@ -13806,6 +13827,8 @@ function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
|
|
|
13806
13827
|
route: routeForViewport(firstViewport, evidence?.target_url),
|
|
13807
13828
|
artifacts: {
|
|
13808
13829
|
screenshots,
|
|
13830
|
+
canonical_screenshots: canonicalScreenshots,
|
|
13831
|
+
setup_screenshots: setupScreenshots,
|
|
13809
13832
|
console: "console.json",
|
|
13810
13833
|
proof_json: "proof.json",
|
|
13811
13834
|
dom_summary: "dom-summary.json",
|
|
@@ -15124,6 +15147,12 @@ function profileScreenshotLabels(viewports) {
|
|
|
15124
15147
|
}
|
|
15125
15148
|
return labels;
|
|
15126
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
|
+
}
|
|
15127
15156
|
function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport, finalScreenshotFullPage) {
|
|
15128
15157
|
const normalizedFinalScreenshotFullPage = finalScreenshotFullPage === undefined
|
|
15129
15158
|
? undefined
|
|
@@ -15992,6 +16021,8 @@ function assessProfile(profile, evidence) {
|
|
|
15992
16021
|
else if (checks.some((check) => check.status === "needs_human_review")) status = "needs_human_review";
|
|
15993
16022
|
else if (checks.some((check) => check.status === "failed")) status = "product_regression";
|
|
15994
16023
|
const screenshotLabels = profileScreenshotLabels(viewports);
|
|
16024
|
+
const canonicalScreenshotLabels = profileFinalScreenshotLabels(viewports);
|
|
16025
|
+
const setupScreenshotLabels = profileAllSetupScreenshotLabels(viewports);
|
|
15995
16026
|
const route = viewports[0] && viewports[0].route ? viewports[0].route : { requested: evidence.target_url, observed: "", matched: false, error: "missing viewport evidence" };
|
|
15996
16027
|
const passedChecks = checks.filter((check) => check.status === "passed").length;
|
|
15997
16028
|
const failedChecks = checks.filter((check) => check.status === "failed").length;
|
|
@@ -16008,7 +16039,14 @@ function assessProfile(profile, evidence) {
|
|
|
16008
16039
|
status,
|
|
16009
16040
|
baseline_policy: profile.baseline_policy || "invariant_only",
|
|
16010
16041
|
route,
|
|
16011
|
-
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
|
+
},
|
|
16012
16050
|
checks,
|
|
16013
16051
|
summary,
|
|
16014
16052
|
captured_at: evidence.captured_at,
|
|
@@ -19936,10 +19974,263 @@ function suggestRiddleProofProfileChecks(input) {
|
|
|
19936
19974
|
};
|
|
19937
19975
|
}
|
|
19938
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
|
+
|
|
19939
20228
|
// src/change-proof.ts
|
|
19940
20229
|
var RIDDLE_PROOF_CHANGE_CONTRACT_VERSION = "riddle-proof.change-contract.v1";
|
|
19941
20230
|
var RIDDLE_PROOF_CHANGE_RESULT_VERSION = "riddle-proof.change-result.v1";
|
|
19942
|
-
var
|
|
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";
|
|
19943
20234
|
var DEFAULT_BEFORE_STATUSES = ["passed", "product_regression"];
|
|
19944
20235
|
var DEFAULT_AFTER_STATUSES = ["passed"];
|
|
19945
20236
|
var DEFAULT_PROFILE_STATUS_TRANSITION_BEFORE = ["product_regression"];
|
|
@@ -20061,13 +20352,163 @@ function assessDelta(delta, before, after) {
|
|
|
20061
20352
|
}
|
|
20062
20353
|
return checkStatusTransitionResult(delta, before, after);
|
|
20063
20354
|
}
|
|
20064
|
-
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) {
|
|
20065
20505
|
const groupResults = [groups.before, groups.after];
|
|
20066
20506
|
if (groupResults.some((group) => group.status === "environment_blocked")) return "environment_blocked";
|
|
20067
20507
|
if (groupResults.some((group) => group.status === "configuration_error")) return "configuration_error";
|
|
20068
20508
|
if (deltas.some((delta) => delta.status === "configuration_error")) return "configuration_error";
|
|
20069
20509
|
if (groupResults.some((group) => group.status === "needs_human_review")) return "needs_human_review";
|
|
20070
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";
|
|
20071
20512
|
if (!deltas.length || deltas.some((delta) => delta.status === "proof_insufficient")) return "proof_insufficient";
|
|
20072
20513
|
if (groupResults.some((group) => !group.ok)) return "product_regression";
|
|
20073
20514
|
if (deltas.some((delta) => delta.status === "failed")) return "product_regression";
|
|
@@ -20082,18 +20523,38 @@ function changeSummary(name, status, deltas) {
|
|
|
20082
20523
|
return `${name} failed ${deltas.filter((delta) => delta.status === "failed").length} change delta(s).`;
|
|
20083
20524
|
}
|
|
20084
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);
|
|
20085
20528
|
const groups = {
|
|
20086
|
-
before: groupResult("before", contract.before,
|
|
20087
|
-
after: groupResult("after", contract.after,
|
|
20529
|
+
before: groupResult("before", contract.before, beforeResult),
|
|
20530
|
+
after: groupResult("after", contract.after, afterResult)
|
|
20088
20531
|
};
|
|
20089
|
-
const deltas = (contract.deltas || []).map((delta) => assessDelta(delta,
|
|
20090
|
-
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);
|
|
20091
20551
|
return {
|
|
20092
20552
|
version: RIDDLE_PROOF_CHANGE_RESULT_VERSION,
|
|
20093
20553
|
contract_name: contract.name,
|
|
20094
20554
|
status,
|
|
20095
20555
|
groups,
|
|
20096
20556
|
deltas,
|
|
20557
|
+
source_bindings: sourceBindings,
|
|
20097
20558
|
summary: changeSummary(contract.name, status, deltas),
|
|
20098
20559
|
metadata: contract.metadata
|
|
20099
20560
|
};
|
|
@@ -20106,7 +20567,7 @@ function changeReceiptVerdict(status) {
|
|
|
20106
20567
|
if (status === "proof_insufficient") return "proof_insufficient";
|
|
20107
20568
|
return "not_mergeable";
|
|
20108
20569
|
}
|
|
20109
|
-
function
|
|
20570
|
+
function profileCheckCounts2(result) {
|
|
20110
20571
|
const counts = {
|
|
20111
20572
|
total: result.checks.length,
|
|
20112
20573
|
passed: 0,
|
|
@@ -20122,86 +20583,90 @@ function profileCheckCounts(result) {
|
|
|
20122
20583
|
}
|
|
20123
20584
|
return counts;
|
|
20124
20585
|
}
|
|
20125
|
-
function
|
|
20126
|
-
|
|
20127
|
-
|
|
20128
|
-
if (/\bjson\b|\btext\b|\bmarkdown\b|\bhtml\b|\blog\b/.test(text) || /\.(json|md|txt|html|log|har)(\?|#|$)/.test(text)) return "data";
|
|
20129
|
-
return "artifact";
|
|
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(" "));
|
|
20130
20589
|
}
|
|
20131
|
-
function
|
|
20132
|
-
|
|
20133
|
-
|
|
20134
|
-
|
|
20135
|
-
kind: artifactKind(ref),
|
|
20136
|
-
url: ref.url,
|
|
20137
|
-
path: ref.path,
|
|
20138
|
-
source: ref.source
|
|
20139
|
-
};
|
|
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());
|
|
20140
20594
|
}
|
|
20141
|
-
function
|
|
20142
|
-
|
|
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 };
|
|
20143
20606
|
}
|
|
20144
|
-
function
|
|
20145
|
-
|
|
20146
|
-
if (!screenshotName) return false;
|
|
20147
|
-
return [artifact.name, artifact.url, artifact.path].map(comparableArtifactName).some((name) => name === screenshotName || name.endsWith(`-${screenshotName}`));
|
|
20607
|
+
function noShippingAuthorization() {
|
|
20608
|
+
return { status: "not_granted", authorized: false, source: "none" };
|
|
20148
20609
|
}
|
|
20149
|
-
function
|
|
20150
|
-
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
20154
|
-
|
|
20155
|
-
|
|
20156
|
-
artifacts.push(artifact);
|
|
20157
|
-
};
|
|
20158
|
-
for (const ref of result.artifacts.riddle_artifacts || []) {
|
|
20159
|
-
add(receiptArtifactFromRef(side, ref));
|
|
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.`);
|
|
20160
20617
|
}
|
|
20161
|
-
|
|
20162
|
-
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
20166
|
-
|
|
20167
|
-
|
|
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.`);
|
|
20168
20627
|
}
|
|
20169
|
-
return artifacts;
|
|
20170
20628
|
}
|
|
20171
|
-
function
|
|
20172
|
-
if (
|
|
20173
|
-
return
|
|
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;
|
|
20174
20632
|
}
|
|
20175
|
-
function
|
|
20176
|
-
|
|
20177
|
-
|
|
20178
|
-
|
|
20179
|
-
|
|
20180
|
-
profile_name: result.profile_name,
|
|
20181
|
-
status: result.status,
|
|
20182
|
-
summary: result.summary,
|
|
20183
|
-
route: result.route,
|
|
20184
|
-
captured_at: result.captured_at,
|
|
20185
|
-
checks: profileCheckCounts(result),
|
|
20186
|
-
screenshots: artifacts.filter(artifactIsScreenshot),
|
|
20187
|
-
artifacts
|
|
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
|
|
20188
20638
|
};
|
|
20189
20639
|
}
|
|
20190
|
-
function
|
|
20191
|
-
|
|
20192
|
-
if (!
|
|
20193
|
-
return
|
|
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
|
+
});
|
|
20194
20652
|
}
|
|
20195
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");
|
|
20196
20659
|
return {
|
|
20197
20660
|
version: RIDDLE_PROOF_CHANGE_RECEIPT_VERSION,
|
|
20198
20661
|
contract_name: input.result.contract_name,
|
|
20199
20662
|
profile_name: input.profile_name,
|
|
20200
20663
|
status: input.result.status,
|
|
20201
|
-
verdict
|
|
20664
|
+
verdict,
|
|
20202
20665
|
summary: input.result.summary,
|
|
20203
|
-
before
|
|
20204
|
-
after
|
|
20666
|
+
before,
|
|
20667
|
+
after,
|
|
20668
|
+
groups: input.result.groups,
|
|
20669
|
+
source_bindings: input.result.source_bindings,
|
|
20205
20670
|
deltas: input.result.deltas.map((delta) => ({
|
|
20206
20671
|
type: delta.type,
|
|
20207
20672
|
label: delta.label,
|
|
@@ -20210,17 +20675,201 @@ function createRiddleProofChangeReceipt(input) {
|
|
|
20210
20675
|
after_observed: delta.after_observed,
|
|
20211
20676
|
message: delta.message
|
|
20212
20677
|
})),
|
|
20678
|
+
recommendation: changeRecommendation(verdict),
|
|
20679
|
+
shipping_authorization: shippingAuthorization,
|
|
20213
20680
|
proves: metadataStringList(input.contract.metadata, "required_receipts"),
|
|
20214
20681
|
does_not_prove: metadataStringList(input.contract.metadata, "does_not_prove"),
|
|
20215
20682
|
metadata: input.result.metadata
|
|
20216
20683
|
};
|
|
20217
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
|
+
}
|
|
20218
20823
|
function markdownTableCell(value) {
|
|
20219
20824
|
return String(value ?? "").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
20220
20825
|
}
|
|
20221
20826
|
function artifactTarget(artifact) {
|
|
20222
20827
|
return artifact.url || artifact.path;
|
|
20223
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
|
+
}
|
|
20224
20873
|
function markdownLink(label, target) {
|
|
20225
20874
|
return `[${label.replace(/\]/g, "\\]")}](${target})`;
|
|
20226
20875
|
}
|
|
@@ -20244,6 +20893,8 @@ function appendMarkdownArtifacts(lines, title, artifacts) {
|
|
|
20244
20893
|
lines.push("");
|
|
20245
20894
|
}
|
|
20246
20895
|
function riddleProofChangeReceiptMarkdown(receipt) {
|
|
20896
|
+
const before = receiptSideView("before", receipt.before);
|
|
20897
|
+
const after = receiptSideView("after", receipt.after);
|
|
20247
20898
|
const lines = [
|
|
20248
20899
|
"# Riddle Proof Change Receipt",
|
|
20249
20900
|
"",
|
|
@@ -20251,6 +20902,8 @@ function riddleProofChangeReceiptMarkdown(receipt) {
|
|
|
20251
20902
|
`**Status:** ${receipt.status}`,
|
|
20252
20903
|
`**Contract:** ${receipt.contract_name}`,
|
|
20253
20904
|
receipt.profile_name ? `**Profile:** ${receipt.profile_name}` : "",
|
|
20905
|
+
`**Recommendation:** ${receipt.recommendation.label}`,
|
|
20906
|
+
`**Shipping authorization:** ${receipt.shipping_authorization.status}`,
|
|
20254
20907
|
"",
|
|
20255
20908
|
receipt.summary,
|
|
20256
20909
|
"",
|
|
@@ -20258,8 +20911,15 @@ function riddleProofChangeReceiptMarkdown(receipt) {
|
|
|
20258
20911
|
"",
|
|
20259
20912
|
"| Side | Source | Status | Checks |",
|
|
20260
20913
|
"| --- | --- | --- | --- |",
|
|
20261
|
-
`| Before | ${markdownTableCell(
|
|
20262
|
-
`| After | ${markdownTableCell(
|
|
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")} |`,
|
|
20263
20923
|
"",
|
|
20264
20924
|
"## Delta Checks",
|
|
20265
20925
|
"",
|
|
@@ -20271,8 +20931,8 @@ function riddleProofChangeReceiptMarkdown(receipt) {
|
|
|
20271
20931
|
if (delta.message) lines.push(`| ${markdownTableCell(`${delta.label} message`)} | ${markdownTableCell(delta.message)} | | |`);
|
|
20272
20932
|
}
|
|
20273
20933
|
lines.push("");
|
|
20274
|
-
appendMarkdownArtifacts(lines, "Before Screenshot",
|
|
20275
|
-
appendMarkdownArtifacts(lines, "After Screenshot",
|
|
20934
|
+
appendMarkdownArtifacts(lines, "Before Canonical Screenshot", before.screenshots.slice(0, 1));
|
|
20935
|
+
appendMarkdownArtifacts(lines, "After Canonical Screenshot", after.screenshots.slice(0, 1));
|
|
20276
20936
|
if (receipt.proves.length) {
|
|
20277
20937
|
lines.push("## What This Proves", "");
|
|
20278
20938
|
for (const claim of receipt.proves) lines.push(`- ${claim}`);
|
|
@@ -20283,7 +20943,7 @@ function riddleProofChangeReceiptMarkdown(receipt) {
|
|
|
20283
20943
|
for (const claim of receipt.does_not_prove) lines.push(`- ${claim}`);
|
|
20284
20944
|
lines.push("");
|
|
20285
20945
|
}
|
|
20286
|
-
const linkedArtifacts = [...
|
|
20946
|
+
const linkedArtifacts = [...before.artifacts, ...after.artifacts].filter((artifact) => artifactTarget(artifact)).slice(0, 24);
|
|
20287
20947
|
if (linkedArtifacts.length) {
|
|
20288
20948
|
lines.push("## Artifacts", "");
|
|
20289
20949
|
for (const artifact of linkedArtifacts) {
|
|
@@ -20315,7 +20975,9 @@ function htmlList(items, emptyText) {
|
|
|
20315
20975
|
return `<ul>${items.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>`;
|
|
20316
20976
|
}
|
|
20317
20977
|
function riddleProofChangeReceiptHtml(receipt) {
|
|
20318
|
-
const
|
|
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);
|
|
20319
20981
|
const deltaRows = receipt.deltas.map((delta) => `
|
|
20320
20982
|
<tr>
|
|
20321
20983
|
<td>${escapeHtml(delta.label)}</td>
|
|
@@ -20363,26 +21025,37 @@ function riddleProofChangeReceiptHtml(receipt) {
|
|
|
20363
21025
|
<h1>${escapeHtml(receipt.contract_name)}</h1>
|
|
20364
21026
|
<p>${escapeHtml(receipt.summary)}</p>
|
|
20365
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>
|
|
20366
21029
|
</header>
|
|
20367
21030
|
<section>
|
|
20368
21031
|
<h2>Evidence Pair</h2>
|
|
20369
21032
|
<div class="grid">
|
|
20370
21033
|
<div class="side">
|
|
20371
21034
|
<h3>Before</h3>
|
|
20372
|
-
<p><code>${escapeHtml(
|
|
20373
|
-
<p>Status: <strong class="${escapeHtml(
|
|
20374
|
-
<p>${escapeHtml(
|
|
20375
|
-
<p class="muted">${
|
|
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>
|
|
20376
21039
|
</div>
|
|
20377
21040
|
<div class="side">
|
|
20378
21041
|
<h3>After</h3>
|
|
20379
|
-
<p><code>${escapeHtml(
|
|
20380
|
-
<p>Status: <strong class="${escapeHtml(
|
|
20381
|
-
<p>${escapeHtml(
|
|
20382
|
-
<p class="muted">${
|
|
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>
|
|
20383
21046
|
</div>
|
|
20384
21047
|
</div>
|
|
20385
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>
|
|
20386
21059
|
<section>
|
|
20387
21060
|
<h2>Delta Checks</h2>
|
|
20388
21061
|
<table>
|
|
@@ -20393,8 +21066,8 @@ function riddleProofChangeReceiptHtml(receipt) {
|
|
|
20393
21066
|
<section>
|
|
20394
21067
|
<h2>Screenshots</h2>
|
|
20395
21068
|
<div class="grid">
|
|
20396
|
-
<div>${
|
|
20397
|
-
<div>${
|
|
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>
|
|
20398
21071
|
</div>
|
|
20399
21072
|
</section>
|
|
20400
21073
|
<section>
|
|
@@ -20481,6 +21154,7 @@ async function getRiddleBalance(config = {}) {
|
|
|
20481
21154
|
}
|
|
20482
21155
|
function previewDeployResultFromRecord(input) {
|
|
20483
21156
|
const { record, id, label, framework, expiresAt, publishRecovered, publishError } = input;
|
|
21157
|
+
const receipt = record.receipt && typeof record.receipt === "object" ? parseRiddlePreviewReceipt(record.receipt) : void 0;
|
|
20484
21158
|
return {
|
|
20485
21159
|
ok: true,
|
|
20486
21160
|
id: String(record.id || record.preview_id || id),
|
|
@@ -20489,13 +21163,32 @@ function previewDeployResultFromRecord(input) {
|
|
|
20489
21163
|
preview_url: String(record.preview_url || ""),
|
|
20490
21164
|
file_count: typeof record.file_count === "number" ? record.file_count : void 0,
|
|
20491
21165
|
total_bytes: typeof record.total_bytes === "number" ? record.total_bytes : void 0,
|
|
20492
|
-
expires_at: expiresAt,
|
|
21166
|
+
expires_at: receipt?.expires_at || expiresAt,
|
|
21167
|
+
receipt,
|
|
20493
21168
|
publish_recovered: publishRecovered || void 0,
|
|
20494
21169
|
publish_error: publishError,
|
|
20495
21170
|
warnings: input.warnings?.length ? input.warnings : void 0,
|
|
20496
21171
|
raw: record
|
|
20497
21172
|
};
|
|
20498
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
|
+
}
|
|
20499
21192
|
function canRecoverPreviewPublish(error) {
|
|
20500
21193
|
return error instanceof RiddleApiError && PREVIEW_PUBLISH_RECOVERY_STATUSES.has(error.status);
|
|
20501
21194
|
}
|
|
@@ -20578,12 +21271,13 @@ async function waitForPublishedPreview(config, input) {
|
|
|
20578
21271
|
}
|
|
20579
21272
|
throw input.publishError;
|
|
20580
21273
|
}
|
|
20581
|
-
async function deployRiddlePreview(config, directory, label, framework = "static") {
|
|
21274
|
+
async function deployRiddlePreview(config, directory, label, framework = "static", options = {}) {
|
|
20582
21275
|
if (!directory?.trim()) throw new Error("directory is required");
|
|
20583
21276
|
if (!label?.trim()) throw new Error("label is required");
|
|
20584
21277
|
if (framework !== "spa" && framework !== "static") throw new Error("framework must be spa or static");
|
|
20585
21278
|
const startedAt = Date.now();
|
|
20586
21279
|
const warnings = collectRiddlePreviewDeployWarnings(directory, framework);
|
|
21280
|
+
const source = options.source || detectRiddlePreviewSource(directory);
|
|
20587
21281
|
const emitProgress = previewProgressEmitter(config, { label, framework, directory, startedAt, warnings });
|
|
20588
21282
|
await emitProgress({ stage: "validating", message: "checking preview input directory" });
|
|
20589
21283
|
const localSummary = summarizePreviewDirectory(directory);
|
|
@@ -20595,7 +21289,7 @@ async function deployRiddlePreview(config, directory, label, framework = "static
|
|
|
20595
21289
|
});
|
|
20596
21290
|
const created = await riddleRequestJson(config, "/v1/preview", {
|
|
20597
21291
|
method: "POST",
|
|
20598
|
-
body: JSON.stringify({ framework, label })
|
|
21292
|
+
body: JSON.stringify({ framework, label, source })
|
|
20599
21293
|
});
|
|
20600
21294
|
const id = String(created.id || "");
|
|
20601
21295
|
const uploadUrl = String(created.upload_url || "");
|
|
@@ -20737,8 +21431,8 @@ function collectRiddlePreviewDeployWarnings(directory, framework = "static") {
|
|
|
20737
21431
|
return [];
|
|
20738
21432
|
}
|
|
20739
21433
|
}
|
|
20740
|
-
async function deployRiddleStaticPreview(config, directory, label) {
|
|
20741
|
-
return deployRiddlePreview(config, directory, label, "static");
|
|
21434
|
+
async function deployRiddleStaticPreview(config, directory, label, options = {}) {
|
|
21435
|
+
return deployRiddlePreview(config, directory, label, "static", options);
|
|
20742
21436
|
}
|
|
20743
21437
|
function createTarball(directory, label, exclude = []) {
|
|
20744
21438
|
const scratch = (0, import_node_fs5.mkdtempSync)(import_node_path5.default.join((0, import_node_os2.tmpdir)(), "riddle-upload-"));
|
|
@@ -20860,21 +21554,31 @@ function parseTimestampMs(value) {
|
|
|
20860
21554
|
}
|
|
20861
21555
|
function buildPollSnapshot(jobId, job, input) {
|
|
20862
21556
|
const status = job?.status ? String(job.status) : null;
|
|
21557
|
+
const phase = job?.phase ? String(job.phase) : null;
|
|
20863
21558
|
const terminal = isTerminalRiddleJobStatus(status);
|
|
20864
21559
|
const createdAt = stringField(job, "created_at");
|
|
20865
21560
|
const submittedAt = stringField(job, "submitted_at");
|
|
20866
21561
|
const completedAt = stringField(job, "completed_at");
|
|
20867
21562
|
const createdMs = parseTimestampMs(createdAt);
|
|
20868
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);
|
|
20869
21570
|
let queueElapsedMs = null;
|
|
20870
|
-
if (
|
|
20871
|
-
queueElapsedMs = Math.max(0,
|
|
20872
|
-
} else if (
|
|
20873
|
-
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);
|
|
20874
21577
|
}
|
|
20875
21578
|
return {
|
|
20876
21579
|
job_id: jobId,
|
|
20877
21580
|
status,
|
|
21581
|
+
phase,
|
|
20878
21582
|
terminal,
|
|
20879
21583
|
attempt: input.attempt,
|
|
20880
21584
|
attempts: input.attempts,
|
|
@@ -20884,7 +21588,9 @@ function buildPollSnapshot(jobId, job, input) {
|
|
|
20884
21588
|
completed_at: completedAt,
|
|
20885
21589
|
queue_elapsed_ms: queueElapsedMs,
|
|
20886
21590
|
pre_submission_elapsed_ms: Math.max(0, Math.floor(input.preSubmissionElapsedMs ?? 0)),
|
|
20887
|
-
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
|
|
20888
21594
|
};
|
|
20889
21595
|
}
|
|
20890
21596
|
function pollMessage(snapshot, timedOut) {
|
|
@@ -20893,7 +21599,7 @@ function pollMessage(snapshot, timedOut) {
|
|
|
20893
21599
|
const wakeHint = snapshot.running_without_submission && !snapshot.created_at && !snapshot.submitted_at ? ` ${RIDDLE_UNSUBMITTED_WAKE_HINT}.` : "";
|
|
20894
21600
|
const queue = snapshot.queue_elapsed_ms !== null ? ` queue_elapsed_ms=${snapshot.queue_elapsed_ms}` : "";
|
|
20895
21601
|
const preSubmit = snapshot.pre_submission_elapsed_ms > 0 ? ` pre_submission_elapsed_ms=${snapshot.pre_submission_elapsed_ms}` : "";
|
|
20896
|
-
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}`;
|
|
20897
21603
|
}
|
|
20898
21604
|
async function pollRiddleJob(config, jobId, options = {}) {
|
|
20899
21605
|
if (!jobId?.trim()) throw new Error("jobId is required");
|
|
@@ -20927,6 +21633,7 @@ async function pollRiddleJob(config, jobId, options = {}) {
|
|
|
20927
21633
|
};
|
|
20928
21634
|
const progressKey = [
|
|
20929
21635
|
lastSnapshot.status || "unknown",
|
|
21636
|
+
lastSnapshot.phase || "unknown",
|
|
20930
21637
|
lastSnapshot.terminal ? "terminal" : "nonterminal",
|
|
20931
21638
|
lastSnapshot.submitted_at ? "submitted" : "unsubmitted"
|
|
20932
21639
|
].join(":");
|
|
@@ -20993,8 +21700,8 @@ function createRiddleApiClient(config = {}) {
|
|
|
20993
21700
|
apiKeySource: () => resolveRiddleApiKeySource(config),
|
|
20994
21701
|
requestJson: (pathname, init) => riddleRequestJson(config, pathname, init),
|
|
20995
21702
|
getBalance: () => getRiddleBalance(config),
|
|
20996
|
-
deployPreview: (directory, label, framework = "static") => deployRiddlePreview(config, directory, label, framework),
|
|
20997
|
-
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),
|
|
20998
21705
|
runScript: (input) => runRiddleScript(config, input),
|
|
20999
21706
|
runServerPreview: (input) => runRiddleServerPreview(config, input),
|
|
21000
21707
|
pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
|
|
@@ -21025,7 +21732,7 @@ function firstStringValue2(...values) {
|
|
|
21025
21732
|
}
|
|
21026
21733
|
return void 0;
|
|
21027
21734
|
}
|
|
21028
|
-
function
|
|
21735
|
+
function artifactKind(name, url) {
|
|
21029
21736
|
const target = `${name} ${url}`.toLowerCase();
|
|
21030
21737
|
if (/\.(png|jpe?g|gif|webp|avif|svg)(\?|#|$)/.test(target)) return "image";
|
|
21031
21738
|
if (/\.(json|har|txt|md|html|log)(\?|#|$)/.test(target)) return "data";
|
|
@@ -21050,7 +21757,7 @@ function collectArtifacts(runResponse) {
|
|
|
21050
21757
|
artifacts.push({
|
|
21051
21758
|
name,
|
|
21052
21759
|
url,
|
|
21053
|
-
kind:
|
|
21760
|
+
kind: artifactKind(name, url),
|
|
21054
21761
|
size_bytes: numberValue5(artifact.size)
|
|
21055
21762
|
});
|
|
21056
21763
|
}
|
|
@@ -21070,7 +21777,7 @@ function collectProfileArtifacts(result) {
|
|
|
21070
21777
|
artifacts.push({
|
|
21071
21778
|
name,
|
|
21072
21779
|
url,
|
|
21073
|
-
kind:
|
|
21780
|
+
kind: artifactKind(name, url),
|
|
21074
21781
|
size_bytes: numberValue5(artifact.size_bytes) ?? numberValue5(artifact.size)
|
|
21075
21782
|
});
|
|
21076
21783
|
}
|
|
@@ -21081,9 +21788,10 @@ function collectChangeReceiptArtifacts(result) {
|
|
|
21081
21788
|
const seen = /* @__PURE__ */ new Set();
|
|
21082
21789
|
const collectSide = (sideName, side) => {
|
|
21083
21790
|
const candidates = [
|
|
21791
|
+
side.canonical_screenshot,
|
|
21084
21792
|
...asArray(side.screenshots),
|
|
21085
21793
|
...asArray(side.artifacts)
|
|
21086
|
-
];
|
|
21794
|
+
].filter(Boolean);
|
|
21087
21795
|
for (const [index, item] of candidates.entries()) {
|
|
21088
21796
|
const artifact = asRecord2(item);
|
|
21089
21797
|
const url = stringValue7(artifact.url) || stringValue7(artifact.path);
|
|
@@ -21094,7 +21802,7 @@ function collectChangeReceiptArtifacts(result) {
|
|
|
21094
21802
|
artifacts.push({
|
|
21095
21803
|
name,
|
|
21096
21804
|
url,
|
|
21097
|
-
kind:
|
|
21805
|
+
kind: artifactKind(name, url),
|
|
21098
21806
|
size_bytes: numberValue5(artifact.size_bytes) ?? numberValue5(artifact.size)
|
|
21099
21807
|
});
|
|
21100
21808
|
}
|
|
@@ -21129,7 +21837,7 @@ function pageSummaries(result) {
|
|
|
21129
21837
|
}
|
|
21130
21838
|
return pages;
|
|
21131
21839
|
}
|
|
21132
|
-
function
|
|
21840
|
+
function profileCheckCounts3(result) {
|
|
21133
21841
|
const checks = asArray(result.checks);
|
|
21134
21842
|
if (checks.length) {
|
|
21135
21843
|
let passed2 = 0;
|
|
@@ -21175,9 +21883,10 @@ function changeReceiptPageSummaries(result) {
|
|
|
21175
21883
|
for (const sideName of ["before", "after"]) {
|
|
21176
21884
|
const side = asRecord2(result[sideName]);
|
|
21177
21885
|
if (!Object.keys(side).length) continue;
|
|
21178
|
-
const
|
|
21886
|
+
const profileSummary = asRecord2(side.profile_summary);
|
|
21887
|
+
const checks = Object.keys(asRecord2(side.checks)).length ? asRecord2(side.checks) : asRecord2(profileSummary.checks);
|
|
21179
21888
|
pages.push({
|
|
21180
|
-
route: firstStringValue2(side.source, side.profile_name) || sideName,
|
|
21889
|
+
route: firstStringValue2(asRecord2(side.target).url, side.source, profileSummary.profile_name, side.profile_name) || sideName,
|
|
21181
21890
|
passed: numberValue5(checks.passed) ?? 0,
|
|
21182
21891
|
failed: numberValue5(checks.failed) ?? 0
|
|
21183
21892
|
});
|
|
@@ -21240,7 +21949,11 @@ function isProfileResult(result) {
|
|
|
21240
21949
|
return version === "riddle-proof.profile-result.v1" || version === "riddle-proof.profile-compact-result.v1";
|
|
21241
21950
|
}
|
|
21242
21951
|
function isChangeReceiptResult(result) {
|
|
21243
|
-
|
|
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;
|
|
21244
21957
|
}
|
|
21245
21958
|
function isChangeResult(result) {
|
|
21246
21959
|
const version = stringValue7(result.version);
|
|
@@ -21248,10 +21961,13 @@ function isChangeResult(result) {
|
|
|
21248
21961
|
}
|
|
21249
21962
|
function summarizeRiddleProofPrComment(input) {
|
|
21250
21963
|
const runResponse = asRecord2(input.runResponse);
|
|
21251
|
-
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;
|
|
21252
21968
|
const proofResult = asRecord2(runResponse.proofResult);
|
|
21253
21969
|
const profileResult = isProfileResult(result);
|
|
21254
|
-
const changeReceiptResult =
|
|
21970
|
+
const changeReceiptResult = Boolean(parsedChangeReceipt);
|
|
21255
21971
|
const changeResult = changeReceiptResult || isChangeResult(result);
|
|
21256
21972
|
const profileRiddle = asRecord2(result.riddle);
|
|
21257
21973
|
const preview = asRecord2(runResponse.preview);
|
|
@@ -21260,7 +21976,7 @@ function summarizeRiddleProofPrComment(input) {
|
|
|
21260
21976
|
const resultDetails = asRecord2(result.details);
|
|
21261
21977
|
const resultRaw = asRecord2(result.raw);
|
|
21262
21978
|
const rawDetails = asRecord2(resultRaw.details);
|
|
21263
|
-
const profileChecks = profileResult ?
|
|
21979
|
+
const profileChecks = profileResult ? profileCheckCounts3(result) : void 0;
|
|
21264
21980
|
const changeChecks = changeResult ? changeReceiptCheckCounts(result) : void 0;
|
|
21265
21981
|
const artifacts = mergeArtifacts(
|
|
21266
21982
|
collectArtifacts(runResponse),
|
|
@@ -21272,7 +21988,7 @@ function summarizeRiddleProofPrComment(input) {
|
|
|
21272
21988
|
delete checkSource.ok;
|
|
21273
21989
|
const nestedChecks = summarizeExplicitChecks(checkSource);
|
|
21274
21990
|
const resultStatus = firstStringValue2(result.status, stopCondition.status);
|
|
21275
|
-
const ok = changeResult ? resultStatus === "passed" : booleanValue3(result.ok) ?? booleanValue3(runResponse.ok) ?? null;
|
|
21991
|
+
const ok = changeReceiptResult ? parsedChangeReceipt?.recommendation.merge_recommended ?? false : changeResult ? resultStatus === "passed" : booleanValue3(result.ok) ?? booleanValue3(runResponse.ok) ?? null;
|
|
21276
21992
|
const checkpointSummary = checkpointSummaryFrom2(
|
|
21277
21993
|
result.checkpoint_summary,
|
|
21278
21994
|
stopCondition.checkpoint_summary,
|
|
@@ -21280,19 +21996,19 @@ function summarizeRiddleProofPrComment(input) {
|
|
|
21280
21996
|
rawDetails.checkpoint_summary,
|
|
21281
21997
|
proofResult.checkpoint_summary
|
|
21282
21998
|
);
|
|
21283
|
-
const publicState = summarizeRiddleProofPublicState({
|
|
21999
|
+
const publicState = changeReceiptResult ? void 0 : summarizeRiddleProofPublicState({
|
|
21284
22000
|
...result,
|
|
21285
22001
|
status: resultStatus,
|
|
21286
22002
|
checkpoint_summary: checkpointSummary || result.checkpoint_summary
|
|
21287
22003
|
});
|
|
21288
|
-
const mergeRecommendation = riddleProofPublicStateMergeRecommendation(
|
|
22004
|
+
const mergeRecommendation = publicState ? riddleProofPublicStateMergeRecommendation(
|
|
21289
22005
|
publicState,
|
|
21290
22006
|
firstStringValue2(result.merge_recommendation, stopCondition.merge_recommendation, resultRaw.merge_recommendation)
|
|
21291
|
-
);
|
|
22007
|
+
) : void 0;
|
|
21292
22008
|
return {
|
|
21293
22009
|
ok,
|
|
21294
22010
|
status: firstStringValue2(proofResult.status, profileRiddle.status),
|
|
21295
|
-
result_status: changeResult ? resultStatus : publicState
|
|
22011
|
+
result_status: changeResult ? resultStatus : publicState?.status,
|
|
21296
22012
|
job_id: firstStringValue2(proofResult.job_id, profileRiddle.job_id),
|
|
21297
22013
|
duration_ms: numberValue5(proofResult.duration_ms) ?? numberValue5(profileRiddle.elapsed_ms),
|
|
21298
22014
|
proof_url: stringValue7(runResponse.proofUrl),
|
|
@@ -21300,13 +22016,13 @@ function summarizeRiddleProofPrComment(input) {
|
|
|
21300
22016
|
preview_url: stringValue7(preview.preview_url) || stringValue7(preview.url),
|
|
21301
22017
|
preview_publish_recovered: booleanValue3(preview.publish_recovered),
|
|
21302
22018
|
preview_publish_error: stringValue7(preview.publish_error),
|
|
21303
|
-
ship_held: publicState
|
|
21304
|
-
shipping_disabled: publicState
|
|
21305
|
-
ship_authorized: publicState
|
|
21306
|
-
merge_ready: publicState
|
|
21307
|
-
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,
|
|
21308
22024
|
proof_decision: firstStringValue2(result.proof_decision, stopCondition.proof_decision, resultRaw.proof_decision),
|
|
21309
|
-
merge_recommendation: changeReceiptResult
|
|
22025
|
+
merge_recommendation: changeReceiptResult ? parsedChangeReceipt?.recommendation.label : mergeRecommendation,
|
|
21310
22026
|
checkpoint_summary: checkpointSummary,
|
|
21311
22027
|
public_state: publicState,
|
|
21312
22028
|
passed_checks: changeChecks?.passed ?? profileChecks?.passed ?? nestedChecks.passed,
|
|
@@ -21374,7 +22090,88 @@ function checkpointSummaryLine(summary) {
|
|
|
21374
22090
|
summary.latest_decision ? `latest decision \`${summary.latest_decision}\`` : ""
|
|
21375
22091
|
].filter(Boolean).join("; ");
|
|
21376
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
|
+
}
|
|
21377
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
|
+
}
|
|
21378
22175
|
const summary = summarizeRiddleProofPrComment(input);
|
|
21379
22176
|
const title = input.title?.trim() || "Riddle Proof Evidence";
|
|
21380
22177
|
const lines = [
|
|
@@ -21450,16 +22247,20 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21450
22247
|
DEFAULT_DIAGNOSTIC_STRING_LIMIT,
|
|
21451
22248
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
21452
22249
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
|
22250
|
+
RIDDLE_PREVIEW_RECEIPT_VERSION,
|
|
21453
22251
|
RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
|
|
21454
22252
|
RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
|
|
21455
22253
|
RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
|
|
21456
22254
|
RIDDLE_PROOF_CAPTURE_DIAGNOSTIC_VERSION,
|
|
21457
22255
|
RIDDLE_PROOF_CHANGE_CONTRACT_VERSION,
|
|
22256
|
+
RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION,
|
|
21458
22257
|
RIDDLE_PROOF_CHANGE_RECEIPT_VERSION,
|
|
21459
22258
|
RIDDLE_PROOF_CHANGE_RESULT_VERSION,
|
|
21460
22259
|
RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
|
|
21461
22260
|
RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
|
|
22261
|
+
RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION,
|
|
21462
22262
|
RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
|
|
22263
|
+
RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
|
|
21463
22264
|
RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION,
|
|
21464
22265
|
RIDDLE_PROOF_PLAYABILITY_VERSION,
|
|
21465
22266
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
@@ -21498,6 +22299,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21498
22299
|
buildAuthorCheckpointPacket,
|
|
21499
22300
|
buildCheckpointPacketForEngineResult,
|
|
21500
22301
|
buildProofAssessmentCheckpointPacket,
|
|
22302
|
+
buildRiddleProofHandoffPrCommentMarkdown,
|
|
21501
22303
|
buildRiddleProofPrCommentMarkdown,
|
|
21502
22304
|
buildRiddleProofProfileScript,
|
|
21503
22305
|
buildStageCheckpointPacket,
|
|
@@ -21522,6 +22324,8 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21522
22324
|
createLocalAgentJsonRunner,
|
|
21523
22325
|
createRiddleApiClient,
|
|
21524
22326
|
createRiddleProofChangeReceipt,
|
|
22327
|
+
createRiddleProofHandoffReceipt,
|
|
22328
|
+
createRiddleProofObservationReceipt,
|
|
21525
22329
|
createRiddleProofProfileConfigurationError,
|
|
21526
22330
|
createRiddleProofProfileEnvironmentBlockedResult,
|
|
21527
22331
|
createRiddleProofProfileInsufficientResult,
|
|
@@ -21532,6 +22336,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21532
22336
|
deployRiddlePreview,
|
|
21533
22337
|
deployRiddleStaticPreview,
|
|
21534
22338
|
deriveRiddleProofArtifactBodyAssertions,
|
|
22339
|
+
detectRiddlePreviewSource,
|
|
21535
22340
|
extractBasicGameplayEvidence,
|
|
21536
22341
|
extractPlayabilityEvidence,
|
|
21537
22342
|
extractRiddleProofProfileResult,
|
|
@@ -21542,6 +22347,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21542
22347
|
isSuccessfulStatus,
|
|
21543
22348
|
isTerminalRiddleJobStatus,
|
|
21544
22349
|
isTerminalStatus,
|
|
22350
|
+
migrateRiddleProofChangeReceipt,
|
|
21545
22351
|
nonEmptyString,
|
|
21546
22352
|
normalizeCheckpointResponse,
|
|
21547
22353
|
normalizeIntegrationContext,
|
|
@@ -21549,6 +22355,10 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
21549
22355
|
normalizeRiddleProofProfile,
|
|
21550
22356
|
normalizeRunParams,
|
|
21551
22357
|
normalizeTerminalMetadata,
|
|
22358
|
+
parseRiddlePreviewReceipt,
|
|
22359
|
+
parseRiddleProofChangeReceipt,
|
|
22360
|
+
parseRiddleProofHandoffReceipt,
|
|
22361
|
+
parseRiddleProofObservationReceipt,
|
|
21552
22362
|
parseRiddleViewport,
|
|
21553
22363
|
parseVisualProofSession,
|
|
21554
22364
|
pollRiddleJob,
|