@riddledc/riddle-proof 0.8.80 → 0.8.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,6 +11,13 @@ import {
11
11
  import {
12
12
  runRiddleProof
13
13
  } from "./chunk-YH7ADFY4.js";
14
+ import {
15
+ RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
16
+ composeRiddleProofSemanticCertificates,
17
+ createRiddleProofSemanticCertificate,
18
+ parseRiddleProofSemanticCertificate,
19
+ riddleProofSemanticScopesEqual
20
+ } from "./chunk-ZZ6UNKJQ.js";
14
21
  import {
15
22
  RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION,
16
23
  RIDDLE_PROOF_PLAYABILITY_VERSION,
@@ -63,11 +70,11 @@ import {
63
70
  buildRiddleProofHandoffPrCommentMarkdown,
64
71
  buildRiddleProofPrCommentMarkdown,
65
72
  summarizeRiddleProofPrComment
66
- } from "./chunk-6T6ZAK77.js";
73
+ } from "./chunk-7OAETQU3.js";
67
74
  import {
68
75
  RIDDLE_PROOF_PROFILE_SUGGESTIONS_VERSION,
69
76
  suggestRiddleProofProfileChecks
70
- } from "./chunk-A4EF4M3B.js";
77
+ } from "./chunk-FW7CKARF.js";
71
78
  import {
72
79
  RIDDLE_PROOF_CHANGE_CONTRACT_VERSION,
73
80
  RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION,
@@ -82,7 +89,7 @@ import {
82
89
  parseRiddleProofHandoffReceipt,
83
90
  riddleProofChangeReceiptHtml,
84
91
  riddleProofChangeReceiptMarkdown
85
- } from "./chunk-IL7MLYB5.js";
92
+ } from "./chunk-LR4UYJDY.js";
86
93
  import {
87
94
  RIDDLE_PREVIEW_RECEIPT_VERSION,
88
95
  RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
@@ -122,7 +129,7 @@ import {
122
129
  resolveRiddleProofProfileTimeoutSec,
123
130
  slugifyRiddleProofProfileName,
124
131
  summarizeRiddleProofProfileResult
125
- } from "./chunk-ZNVYJFR7.js";
132
+ } from "./chunk-2K3DIK7A.js";
126
133
  import {
127
134
  createCodexExecAgentAdapter,
128
135
  createCodexExecJsonRunner,
@@ -238,6 +245,7 @@ export {
238
245
  RIDDLE_PROOF_PR_COMMENT_MARKER,
239
246
  RIDDLE_PROOF_RUN_CARD_VERSION,
240
247
  RIDDLE_PROOF_RUN_STATE_VERSION,
248
+ RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
241
249
  RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION,
242
250
  RIDDLE_PROOF_VISUAL_SESSION_VERSION,
243
251
  RIDDLE_UNSUBMITTED_WAKE_HINT,
@@ -279,6 +287,7 @@ export {
279
287
  compactBasicGameplayText,
280
288
  compactRecord,
281
289
  compareVisualProofSessionFingerprint,
290
+ composeRiddleProofSemanticCertificates,
282
291
  createBasicGameplayCatchRecords,
283
292
  createBasicGameplayCatchSummary,
284
293
  createCaptureDiagnostic,
@@ -296,6 +305,7 @@ export {
296
305
  createRiddleProofProfileEnvironmentBlockedResult,
297
306
  createRiddleProofProfileInsufficientResult,
298
307
  createRiddleProofRunCard,
308
+ createRiddleProofSemanticCertificate,
299
309
  createRunResult,
300
310
  createRunState,
301
311
  createRunStatusSnapshot,
@@ -325,6 +335,7 @@ export {
325
335
  parseRiddleProofChangeReceipt,
326
336
  parseRiddleProofHandoffReceipt,
327
337
  parseRiddleProofObservationReceipt,
338
+ parseRiddleProofSemanticCertificate,
328
339
  parseRiddleViewport,
329
340
  parseVisualProofSession,
330
341
  pollRiddleJob,
@@ -348,6 +359,7 @@ export {
348
359
  riddleProofPublicStateAllowsClaim,
349
360
  riddleProofPublicStateAllowsMergeRecommendation,
350
361
  riddleProofPublicStateMergeRecommendation,
362
+ riddleProofSemanticScopesEqual,
351
363
  riddleRequestJson,
352
364
  runCodexExecAgentDoctor,
353
365
  runCodexExecAgentDoctor as runLocalAgentDoctor,
@@ -3,10 +3,10 @@ import {
3
3
  buildRiddleProofHandoffPrCommentMarkdown,
4
4
  buildRiddleProofPrCommentMarkdown,
5
5
  summarizeRiddleProofPrComment
6
- } from "./chunk-6T6ZAK77.js";
7
- import "./chunk-IL7MLYB5.js";
6
+ } from "./chunk-7OAETQU3.js";
7
+ import "./chunk-LR4UYJDY.js";
8
8
  import "./chunk-MEVVL4TI.js";
9
- import "./chunk-ZNVYJFR7.js";
9
+ import "./chunk-2K3DIK7A.js";
10
10
  import "./chunk-ZAR7BWMN.js";
11
11
  import "./chunk-MLKGABMK.js";
12
12
  export {
@@ -1200,10 +1200,14 @@ function normalizeViewport(input, index) {
1200
1200
  if (!width || !height || width < 100 || height < 100) {
1201
1201
  throw new Error(`target.viewports[${index}] requires numeric width and height >= 100.`);
1202
1202
  }
1203
+ const hasTouch = booleanValue(valueFromOwn(input, "hasTouch", "has_touch"));
1204
+ const isMobile = booleanValue(valueFromOwn(input, "isMobile", "is_mobile"));
1203
1205
  return {
1204
1206
  name: normalizeName(input.name || input.label, `viewport-${index + 1}`),
1205
1207
  width: Math.round(width),
1206
- height: Math.round(height)
1208
+ height: Math.round(height),
1209
+ ...hasTouch === void 0 ? {} : { hasTouch },
1210
+ ...isMobile === void 0 ? {} : { isMobile }
1207
1211
  };
1208
1212
  }
1209
1213
  function normalizeViewports(value) {
@@ -30,7 +30,7 @@ import {
30
30
  resolveRiddleProofProfileTimeoutSec,
31
31
  slugifyRiddleProofProfileName,
32
32
  summarizeRiddleProofProfileResult
33
- } from "../chunk-ZNVYJFR7.js";
33
+ } from "../chunk-2K3DIK7A.js";
34
34
  import "../chunk-MLKGABMK.js";
35
35
  export {
36
36
  RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  RIDDLE_PROOF_PROFILE_SUGGESTIONS_VERSION,
3
3
  suggestRiddleProofProfileChecks
4
- } from "./chunk-A4EF4M3B.js";
5
- import "./chunk-ZNVYJFR7.js";
4
+ } from "./chunk-FW7CKARF.js";
5
+ import "./chunk-2K3DIK7A.js";
6
6
  import "./chunk-MLKGABMK.js";
7
7
  export {
8
8
  RIDDLE_PROOF_PROFILE_SUGGESTIONS_VERSION,
package/dist/profile.cjs CHANGED
@@ -1198,10 +1198,14 @@ function normalizeViewport(input, index) {
1198
1198
  if (!width || !height || width < 100 || height < 100) {
1199
1199
  throw new Error(`target.viewports[${index}] requires numeric width and height >= 100.`);
1200
1200
  }
1201
+ const hasTouch = booleanValue(valueFromOwn(input, "hasTouch", "has_touch"));
1202
+ const isMobile = booleanValue(valueFromOwn(input, "isMobile", "is_mobile"));
1201
1203
  return {
1202
1204
  name: normalizeName(input.name || input.label, `viewport-${index + 1}`),
1203
1205
  width: Math.round(width),
1204
- height: Math.round(height)
1206
+ height: Math.round(height),
1207
+ ...hasTouch === void 0 ? {} : { hasTouch },
1208
+ ...isMobile === void 0 ? {} : { isMobile }
1205
1209
  };
1206
1210
  }
1207
1211
  function normalizeViewports(value) {
@@ -137,6 +137,8 @@ interface RiddleProofProfileViewport {
137
137
  name: string;
138
138
  width: number;
139
139
  height: number;
140
+ hasTouch?: boolean;
141
+ isMobile?: boolean;
140
142
  }
141
143
  interface RiddleProofProfileSetupAction {
142
144
  type: RiddleProofProfileSetupActionType;
package/dist/profile.d.ts CHANGED
@@ -137,6 +137,8 @@ interface RiddleProofProfileViewport {
137
137
  name: string;
138
138
  width: number;
139
139
  height: number;
140
+ hasTouch?: boolean;
141
+ isMobile?: boolean;
140
142
  }
141
143
  interface RiddleProofProfileSetupAction {
142
144
  type: RiddleProofProfileSetupActionType;
package/dist/profile.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  resolveRiddleProofProfileTimeoutSec,
31
31
  slugifyRiddleProofProfileName,
32
32
  summarizeRiddleProofProfileResult
33
- } from "./chunk-ZNVYJFR7.js";
33
+ } from "./chunk-2K3DIK7A.js";
34
34
  import "./chunk-MLKGABMK.js";
35
35
  export {
36
36
  RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
@@ -0,0 +1,497 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/semantic-certificate.ts
21
+ var semantic_certificate_exports = {};
22
+ __export(semantic_certificate_exports, {
23
+ RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION: () => RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
24
+ composeRiddleProofSemanticCertificates: () => composeRiddleProofSemanticCertificates,
25
+ createRiddleProofSemanticCertificate: () => createRiddleProofSemanticCertificate,
26
+ parseRiddleProofSemanticCertificate: () => parseRiddleProofSemanticCertificate,
27
+ riddleProofSemanticScopesEqual: () => riddleProofSemanticScopesEqual
28
+ });
29
+ module.exports = __toCommonJS(semantic_certificate_exports);
30
+ var import_node_crypto = require("crypto");
31
+ var RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION = "riddle-proof.semantic-certificate.v0";
32
+ var SCOPE_FIELDS = [
33
+ "repository",
34
+ "revision",
35
+ "environment",
36
+ "target",
37
+ "proof_attempt"
38
+ ];
39
+ var AUTHORITY_FIELDS = [
40
+ "authority",
41
+ "status",
42
+ "verdict",
43
+ "ready_to_ship",
44
+ "merge_ready",
45
+ "sync_allowed",
46
+ "ship_authorized",
47
+ "shipping_authorized",
48
+ "shipping_disabled",
49
+ "merge_recommended",
50
+ "merge_recommendation",
51
+ "shipping_authorization"
52
+ ];
53
+ var CERTIFICATE_FIELDS = /* @__PURE__ */ new Set([
54
+ "version",
55
+ "certificate_id",
56
+ "scope",
57
+ "claim",
58
+ "evidence",
59
+ "derivation",
60
+ "issued_at"
61
+ ]);
62
+ function isRecord(value) {
63
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
64
+ }
65
+ function assertOnlyKeys(record, allowed, context) {
66
+ const allowedSet = new Set(allowed);
67
+ for (const key of Object.keys(record)) {
68
+ if (!allowedSet.has(key)) {
69
+ throw new Error(`${context} contains unsupported field ${key}.`);
70
+ }
71
+ }
72
+ }
73
+ function requiredString(record, key, context) {
74
+ const value = record[key];
75
+ if (typeof value !== "string" || !value.trim()) {
76
+ throw new Error(`${context}.${key} must be a non-empty string.`);
77
+ }
78
+ return value.trim();
79
+ }
80
+ function optionalString(record, key, context) {
81
+ if (record[key] === void 0) return void 0;
82
+ return requiredString(record, key, context);
83
+ }
84
+ function isJsonValue(value, ancestors = /* @__PURE__ */ new Set()) {
85
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
86
+ return true;
87
+ }
88
+ if (typeof value === "number") return Number.isFinite(value);
89
+ if (Array.isArray(value)) {
90
+ if (ancestors.has(value)) return false;
91
+ ancestors.add(value);
92
+ const valid2 = value.every((entry) => isJsonValue(entry, ancestors));
93
+ ancestors.delete(value);
94
+ return valid2;
95
+ }
96
+ if (!isRecord(value)) return false;
97
+ const prototype = Object.getPrototypeOf(value);
98
+ if (prototype !== Object.prototype && prototype !== null) return false;
99
+ if (ancestors.has(value)) return false;
100
+ ancestors.add(value);
101
+ const valid = Object.values(value).every((entry) => isJsonValue(entry, ancestors));
102
+ ancestors.delete(value);
103
+ return valid;
104
+ }
105
+ function parseJsonObject(value, context) {
106
+ if (value === void 0) return void 0;
107
+ if (!isRecord(value) || !isJsonValue(value)) {
108
+ throw new Error(`${context} must be a JSON object.`);
109
+ }
110
+ const cloned = JSON.parse(JSON.stringify(value));
111
+ if (!isRecord(cloned) || !isJsonValue(cloned)) {
112
+ throw new Error(`${context} must remain a JSON object when serialized.`);
113
+ }
114
+ return cloned;
115
+ }
116
+ function parseIssuedAt(value, context) {
117
+ if (typeof value !== "string" || !value.trim() || !Number.isFinite(Date.parse(value))) {
118
+ throw new Error(`${context} must be a valid timestamp.`);
119
+ }
120
+ return value.trim();
121
+ }
122
+ function parseScope(value, context) {
123
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
124
+ assertOnlyKeys(value, SCOPE_FIELDS, context);
125
+ return {
126
+ repository: requiredString(value, "repository", context),
127
+ revision: requiredString(value, "revision", context),
128
+ environment: requiredString(value, "environment", context),
129
+ target: requiredString(value, "target", context),
130
+ proof_attempt: requiredString(value, "proof_attempt", context)
131
+ };
132
+ }
133
+ function parseClaimRef(value, context, allowedExtras = []) {
134
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
135
+ assertOnlyKeys(value, ["claim_id", "claim_version", "parameters", ...allowedExtras], context);
136
+ const parameters = parseJsonObject(value.parameters, `${context}.parameters`);
137
+ return {
138
+ claim_id: requiredString(value, "claim_id", context),
139
+ claim_version: requiredString(value, "claim_version", context),
140
+ ...parameters ? { parameters } : {}
141
+ };
142
+ }
143
+ function parseClaim(value, context) {
144
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
145
+ return {
146
+ ...parseClaimRef(value, context, ["label"]),
147
+ label: requiredString(value, "label", context)
148
+ };
149
+ }
150
+ function parseEvidenceRef(value, context) {
151
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
152
+ assertOnlyKeys(
153
+ value,
154
+ ["receipt_id", "artifact_digest", "role", "artifact_url", "artifact_path"],
155
+ context
156
+ );
157
+ const artifactDigest = requiredString(value, "artifact_digest", context).toLowerCase();
158
+ if (!/^sha256:[0-9a-f]{64}$/u.test(artifactDigest)) {
159
+ throw new Error(`${context}.artifact_digest must be a full sha256 digest.`);
160
+ }
161
+ const artifactUrl = optionalString(value, "artifact_url", context);
162
+ const artifactPath = optionalString(value, "artifact_path", context);
163
+ return {
164
+ receipt_id: requiredString(value, "receipt_id", context),
165
+ artifact_digest: artifactDigest,
166
+ role: requiredString(value, "role", context),
167
+ ...artifactUrl ? { artifact_url: artifactUrl } : {},
168
+ ...artifactPath ? { artifact_path: artifactPath } : {}
169
+ };
170
+ }
171
+ function parseEvidenceBundle(value, context) {
172
+ if (!Array.isArray(value) || value.length === 0) {
173
+ throw new Error(`${context} must contain at least one evidence reference.`);
174
+ }
175
+ return value.map((entry, index) => parseEvidenceRef(entry, `${context}[${index}]`));
176
+ }
177
+ function parseContractRef(value, context) {
178
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
179
+ return {
180
+ contract_id: requiredString(value, "contract_id", context),
181
+ contract_version: requiredString(value, "contract_version", context),
182
+ label: requiredString(value, "label", context)
183
+ };
184
+ }
185
+ function parseContract(value, context, allowRuntimePredicate = false) {
186
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
187
+ assertOnlyKeys(
188
+ value,
189
+ ["contract_id", "contract_version", "label", "claim", ...allowRuntimePredicate ? ["accepts"] : []],
190
+ context
191
+ );
192
+ if (allowRuntimePredicate && typeof value.accepts !== "function") {
193
+ throw new Error(`${context}.accepts must be a function.`);
194
+ }
195
+ return {
196
+ ...parseContractRef(value, context),
197
+ claim: parseClaim(value.claim, `${context}.claim`)
198
+ };
199
+ }
200
+ function parseRule(value, context, allowFullPremises = false) {
201
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
202
+ assertOnlyKeys(value, ["rule_id", "rule_version", "label", "premises", "conclusion"], context);
203
+ if (!Array.isArray(value.premises) || value.premises.length === 0) {
204
+ throw new Error(`${context}.premises must contain at least one claim reference.`);
205
+ }
206
+ return {
207
+ rule_id: requiredString(value, "rule_id", context),
208
+ rule_version: requiredString(value, "rule_version", context),
209
+ label: requiredString(value, "label", context),
210
+ premises: value.premises.map((premise, index) => parseClaimRef(
211
+ premise,
212
+ `${context}.premises[${index}]`,
213
+ allowFullPremises ? ["label"] : []
214
+ )),
215
+ conclusion: parseClaim(value.conclusion, `${context}.conclusion`)
216
+ };
217
+ }
218
+ function parsePremise(value, context) {
219
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
220
+ assertOnlyKeys(
221
+ value,
222
+ ["certificate_id", "derivation_kind", "assurance", "scope", "claim", "evidence"],
223
+ context
224
+ );
225
+ const derivationKind = requiredString(value, "derivation_kind", context);
226
+ const assurance = requiredString(value, "assurance", context);
227
+ const validAssurance = derivationKind === "contract" && assurance === "runtime_contract_accepted" || derivationKind === "composition" && assurance === "declared_runtime_rule";
228
+ if (!validAssurance) {
229
+ throw new Error(`${context} must preserve a valid derivation_kind and assurance pair.`);
230
+ }
231
+ return {
232
+ certificate_id: requiredString(value, "certificate_id", context),
233
+ derivation_kind: derivationKind,
234
+ assurance,
235
+ scope: parseScope(value.scope, `${context}.scope`),
236
+ claim: parseClaim(value.claim, `${context}.claim`),
237
+ evidence: parseEvidenceBundle(value.evidence, `${context}.evidence`)
238
+ };
239
+ }
240
+ function stableJson(value) {
241
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
242
+ if (isRecord(value)) {
243
+ return `{${Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
244
+ }
245
+ const encoded = JSON.stringify(value);
246
+ if (encoded === void 0) throw new Error("Semantic certificate contains a non-JSON value.");
247
+ return encoded;
248
+ }
249
+ function sameClaimRef(left, right) {
250
+ return left.claim_id === right.claim_id && left.claim_version === right.claim_version && stableJson(left.parameters || {}) === stableJson(right.parameters || {});
251
+ }
252
+ function sameEvidence(left, right) {
253
+ return stableJson(left) === stableJson(right);
254
+ }
255
+ function certificateId(body) {
256
+ const digest = (0, import_node_crypto.createHash)("sha256").update(stableJson(body)).digest("hex");
257
+ return `rpsc_${digest}`;
258
+ }
259
+ function withCertificateId(body) {
260
+ return { ...body, certificate_id: certificateId(body) };
261
+ }
262
+ function parseDerivation(value, context) {
263
+ if (!isRecord(value)) throw new Error(`${context} must be an object.`);
264
+ const kind = requiredString(value, "kind", context);
265
+ if (kind === "contract") {
266
+ assertOnlyKeys(value, ["kind", "assurance", "contract"], context);
267
+ if (value.assurance !== "runtime_contract_accepted") {
268
+ throw new Error(`${context}.assurance must be runtime_contract_accepted.`);
269
+ }
270
+ return {
271
+ kind,
272
+ assurance: "runtime_contract_accepted",
273
+ contract: parseContract(value.contract, `${context}.contract`)
274
+ };
275
+ }
276
+ if (kind === "composition") {
277
+ assertOnlyKeys(value, ["kind", "assurance", "rule", "premises"], context);
278
+ if (value.assurance !== "declared_runtime_rule") {
279
+ throw new Error(`${context}.assurance must be declared_runtime_rule.`);
280
+ }
281
+ if (!Array.isArray(value.premises) || value.premises.length === 0) {
282
+ throw new Error(`${context}.premises must contain at least one certificate premise.`);
283
+ }
284
+ return {
285
+ kind,
286
+ assurance: "declared_runtime_rule",
287
+ rule: parseRule(value.rule, `${context}.rule`),
288
+ premises: value.premises.map((premise, index) => parsePremise(premise, `${context}.premises[${index}]`))
289
+ };
290
+ }
291
+ throw new Error(`${context}.kind must be contract or composition.`);
292
+ }
293
+ function riddleProofSemanticScopesEqual(left, right) {
294
+ return SCOPE_FIELDS.every((field) => left[field] === right[field]);
295
+ }
296
+ function createRiddleProofSemanticCertificate(input) {
297
+ if (!isRecord(input)) throw new Error("Semantic certificate input must be an object.");
298
+ assertOnlyKeys(
299
+ input,
300
+ ["scope", "evidence", "observation", "contract", "issued_at"],
301
+ "semantic certificate input"
302
+ );
303
+ const scope = parseScope(input.scope, "semantic certificate scope");
304
+ const evidence = parseEvidenceBundle(input.evidence, "semantic certificate evidence");
305
+ const contract = parseContract(input.contract, "semantic certificate contract", true);
306
+ const contractRef = {
307
+ contract_id: contract.contract_id,
308
+ contract_version: contract.contract_version,
309
+ label: contract.label
310
+ };
311
+ const claim = contract.claim;
312
+ let accepted;
313
+ try {
314
+ accepted = input.contract.accepts({ ...scope }, input.observation) === true;
315
+ } catch (error) {
316
+ return {
317
+ ok: false,
318
+ error: {
319
+ code: "contract_error",
320
+ contract: contractRef,
321
+ message: `Semantic contract evaluation failed: ${error instanceof Error ? error.message : String(error)}.`
322
+ }
323
+ };
324
+ }
325
+ if (!accepted) {
326
+ return {
327
+ ok: false,
328
+ error: {
329
+ code: "contract_rejected",
330
+ contract: contractRef,
331
+ message: "Semantic contract rejected the supplied observation at this scope."
332
+ }
333
+ };
334
+ }
335
+ const body = {
336
+ version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
337
+ scope,
338
+ claim,
339
+ evidence,
340
+ derivation: { kind: "contract", assurance: "runtime_contract_accepted", contract },
341
+ issued_at: parseIssuedAt(input.issued_at || (/* @__PURE__ */ new Date()).toISOString(), "semantic certificate issued_at")
342
+ };
343
+ return { ok: true, certificate: withCertificateId(body) };
344
+ }
345
+ function parseRiddleProofSemanticCertificate(value) {
346
+ if (!isRecord(value)) throw new Error("Semantic certificate must be an object.");
347
+ if (value.version !== RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION) {
348
+ throw new Error(`Unsupported Semantic certificate version ${String(value.version || "missing")}.`);
349
+ }
350
+ for (const field of AUTHORITY_FIELDS) {
351
+ if (Object.prototype.hasOwnProperty.call(value, field)) {
352
+ throw new Error(`Semantic certificate must not contain authority field ${field}.`);
353
+ }
354
+ }
355
+ for (const field of Object.keys(value)) {
356
+ if (!CERTIFICATE_FIELDS.has(field)) {
357
+ throw new Error(`Semantic certificate contains unsupported field ${field}.`);
358
+ }
359
+ }
360
+ const scope = parseScope(value.scope, "semantic certificate scope");
361
+ const claim = parseClaim(value.claim, "semantic certificate claim");
362
+ const evidence = parseEvidenceBundle(value.evidence, "semantic certificate evidence");
363
+ const derivation = parseDerivation(value.derivation, "semantic certificate derivation");
364
+ if (derivation.kind === "contract" && !sameClaimRef(claim, derivation.contract.claim)) {
365
+ throw new Error("Semantic contract-derived claim must match its contract claim.");
366
+ }
367
+ if (derivation.kind === "composition") {
368
+ if (derivation.premises.length !== derivation.rule.premises.length) {
369
+ throw new Error("Semantic composition premises must match the rule premise count.");
370
+ }
371
+ derivation.premises.forEach((premise, index) => {
372
+ if (!riddleProofSemanticScopesEqual(scope, premise.scope)) {
373
+ throw new Error(`Semantic composition premise ${index} must have the certificate scope.`);
374
+ }
375
+ if (!sameClaimRef(premise.claim, derivation.rule.premises[index])) {
376
+ throw new Error(`Semantic composition premise ${index} must match its rule claim.`);
377
+ }
378
+ });
379
+ if (!sameClaimRef(claim, derivation.rule.conclusion)) {
380
+ throw new Error("Semantic composition claim must match its rule conclusion.");
381
+ }
382
+ const expectedEvidence = derivation.premises.flatMap((premise) => premise.evidence);
383
+ if (!sameEvidence(evidence, expectedEvidence)) {
384
+ throw new Error("Semantic composition evidence must be the ordered concatenation of premise evidence.");
385
+ }
386
+ }
387
+ const body = {
388
+ version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
389
+ scope,
390
+ claim,
391
+ evidence,
392
+ derivation,
393
+ issued_at: parseIssuedAt(value.issued_at, "semantic certificate issued_at")
394
+ };
395
+ const observedId = requiredString(value, "certificate_id", "semantic certificate");
396
+ const expectedId = certificateId(body);
397
+ if (observedId !== expectedId) {
398
+ throw new Error("Semantic certificate_id must match its content.");
399
+ }
400
+ return { ...body, certificate_id: observedId };
401
+ }
402
+ function firstScopeMismatch(expected, observed) {
403
+ for (const field of SCOPE_FIELDS) {
404
+ if (expected[field] !== observed[field]) {
405
+ return { field, expected: expected[field], observed: observed[field] };
406
+ }
407
+ }
408
+ return void 0;
409
+ }
410
+ function premiseFromCertificate(certificate) {
411
+ return {
412
+ certificate_id: certificate.certificate_id,
413
+ derivation_kind: certificate.derivation.kind,
414
+ assurance: certificate.derivation.assurance,
415
+ scope: { ...certificate.scope },
416
+ claim: parseClaim(certificate.claim, "semantic composition premise claim"),
417
+ evidence: certificate.evidence.map((entry) => ({ ...entry }))
418
+ };
419
+ }
420
+ function composeRiddleProofSemanticCertificates(input) {
421
+ if (!isRecord(input)) throw new Error("Semantic composition input must be an object.");
422
+ assertOnlyKeys(
423
+ input,
424
+ ["rule", "certificates", "issued_at"],
425
+ "semantic composition input"
426
+ );
427
+ const rule = parseRule(input.rule, "semantic composition rule", true);
428
+ if (!Array.isArray(input.certificates) || input.certificates.length === 0) {
429
+ throw new Error("Semantic composition requires at least one certificate.");
430
+ }
431
+ const certificates = input.certificates.map((certificate) => parseRiddleProofSemanticCertificate(certificate));
432
+ if (certificates.length !== rule.premises.length) {
433
+ return {
434
+ ok: false,
435
+ error: {
436
+ code: "premise_count_mismatch",
437
+ expected: rule.premises.length,
438
+ observed: certificates.length,
439
+ message: `Semantic rule expected ${rule.premises.length} certificate(s), received ${certificates.length}.`
440
+ }
441
+ };
442
+ }
443
+ const expectedScope = certificates[0].scope;
444
+ for (let index = 1; index < certificates.length; index += 1) {
445
+ const mismatch = firstScopeMismatch(expectedScope, certificates[index].scope);
446
+ if (mismatch) {
447
+ return {
448
+ ok: false,
449
+ error: {
450
+ code: "scope_mismatch",
451
+ input_index: index,
452
+ ...mismatch,
453
+ message: `Semantic certificate ${index} has a different ${mismatch.field}.`
454
+ }
455
+ };
456
+ }
457
+ }
458
+ for (let index = 0; index < certificates.length; index += 1) {
459
+ const expected = rule.premises[index];
460
+ const observed = certificates[index].claim;
461
+ if (!sameClaimRef(expected, observed)) {
462
+ return {
463
+ ok: false,
464
+ error: {
465
+ code: "premise_mismatch",
466
+ input_index: index,
467
+ expected,
468
+ observed: parseClaimRef(observed, "semantic composition observed claim", ["label"]),
469
+ message: `Semantic certificate ${index} does not satisfy its declared rule premise.`
470
+ }
471
+ };
472
+ }
473
+ }
474
+ const evidence = certificates.flatMap((certificate) => certificate.evidence);
475
+ const body = {
476
+ version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
477
+ scope: { ...expectedScope },
478
+ claim: { ...rule.conclusion },
479
+ evidence,
480
+ derivation: {
481
+ kind: "composition",
482
+ assurance: "declared_runtime_rule",
483
+ rule,
484
+ premises: certificates.map(premiseFromCertificate)
485
+ },
486
+ issued_at: parseIssuedAt(input.issued_at || (/* @__PURE__ */ new Date()).toISOString(), "semantic certificate issued_at")
487
+ };
488
+ return { ok: true, certificate: withCertificateId(body) };
489
+ }
490
+ // Annotate the CommonJS export names for ESM import in node:
491
+ 0 && (module.exports = {
492
+ RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
493
+ composeRiddleProofSemanticCertificates,
494
+ createRiddleProofSemanticCertificate,
495
+ parseRiddleProofSemanticCertificate,
496
+ riddleProofSemanticScopesEqual
497
+ });