@riddledc/riddle-proof 0.8.82 → 0.8.84
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 +66 -10
- 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/chunk-AQTCU6W5.js +1086 -0
- package/dist/index.cjs +682 -58
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -2
- package/dist/{proof-run-engine-MiKZt9oY.d.ts → proof-run-engine-BqRoA3Do.d.ts} +3 -3
- package/dist/{proof-run-engine-Baiv6l3A.d.cts → proof-run-engine-DpChFR5H.d.cts} +3 -3
- package/dist/proof-run-engine.d.cts +1 -1
- package/dist/proof-run-engine.d.ts +1 -1
- package/dist/semantic-certificate.cjs +684 -60
- package/dist/semantic-certificate.d.cts +170 -2
- package/dist/semantic-certificate.d.ts +170 -2
- package/dist/semantic-certificate.js +17 -3
- package/package.json +1 -1
- package/dist/chunk-ZZ6UNKJQ.js +0 -469
package/dist/index.cjs
CHANGED
|
@@ -3442,6 +3442,8 @@ __export(index_exports, {
|
|
|
3442
3442
|
RIDDLE_PROOF_PR_COMMENT_MARKER: () => RIDDLE_PROOF_PR_COMMENT_MARKER,
|
|
3443
3443
|
RIDDLE_PROOF_RUN_CARD_VERSION: () => RIDDLE_PROOF_RUN_CARD_VERSION,
|
|
3444
3444
|
RIDDLE_PROOF_RUN_STATE_VERSION: () => RIDDLE_PROOF_RUN_STATE_VERSION,
|
|
3445
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES: () => RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES,
|
|
3446
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION: () => RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
3445
3447
|
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION: () => RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
|
|
3446
3448
|
RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION: () => RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION,
|
|
3447
3449
|
RIDDLE_PROOF_VISUAL_SESSION_VERSION: () => RIDDLE_PROOF_VISUAL_SESSION_VERSION,
|
|
@@ -3484,6 +3486,7 @@ __export(index_exports, {
|
|
|
3484
3486
|
compactBasicGameplayText: () => compactBasicGameplayText,
|
|
3485
3487
|
compactRecord: () => compactRecord,
|
|
3486
3488
|
compareVisualProofSessionFingerprint: () => compareVisualProofSessionFingerprint,
|
|
3489
|
+
composeRiddleProofSemanticCertificateClosures: () => composeRiddleProofSemanticCertificateClosures,
|
|
3487
3490
|
composeRiddleProofSemanticCertificates: () => composeRiddleProofSemanticCertificates,
|
|
3488
3491
|
createBasicGameplayCatchRecords: () => createBasicGameplayCatchRecords,
|
|
3489
3492
|
createBasicGameplayCatchSummary: () => createBasicGameplayCatchSummary,
|
|
@@ -3502,6 +3505,7 @@ __export(index_exports, {
|
|
|
3502
3505
|
createRiddleProofProfileEnvironmentBlockedResult: () => createRiddleProofProfileEnvironmentBlockedResult,
|
|
3503
3506
|
createRiddleProofProfileInsufficientResult: () => createRiddleProofProfileInsufficientResult,
|
|
3504
3507
|
createRiddleProofRunCard: () => createRiddleProofRunCard,
|
|
3508
|
+
createRiddleProofSemanticAtomicCertificateClosure: () => createRiddleProofSemanticAtomicCertificateClosure,
|
|
3505
3509
|
createRiddleProofSemanticCertificate: () => createRiddleProofSemanticCertificate,
|
|
3506
3510
|
createRunResult: () => createRunResult,
|
|
3507
3511
|
createRunState: () => createRunState,
|
|
@@ -3520,6 +3524,8 @@ __export(index_exports, {
|
|
|
3520
3524
|
isSuccessfulStatus: () => isSuccessfulStatus,
|
|
3521
3525
|
isTerminalRiddleJobStatus: () => isTerminalRiddleJobStatus,
|
|
3522
3526
|
isTerminalStatus: () => isTerminalStatus,
|
|
3527
|
+
matchRiddleProofSemanticCertificate: () => matchRiddleProofSemanticCertificate,
|
|
3528
|
+
matchRiddleProofSemanticCertificateClosure: () => matchRiddleProofSemanticCertificateClosure,
|
|
3523
3529
|
migrateRiddleProofChangeReceipt: () => migrateRiddleProofChangeReceipt,
|
|
3524
3530
|
nonEmptyString: () => nonEmptyString,
|
|
3525
3531
|
normalizeCheckpointResponse: () => normalizeCheckpointResponse,
|
|
@@ -3577,6 +3583,7 @@ __export(index_exports, {
|
|
|
3577
3583
|
summarizeRiddleProofProfileResult: () => summarizeRiddleProofProfileResult,
|
|
3578
3584
|
summarizeRiddleProofPublicConsumerSurface: () => summarizeRiddleProofPublicConsumerSurface,
|
|
3579
3585
|
summarizeRiddleProofPublicState: () => summarizeRiddleProofPublicState,
|
|
3586
|
+
validateRiddleProofSemanticCertificateClosure: () => validateRiddleProofSemanticCertificateClosure,
|
|
3580
3587
|
visualSessionFingerprint: () => visualSessionFingerprint,
|
|
3581
3588
|
visualSessionFingerprintBasis: () => visualSessionFingerprintBasis
|
|
3582
3589
|
});
|
|
@@ -20574,6 +20581,8 @@ function parseRiddleProofObservationReceipt(value) {
|
|
|
20574
20581
|
// src/semantic-certificate.ts
|
|
20575
20582
|
var import_node_crypto5 = require("crypto");
|
|
20576
20583
|
var RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION = "riddle-proof.semantic-certificate.v0";
|
|
20584
|
+
var RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION = "riddle-proof.semantic-certificate-closure.v0";
|
|
20585
|
+
var RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES = 4096;
|
|
20577
20586
|
var SCOPE_FIELDS = [
|
|
20578
20587
|
"repository",
|
|
20579
20588
|
"revision",
|
|
@@ -20605,55 +20614,146 @@ var CERTIFICATE_FIELDS = /* @__PURE__ */ new Set([
|
|
|
20605
20614
|
"issued_at"
|
|
20606
20615
|
]);
|
|
20607
20616
|
function isRecord4(value) {
|
|
20608
|
-
|
|
20617
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
20618
|
+
const prototype = Object.getPrototypeOf(value);
|
|
20619
|
+
return prototype === Object.prototype || prototype === null;
|
|
20620
|
+
}
|
|
20621
|
+
function safeErrorMessage(error) {
|
|
20622
|
+
try {
|
|
20623
|
+
if (error instanceof Error) return String(error.message);
|
|
20624
|
+
} catch {
|
|
20625
|
+
}
|
|
20626
|
+
try {
|
|
20627
|
+
return String(error);
|
|
20628
|
+
} catch {
|
|
20629
|
+
return "unprintable thrown value";
|
|
20630
|
+
}
|
|
20609
20631
|
}
|
|
20610
20632
|
function assertOnlyKeys(record, allowed, context) {
|
|
20611
20633
|
const allowedSet = new Set(allowed);
|
|
20612
|
-
for (const key of
|
|
20634
|
+
for (const key of Reflect.ownKeys(record)) {
|
|
20635
|
+
if (typeof key !== "string") {
|
|
20636
|
+
throw new Error(`${context} contains an unsupported symbol field.`);
|
|
20637
|
+
}
|
|
20613
20638
|
if (!allowedSet.has(key)) {
|
|
20614
20639
|
throw new Error(`${context} contains unsupported field ${key}.`);
|
|
20615
20640
|
}
|
|
20641
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
20642
|
+
if (!descriptor || descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
20643
|
+
throw new Error(`${context}.${key} must be an enumerable data field.`);
|
|
20644
|
+
}
|
|
20616
20645
|
}
|
|
20617
20646
|
}
|
|
20647
|
+
function readDenseDataArray(value, context, maximumLength) {
|
|
20648
|
+
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) {
|
|
20649
|
+
throw new Error(`${context} must be a plain array.`);
|
|
20650
|
+
}
|
|
20651
|
+
const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
|
|
20652
|
+
if (!lengthDescriptor || typeof lengthDescriptor.value !== "number" || !Number.isSafeInteger(lengthDescriptor.value) || lengthDescriptor.value < 0) {
|
|
20653
|
+
throw new Error(`${context}.length must be an own data field.`);
|
|
20654
|
+
}
|
|
20655
|
+
const length = lengthDescriptor.value;
|
|
20656
|
+
if (maximumLength !== void 0 && length > maximumLength) {
|
|
20657
|
+
throw new Error(`${context} exceeds ${maximumLength} entries.`);
|
|
20658
|
+
}
|
|
20659
|
+
const indexedElements = [];
|
|
20660
|
+
let elementCount = 0;
|
|
20661
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
20662
|
+
if (key === "length") continue;
|
|
20663
|
+
if (typeof key !== "string") {
|
|
20664
|
+
throw new Error(`${context} contains an unsupported symbol field.`);
|
|
20665
|
+
}
|
|
20666
|
+
const index = Number(key);
|
|
20667
|
+
if (!Number.isInteger(index) || index < 0 || index >= length || index >= 2 ** 32 - 1 || String(index) !== key) {
|
|
20668
|
+
throw new Error(`${context} contains unsupported array field ${key}.`);
|
|
20669
|
+
}
|
|
20670
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
20671
|
+
if (!descriptor || descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
20672
|
+
throw new Error(`${context}[${key}] must be an enumerable data field.`);
|
|
20673
|
+
}
|
|
20674
|
+
indexedElements.push([index, descriptor.value]);
|
|
20675
|
+
elementCount += 1;
|
|
20676
|
+
}
|
|
20677
|
+
if (elementCount !== length) {
|
|
20678
|
+
throw new Error(`${context} must not contain sparse or inherited entries.`);
|
|
20679
|
+
}
|
|
20680
|
+
indexedElements.sort(([left], [right]) => left - right);
|
|
20681
|
+
return indexedElements.map(([, entry]) => entry);
|
|
20682
|
+
}
|
|
20683
|
+
function requiredField(record, key, context) {
|
|
20684
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
20685
|
+
if (!descriptor) {
|
|
20686
|
+
throw new Error(`${context}.${key} is required.`);
|
|
20687
|
+
}
|
|
20688
|
+
if (descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
20689
|
+
throw new Error(`${context}.${key} must be an enumerable data field.`);
|
|
20690
|
+
}
|
|
20691
|
+
return descriptor.value;
|
|
20692
|
+
}
|
|
20693
|
+
function optionalField(record, key) {
|
|
20694
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
20695
|
+
if (!descriptor) return void 0;
|
|
20696
|
+
if (descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
20697
|
+
throw new Error(`${key} must be an enumerable data field.`);
|
|
20698
|
+
}
|
|
20699
|
+
return descriptor.value;
|
|
20700
|
+
}
|
|
20618
20701
|
function requiredString2(record, key, context) {
|
|
20619
|
-
const value = record
|
|
20702
|
+
const value = requiredField(record, key, context);
|
|
20620
20703
|
if (typeof value !== "string" || !value.trim()) {
|
|
20621
20704
|
throw new Error(`${context}.${key} must be a non-empty string.`);
|
|
20622
20705
|
}
|
|
20623
20706
|
return value.trim();
|
|
20624
20707
|
}
|
|
20625
20708
|
function optionalString(record, key, context) {
|
|
20626
|
-
if (record
|
|
20709
|
+
if (optionalField(record, key) === void 0) return void 0;
|
|
20627
20710
|
return requiredString2(record, key, context);
|
|
20628
20711
|
}
|
|
20629
|
-
function
|
|
20712
|
+
function cloneJsonValue(value, context, ancestors = /* @__PURE__ */ new Set()) {
|
|
20630
20713
|
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
20631
|
-
return
|
|
20714
|
+
return value;
|
|
20715
|
+
}
|
|
20716
|
+
if (typeof value === "number") {
|
|
20717
|
+
if (!Number.isFinite(value)) throw new Error(`${context} must contain only finite numbers.`);
|
|
20718
|
+
return value;
|
|
20632
20719
|
}
|
|
20633
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
20634
20720
|
if (Array.isArray(value)) {
|
|
20635
|
-
|
|
20721
|
+
const elements = readDenseDataArray(value, context);
|
|
20722
|
+
if (ancestors.has(value)) throw new Error(`${context} must not be cyclic.`);
|
|
20636
20723
|
ancestors.add(value);
|
|
20637
|
-
const
|
|
20724
|
+
const cloned2 = elements.map((entry, index) => cloneJsonValue(entry, `${context}[${index}]`, ancestors));
|
|
20638
20725
|
ancestors.delete(value);
|
|
20639
|
-
return
|
|
20726
|
+
return cloned2;
|
|
20640
20727
|
}
|
|
20641
|
-
if (!isRecord4(value))
|
|
20642
|
-
|
|
20643
|
-
if (prototype !== Object.prototype && prototype !== null) return false;
|
|
20644
|
-
if (ancestors.has(value)) return false;
|
|
20728
|
+
if (!isRecord4(value)) throw new Error(`${context} must contain only JSON values.`);
|
|
20729
|
+
if (ancestors.has(value)) throw new Error(`${context} must not be cyclic.`);
|
|
20645
20730
|
ancestors.add(value);
|
|
20646
|
-
const
|
|
20731
|
+
const cloned = {};
|
|
20732
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
20733
|
+
if (typeof key !== "string") {
|
|
20734
|
+
throw new Error(`${context} contains an unsupported symbol field.`);
|
|
20735
|
+
}
|
|
20736
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
20737
|
+
if (!descriptor || descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
20738
|
+
throw new Error(`${context}.${key} must be an enumerable data field.`);
|
|
20739
|
+
}
|
|
20740
|
+
Object.defineProperty(cloned, key, {
|
|
20741
|
+
value: cloneJsonValue(descriptor.value, `${context}.${key}`, ancestors),
|
|
20742
|
+
enumerable: true,
|
|
20743
|
+
configurable: true,
|
|
20744
|
+
writable: true
|
|
20745
|
+
});
|
|
20746
|
+
}
|
|
20647
20747
|
ancestors.delete(value);
|
|
20648
|
-
return
|
|
20748
|
+
return cloned;
|
|
20649
20749
|
}
|
|
20650
20750
|
function parseJsonObject2(value, context) {
|
|
20651
20751
|
if (value === void 0) return void 0;
|
|
20652
|
-
if (!isRecord4(value)
|
|
20752
|
+
if (!isRecord4(value)) {
|
|
20653
20753
|
throw new Error(`${context} must be a JSON object.`);
|
|
20654
20754
|
}
|
|
20655
|
-
const cloned =
|
|
20656
|
-
if (!isRecord4(cloned)
|
|
20755
|
+
const cloned = cloneJsonValue(value, context);
|
|
20756
|
+
if (!isRecord4(cloned)) {
|
|
20657
20757
|
throw new Error(`${context} must remain a JSON object when serialized.`);
|
|
20658
20758
|
}
|
|
20659
20759
|
return cloned;
|
|
@@ -20678,7 +20778,7 @@ function parseScope(value, context) {
|
|
|
20678
20778
|
function parseClaimRef(value, context, allowedExtras = []) {
|
|
20679
20779
|
if (!isRecord4(value)) throw new Error(`${context} must be an object.`);
|
|
20680
20780
|
assertOnlyKeys(value, ["claim_id", "claim_version", "parameters", ...allowedExtras], context);
|
|
20681
|
-
const parameters = parseJsonObject2(value
|
|
20781
|
+
const parameters = parseJsonObject2(optionalField(value, "parameters"), `${context}.parameters`);
|
|
20682
20782
|
return {
|
|
20683
20783
|
claim_id: requiredString2(value, "claim_id", context),
|
|
20684
20784
|
claim_version: requiredString2(value, "claim_version", context),
|
|
@@ -20714,10 +20814,11 @@ function parseEvidenceRef(value, context) {
|
|
|
20714
20814
|
};
|
|
20715
20815
|
}
|
|
20716
20816
|
function parseEvidenceBundle(value, context) {
|
|
20717
|
-
|
|
20817
|
+
const entries = readDenseDataArray(value, context);
|
|
20818
|
+
if (entries.length === 0) {
|
|
20718
20819
|
throw new Error(`${context} must contain at least one evidence reference.`);
|
|
20719
20820
|
}
|
|
20720
|
-
return
|
|
20821
|
+
return entries.map((entry, index) => parseEvidenceRef(entry, `${context}[${index}]`));
|
|
20721
20822
|
}
|
|
20722
20823
|
function parseContractRef(value, context) {
|
|
20723
20824
|
if (!isRecord4(value)) throw new Error(`${context} must be an object.`);
|
|
@@ -20734,30 +20835,32 @@ function parseContract(value, context, allowRuntimePredicate = false) {
|
|
|
20734
20835
|
["contract_id", "contract_version", "label", "claim", ...allowRuntimePredicate ? ["accepts"] : []],
|
|
20735
20836
|
context
|
|
20736
20837
|
);
|
|
20737
|
-
if (allowRuntimePredicate && typeof value
|
|
20838
|
+
if (allowRuntimePredicate && typeof requiredField(value, "accepts", context) !== "function") {
|
|
20738
20839
|
throw new Error(`${context}.accepts must be a function.`);
|
|
20739
20840
|
}
|
|
20740
20841
|
return {
|
|
20741
20842
|
...parseContractRef(value, context),
|
|
20742
|
-
claim: parseClaim(value
|
|
20843
|
+
claim: parseClaim(requiredField(value, "claim", context), `${context}.claim`)
|
|
20743
20844
|
};
|
|
20744
20845
|
}
|
|
20745
20846
|
function parseRule(value, context, allowFullPremises = false) {
|
|
20746
20847
|
if (!isRecord4(value)) throw new Error(`${context} must be an object.`);
|
|
20747
20848
|
assertOnlyKeys(value, ["rule_id", "rule_version", "label", "premises", "conclusion"], context);
|
|
20748
|
-
|
|
20849
|
+
const premises = requiredField(value, "premises", context);
|
|
20850
|
+
const premiseValues = readDenseDataArray(premises, `${context}.premises`);
|
|
20851
|
+
if (premiseValues.length === 0) {
|
|
20749
20852
|
throw new Error(`${context}.premises must contain at least one claim reference.`);
|
|
20750
20853
|
}
|
|
20751
20854
|
return {
|
|
20752
20855
|
rule_id: requiredString2(value, "rule_id", context),
|
|
20753
20856
|
rule_version: requiredString2(value, "rule_version", context),
|
|
20754
20857
|
label: requiredString2(value, "label", context),
|
|
20755
|
-
premises:
|
|
20858
|
+
premises: premiseValues.map((premise, index) => parseClaimRef(
|
|
20756
20859
|
premise,
|
|
20757
20860
|
`${context}.premises[${index}]`,
|
|
20758
20861
|
allowFullPremises ? ["label"] : []
|
|
20759
20862
|
)),
|
|
20760
|
-
conclusion: parseClaim(value
|
|
20863
|
+
conclusion: parseClaim(requiredField(value, "conclusion", context), `${context}.conclusion`)
|
|
20761
20864
|
};
|
|
20762
20865
|
}
|
|
20763
20866
|
function parsePremise(value, context) {
|
|
@@ -20777,9 +20880,9 @@ function parsePremise(value, context) {
|
|
|
20777
20880
|
certificate_id: requiredString2(value, "certificate_id", context),
|
|
20778
20881
|
derivation_kind: derivationKind,
|
|
20779
20882
|
assurance,
|
|
20780
|
-
scope: parseScope(value
|
|
20781
|
-
claim: parseClaim(value
|
|
20782
|
-
evidence: parseEvidenceBundle(value
|
|
20883
|
+
scope: parseScope(requiredField(value, "scope", context), `${context}.scope`),
|
|
20884
|
+
claim: parseClaim(requiredField(value, "claim", context), `${context}.claim`),
|
|
20885
|
+
evidence: parseEvidenceBundle(requiredField(value, "evidence", context), `${context}.evidence`)
|
|
20783
20886
|
};
|
|
20784
20887
|
}
|
|
20785
20888
|
function stableJson3(value) {
|
|
@@ -20809,28 +20912,30 @@ function parseDerivation(value, context) {
|
|
|
20809
20912
|
const kind = requiredString2(value, "kind", context);
|
|
20810
20913
|
if (kind === "contract") {
|
|
20811
20914
|
assertOnlyKeys(value, ["kind", "assurance", "contract"], context);
|
|
20812
|
-
if (value
|
|
20915
|
+
if (requiredField(value, "assurance", context) !== "runtime_contract_accepted") {
|
|
20813
20916
|
throw new Error(`${context}.assurance must be runtime_contract_accepted.`);
|
|
20814
20917
|
}
|
|
20815
20918
|
return {
|
|
20816
20919
|
kind,
|
|
20817
20920
|
assurance: "runtime_contract_accepted",
|
|
20818
|
-
contract: parseContract(value
|
|
20921
|
+
contract: parseContract(requiredField(value, "contract", context), `${context}.contract`)
|
|
20819
20922
|
};
|
|
20820
20923
|
}
|
|
20821
20924
|
if (kind === "composition") {
|
|
20822
20925
|
assertOnlyKeys(value, ["kind", "assurance", "rule", "premises"], context);
|
|
20823
|
-
if (value
|
|
20926
|
+
if (requiredField(value, "assurance", context) !== "declared_runtime_rule") {
|
|
20824
20927
|
throw new Error(`${context}.assurance must be declared_runtime_rule.`);
|
|
20825
20928
|
}
|
|
20826
|
-
|
|
20929
|
+
const premises = requiredField(value, "premises", context);
|
|
20930
|
+
const premiseValues = readDenseDataArray(premises, `${context}.premises`);
|
|
20931
|
+
if (premiseValues.length === 0) {
|
|
20827
20932
|
throw new Error(`${context}.premises must contain at least one certificate premise.`);
|
|
20828
20933
|
}
|
|
20829
20934
|
return {
|
|
20830
20935
|
kind,
|
|
20831
20936
|
assurance: "declared_runtime_rule",
|
|
20832
|
-
rule: parseRule(value
|
|
20833
|
-
premises:
|
|
20937
|
+
rule: parseRule(requiredField(value, "rule", context), `${context}.rule`),
|
|
20938
|
+
premises: premiseValues.map((premise, index) => parsePremise(premise, `${context}.premises[${index}]`))
|
|
20834
20939
|
};
|
|
20835
20940
|
}
|
|
20836
20941
|
throw new Error(`${context}.kind must be contract or composition.`);
|
|
@@ -20845,9 +20950,25 @@ function createRiddleProofSemanticCertificate(input) {
|
|
|
20845
20950
|
["scope", "evidence", "observation", "contract", "issued_at"],
|
|
20846
20951
|
"semantic certificate input"
|
|
20847
20952
|
);
|
|
20848
|
-
const scope = parseScope(input
|
|
20849
|
-
const evidence = parseEvidenceBundle(
|
|
20850
|
-
|
|
20953
|
+
const scope = parseScope(requiredField(input, "scope", "semantic certificate input"), "semantic certificate scope");
|
|
20954
|
+
const evidence = parseEvidenceBundle(
|
|
20955
|
+
requiredField(input, "evidence", "semantic certificate input"),
|
|
20956
|
+
"semantic certificate evidence"
|
|
20957
|
+
);
|
|
20958
|
+
const runtimeContract = requiredField(
|
|
20959
|
+
input,
|
|
20960
|
+
"contract",
|
|
20961
|
+
"semantic certificate input"
|
|
20962
|
+
);
|
|
20963
|
+
const contract = parseContract(runtimeContract, "semantic certificate contract", true);
|
|
20964
|
+
const accepts = requiredField(
|
|
20965
|
+
runtimeContract,
|
|
20966
|
+
"accepts",
|
|
20967
|
+
"semantic certificate contract"
|
|
20968
|
+
);
|
|
20969
|
+
if (typeof accepts !== "function") {
|
|
20970
|
+
throw new Error("semantic certificate contract.accepts must be a function.");
|
|
20971
|
+
}
|
|
20851
20972
|
const contractRef = {
|
|
20852
20973
|
contract_id: contract.contract_id,
|
|
20853
20974
|
contract_version: contract.contract_version,
|
|
@@ -20856,14 +20977,17 @@ function createRiddleProofSemanticCertificate(input) {
|
|
|
20856
20977
|
const claim = contract.claim;
|
|
20857
20978
|
let accepted;
|
|
20858
20979
|
try {
|
|
20859
|
-
accepted =
|
|
20980
|
+
accepted = accepts(
|
|
20981
|
+
{ ...scope },
|
|
20982
|
+
requiredField(input, "observation", "semantic certificate input")
|
|
20983
|
+
) === true;
|
|
20860
20984
|
} catch (error) {
|
|
20861
20985
|
return {
|
|
20862
20986
|
ok: false,
|
|
20863
20987
|
error: {
|
|
20864
20988
|
code: "contract_error",
|
|
20865
20989
|
contract: contractRef,
|
|
20866
|
-
message: `Semantic contract evaluation failed: ${
|
|
20990
|
+
message: `Semantic contract evaluation failed: ${safeErrorMessage(error)}.`
|
|
20867
20991
|
}
|
|
20868
20992
|
};
|
|
20869
20993
|
}
|
|
@@ -20883,29 +21007,35 @@ function createRiddleProofSemanticCertificate(input) {
|
|
|
20883
21007
|
claim,
|
|
20884
21008
|
evidence,
|
|
20885
21009
|
derivation: { kind: "contract", assurance: "runtime_contract_accepted", contract },
|
|
20886
|
-
issued_at: parseIssuedAt(
|
|
21010
|
+
issued_at: parseIssuedAt(
|
|
21011
|
+
optionalField(input, "issued_at") || (/* @__PURE__ */ new Date()).toISOString(),
|
|
21012
|
+
"semantic certificate issued_at"
|
|
21013
|
+
)
|
|
20887
21014
|
};
|
|
20888
21015
|
return { ok: true, certificate: withCertificateId(body) };
|
|
20889
21016
|
}
|
|
20890
21017
|
function parseRiddleProofSemanticCertificate(value) {
|
|
20891
21018
|
if (!isRecord4(value)) throw new Error("Semantic certificate must be an object.");
|
|
20892
|
-
|
|
20893
|
-
|
|
21019
|
+
const version = optionalField(value, "version");
|
|
21020
|
+
if (version !== RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION) {
|
|
21021
|
+
throw new Error(`Unsupported Semantic certificate version ${String(version || "missing")}.`);
|
|
20894
21022
|
}
|
|
20895
21023
|
for (const field of AUTHORITY_FIELDS) {
|
|
20896
21024
|
if (Object.prototype.hasOwnProperty.call(value, field)) {
|
|
20897
21025
|
throw new Error(`Semantic certificate must not contain authority field ${field}.`);
|
|
20898
21026
|
}
|
|
20899
21027
|
}
|
|
20900
|
-
|
|
20901
|
-
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
const
|
|
20908
|
-
|
|
21028
|
+
assertOnlyKeys(value, [...CERTIFICATE_FIELDS], "Semantic certificate");
|
|
21029
|
+
const scope = parseScope(requiredField(value, "scope", "semantic certificate"), "semantic certificate scope");
|
|
21030
|
+
const claim = parseClaim(requiredField(value, "claim", "semantic certificate"), "semantic certificate claim");
|
|
21031
|
+
const evidence = parseEvidenceBundle(
|
|
21032
|
+
requiredField(value, "evidence", "semantic certificate"),
|
|
21033
|
+
"semantic certificate evidence"
|
|
21034
|
+
);
|
|
21035
|
+
const derivation = parseDerivation(
|
|
21036
|
+
requiredField(value, "derivation", "semantic certificate"),
|
|
21037
|
+
"semantic certificate derivation"
|
|
21038
|
+
);
|
|
20909
21039
|
if (derivation.kind === "contract" && !sameClaimRef(claim, derivation.contract.claim)) {
|
|
20910
21040
|
throw new Error("Semantic contract-derived claim must match its contract claim.");
|
|
20911
21041
|
}
|
|
@@ -20935,7 +21065,10 @@ function parseRiddleProofSemanticCertificate(value) {
|
|
|
20935
21065
|
claim,
|
|
20936
21066
|
evidence,
|
|
20937
21067
|
derivation,
|
|
20938
|
-
issued_at: parseIssuedAt(
|
|
21068
|
+
issued_at: parseIssuedAt(
|
|
21069
|
+
requiredField(value, "issued_at", "semantic certificate"),
|
|
21070
|
+
"semantic certificate issued_at"
|
|
21071
|
+
)
|
|
20939
21072
|
};
|
|
20940
21073
|
const observedId = requiredString2(value, "certificate_id", "semantic certificate");
|
|
20941
21074
|
const expectedId = certificateId(body);
|
|
@@ -20944,6 +21077,112 @@ function parseRiddleProofSemanticCertificate(value) {
|
|
|
20944
21077
|
}
|
|
20945
21078
|
return { ...body, certificate_id: observedId };
|
|
20946
21079
|
}
|
|
21080
|
+
function matchRiddleProofSemanticCertificate(input) {
|
|
21081
|
+
if (!isRecord4(input)) throw new Error("Semantic certificate match input must be a plain object.");
|
|
21082
|
+
assertOnlyKeys(
|
|
21083
|
+
input,
|
|
21084
|
+
[
|
|
21085
|
+
"certificate",
|
|
21086
|
+
"expected_certificate_id",
|
|
21087
|
+
"expected_scope",
|
|
21088
|
+
"expected_claim",
|
|
21089
|
+
"expected_assurance"
|
|
21090
|
+
],
|
|
21091
|
+
"semantic certificate match input"
|
|
21092
|
+
);
|
|
21093
|
+
const expectedCertificateId = requiredString2(
|
|
21094
|
+
input,
|
|
21095
|
+
"expected_certificate_id",
|
|
21096
|
+
"semantic certificate match input"
|
|
21097
|
+
);
|
|
21098
|
+
if (!/^rpsc_[0-9a-f]{64}$/u.test(expectedCertificateId)) {
|
|
21099
|
+
throw new Error(
|
|
21100
|
+
"Semantic certificate match input.expected_certificate_id must be a full rpsc content ID."
|
|
21101
|
+
);
|
|
21102
|
+
}
|
|
21103
|
+
const expectedScope = parseScope(
|
|
21104
|
+
requiredField(input, "expected_scope", "semantic certificate match input"),
|
|
21105
|
+
"semantic certificate match expected_scope"
|
|
21106
|
+
);
|
|
21107
|
+
const expectedClaim = parseClaimRef(
|
|
21108
|
+
requiredField(input, "expected_claim", "semantic certificate match input"),
|
|
21109
|
+
"semantic certificate match expected_claim",
|
|
21110
|
+
["label"]
|
|
21111
|
+
);
|
|
21112
|
+
const expectedAssurance = requiredString2(
|
|
21113
|
+
input,
|
|
21114
|
+
"expected_assurance",
|
|
21115
|
+
"semantic certificate match input"
|
|
21116
|
+
);
|
|
21117
|
+
if (expectedAssurance !== "runtime_contract_accepted" && expectedAssurance !== "declared_runtime_rule") {
|
|
21118
|
+
throw new Error(
|
|
21119
|
+
"Semantic certificate match input.expected_assurance must be runtime_contract_accepted or declared_runtime_rule."
|
|
21120
|
+
);
|
|
21121
|
+
}
|
|
21122
|
+
let certificate;
|
|
21123
|
+
try {
|
|
21124
|
+
certificate = parseRiddleProofSemanticCertificate(
|
|
21125
|
+
requiredField(input, "certificate", "semantic certificate match input")
|
|
21126
|
+
);
|
|
21127
|
+
} catch (error) {
|
|
21128
|
+
return {
|
|
21129
|
+
ok: false,
|
|
21130
|
+
error: {
|
|
21131
|
+
code: "invalid_certificate",
|
|
21132
|
+
message: `Semantic certificate did not parse: ${safeErrorMessage(error)}`
|
|
21133
|
+
}
|
|
21134
|
+
};
|
|
21135
|
+
}
|
|
21136
|
+
if (certificate.certificate_id !== expectedCertificateId) {
|
|
21137
|
+
return {
|
|
21138
|
+
ok: false,
|
|
21139
|
+
error: {
|
|
21140
|
+
code: "certificate_id_mismatch",
|
|
21141
|
+
expected: expectedCertificateId,
|
|
21142
|
+
observed: certificate.certificate_id,
|
|
21143
|
+
message: "Semantic certificate does not match the trusted expected content ID."
|
|
21144
|
+
}
|
|
21145
|
+
};
|
|
21146
|
+
}
|
|
21147
|
+
const scopeMismatch = firstScopeMismatch(expectedScope, certificate.scope);
|
|
21148
|
+
if (scopeMismatch) {
|
|
21149
|
+
return {
|
|
21150
|
+
ok: false,
|
|
21151
|
+
error: {
|
|
21152
|
+
code: "scope_mismatch",
|
|
21153
|
+
...scopeMismatch,
|
|
21154
|
+
message: `Semantic certificate has a different ${scopeMismatch.field} than the consumer expected.`
|
|
21155
|
+
}
|
|
21156
|
+
};
|
|
21157
|
+
}
|
|
21158
|
+
if (!sameClaimRef(expectedClaim, certificate.claim)) {
|
|
21159
|
+
return {
|
|
21160
|
+
ok: false,
|
|
21161
|
+
error: {
|
|
21162
|
+
code: "claim_mismatch",
|
|
21163
|
+
expected: expectedClaim,
|
|
21164
|
+
observed: parseClaimRef(
|
|
21165
|
+
certificate.claim,
|
|
21166
|
+
"semantic certificate match observed claim",
|
|
21167
|
+
["label"]
|
|
21168
|
+
),
|
|
21169
|
+
message: "Semantic certificate does not state the claim the consumer expected."
|
|
21170
|
+
}
|
|
21171
|
+
};
|
|
21172
|
+
}
|
|
21173
|
+
if (certificate.derivation.assurance !== expectedAssurance) {
|
|
21174
|
+
return {
|
|
21175
|
+
ok: false,
|
|
21176
|
+
error: {
|
|
21177
|
+
code: "assurance_mismatch",
|
|
21178
|
+
expected: expectedAssurance,
|
|
21179
|
+
observed: certificate.derivation.assurance,
|
|
21180
|
+
message: "Semantic certificate does not have the assurance the consumer expected."
|
|
21181
|
+
}
|
|
21182
|
+
};
|
|
21183
|
+
}
|
|
21184
|
+
return { ok: true, certificate };
|
|
21185
|
+
}
|
|
20947
21186
|
function firstScopeMismatch(expected, observed) {
|
|
20948
21187
|
for (const field of SCOPE_FIELDS) {
|
|
20949
21188
|
if (expected[field] !== observed[field]) {
|
|
@@ -20969,11 +21208,20 @@ function composeRiddleProofSemanticCertificates(input) {
|
|
|
20969
21208
|
["rule", "certificates", "issued_at"],
|
|
20970
21209
|
"semantic composition input"
|
|
20971
21210
|
);
|
|
20972
|
-
const rule = parseRule(
|
|
20973
|
-
|
|
21211
|
+
const rule = parseRule(
|
|
21212
|
+
requiredField(input, "rule", "semantic composition input"),
|
|
21213
|
+
"semantic composition rule",
|
|
21214
|
+
true
|
|
21215
|
+
);
|
|
21216
|
+
const inputCertificates = requiredField(input, "certificates", "semantic composition input");
|
|
21217
|
+
const certificateValues = readDenseDataArray(
|
|
21218
|
+
inputCertificates,
|
|
21219
|
+
"semantic composition input.certificates"
|
|
21220
|
+
);
|
|
21221
|
+
if (certificateValues.length === 0) {
|
|
20974
21222
|
throw new Error("Semantic composition requires at least one certificate.");
|
|
20975
21223
|
}
|
|
20976
|
-
const certificates =
|
|
21224
|
+
const certificates = certificateValues.map((certificate) => parseRiddleProofSemanticCertificate(certificate));
|
|
20977
21225
|
if (certificates.length !== rule.premises.length) {
|
|
20978
21226
|
return {
|
|
20979
21227
|
ok: false,
|
|
@@ -21028,10 +21276,379 @@ function composeRiddleProofSemanticCertificates(input) {
|
|
|
21028
21276
|
rule,
|
|
21029
21277
|
premises: certificates.map(premiseFromCertificate)
|
|
21030
21278
|
},
|
|
21031
|
-
issued_at: parseIssuedAt(
|
|
21279
|
+
issued_at: parseIssuedAt(
|
|
21280
|
+
optionalField(input, "issued_at") || (/* @__PURE__ */ new Date()).toISOString(),
|
|
21281
|
+
"semantic certificate issued_at"
|
|
21282
|
+
)
|
|
21032
21283
|
};
|
|
21033
21284
|
return { ok: true, certificate: withCertificateId(body) };
|
|
21034
21285
|
}
|
|
21286
|
+
function invalidClosure(message) {
|
|
21287
|
+
return { ok: false, error: { code: "invalid_closure", message } };
|
|
21288
|
+
}
|
|
21289
|
+
function firstPremiseSnapshotMismatch(snapshot, certificate) {
|
|
21290
|
+
const observed = premiseFromCertificate(certificate);
|
|
21291
|
+
if (snapshot.derivation_kind !== observed.derivation_kind) return "derivation_kind";
|
|
21292
|
+
if (snapshot.assurance !== observed.assurance) return "assurance";
|
|
21293
|
+
if (stableJson3(snapshot.scope) !== stableJson3(observed.scope)) return "scope";
|
|
21294
|
+
if (stableJson3(snapshot.claim) !== stableJson3(observed.claim)) return "claim";
|
|
21295
|
+
if (stableJson3(snapshot.evidence) !== stableJson3(observed.evidence)) return "evidence";
|
|
21296
|
+
return void 0;
|
|
21297
|
+
}
|
|
21298
|
+
function validateSemanticCertificateClosureInternal(value) {
|
|
21299
|
+
if (!isRecord4(value)) {
|
|
21300
|
+
return invalidClosure("Semantic certificate closure must be a plain object.");
|
|
21301
|
+
}
|
|
21302
|
+
assertOnlyKeys(
|
|
21303
|
+
value,
|
|
21304
|
+
["version", "root_certificate_id", "certificates"],
|
|
21305
|
+
"Semantic certificate closure"
|
|
21306
|
+
);
|
|
21307
|
+
if (requiredField(value, "version", "Semantic certificate closure") !== RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION) {
|
|
21308
|
+
return invalidClosure("Unsupported Semantic certificate closure version.");
|
|
21309
|
+
}
|
|
21310
|
+
const rootCertificateId = requiredString2(
|
|
21311
|
+
value,
|
|
21312
|
+
"root_certificate_id",
|
|
21313
|
+
"Semantic certificate closure"
|
|
21314
|
+
);
|
|
21315
|
+
if (!/^rpsc_[0-9a-f]{64}$/u.test(rootCertificateId)) {
|
|
21316
|
+
return invalidClosure(
|
|
21317
|
+
"Semantic certificate closure.root_certificate_id must be a full rpsc content ID."
|
|
21318
|
+
);
|
|
21319
|
+
}
|
|
21320
|
+
const inputCertificates = requiredField(
|
|
21321
|
+
value,
|
|
21322
|
+
"certificates",
|
|
21323
|
+
"Semantic certificate closure"
|
|
21324
|
+
);
|
|
21325
|
+
const certificateValues = readDenseDataArray(
|
|
21326
|
+
inputCertificates,
|
|
21327
|
+
"Semantic certificate closure.certificates",
|
|
21328
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES
|
|
21329
|
+
);
|
|
21330
|
+
if (certificateValues.length === 0) {
|
|
21331
|
+
return invalidClosure("Semantic certificate closure must contain at least one certificate.");
|
|
21332
|
+
}
|
|
21333
|
+
const certificates = [];
|
|
21334
|
+
for (let index = 0; index < certificateValues.length; index += 1) {
|
|
21335
|
+
try {
|
|
21336
|
+
certificates.push(parseRiddleProofSemanticCertificate(certificateValues[index]));
|
|
21337
|
+
} catch (error) {
|
|
21338
|
+
return {
|
|
21339
|
+
ok: false,
|
|
21340
|
+
error: {
|
|
21341
|
+
code: "invalid_closure_certificate",
|
|
21342
|
+
input_index: index,
|
|
21343
|
+
message: `Semantic certificate closure certificate ${index} did not parse: ${safeErrorMessage(error)}`
|
|
21344
|
+
}
|
|
21345
|
+
};
|
|
21346
|
+
}
|
|
21347
|
+
}
|
|
21348
|
+
const certificatesById = /* @__PURE__ */ new Map();
|
|
21349
|
+
const firstIndexById = /* @__PURE__ */ new Map();
|
|
21350
|
+
for (let index = 0; index < certificates.length; index += 1) {
|
|
21351
|
+
const certificate = certificates[index];
|
|
21352
|
+
const firstIndex = firstIndexById.get(certificate.certificate_id);
|
|
21353
|
+
if (firstIndex !== void 0) {
|
|
21354
|
+
return {
|
|
21355
|
+
ok: false,
|
|
21356
|
+
error: {
|
|
21357
|
+
code: "duplicate_certificate_id",
|
|
21358
|
+
certificate_id: certificate.certificate_id,
|
|
21359
|
+
first_index: firstIndex,
|
|
21360
|
+
duplicate_index: index,
|
|
21361
|
+
message: `Semantic certificate closure repeats certificate ${certificate.certificate_id}.`
|
|
21362
|
+
}
|
|
21363
|
+
};
|
|
21364
|
+
}
|
|
21365
|
+
firstIndexById.set(certificate.certificate_id, index);
|
|
21366
|
+
certificatesById.set(certificate.certificate_id, certificate);
|
|
21367
|
+
}
|
|
21368
|
+
const rootCertificate = certificatesById.get(rootCertificateId);
|
|
21369
|
+
if (!rootCertificate) {
|
|
21370
|
+
return {
|
|
21371
|
+
ok: false,
|
|
21372
|
+
error: {
|
|
21373
|
+
code: "root_certificate_missing",
|
|
21374
|
+
root_certificate_id: rootCertificateId,
|
|
21375
|
+
message: "Semantic certificate closure does not contain its declared root certificate."
|
|
21376
|
+
}
|
|
21377
|
+
};
|
|
21378
|
+
}
|
|
21379
|
+
const states = /* @__PURE__ */ new Map();
|
|
21380
|
+
const stack = [{ certificate: rootCertificate, next_premise_index: 0 }];
|
|
21381
|
+
const dependencyFirst = [];
|
|
21382
|
+
states.set(rootCertificateId, "visiting");
|
|
21383
|
+
while (stack.length > 0) {
|
|
21384
|
+
const frame = stack[stack.length - 1];
|
|
21385
|
+
const premises = frame.certificate.derivation.kind === "composition" ? frame.certificate.derivation.premises : [];
|
|
21386
|
+
if (frame.next_premise_index < premises.length) {
|
|
21387
|
+
const premiseIndex = frame.next_premise_index;
|
|
21388
|
+
frame.next_premise_index += 1;
|
|
21389
|
+
const snapshot = premises[premiseIndex];
|
|
21390
|
+
const child = certificatesById.get(snapshot.certificate_id);
|
|
21391
|
+
if (!child) {
|
|
21392
|
+
return {
|
|
21393
|
+
ok: false,
|
|
21394
|
+
error: {
|
|
21395
|
+
code: "dangling_premise",
|
|
21396
|
+
parent_certificate_id: frame.certificate.certificate_id,
|
|
21397
|
+
premise_index: premiseIndex,
|
|
21398
|
+
premise_certificate_id: snapshot.certificate_id,
|
|
21399
|
+
message: `Semantic certificate ${frame.certificate.certificate_id} premise ${premiseIndex} has no full certificate body.`
|
|
21400
|
+
}
|
|
21401
|
+
};
|
|
21402
|
+
}
|
|
21403
|
+
const mismatch = firstPremiseSnapshotMismatch(snapshot, child);
|
|
21404
|
+
if (mismatch) {
|
|
21405
|
+
return {
|
|
21406
|
+
ok: false,
|
|
21407
|
+
error: {
|
|
21408
|
+
code: "premise_snapshot_mismatch",
|
|
21409
|
+
parent_certificate_id: frame.certificate.certificate_id,
|
|
21410
|
+
premise_index: premiseIndex,
|
|
21411
|
+
premise_certificate_id: snapshot.certificate_id,
|
|
21412
|
+
field: mismatch,
|
|
21413
|
+
message: `Semantic certificate ${frame.certificate.certificate_id} premise ${premiseIndex} has a different ${mismatch} than its full certificate body.`
|
|
21414
|
+
}
|
|
21415
|
+
};
|
|
21416
|
+
}
|
|
21417
|
+
const childState = states.get(child.certificate_id);
|
|
21418
|
+
if (childState === "visiting") {
|
|
21419
|
+
const cycleStart = stack.findIndex(
|
|
21420
|
+
(candidate) => candidate.certificate.certificate_id === child.certificate_id
|
|
21421
|
+
);
|
|
21422
|
+
const certificateIds = stack.slice(Math.max(0, cycleStart)).map((candidate) => candidate.certificate.certificate_id);
|
|
21423
|
+
certificateIds.push(child.certificate_id);
|
|
21424
|
+
return {
|
|
21425
|
+
ok: false,
|
|
21426
|
+
error: {
|
|
21427
|
+
code: "certificate_cycle",
|
|
21428
|
+
certificate_ids: certificateIds,
|
|
21429
|
+
message: "Semantic certificate closure contains a certificate cycle."
|
|
21430
|
+
}
|
|
21431
|
+
};
|
|
21432
|
+
}
|
|
21433
|
+
if (childState !== "visited") {
|
|
21434
|
+
states.set(child.certificate_id, "visiting");
|
|
21435
|
+
stack.push({ certificate: child, next_premise_index: 0 });
|
|
21436
|
+
}
|
|
21437
|
+
continue;
|
|
21438
|
+
}
|
|
21439
|
+
stack.pop();
|
|
21440
|
+
states.set(frame.certificate.certificate_id, "visited");
|
|
21441
|
+
dependencyFirst.push(frame.certificate);
|
|
21442
|
+
}
|
|
21443
|
+
if (dependencyFirst.length !== certificates.length) {
|
|
21444
|
+
const reachable = new Set(dependencyFirst.map((certificate) => certificate.certificate_id));
|
|
21445
|
+
const unreachable = certificates.filter((certificate) => !reachable.has(certificate.certificate_id)).map((certificate) => certificate.certificate_id).sort();
|
|
21446
|
+
return {
|
|
21447
|
+
ok: false,
|
|
21448
|
+
error: {
|
|
21449
|
+
code: "unreachable_certificates",
|
|
21450
|
+
certificate_ids: unreachable,
|
|
21451
|
+
message: "Semantic certificate closure contains certificates unreachable from its root."
|
|
21452
|
+
}
|
|
21453
|
+
};
|
|
21454
|
+
}
|
|
21455
|
+
const closure = {
|
|
21456
|
+
version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
21457
|
+
root_certificate_id: rootCertificateId,
|
|
21458
|
+
certificates: dependencyFirst
|
|
21459
|
+
};
|
|
21460
|
+
return { ok: true, closure, root_certificate: rootCertificate };
|
|
21461
|
+
}
|
|
21462
|
+
function validateRiddleProofSemanticCertificateClosure(value) {
|
|
21463
|
+
try {
|
|
21464
|
+
return validateSemanticCertificateClosureInternal(value);
|
|
21465
|
+
} catch (error) {
|
|
21466
|
+
return invalidClosure(
|
|
21467
|
+
`Semantic certificate closure did not parse: ${safeErrorMessage(error)}`
|
|
21468
|
+
);
|
|
21469
|
+
}
|
|
21470
|
+
}
|
|
21471
|
+
function createRiddleProofSemanticAtomicCertificateClosure(input) {
|
|
21472
|
+
if (!isRecord4(input)) throw new Error("Semantic certificate closure input must be a plain object.");
|
|
21473
|
+
assertOnlyKeys(input, ["certificate"], "Semantic certificate closure input");
|
|
21474
|
+
const certificate = requiredField(input, "certificate", "Semantic certificate closure input");
|
|
21475
|
+
let parsedCertificate;
|
|
21476
|
+
try {
|
|
21477
|
+
parsedCertificate = parseRiddleProofSemanticCertificate(certificate);
|
|
21478
|
+
} catch (error) {
|
|
21479
|
+
return {
|
|
21480
|
+
ok: false,
|
|
21481
|
+
error: {
|
|
21482
|
+
code: "invalid_closure_certificate",
|
|
21483
|
+
input_index: 0,
|
|
21484
|
+
message: `Semantic certificate closure certificate 0 did not parse: ${safeErrorMessage(error)}`
|
|
21485
|
+
}
|
|
21486
|
+
};
|
|
21487
|
+
}
|
|
21488
|
+
if (parsedCertificate.derivation.kind !== "contract") {
|
|
21489
|
+
return invalidClosure(
|
|
21490
|
+
"An atomic Semantic certificate closure requires a contract-derived certificate."
|
|
21491
|
+
);
|
|
21492
|
+
}
|
|
21493
|
+
return validateRiddleProofSemanticCertificateClosure({
|
|
21494
|
+
version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
21495
|
+
root_certificate_id: parsedCertificate.certificate_id,
|
|
21496
|
+
certificates: [certificate]
|
|
21497
|
+
});
|
|
21498
|
+
}
|
|
21499
|
+
function composeRiddleProofSemanticCertificateClosures(input) {
|
|
21500
|
+
if (!isRecord4(input)) throw new Error("Semantic closure composition input must be a plain object.");
|
|
21501
|
+
assertOnlyKeys(
|
|
21502
|
+
input,
|
|
21503
|
+
["rule", "closures", "issued_at"],
|
|
21504
|
+
"Semantic closure composition input"
|
|
21505
|
+
);
|
|
21506
|
+
const inputClosures = requiredField(
|
|
21507
|
+
input,
|
|
21508
|
+
"closures",
|
|
21509
|
+
"Semantic closure composition input"
|
|
21510
|
+
);
|
|
21511
|
+
const closureValues = readDenseDataArray(
|
|
21512
|
+
inputClosures,
|
|
21513
|
+
"Semantic closure composition input.closures"
|
|
21514
|
+
);
|
|
21515
|
+
if (closureValues.length === 0) {
|
|
21516
|
+
throw new Error("Semantic closure composition requires at least one closure.");
|
|
21517
|
+
}
|
|
21518
|
+
const validatedClosures = [];
|
|
21519
|
+
for (let index = 0; index < closureValues.length; index += 1) {
|
|
21520
|
+
const result = validateRiddleProofSemanticCertificateClosure(closureValues[index]);
|
|
21521
|
+
if (!result.ok) {
|
|
21522
|
+
return {
|
|
21523
|
+
ok: false,
|
|
21524
|
+
error: {
|
|
21525
|
+
code: "input_closure_invalid",
|
|
21526
|
+
input_index: index,
|
|
21527
|
+
cause: result.error,
|
|
21528
|
+
message: `Semantic input closure ${index} is invalid: ${result.error.message}`
|
|
21529
|
+
}
|
|
21530
|
+
};
|
|
21531
|
+
}
|
|
21532
|
+
validatedClosures.push(result);
|
|
21533
|
+
}
|
|
21534
|
+
const roots = validatedClosures.map((result) => {
|
|
21535
|
+
if (!result.ok) throw new Error("Validated Semantic closure unexpectedly became invalid.");
|
|
21536
|
+
return result.root_certificate;
|
|
21537
|
+
});
|
|
21538
|
+
const composition = composeRiddleProofSemanticCertificates({
|
|
21539
|
+
rule: requiredField(input, "rule", "Semantic closure composition input"),
|
|
21540
|
+
certificates: roots,
|
|
21541
|
+
issued_at: optionalField(input, "issued_at")
|
|
21542
|
+
});
|
|
21543
|
+
if (!composition.ok) return composition;
|
|
21544
|
+
const merged = [];
|
|
21545
|
+
const byId = /* @__PURE__ */ new Map();
|
|
21546
|
+
for (const result of validatedClosures) {
|
|
21547
|
+
if (!result.ok) continue;
|
|
21548
|
+
for (const certificate of result.closure.certificates) {
|
|
21549
|
+
const existing = byId.get(certificate.certificate_id);
|
|
21550
|
+
if (existing) {
|
|
21551
|
+
if (stableJson3(existing) !== stableJson3(certificate)) {
|
|
21552
|
+
return {
|
|
21553
|
+
ok: false,
|
|
21554
|
+
error: {
|
|
21555
|
+
code: "certificate_id_collision",
|
|
21556
|
+
certificate_id: certificate.certificate_id,
|
|
21557
|
+
message: `Semantic closures contain unequal bodies for ${certificate.certificate_id}.`
|
|
21558
|
+
}
|
|
21559
|
+
};
|
|
21560
|
+
}
|
|
21561
|
+
continue;
|
|
21562
|
+
}
|
|
21563
|
+
byId.set(certificate.certificate_id, certificate);
|
|
21564
|
+
merged.push(certificate);
|
|
21565
|
+
}
|
|
21566
|
+
}
|
|
21567
|
+
if (byId.has(composition.certificate.certificate_id)) {
|
|
21568
|
+
return {
|
|
21569
|
+
ok: false,
|
|
21570
|
+
error: {
|
|
21571
|
+
code: "certificate_id_collision",
|
|
21572
|
+
certificate_id: composition.certificate.certificate_id,
|
|
21573
|
+
message: "Semantic composition produced a root ID already present in its premise closures."
|
|
21574
|
+
}
|
|
21575
|
+
};
|
|
21576
|
+
}
|
|
21577
|
+
merged.push(composition.certificate);
|
|
21578
|
+
const validation = validateRiddleProofSemanticCertificateClosure({
|
|
21579
|
+
version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
21580
|
+
root_certificate_id: composition.certificate.certificate_id,
|
|
21581
|
+
certificates: merged
|
|
21582
|
+
});
|
|
21583
|
+
if (!validation.ok) {
|
|
21584
|
+
return {
|
|
21585
|
+
ok: false,
|
|
21586
|
+
error: {
|
|
21587
|
+
code: "closure_construction_failed",
|
|
21588
|
+
cause: validation.error,
|
|
21589
|
+
message: `Semantic closure construction failed: ${validation.error.message}`
|
|
21590
|
+
}
|
|
21591
|
+
};
|
|
21592
|
+
}
|
|
21593
|
+
return {
|
|
21594
|
+
ok: true,
|
|
21595
|
+
certificate: composition.certificate,
|
|
21596
|
+
closure: validation.closure
|
|
21597
|
+
};
|
|
21598
|
+
}
|
|
21599
|
+
function matchRiddleProofSemanticCertificateClosure(input) {
|
|
21600
|
+
if (!isRecord4(input)) throw new Error("Semantic certificate closure match input must be a plain object.");
|
|
21601
|
+
assertOnlyKeys(
|
|
21602
|
+
input,
|
|
21603
|
+
[
|
|
21604
|
+
"closure",
|
|
21605
|
+
"expected_root_certificate_id",
|
|
21606
|
+
"expected_scope",
|
|
21607
|
+
"expected_claim",
|
|
21608
|
+
"expected_assurance"
|
|
21609
|
+
],
|
|
21610
|
+
"Semantic certificate closure match input"
|
|
21611
|
+
);
|
|
21612
|
+
const validation = validateRiddleProofSemanticCertificateClosure(
|
|
21613
|
+
requiredField(input, "closure", "Semantic certificate closure match input")
|
|
21614
|
+
);
|
|
21615
|
+
if (!validation.ok) return validation;
|
|
21616
|
+
const expectedRootCertificateId = requiredString2(
|
|
21617
|
+
input,
|
|
21618
|
+
"expected_root_certificate_id",
|
|
21619
|
+
"Semantic certificate closure match input"
|
|
21620
|
+
);
|
|
21621
|
+
if (!/^rpsc_[0-9a-f]{64}$/u.test(expectedRootCertificateId)) {
|
|
21622
|
+
throw new Error(
|
|
21623
|
+
"Semantic certificate closure match input.expected_root_certificate_id must be a full rpsc content ID."
|
|
21624
|
+
);
|
|
21625
|
+
}
|
|
21626
|
+
const rootMatch = matchRiddleProofSemanticCertificate({
|
|
21627
|
+
certificate: validation.root_certificate,
|
|
21628
|
+
expected_certificate_id: expectedRootCertificateId,
|
|
21629
|
+
expected_scope: requiredField(
|
|
21630
|
+
input,
|
|
21631
|
+
"expected_scope",
|
|
21632
|
+
"Semantic certificate closure match input"
|
|
21633
|
+
),
|
|
21634
|
+
expected_claim: requiredField(
|
|
21635
|
+
input,
|
|
21636
|
+
"expected_claim",
|
|
21637
|
+
"Semantic certificate closure match input"
|
|
21638
|
+
),
|
|
21639
|
+
expected_assurance: requiredField(
|
|
21640
|
+
input,
|
|
21641
|
+
"expected_assurance",
|
|
21642
|
+
"Semantic certificate closure match input"
|
|
21643
|
+
)
|
|
21644
|
+
});
|
|
21645
|
+
if (!rootMatch.ok) return rootMatch;
|
|
21646
|
+
return {
|
|
21647
|
+
ok: true,
|
|
21648
|
+
closure: validation.closure,
|
|
21649
|
+
root_certificate: rootMatch.certificate
|
|
21650
|
+
};
|
|
21651
|
+
}
|
|
21035
21652
|
|
|
21036
21653
|
// src/change-proof.ts
|
|
21037
21654
|
var RIDDLE_PROOF_CHANGE_CONTRACT_VERSION = "riddle-proof.change-contract.v1";
|
|
@@ -23083,6 +23700,8 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
23083
23700
|
RIDDLE_PROOF_PR_COMMENT_MARKER,
|
|
23084
23701
|
RIDDLE_PROOF_RUN_CARD_VERSION,
|
|
23085
23702
|
RIDDLE_PROOF_RUN_STATE_VERSION,
|
|
23703
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES,
|
|
23704
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
23086
23705
|
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
|
|
23087
23706
|
RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION,
|
|
23088
23707
|
RIDDLE_PROOF_VISUAL_SESSION_VERSION,
|
|
@@ -23125,6 +23744,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
23125
23744
|
compactBasicGameplayText,
|
|
23126
23745
|
compactRecord,
|
|
23127
23746
|
compareVisualProofSessionFingerprint,
|
|
23747
|
+
composeRiddleProofSemanticCertificateClosures,
|
|
23128
23748
|
composeRiddleProofSemanticCertificates,
|
|
23129
23749
|
createBasicGameplayCatchRecords,
|
|
23130
23750
|
createBasicGameplayCatchSummary,
|
|
@@ -23143,6 +23763,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
23143
23763
|
createRiddleProofProfileEnvironmentBlockedResult,
|
|
23144
23764
|
createRiddleProofProfileInsufficientResult,
|
|
23145
23765
|
createRiddleProofRunCard,
|
|
23766
|
+
createRiddleProofSemanticAtomicCertificateClosure,
|
|
23146
23767
|
createRiddleProofSemanticCertificate,
|
|
23147
23768
|
createRunResult,
|
|
23148
23769
|
createRunState,
|
|
@@ -23161,6 +23782,8 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
23161
23782
|
isSuccessfulStatus,
|
|
23162
23783
|
isTerminalRiddleJobStatus,
|
|
23163
23784
|
isTerminalStatus,
|
|
23785
|
+
matchRiddleProofSemanticCertificate,
|
|
23786
|
+
matchRiddleProofSemanticCertificateClosure,
|
|
23164
23787
|
migrateRiddleProofChangeReceipt,
|
|
23165
23788
|
nonEmptyString,
|
|
23166
23789
|
normalizeCheckpointResponse,
|
|
@@ -23218,6 +23841,7 @@ function buildRiddleProofPrCommentMarkdown(input) {
|
|
|
23218
23841
|
summarizeRiddleProofProfileResult,
|
|
23219
23842
|
summarizeRiddleProofPublicConsumerSurface,
|
|
23220
23843
|
summarizeRiddleProofPublicState,
|
|
23844
|
+
validateRiddleProofSemanticCertificateClosure,
|
|
23221
23845
|
visualSessionFingerprint,
|
|
23222
23846
|
visualSessionFingerprintBasis
|
|
23223
23847
|
});
|