@granular-software/sdk 0.4.72 → 0.4.73

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.mjs CHANGED
@@ -4278,8 +4278,8 @@ function normalizeFeedItems(values) {
4278
4278
  return { items: Object.freeze(items), error };
4279
4279
  }
4280
4280
  function normalizeTransients(values) {
4281
- const record2 = asRecord(values);
4282
- if (!record2) {
4281
+ const record3 = asRecord(values);
4282
+ if (!record3) {
4283
4283
  return {
4284
4284
  items: [],
4285
4285
  error: new Error("Canonical feed transientById is not an object.")
@@ -4288,7 +4288,7 @@ function normalizeTransients(values) {
4288
4288
  let error = null;
4289
4289
  const byId = /* @__PURE__ */ new Map();
4290
4290
  const idByOrdinal = /* @__PURE__ */ new Map();
4291
- for (const [key, value] of Object.entries(record2)) {
4291
+ for (const [key, value] of Object.entries(record3)) {
4292
4292
  const item = normalizeTransientFeedItem(value);
4293
4293
  if (!item || item.id !== key) {
4294
4294
  error ||= new Error("Canonical feed contains an invalid transient item.");
@@ -5161,11 +5161,11 @@ function operationId(prefix) {
5161
5161
  return randomUuid ? `${prefix}_${randomUuid}` : `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
5162
5162
  }
5163
5163
  function unwrapPublishedItem(value) {
5164
- const record2 = asRecord(value);
5165
- const directItems = Array.isArray(record2?.items) ? record2.items : [];
5166
- const durable = asRecord(record2?.durable);
5164
+ const record3 = asRecord(value);
5165
+ const directItems = Array.isArray(record3?.items) ? record3.items : [];
5166
+ const durable = asRecord(record3?.durable);
5167
5167
  const durableItems = Array.isArray(durable?.items) ? durable.items : [];
5168
- return record2?.item || directItems[0] || durableItems[0] || value;
5168
+ return record3?.item || directItems[0] || durableItems[0] || value;
5169
5169
  }
5170
5170
  function requireFeedbackItem(value) {
5171
5171
  const item = normalizeFeedItem(unwrapPublishedItem(value));
@@ -5287,9 +5287,9 @@ var DEFAULT_MAX_RECONNECT_ATTEMPTS = 5;
5287
5287
  var DOCUMENT_RESYNC_CLOSE_CODE = 4e3;
5288
5288
  var DOCUMENT_RESYNC_CLOSE_REASON = "Document resync required";
5289
5289
  function documentVersion(document) {
5290
- const record2 = document;
5291
- const epochValue = record2.documentEpoch;
5292
- const revisionValue = record2.documentRevision;
5290
+ const record3 = document;
5291
+ const epochValue = record3.documentEpoch;
5292
+ const revisionValue = record3.documentRevision;
5293
5293
  const epoch = epochValue === void 0 ? 0 : epochValue;
5294
5294
  const revision = revisionValue === void 0 ? 0 : revisionValue;
5295
5295
  if (!Number.isSafeInteger(epoch) || Number(epoch) < 0 || !Number.isSafeInteger(revision) || Number(revision) < 0) {
@@ -5311,9 +5311,9 @@ function stableDocumentFingerprint(value) {
5311
5311
  if (Array.isArray(value)) {
5312
5312
  return `[${value.map(stableDocumentFingerprint).join(",")}]`;
5313
5313
  }
5314
- const record2 = value;
5315
- return `{${Object.keys(record2).sort().map(
5316
- (key) => `${JSON.stringify(key)}:${stableDocumentFingerprint(record2[key])}`
5314
+ const record3 = value;
5315
+ return `{${Object.keys(record3).sort().map(
5316
+ (key) => `${JSON.stringify(key)}:${stableDocumentFingerprint(record3[key])}`
5317
5317
  ).join(",")}}`;
5318
5318
  }
5319
5319
  function canonicalDocumentFingerprint(value) {
@@ -5323,9 +5323,9 @@ function canonicalDocumentFingerprint(value) {
5323
5323
  if (Array.isArray(input)) {
5324
5324
  return input.map((entry) => stripPresentation(entry, path));
5325
5325
  }
5326
- const record2 = input;
5326
+ const record3 = input;
5327
5327
  const output = {};
5328
- for (const [key, entry] of Object.entries(record2)) {
5328
+ for (const [key, entry] of Object.entries(record3)) {
5329
5329
  if (path.length === 1 && path[0] === "feed" && [
5330
5330
  "transientById",
5331
5331
  "feedbackUsageByJob",
@@ -6429,30 +6429,30 @@ function parseJsonPromptChoiceOption(option) {
6429
6429
  }
6430
6430
  function normalizePromptChoiceOption(option) {
6431
6431
  if (typeof option === "string") {
6432
- const record3 = parseJsonPromptChoiceOption(option);
6433
- if (!record3) {
6432
+ const record4 = parseJsonPromptChoiceOption(option);
6433
+ if (!record4) {
6434
6434
  return { value: option, label: option };
6435
6435
  }
6436
- const value2 = typeof record3.value === "string" ? record3.value : typeof record3.id === "string" ? record3.id : typeof record3.label === "string" ? record3.label : JSON.stringify(record3);
6436
+ const value2 = typeof record4.value === "string" ? record4.value : typeof record4.id === "string" ? record4.id : typeof record4.label === "string" ? record4.label : JSON.stringify(record4);
6437
6437
  return {
6438
6438
  value: value2,
6439
- label: typeof record3.label === "string" ? record3.label : value2,
6440
- description: typeof record3.description === "string" ? record3.description : void 0
6439
+ label: typeof record4.label === "string" ? record4.label : value2,
6440
+ description: typeof record4.description === "string" ? record4.description : void 0
6441
6441
  };
6442
6442
  }
6443
- const record2 = option;
6444
- if (!record2) {
6443
+ const record3 = option;
6444
+ if (!record3) {
6445
6445
  return { value: "", label: "" };
6446
6446
  }
6447
- const nestedJson = (typeof record2.value === "string" ? parseJsonPromptChoiceOption(record2.value) : null) || (typeof record2.label === "string" ? parseJsonPromptChoiceOption(record2.label) : null);
6447
+ const nestedJson = (typeof record3.value === "string" ? parseJsonPromptChoiceOption(record3.value) : null) || (typeof record3.label === "string" ? parseJsonPromptChoiceOption(record3.label) : null);
6448
6448
  if (nestedJson) {
6449
6449
  return normalizePromptChoiceOption(nestedJson);
6450
6450
  }
6451
- const value = typeof record2.value === "string" ? record2.value : typeof record2.label === "string" ? record2.label : JSON.stringify(record2);
6451
+ const value = typeof record3.value === "string" ? record3.value : typeof record3.label === "string" ? record3.label : JSON.stringify(record3);
6452
6452
  return {
6453
6453
  value,
6454
- label: typeof record2.label === "string" ? record2.label : value,
6455
- description: typeof record2.description === "string" ? record2.description : void 0
6454
+ label: typeof record3.label === "string" ? record3.label : value,
6455
+ description: typeof record3.description === "string" ? record3.description : void 0
6456
6456
  };
6457
6457
  }
6458
6458
  function scorePromptChoiceMatch(answer, answerTokens, option) {
@@ -7960,8 +7960,8 @@ function artifactRecordsById(liveDoc) {
7960
7960
  const byId = asRecord3(artifacts?.byId) || {};
7961
7961
  return Object.fromEntries(
7962
7962
  Object.entries(byId).map(([artifactId, value]) => {
7963
- const record2 = asRecord3(value);
7964
- return record2 ? [artifactId, record2] : null;
7963
+ const record3 = asRecord3(value);
7964
+ return record3 ? [artifactId, record3] : null;
7965
7965
  }).filter((entry) => Boolean(entry))
7966
7966
  );
7967
7967
  }
@@ -7994,8 +7994,8 @@ function latestInputEditSummary(metadata) {
7994
7994
  ].filter(Boolean);
7995
7995
  return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
7996
7996
  }
7997
- function artifactIssueSummary(record2) {
7998
- const validation = asRecord3(record2.validation);
7997
+ function artifactIssueSummary(record3) {
7998
+ const validation = asRecord3(record3.validation);
7999
7999
  if (!validation) return null;
8000
8000
  const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
8001
8001
  if (issues.length > 0) {
@@ -8042,18 +8042,18 @@ function artifactStatePathSummary(metadata) {
8042
8042
  ].filter(Boolean);
8043
8043
  return pieces.length ? pieces.join("; ") : null;
8044
8044
  }
8045
- function artifactSummaryLine(artifactId, record2) {
8046
- if (!record2) return `- ${artifactId}: unavailable in session artifact store`;
8047
- const label = trimString(record2.label) || artifactId;
8048
- const kind = asString(record2.kind) || "artifact";
8049
- const status = asString(record2.status) || "unknown";
8050
- const createdByJobId = asString(record2.createdByJobId);
8051
- const target = asRecord3(record2.target);
8052
- const metadata = asRecord3(record2.metadata) || {};
8053
- const subArtifactIds = Array.isArray(record2.subArtifactIds) ? record2.subArtifactIds.filter(
8045
+ function artifactSummaryLine(artifactId, record3) {
8046
+ if (!record3) return `- ${artifactId}: unavailable in session artifact store`;
8047
+ const label = trimString(record3.label) || artifactId;
8048
+ const kind = asString(record3.kind) || "artifact";
8049
+ const status = asString(record3.status) || "unknown";
8050
+ const createdByJobId = asString(record3.createdByJobId);
8051
+ const target = asRecord3(record3.target);
8052
+ const metadata = asRecord3(record3.metadata) || {};
8053
+ const subArtifactIds = Array.isArray(record3.subArtifactIds) ? record3.subArtifactIds.filter(
8054
8054
  (id) => typeof id === "string" && id.trim().length > 0
8055
8055
  ).slice(0, 8) : [];
8056
- const relationships = compactJson(record2.relationships, 220);
8056
+ const relationships = compactJson(record3.relationships, 220);
8057
8057
  const pieces = [
8058
8058
  `kind=${kind}`,
8059
8059
  `status=${status}`,
@@ -8061,7 +8061,7 @@ function artifactSummaryLine(artifactId, record2) {
8061
8061
  target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
8062
8062
  artifactStatePathSummary(metadata),
8063
8063
  artifactExecutionSummary(metadata),
8064
- artifactIssueSummary(record2),
8064
+ artifactIssueSummary(record3),
8065
8065
  latestInputEditSummary(metadata),
8066
8066
  subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
8067
8067
  relationships ? `relationships=${relationships}` : null
@@ -13172,6 +13172,300 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
13172
13172
  }
13173
13173
  });
13174
13174
 
13175
+ // src/record-snapshot-projection.ts
13176
+ function stableValue(value) {
13177
+ if (Array.isArray(value)) return value.map(stableValue);
13178
+ if (value && typeof value === "object") {
13179
+ return Object.fromEntries(
13180
+ Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, stableValue(item)])
13181
+ );
13182
+ }
13183
+ return value;
13184
+ }
13185
+ function stableJson(value) {
13186
+ return JSON.stringify(stableValue(value));
13187
+ }
13188
+ function recordKey(record3) {
13189
+ return `${record3.className}\0${record3.id}`;
13190
+ }
13191
+ function recordReference(className, id) {
13192
+ return { className, id };
13193
+ }
13194
+ function changedRecordSnapshots(beforeRecords, afterRecords) {
13195
+ const before = new Map(
13196
+ beforeRecords.map((record3) => [recordKey(record3), record3])
13197
+ );
13198
+ const after = new Map(
13199
+ afterRecords.map((record3) => [recordKey(record3), record3])
13200
+ );
13201
+ const changedKeys = /* @__PURE__ */ new Set();
13202
+ for (const key of /* @__PURE__ */ new Set([...before.keys(), ...after.keys()])) {
13203
+ if (stableJson(before.get(key)) !== stableJson(after.get(key))) {
13204
+ changedKeys.add(key);
13205
+ }
13206
+ }
13207
+ return {
13208
+ beforeRecords: beforeRecords.filter(
13209
+ (record3) => changedKeys.has(recordKey(record3))
13210
+ ),
13211
+ afterRecords: afterRecords.filter(
13212
+ (record3) => changedKeys.has(recordKey(record3))
13213
+ )
13214
+ };
13215
+ }
13216
+ function relationshipTargets(manifest) {
13217
+ const targets = /* @__PURE__ */ new Map();
13218
+ for (const volume of manifest.volumes) {
13219
+ for (const operation of volume.operations) {
13220
+ const relationship = operation.defineRelationship;
13221
+ if (!relationship) continue;
13222
+ targets.set(`${relationship.left}\0${relationship.leftSubmodel}`, {
13223
+ className: relationship.right
13224
+ });
13225
+ targets.set(`${relationship.right}\0${relationship.rightSubmodel}`, {
13226
+ className: relationship.left
13227
+ });
13228
+ }
13229
+ }
13230
+ return targets;
13231
+ }
13232
+ function stateName(value) {
13233
+ return typeof value === "string" ? value : value.state;
13234
+ }
13235
+ function asIds(value) {
13236
+ return value === void 0 ? [] : Array.isArray(value) ? value : [value];
13237
+ }
13238
+ function changedObjectProjection(before, after) {
13239
+ const beforeFields = before?.fields || {};
13240
+ const afterFields = after.fields || {};
13241
+ const fields = { ...afterFields };
13242
+ for (const fieldName of Object.keys(beforeFields)) {
13243
+ if (!(fieldName in afterFields)) fields[fieldName] = null;
13244
+ }
13245
+ if (before && before.label === after.label && stableJson(beforeFields) === stableJson(afterFields)) {
13246
+ return null;
13247
+ }
13248
+ return {
13249
+ kind: "object",
13250
+ operation: before ? "updated" : "created",
13251
+ record: {
13252
+ className: after.className,
13253
+ id: after.id,
13254
+ ...after.label !== void 0 ? { label: after.label } : {},
13255
+ fields
13256
+ }
13257
+ };
13258
+ }
13259
+ function projectionChanges(input) {
13260
+ const before = new Map(
13261
+ input.beforeRecords.map((record3) => [recordKey(record3), record3])
13262
+ );
13263
+ const after = new Map(
13264
+ input.afterRecords.map((record3) => [recordKey(record3), record3])
13265
+ );
13266
+ const targets = relationshipTargets(input.manifest);
13267
+ const changes = [];
13268
+ for (const record3 of input.afterRecords) {
13269
+ const previous = before.get(recordKey(record3));
13270
+ const objectChange = changedObjectProjection(previous, record3);
13271
+ if (objectChange) changes.push(objectChange);
13272
+ const relationshipNames = /* @__PURE__ */ new Set([
13273
+ ...Object.keys(previous?.relationships || {}),
13274
+ ...Object.keys(record3.relationships || {})
13275
+ ]);
13276
+ for (const relationshipName of [...relationshipNames].sort()) {
13277
+ const target = targets.get(
13278
+ `${record3.className}\0${relationshipName}`
13279
+ );
13280
+ if (!target) {
13281
+ throw new Error(
13282
+ `No ontology relationship target is declared for ${record3.className}.${relationshipName}`
13283
+ );
13284
+ }
13285
+ const previousIds = new Set(
13286
+ asIds(previous?.relationships?.[relationshipName])
13287
+ );
13288
+ const currentIds = new Set(
13289
+ asIds(record3.relationships?.[relationshipName])
13290
+ );
13291
+ for (const id of [...previousIds].sort()) {
13292
+ if (currentIds.has(id)) continue;
13293
+ changes.push({
13294
+ kind: "relationship",
13295
+ operation: "disconnected",
13296
+ relationship: relationshipName,
13297
+ from: recordReference(record3.className, record3.id),
13298
+ to: recordReference(target.className, id)
13299
+ });
13300
+ }
13301
+ for (const id of [...currentIds].sort()) {
13302
+ if (previousIds.has(id)) continue;
13303
+ changes.push({
13304
+ kind: "relationship",
13305
+ operation: "connected",
13306
+ relationship: relationshipName,
13307
+ from: recordReference(record3.className, record3.id),
13308
+ to: recordReference(target.className, id)
13309
+ });
13310
+ }
13311
+ }
13312
+ const machines = /* @__PURE__ */ new Set([
13313
+ ...Object.keys(previous?.states || {}),
13314
+ ...Object.keys(record3.states || {})
13315
+ ]);
13316
+ for (const machine of [...machines].sort()) {
13317
+ const next = record3.states?.[machine];
13318
+ if (next === void 0) continue;
13319
+ const prior = previous?.states?.[machine];
13320
+ if (prior !== void 0 && stateName(prior) === stateName(next)) continue;
13321
+ if (input.transition && input.transition.className === record3.className && input.transition.objectId === record3.id && input.transition.machine === machine) {
13322
+ continue;
13323
+ }
13324
+ changes.push({
13325
+ kind: "state_observation",
13326
+ target: recordReference(record3.className, record3.id),
13327
+ machine,
13328
+ state: stateName(next)
13329
+ });
13330
+ }
13331
+ }
13332
+ for (const record3 of input.beforeRecords) {
13333
+ if (after.has(recordKey(record3))) continue;
13334
+ changes.push({
13335
+ kind: "object",
13336
+ operation: "deleted",
13337
+ target: recordReference(record3.className, record3.id)
13338
+ });
13339
+ }
13340
+ return changes;
13341
+ }
13342
+ function valueAtPath(value, path) {
13343
+ return path.split(".").filter(Boolean).reduce((current, segment) => {
13344
+ if (!current || typeof current !== "object" || Array.isArray(current)) {
13345
+ return void 0;
13346
+ }
13347
+ return current[segment];
13348
+ }, value);
13349
+ }
13350
+ function primaryTarget(input) {
13351
+ if (input.transition) {
13352
+ return recordReference(
13353
+ input.transition.className,
13354
+ input.transition.objectId
13355
+ );
13356
+ }
13357
+ const creates = input.effect.metamodels?.creates;
13358
+ if (creates) {
13359
+ const declaration = typeof creates === "string" ? { className: creates } : creates;
13360
+ const id = declaration.idPath ? valueAtPath(input.result, declaration.idPath) : void 0;
13361
+ if (typeof id === "string" && id) {
13362
+ return recordReference(declaration.className, id);
13363
+ }
13364
+ }
13365
+ if (input.effect.className && !input.effect.static) {
13366
+ const objectId = input.effectInput && typeof input.effectInput === "object" && !Array.isArray(input.effectInput) ? input.effectInput._objectId : void 0;
13367
+ if (typeof objectId === "string" && objectId) {
13368
+ return recordReference(input.effect.className, objectId);
13369
+ }
13370
+ }
13371
+ const created = input.changes.filter(
13372
+ (change) => change.kind === "object" && change.operation === "created"
13373
+ );
13374
+ const onlyCreated = created.length === 1 ? created[0] : void 0;
13375
+ return onlyCreated ? recordReference(onlyCreated.record.className, onlyCreated.record.id) : void 0;
13376
+ }
13377
+ function assertRecordSnapshotTransitionMapping(transition) {
13378
+ if (!transition)
13379
+ throw new Error("A transition commit has no authored transition context.");
13380
+ if (!transition.outcomes || !Object.keys(transition.outcomes).length) {
13381
+ throw new Error(
13382
+ "Automatic product-state mapping requires at least one declared outcome."
13383
+ );
13384
+ }
13385
+ const destinations = /* @__PURE__ */ new Map();
13386
+ for (const [key, outcome] of Object.entries(transition.outcomes)) {
13387
+ if (!outcome || typeof outcome.to !== "string" || !outcome.to) {
13388
+ throw new Error(
13389
+ `Automatic product-state mapping requires a destination for outcome ${key}.`
13390
+ );
13391
+ }
13392
+ const destination = outcome.to === "$current" ? transition.from : outcome.to;
13393
+ const previous = destinations.get(destination);
13394
+ if (previous !== void 0) {
13395
+ throw new Error(
13396
+ `Ambiguous product-state mapping for ${transition.machine}.${transition.transition}: outcomes ${previous} and ${key} both resolve to ${destination}; automatic mapping requires distinct outcome destinations.`
13397
+ );
13398
+ }
13399
+ destinations.set(destination, key);
13400
+ }
13401
+ }
13402
+ function transitionOutcome(transition, afterRecords) {
13403
+ assertRecordSnapshotTransitionMapping(transition);
13404
+ const target = afterRecords.find(
13405
+ (record3) => record3.className === transition.className && record3.id === transition.objectId
13406
+ );
13407
+ const observed = target?.states?.[transition.machine];
13408
+ if (!observed) {
13409
+ throw new Error(
13410
+ `The product result did not expose ${transition.className}:${transition.objectId}.${transition.machine}`
13411
+ );
13412
+ }
13413
+ const finalState = stateName(observed);
13414
+ const matches = Object.entries(transition.outcomes).filter(
13415
+ ([, outcome]) => outcome.to === finalState || outcome.to === "$current" && finalState === transition.from
13416
+ );
13417
+ if (matches.length !== 1) {
13418
+ throw new Error(
13419
+ `Product state ${finalState} maps to ${matches.length} authored outcomes for ${transition.machine}.${transition.transition}`
13420
+ );
13421
+ }
13422
+ const [key, declaration] = matches[0];
13423
+ return {
13424
+ key,
13425
+ ...declaration.disposition === "error" ? {
13426
+ error: {
13427
+ code: `product_outcome_${key}`,
13428
+ message: declaration.label || `The product completed in ${finalState} instead of continuing.`,
13429
+ retryable: false
13430
+ }
13431
+ } : {}
13432
+ };
13433
+ }
13434
+ function projectRecordSnapshotMutation(input) {
13435
+ const changes = projectionChanges({
13436
+ manifest: input.manifest,
13437
+ beforeRecords: input.source.beforeRecords,
13438
+ afterRecords: input.source.afterRecords,
13439
+ transition: input.transition
13440
+ });
13441
+ const target = primaryTarget({
13442
+ effect: input.effect,
13443
+ effectInput: input.effectInput,
13444
+ result: input.result,
13445
+ changes,
13446
+ transition: input.transition
13447
+ });
13448
+ const base = {
13449
+ source: {
13450
+ reference: input.source.reference,
13451
+ ...input.source.version ? { version: input.source.version } : {},
13452
+ ...input.source.versionScope ? { versionScope: input.source.versionScope } : {}
13453
+ },
13454
+ ...target ? { primaryTarget: target } : {},
13455
+ changes,
13456
+ safeSummary: {
13457
+ effect: input.effect.name,
13458
+ affectedChanges: changes.length
13459
+ }
13460
+ };
13461
+ if (input.commitKind === "effect") return base;
13462
+ return {
13463
+ ...base,
13464
+ outcome: transitionOutcome(input.transition, input.source.afterRecords)
13465
+ };
13466
+ }
13467
+ projectRecordSnapshotMutation.validateTransition = assertRecordSnapshotTransitionMapping;
13468
+
13175
13469
  // src/commit.ts
13176
13470
  var MAX_PROJECTION_CHANGES = 1e3;
13177
13471
  var MAX_SAFE_SUMMARY_KEYS = 32;
@@ -13265,18 +13559,18 @@ function validateScalarRecord(value, path) {
13265
13559
  }
13266
13560
  function validateProjectedRecord(value, path) {
13267
13561
  validateObjectReference(value, path);
13268
- const record2 = value;
13269
- if (record2.label !== void 0) {
13270
- if (typeof record2.label !== "string") {
13562
+ const record3 = value;
13563
+ if (record3.label !== void 0) {
13564
+ if (typeof record3.label !== "string") {
13271
13565
  throw new Error(`${path}.label must be a string`);
13272
13566
  }
13273
- if (record2.label.length > MAX_SAFE_TEXT_LENGTH) {
13567
+ if (record3.label.length > MAX_SAFE_TEXT_LENGTH) {
13274
13568
  throw new Error(
13275
13569
  `${path}.label exceeds ${MAX_SAFE_TEXT_LENGTH} characters`
13276
13570
  );
13277
13571
  }
13278
13572
  }
13279
- validateScalarRecord(record2.fields, `${path}.fields`);
13573
+ validateScalarRecord(record3.fields, `${path}.fields`);
13280
13574
  }
13281
13575
  function validateBoundedJson(value, path, depth = 0) {
13282
13576
  if (depth > 12) throw new Error(`${path} is nested too deeply`);
@@ -13780,6 +14074,11 @@ async function invokeRegisteredEffect(effectMap, request, options = {}) {
13780
14074
  `Transition effect ${request.effectKey} has no resolved transition context; customer code was not invoked`
13781
14075
  );
13782
14076
  }
14077
+ if (commitRequired && declaration?.kind === "transition" && declaration.outcomeSelection === "product_state") {
14078
+ assertRecordSnapshotTransitionMapping(
14079
+ request.context?.invocation?.transition
14080
+ );
14081
+ }
13783
14082
  const idempotencyKey = commitRequired ? await resolveInvocationIdempotencyKey(request) : request.context?.idempotencyKey;
13784
14083
  let commitStarted = false;
13785
14084
  let commitPromise = null;
@@ -16343,7 +16642,7 @@ function stateTransitionSteps(artifact) {
16343
16642
  {
16344
16643
  index: typeof step.index === "number" ? step.index : fallbackIndex,
16345
16644
  transition,
16346
- label: text(step.label) || humanize(transition),
16645
+ label: text(transitionDescription?.label) || text(step.label) || humanize(transition),
16347
16646
  description: text(step.description) || text(record(step.expectedOutcome)?.summary) || null,
16348
16647
  status: text(step.status) || "pending",
16349
16648
  // State plans may contain bookkeeping transitions that are necessary
@@ -17025,17 +17324,17 @@ function planRecordObjectsChunks(records, batchSize) {
17025
17324
  }
17026
17325
  return plans;
17027
17326
  }
17028
- function preserveRecordObjectRealId(record2) {
17029
- const realId = record2.id.trim();
17327
+ function preserveRecordObjectRealId(record3) {
17328
+ const realId = record3.id.trim();
17030
17329
  if (!realId) {
17031
- return record2;
17330
+ return record3;
17032
17331
  }
17033
- const fields = record2.fields || {};
17332
+ const fields = record3.fields || {};
17034
17333
  if (typeof fields.real_id === "string" && fields.real_id.trim()) {
17035
- return record2;
17334
+ return record3;
17036
17335
  }
17037
17336
  return {
17038
- ...record2,
17337
+ ...record3,
17039
17338
  fields: {
17040
17339
  ...fields,
17041
17340
  real_id: realId
@@ -17367,7 +17666,7 @@ var Environment = class _Environment {
17367
17666
  }
17368
17667
  get data() {
17369
17668
  return {
17370
- record: async (record2) => this.recordObject(record2),
17669
+ record: async (record3) => this.recordObject(record3),
17371
17670
  recordMany: async (records, options) => this.recordObjects(records, options),
17372
17671
  import: async (records, options) => this.enqueueRecordImport(records, options),
17373
17672
  listImports: async (status) => this.listRecordImports(status),
@@ -17864,6 +18163,11 @@ var Environment = class _Environment {
17864
18163
  classNames: options.classNames?.length ? options.classNames : []
17865
18164
  }
17866
18165
  );
18166
+ if (response.errors?.length) {
18167
+ throw new Error(
18168
+ `Record search failed: ${response.errors.map((error) => error.message).join("; ")}`
18169
+ );
18170
+ }
17867
18171
  const seen = /* @__PURE__ */ new Set();
17868
18172
  const results = (response.data?.record_search || []).flatMap((entry) => {
17869
18173
  const className = entry.className?.trim();
@@ -21022,13 +21326,13 @@ var Granular = class _Granular {
21022
21326
  * Permission Profile management for sandboxes
21023
21327
  */
21024
21328
  get permissionProfiles() {
21025
- const profileSourceFromRecord = (record2) => {
21026
- const profile = record2.profile || record2.rules || {};
21329
+ const profileSourceFromRecord = (record3) => {
21330
+ const profile = record3.profile || record3.rules || {};
21027
21331
  return {
21028
21332
  ...profile,
21029
21333
  schemaVersion: profile.schemaVersion || 1,
21030
- name: profile.name || record2.name,
21031
- description: profile.description || record2.description
21334
+ name: profile.name || record3.name,
21335
+ description: profile.description || record3.description
21032
21336
  };
21033
21337
  };
21034
21338
  return {
@@ -21598,276 +21902,6 @@ async function pollEnvironmentSetup(input) {
21598
21902
  }
21599
21903
  }
21600
21904
 
21601
- // src/record-snapshot-projection.ts
21602
- function stableValue(value) {
21603
- if (Array.isArray(value)) return value.map(stableValue);
21604
- if (value && typeof value === "object") {
21605
- return Object.fromEntries(
21606
- Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, stableValue(item)])
21607
- );
21608
- }
21609
- return value;
21610
- }
21611
- function stableJson(value) {
21612
- return JSON.stringify(stableValue(value));
21613
- }
21614
- function recordKey(record2) {
21615
- return `${record2.className}\0${record2.id}`;
21616
- }
21617
- function recordReference(className, id) {
21618
- return { className, id };
21619
- }
21620
- function changedRecordSnapshots(beforeRecords, afterRecords) {
21621
- const before = new Map(
21622
- beforeRecords.map((record2) => [recordKey(record2), record2])
21623
- );
21624
- const after = new Map(
21625
- afterRecords.map((record2) => [recordKey(record2), record2])
21626
- );
21627
- const changedKeys = /* @__PURE__ */ new Set();
21628
- for (const key of /* @__PURE__ */ new Set([...before.keys(), ...after.keys()])) {
21629
- if (stableJson(before.get(key)) !== stableJson(after.get(key))) {
21630
- changedKeys.add(key);
21631
- }
21632
- }
21633
- return {
21634
- beforeRecords: beforeRecords.filter(
21635
- (record2) => changedKeys.has(recordKey(record2))
21636
- ),
21637
- afterRecords: afterRecords.filter(
21638
- (record2) => changedKeys.has(recordKey(record2))
21639
- )
21640
- };
21641
- }
21642
- function relationshipTargets(manifest) {
21643
- const targets = /* @__PURE__ */ new Map();
21644
- for (const volume of manifest.volumes) {
21645
- for (const operation of volume.operations) {
21646
- const relationship = operation.defineRelationship;
21647
- if (!relationship) continue;
21648
- targets.set(`${relationship.left}\0${relationship.leftSubmodel}`, {
21649
- className: relationship.right
21650
- });
21651
- targets.set(`${relationship.right}\0${relationship.rightSubmodel}`, {
21652
- className: relationship.left
21653
- });
21654
- }
21655
- }
21656
- return targets;
21657
- }
21658
- function stateName(value) {
21659
- return typeof value === "string" ? value : value.state;
21660
- }
21661
- function asIds(value) {
21662
- return value === void 0 ? [] : Array.isArray(value) ? value : [value];
21663
- }
21664
- function changedObjectProjection(before, after) {
21665
- const beforeFields = before?.fields || {};
21666
- const afterFields = after.fields || {};
21667
- const fields = { ...afterFields };
21668
- for (const fieldName of Object.keys(beforeFields)) {
21669
- if (!(fieldName in afterFields)) fields[fieldName] = null;
21670
- }
21671
- if (before && before.label === after.label && stableJson(beforeFields) === stableJson(afterFields)) {
21672
- return null;
21673
- }
21674
- return {
21675
- kind: "object",
21676
- operation: before ? "updated" : "created",
21677
- record: {
21678
- className: after.className,
21679
- id: after.id,
21680
- ...after.label !== void 0 ? { label: after.label } : {},
21681
- fields
21682
- }
21683
- };
21684
- }
21685
- function projectionChanges(input) {
21686
- const before = new Map(
21687
- input.beforeRecords.map((record2) => [recordKey(record2), record2])
21688
- );
21689
- const after = new Map(
21690
- input.afterRecords.map((record2) => [recordKey(record2), record2])
21691
- );
21692
- const targets = relationshipTargets(input.manifest);
21693
- const changes = [];
21694
- for (const record2 of input.afterRecords) {
21695
- const previous = before.get(recordKey(record2));
21696
- const objectChange = changedObjectProjection(previous, record2);
21697
- if (objectChange) changes.push(objectChange);
21698
- const relationshipNames = /* @__PURE__ */ new Set([
21699
- ...Object.keys(previous?.relationships || {}),
21700
- ...Object.keys(record2.relationships || {})
21701
- ]);
21702
- for (const relationshipName of [...relationshipNames].sort()) {
21703
- const target = targets.get(
21704
- `${record2.className}\0${relationshipName}`
21705
- );
21706
- if (!target) {
21707
- throw new Error(
21708
- `No ontology relationship target is declared for ${record2.className}.${relationshipName}`
21709
- );
21710
- }
21711
- const previousIds = new Set(
21712
- asIds(previous?.relationships?.[relationshipName])
21713
- );
21714
- const currentIds = new Set(
21715
- asIds(record2.relationships?.[relationshipName])
21716
- );
21717
- for (const id of [...previousIds].sort()) {
21718
- if (currentIds.has(id)) continue;
21719
- changes.push({
21720
- kind: "relationship",
21721
- operation: "disconnected",
21722
- relationship: relationshipName,
21723
- from: recordReference(record2.className, record2.id),
21724
- to: recordReference(target.className, id)
21725
- });
21726
- }
21727
- for (const id of [...currentIds].sort()) {
21728
- if (previousIds.has(id)) continue;
21729
- changes.push({
21730
- kind: "relationship",
21731
- operation: "connected",
21732
- relationship: relationshipName,
21733
- from: recordReference(record2.className, record2.id),
21734
- to: recordReference(target.className, id)
21735
- });
21736
- }
21737
- }
21738
- const machines = /* @__PURE__ */ new Set([
21739
- ...Object.keys(previous?.states || {}),
21740
- ...Object.keys(record2.states || {})
21741
- ]);
21742
- for (const machine of [...machines].sort()) {
21743
- const next = record2.states?.[machine];
21744
- if (next === void 0) continue;
21745
- const prior = previous?.states?.[machine];
21746
- if (prior !== void 0 && stateName(prior) === stateName(next)) continue;
21747
- if (input.transition && input.transition.className === record2.className && input.transition.objectId === record2.id && input.transition.machine === machine) {
21748
- continue;
21749
- }
21750
- changes.push({
21751
- kind: "state_observation",
21752
- target: recordReference(record2.className, record2.id),
21753
- machine,
21754
- state: stateName(next)
21755
- });
21756
- }
21757
- }
21758
- for (const record2 of input.beforeRecords) {
21759
- if (after.has(recordKey(record2))) continue;
21760
- changes.push({
21761
- kind: "object",
21762
- operation: "deleted",
21763
- target: recordReference(record2.className, record2.id)
21764
- });
21765
- }
21766
- return changes;
21767
- }
21768
- function valueAtPath(value, path) {
21769
- return path.split(".").filter(Boolean).reduce((current, segment) => {
21770
- if (!current || typeof current !== "object" || Array.isArray(current)) {
21771
- return void 0;
21772
- }
21773
- return current[segment];
21774
- }, value);
21775
- }
21776
- function primaryTarget(input) {
21777
- if (input.transition) {
21778
- return recordReference(
21779
- input.transition.className,
21780
- input.transition.objectId
21781
- );
21782
- }
21783
- const creates = input.effect.metamodels?.creates;
21784
- if (creates) {
21785
- const declaration = typeof creates === "string" ? { className: creates } : creates;
21786
- const id = declaration.idPath ? valueAtPath(input.result, declaration.idPath) : void 0;
21787
- if (typeof id === "string" && id) {
21788
- return recordReference(declaration.className, id);
21789
- }
21790
- }
21791
- if (input.effect.className && !input.effect.static) {
21792
- const objectId = input.effectInput && typeof input.effectInput === "object" && !Array.isArray(input.effectInput) ? input.effectInput._objectId : void 0;
21793
- if (typeof objectId === "string" && objectId) {
21794
- return recordReference(input.effect.className, objectId);
21795
- }
21796
- }
21797
- const created = input.changes.filter(
21798
- (change) => change.kind === "object" && change.operation === "created"
21799
- );
21800
- const onlyCreated = created.length === 1 ? created[0] : void 0;
21801
- return onlyCreated ? recordReference(onlyCreated.record.className, onlyCreated.record.id) : void 0;
21802
- }
21803
- function transitionOutcome(transition, afterRecords) {
21804
- if (!transition) {
21805
- throw new Error("A transition commit has no authored transition context.");
21806
- }
21807
- const target = afterRecords.find(
21808
- (record2) => record2.className === transition.className && record2.id === transition.objectId
21809
- );
21810
- const observed = target?.states?.[transition.machine];
21811
- if (!observed) {
21812
- throw new Error(
21813
- `The product result did not expose ${transition.className}:${transition.objectId}.${transition.machine}`
21814
- );
21815
- }
21816
- const finalState = stateName(observed);
21817
- const matches = Object.entries(transition.outcomes).filter(
21818
- ([, outcome]) => outcome.to === finalState || outcome.to === "$current" && finalState === transition.from
21819
- );
21820
- if (matches.length !== 1) {
21821
- throw new Error(
21822
- `Product state ${finalState} maps to ${matches.length} authored outcomes for ${transition.machine}.${transition.transition}`
21823
- );
21824
- }
21825
- const [key, declaration] = matches[0];
21826
- return {
21827
- key,
21828
- ...declaration.disposition === "error" ? {
21829
- error: {
21830
- code: `product_outcome_${key}`,
21831
- message: declaration.label || `The product completed in ${finalState} instead of continuing.`,
21832
- retryable: false
21833
- }
21834
- } : {}
21835
- };
21836
- }
21837
- function projectRecordSnapshotMutation(input) {
21838
- const changes = projectionChanges({
21839
- manifest: input.manifest,
21840
- beforeRecords: input.source.beforeRecords,
21841
- afterRecords: input.source.afterRecords,
21842
- transition: input.transition
21843
- });
21844
- const target = primaryTarget({
21845
- effect: input.effect,
21846
- effectInput: input.effectInput,
21847
- result: input.result,
21848
- changes,
21849
- transition: input.transition
21850
- });
21851
- const base = {
21852
- source: {
21853
- reference: input.source.reference,
21854
- ...input.source.version ? { version: input.source.version } : {},
21855
- ...input.source.versionScope ? { versionScope: input.source.versionScope } : {}
21856
- },
21857
- ...target ? { primaryTarget: target } : {},
21858
- changes,
21859
- safeSummary: {
21860
- effect: input.effect.name,
21861
- affectedChanges: changes.length
21862
- }
21863
- };
21864
- if (input.commitKind === "effect") return base;
21865
- return {
21866
- ...base,
21867
- outcome: transitionOutcome(input.transition, input.source.afterRecords)
21868
- };
21869
- }
21870
-
21871
21905
  // src/agent-harness-templates/action-presentation/0.1.0/manifest.json
21872
21906
  var manifest_default = {
21873
21907
  id: "action-presentation",
@@ -22023,29 +22057,29 @@ function requireRecord(value, context) {
22023
22057
  }
22024
22058
  return value;
22025
22059
  }
22026
- function requiredString(record2, key, context) {
22027
- const value = record2[key];
22060
+ function requiredString(record3, key, context) {
22061
+ const value = record3[key];
22028
22062
  if (typeof value !== "string" || !value.trim()) {
22029
22063
  throw new Error(`${context}.${key} must be a non-empty string.`);
22030
22064
  }
22031
22065
  return value;
22032
22066
  }
22033
- function requiredNumber(record2, key, context) {
22034
- const value = record2[key];
22067
+ function requiredNumber(record3, key, context) {
22068
+ const value = record3[key];
22035
22069
  if (typeof value !== "number" || !Number.isFinite(value)) {
22036
22070
  throw new Error(`${context}.${key} must be a finite number.`);
22037
22071
  }
22038
22072
  return value;
22039
22073
  }
22040
- function requiredStringArray(record2, key, context) {
22041
- const value = record2[key];
22074
+ function requiredStringArray(record3, key, context) {
22075
+ const value = record3[key];
22042
22076
  if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
22043
22077
  throw new Error(`${context}.${key} must be an array of non-empty strings.`);
22044
22078
  }
22045
22079
  return [...value];
22046
22080
  }
22047
- function requiredNumberRecord(record2, key, context) {
22048
- const value = requireRecord(record2[key], `${context}.${key}`);
22081
+ function requiredNumberRecord(record3, key, context) {
22082
+ const value = requireRecord(record3[key], `${context}.${key}`);
22049
22083
  const output = {};
22050
22084
  for (const [entryKey, entryValue] of Object.entries(value)) {
22051
22085
  if (typeof entryValue !== "number" || !Number.isFinite(entryValue) || entryValue < 0 || entryValue > 1) {
@@ -22058,22 +22092,22 @@ function requiredNumberRecord(record2, key, context) {
22058
22092
  return output;
22059
22093
  }
22060
22094
  function validateHarnessTemplateManifest(value, context = "HarnessTemplateManifest") {
22061
- const record2 = requireRecord(value, context);
22062
- const status = requiredString(record2, "status", context);
22095
+ const record3 = requireRecord(value, context);
22096
+ const status = requiredString(record3, "status", context);
22063
22097
  if (!HARNESS_TEMPLATE_STATUSES.includes(status)) {
22064
22098
  throw new Error(
22065
22099
  `${context}.status must be one of ${HARNESS_TEMPLATE_STATUSES.join(", ")}.`
22066
22100
  );
22067
22101
  }
22068
- const createdAt = requiredString(record2, "createdAt", context);
22102
+ const createdAt = requiredString(record3, "createdAt", context);
22069
22103
  if (Number.isNaN(Date.parse(createdAt))) {
22070
22104
  throw new Error(`${context}.createdAt must be an ISO timestamp.`);
22071
22105
  }
22072
22106
  const compatibility = requireRecord(
22073
- record2.compatibility,
22107
+ record3.compatibility,
22074
22108
  `${context}.compatibility`
22075
22109
  );
22076
- const evalGates = requireRecord(record2.evalGates, `${context}.evalGates`);
22110
+ const evalGates = requireRecord(record3.evalGates, `${context}.evalGates`);
22077
22111
  const maxRegressionPct = requiredNumber(
22078
22112
  evalGates,
22079
22113
  "maxRegressionPct",
@@ -22085,23 +22119,23 @@ function validateHarnessTemplateManifest(value, context = "HarnessTemplateManife
22085
22119
  );
22086
22120
  }
22087
22121
  return {
22088
- id: requiredString(record2, "id", context),
22089
- version: requiredString(record2, "version", context),
22122
+ id: requiredString(record3, "id", context),
22123
+ version: requiredString(record3, "version", context),
22090
22124
  status,
22091
- owner: requiredString(record2, "owner", context),
22125
+ owner: requiredString(record3, "owner", context),
22092
22126
  createdAt,
22093
- changelog: requiredString(record2, "changelog", context),
22094
- promptBuilder: requiredString(record2, "promptBuilder", context),
22095
- continuationBuilder: requiredString(record2, "continuationBuilder", context),
22127
+ changelog: requiredString(record3, "changelog", context),
22128
+ promptBuilder: requiredString(record3, "promptBuilder", context),
22129
+ continuationBuilder: requiredString(record3, "continuationBuilder", context),
22096
22130
  modelOutputInstruction: requiredString(
22097
- record2,
22131
+ record3,
22098
22132
  "modelOutputInstruction",
22099
22133
  context
22100
22134
  ),
22101
- codeReviewPolicy: requiredString(record2, "codeReviewPolicy", context),
22102
- defaultModel: requiredString(record2, "defaultModel", context),
22103
- modelMatrix: requiredStringArray(record2, "modelMatrix", context),
22104
- temperature: requiredNumber(record2, "temperature", context),
22135
+ codeReviewPolicy: requiredString(record3, "codeReviewPolicy", context),
22136
+ defaultModel: requiredString(record3, "defaultModel", context),
22137
+ modelMatrix: requiredStringArray(record3, "modelMatrix", context),
22138
+ temperature: requiredNumber(record3, "temperature", context),
22105
22139
  compatibility: {
22106
22140
  minSdkVersion: requiredString(
22107
22141
  compatibility,
@@ -22246,8 +22280,8 @@ function stableStringify(value) {
22246
22280
  if (Array.isArray(value)) {
22247
22281
  return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
22248
22282
  }
22249
- const record2 = value;
22250
- return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record2[key])}`).join(",")}}`;
22283
+ const record3 = value;
22284
+ return `{${Object.keys(record3).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record3[key])}`).join(",")}}`;
22251
22285
  }
22252
22286
  function renderConstBlock(name, value) {
22253
22287
  return `const ${name} = ${JSON.stringify(value, null, 2)} as const;`;
@@ -22843,9 +22877,9 @@ function getLatestClosure(liveDoc) {
22843
22877
  }
22844
22878
  const closures = [];
22845
22879
  for (const [closureId, value] of Object.entries(closuresById)) {
22846
- const record2 = asRecord4(value);
22847
- if (!record2) continue;
22848
- closures.push({ ...record2, closureId });
22880
+ const record3 = asRecord4(value);
22881
+ if (!record3) continue;
22882
+ closures.push({ ...record3, closureId });
22849
22883
  }
22850
22884
  closures.sort(
22851
22885
  (left, right) => (Number(right.createdAt) || 0) - (Number(left.createdAt) || 0)
@@ -22883,9 +22917,9 @@ function getJobRecords(liveDoc) {
22883
22917
  const jobsById = asRecord4(asRecord4(liveDoc?.jobs)?.byId) || {};
22884
22918
  const jobs = [];
22885
22919
  for (const [jobId, value] of Object.entries(jobsById)) {
22886
- const record2 = asRecord4(value);
22887
- if (!record2) continue;
22888
- jobs.push({ ...record2, jobId });
22920
+ const record3 = asRecord4(value);
22921
+ if (!record3) continue;
22922
+ jobs.push({ ...record3, jobId });
22889
22923
  }
22890
22924
  jobs.sort(
22891
22925
  (left, right) => getJobTimestamp(right) - getJobTimestamp(left)
@@ -23071,8 +23105,8 @@ function hasOpenPrompt(liveDoc, pendingPrompts) {
23071
23105
  const prompts = asRecord4(asRecord4(job)?.prompts);
23072
23106
  if (!prompts) continue;
23073
23107
  for (const prompt of Object.values(prompts)) {
23074
- const record2 = asRecord4(prompt);
23075
- if (record2?.status === "open") return true;
23108
+ const record3 = asRecord4(prompt);
23109
+ if (record3?.status === "open") return true;
23076
23110
  }
23077
23111
  }
23078
23112
  return false;
@@ -23131,13 +23165,13 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
23131
23165
  title: typeof decision.title === "string" && decision.title.trim() ? decision.title.trim() : "Decision",
23132
23166
  status,
23133
23167
  candidates: status === "open" ? asArray(decision.candidates).slice(0, 5).map((candidate) => {
23134
- const record2 = asRecord4(candidate);
23135
- if (!record2) return null;
23168
+ const record3 = asRecord4(candidate);
23169
+ if (!record3) return null;
23136
23170
  return {
23137
- id: typeof record2.id === "string" ? record2.id : "unknown",
23138
- label: typeof record2.label === "string" && record2.label.trim() ? record2.label.trim() : null,
23139
- description: typeof record2.description === "string" && record2.description.trim() ? record2.description.trim() : null,
23140
- metadata: asRecord4(record2.metadata)
23171
+ id: typeof record3.id === "string" ? record3.id : "unknown",
23172
+ label: typeof record3.label === "string" && record3.label.trim() ? record3.label.trim() : null,
23173
+ description: typeof record3.description === "string" && record3.description.trim() ? record3.description.trim() : null,
23174
+ metadata: asRecord4(record3.metadata)
23141
23175
  };
23142
23176
  }).filter(Boolean) : [],
23143
23177
  selected: status === "open" ? null : {
@@ -23772,11 +23806,11 @@ function normalizeJsonSchema(value) {
23772
23806
  return asRecord4(value);
23773
23807
  }
23774
23808
  function jsonSchemaTypeName(schema) {
23775
- const record2 = normalizeJsonSchema(schema);
23776
- if (!record2) return "unknown";
23777
- const type = record2.type;
23778
- if (record2.format === "date-time") return "date-time";
23779
- if (record2.format === "date" || type === "date" || Array.isArray(type) && type.includes("date")) {
23809
+ const record3 = normalizeJsonSchema(schema);
23810
+ if (!record3) return "unknown";
23811
+ const type = record3.type;
23812
+ if (record3.format === "date-time") return "date-time";
23813
+ if (record3.format === "date" || type === "date" || Array.isArray(type) && type.includes("date")) {
23780
23814
  return "date";
23781
23815
  }
23782
23816
  if (typeof type === "string") {
@@ -23787,12 +23821,12 @@ function jsonSchemaTypeName(schema) {
23787
23821
  return "unknown";
23788
23822
  }
23789
23823
  function summarizeObjectSchema(schema) {
23790
- const record2 = normalizeJsonSchema(schema);
23791
- const properties = asRecord4(record2?.properties);
23824
+ const record3 = normalizeJsonSchema(schema);
23825
+ const properties = asRecord4(record3?.properties);
23792
23826
  if (!properties || Object.keys(properties).length === 0) {
23793
- return record2 ? "{}" : null;
23827
+ return record3 ? "{}" : null;
23794
23828
  }
23795
- const required = new Set(asArray(record2?.required));
23829
+ const required = new Set(asArray(record3?.required));
23796
23830
  const fields = Object.entries(properties).slice(0, 8).map(([name, property]) => {
23797
23831
  const marker = required.has(name) ? "*" : "?";
23798
23832
  return `${name}${marker}: ${jsonSchemaTypeName(property)}`;
@@ -24556,39 +24590,39 @@ function pushStringArray(target, value) {
24556
24590
  pushString(target, item);
24557
24591
  }
24558
24592
  }
24559
- function collectReferencesFromRecord(record2, refs) {
24593
+ function collectReferencesFromRecord(record3, refs) {
24560
24594
  for (const key of ENTRY_KEY_CANDIDATES)
24561
- pushString(refs.entryPaths, record2[key]);
24595
+ pushString(refs.entryPaths, record3[key]);
24562
24596
  for (const key of ENTRY_ARRAY_KEY_CANDIDATES)
24563
- pushStringArray(refs.entryPaths, record2[key]);
24597
+ pushStringArray(refs.entryPaths, record3[key]);
24564
24598
  for (const key of LIST_KEY_CANDIDATES)
24565
- pushString(refs.listNames, record2[key]);
24599
+ pushString(refs.listNames, record3[key]);
24566
24600
  for (const key of LIST_ARRAY_KEY_CANDIDATES)
24567
- pushStringArray(refs.listNames, record2[key]);
24601
+ pushStringArray(refs.listNames, record3[key]);
24568
24602
  for (const key of VARIABLE_KEY_CANDIDATES)
24569
- pushString(refs.variableNames, record2[key]);
24603
+ pushString(refs.variableNames, record3[key]);
24570
24604
  for (const key of VARIABLE_ARRAY_KEY_CANDIDATES)
24571
- pushStringArray(refs.variableNames, record2[key]);
24605
+ pushStringArray(refs.variableNames, record3[key]);
24572
24606
  }
24573
- function stringValue(record2, keys) {
24607
+ function stringValue(record3, keys) {
24574
24608
  for (const key of keys) {
24575
- const value = record2[key];
24609
+ const value = record3[key];
24576
24610
  if (typeof value === "string" && value.trim()) {
24577
24611
  return value.trim();
24578
24612
  }
24579
24613
  }
24580
24614
  return null;
24581
24615
  }
24582
- function findEntryPathForRecord(record2, heap) {
24583
- const directPath = stringValue(record2, ["entryPath", "path"]);
24616
+ function findEntryPathForRecord(record3, heap) {
24617
+ const directPath = stringValue(record3, ["entryPath", "path"]);
24584
24618
  if (directPath && heap.entriesByPath?.[directPath]) {
24585
24619
  return directPath;
24586
24620
  }
24587
- const id = stringValue(record2, ["id", "_id", "recordId", "objectId"]);
24621
+ const id = stringValue(record3, ["id", "_id", "recordId", "objectId"]);
24588
24622
  if (!id) {
24589
24623
  return null;
24590
24624
  }
24591
- const className = stringValue(record2, [
24625
+ const className = stringValue(record3, [
24592
24626
  "className",
24593
24627
  "_className",
24594
24628
  "__className",
@@ -24622,17 +24656,17 @@ function scanForHeapReferences(value, heap, refs, depth = 0, seen = /* @__PURE__
24622
24656
  }
24623
24657
  return;
24624
24658
  }
24625
- const record2 = asRecord5(value);
24626
- if (!record2) return;
24659
+ const record3 = asRecord5(value);
24660
+ if (!record3) return;
24627
24661
  seen.add(value);
24628
- const entryPath = findEntryPathForRecord(record2, heap);
24662
+ const entryPath = findEntryPathForRecord(record3, heap);
24629
24663
  if (entryPath) refs.entryPaths.add(entryPath);
24630
- collectReferencesFromRecord(record2, refs);
24664
+ collectReferencesFromRecord(record3, refs);
24631
24665
  for (const key of UI_CONTAINER_KEYS) {
24632
- const nested = asRecord5(record2[key]);
24666
+ const nested = asRecord5(record3[key]);
24633
24667
  if (nested) collectReferencesFromRecord(nested, refs);
24634
24668
  }
24635
- for (const nested of Object.values(record2).slice(0, 24)) {
24669
+ for (const nested of Object.values(record3).slice(0, 24)) {
24636
24670
  scanForHeapReferences(nested, heap, refs, depth + 1, seen);
24637
24671
  }
24638
24672
  }
@@ -24781,8 +24815,8 @@ var OPENAI_MODEL_PRICING_USD_PER_MILLION = {
24781
24815
  function asRecord6(value) {
24782
24816
  return value && typeof value === "object" ? value : null;
24783
24817
  }
24784
- function numberField(record2, key) {
24785
- const value = record2?.[key];
24818
+ function numberField(record3, key) {
24819
+ const value = record3?.[key];
24786
24820
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
24787
24821
  }
24788
24822
  function microsPerMillion(usdPerMillion) {
@@ -24886,6 +24920,39 @@ function calculateOpenAITokenSpend(model, rawUsage) {
24886
24920
  };
24887
24921
  }
24888
24922
 
24923
+ // src/artifact-action-review.ts
24924
+ function artifactReviewedOperation(artifact, inputValues = artifact.inputValues || {}, relationships = artifact.relationships || {}) {
24925
+ const metadata = artifact.metadata || {};
24926
+ const statePlan = { ...record2(metadata.statePlan) };
24927
+ delete statePlan.approvedTransitions;
24928
+ delete statePlan.approvalDecisions;
24929
+ return {
24930
+ artifactId: artifact.artifactId,
24931
+ sessionId: artifact.sessionId || null,
24932
+ environmentId: artifact.environmentId || null,
24933
+ subjectId: artifact.subjectId || null,
24934
+ buildId: artifact.buildId || null,
24935
+ buildVersionNumber: artifact.buildVersionNumber ?? null,
24936
+ kind: artifact.kind,
24937
+ target: artifact.target || null,
24938
+ policy: artifact.policy ?? null,
24939
+ inputSchema: artifact.inputSchema || null,
24940
+ inputValues,
24941
+ relationships,
24942
+ effectKey: metadata.effectKey || metadata.toolName || null,
24943
+ effect: metadata.effect || null,
24944
+ statePlan,
24945
+ draftRecord: metadata.draftRecord || null,
24946
+ relationshipCreate: metadata.relationshipCreate || null,
24947
+ autonomy: metadata.autonomy || null,
24948
+ batch: metadata.batch || null,
24949
+ subArtifactIds: artifact.subArtifactIds || []
24950
+ };
24951
+ }
24952
+ function record2(value) {
24953
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
24954
+ }
24955
+
24889
24956
  // src/artifact-surface.ts
24890
24957
  function operationNode(workflow) {
24891
24958
  return getArtifactWorkflowNodes(workflow).find(
@@ -25096,6 +25163,6 @@ function selectArtifactSurface(artifact, context = {}) {
25096
25163
  };
25097
25164
  }
25098
25165
 
25099
- export { Environment, EnvironmentSession, GRANULAR_FEED_DIAGNOSTIC_EVENT, Granular, OPENAI_MODEL_PRICING_USD_PER_MILLION, OntologyHandle, Session, SessionFeedController, WSClient, assertArtifactWorkflow, buildContinuationInstruction, buildContinuationInstructionFromTemplate, buildGranularAgentCheckpointBlock, buildGranularAgentDomainBlock, buildGranularAgentFileBlock, buildGranularAgentHeapBlock, buildGranularAgentLoopBlock, buildGranularAgentManualActionBlock, buildGranularAgentManualActionMemorySummary, buildGranularAgentReferentBlock, buildGranularAgentRuntimeImportsBlock, buildGranularAgentSessionBlock, buildGranularAgentSystemPrompt, buildGranularAgentSystemPromptFromTemplate, buildGranularAgentToolBlock, buildGranularAgentWorkflowBlock, buildOpenAISpendEventId, buildSessionTranscript, buildSessionTranscriptFromFeedItems, calculateOpenAITokenSpend, canInspectArtifactWorkflowNode, canonicalizeCommitValue, changedRecordSnapshots, consumeGranularReasoningOnlyChunk, consumeGranularReasoningTraceChunk, createFeedPublisher, createHarnessVerifierSnapshot, defineEffect, defineProjection, defineStateMachine, emitFeedDiagnostic, emitFeedDiagnosticToDefaultSink, emptyFeedSnapshot, environmentSetupProgressFromError, environmentSetupProgressFromResponse, evaluateContinuation, evaluateValidationRule, extractPromptTokens, getArtifactWorkflowNavigationLeaves, getArtifactWorkflowNavigationTarget, getArtifactWorkflowNodes, getCurrentArtifactWorkflowNode, getCurrentClosureId, getDefaultHarnessTemplateId, getExclusivePromptTarget, getOpenAIModelPricing, hasCanonicalSessionFeedActivation, hasOpenPrompt, hashHarnessTemplateValue, invokeRegisteredEffect, isArtifactWorkflowNodeNavigableLeaf, isArtifactWorkflowNodeTerminal, isCanonicalSessionFeedDocument, isGraphQLMutationDocument, isLocalApiUrl, listHarnessTemplates, mergeFeedItemsBySequence, normalizeEffectBehaviors, normalizeFeedDiagnostic, normalizeFeedDiagnosticKind, normalizeFeedPage, normalizeOpenAIUsage, normalizePrompt, normalizePromptChoiceOption, normalizePromptText, normalizePromptType, orderTransientFeedItems, pollEnvironmentSetup, projectArtifactWorkflow, projectConversationReferentFocus, projectConversationReferentSummary, projectHeapSummary, projectLoopSummary, projectRecordSnapshotMutation, projectSessionFileSummary, projectWorkflowFocus, projectWorkflowSummary, readSessionFeedSnapshot, recordOpenAIUsageSpend, renderContinuationInstructionFromTemplate, renderGranularAgentSystemPromptFromTemplate, requireArtifactWorkflow, requireArtifactWorkflowResult, resolveApiUrl, resolveAuthTokenForApiUrl, resolveHarnessTemplate, resolveJobPresentation, resolvePromptAnswer, reviewGeneratedJobCode, scorePromptChoiceMatch, selectArtifactSurface, stripGranularReasoningTrace, toGranularHttpBase, validateHarnessTemplateManifest, validateProjectionResult, validationRuleFailureMessage };
25166
+ export { Environment, EnvironmentSession, GRANULAR_FEED_DIAGNOSTIC_EVENT, Granular, OPENAI_MODEL_PRICING_USD_PER_MILLION, OntologyHandle, Session, SessionFeedController, WSClient, artifactReviewedOperation, assertArtifactWorkflow, buildContinuationInstruction, buildContinuationInstructionFromTemplate, buildGranularAgentCheckpointBlock, buildGranularAgentDomainBlock, buildGranularAgentFileBlock, buildGranularAgentHeapBlock, buildGranularAgentLoopBlock, buildGranularAgentManualActionBlock, buildGranularAgentManualActionMemorySummary, buildGranularAgentReferentBlock, buildGranularAgentRuntimeImportsBlock, buildGranularAgentSessionBlock, buildGranularAgentSystemPrompt, buildGranularAgentSystemPromptFromTemplate, buildGranularAgentToolBlock, buildGranularAgentWorkflowBlock, buildOpenAISpendEventId, buildSessionTranscript, buildSessionTranscriptFromFeedItems, calculateOpenAITokenSpend, canInspectArtifactWorkflowNode, canonicalizeCommitValue, changedRecordSnapshots, consumeGranularReasoningOnlyChunk, consumeGranularReasoningTraceChunk, createFeedPublisher, createHarnessVerifierSnapshot, defineEffect, defineProjection, defineStateMachine, emitFeedDiagnostic, emitFeedDiagnosticToDefaultSink, emptyFeedSnapshot, environmentSetupProgressFromError, environmentSetupProgressFromResponse, evaluateContinuation, evaluateValidationRule, extractPromptTokens, getArtifactWorkflowNavigationLeaves, getArtifactWorkflowNavigationTarget, getArtifactWorkflowNodes, getCurrentArtifactWorkflowNode, getCurrentClosureId, getDefaultHarnessTemplateId, getExclusivePromptTarget, getOpenAIModelPricing, hasCanonicalSessionFeedActivation, hasOpenPrompt, hashHarnessTemplateValue, invokeRegisteredEffect, isArtifactWorkflowNodeNavigableLeaf, isArtifactWorkflowNodeTerminal, isCanonicalSessionFeedDocument, isGraphQLMutationDocument, isLocalApiUrl, listHarnessTemplates, mergeFeedItemsBySequence, normalizeEffectBehaviors, normalizeFeedDiagnostic, normalizeFeedDiagnosticKind, normalizeFeedPage, normalizeOpenAIUsage, normalizePrompt, normalizePromptChoiceOption, normalizePromptText, normalizePromptType, orderTransientFeedItems, pollEnvironmentSetup, projectArtifactWorkflow, projectConversationReferentFocus, projectConversationReferentSummary, projectHeapSummary, projectLoopSummary, projectRecordSnapshotMutation, projectSessionFileSummary, projectWorkflowFocus, projectWorkflowSummary, readSessionFeedSnapshot, recordOpenAIUsageSpend, renderContinuationInstructionFromTemplate, renderGranularAgentSystemPromptFromTemplate, requireArtifactWorkflow, requireArtifactWorkflowResult, resolveApiUrl, resolveAuthTokenForApiUrl, resolveHarnessTemplate, resolveJobPresentation, resolvePromptAnswer, reviewGeneratedJobCode, scorePromptChoiceMatch, selectArtifactSurface, stripGranularReasoningTrace, toGranularHttpBase, validateHarnessTemplateManifest, validateProjectionResult, validationRuleFailureMessage };
25100
25167
  //# sourceMappingURL=index.mjs.map
25101
25168
  //# sourceMappingURL=index.mjs.map