@fabricorg/platform-host 8.5.0 → 8.7.0

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
@@ -1,5 +1,5 @@
1
1
  import { types } from "util";
2
- import { AdapterCircuitBreakerRegistry, AdapterRegistry, FABRIC_GOVERNANCE_CONTRACT_VERSION, ReconciliationRequiredError, aggregatePolicyOutcomes, assertActionFinalization, assertAdapterCircuitBreakerConfig, assertAdapterOutcomeConsistency, assertAdapterStepDeadlines, assertGovernanceRuntimeEvidence, assertMutationGovernanceContext, canonicalJson, createFabricId, evaluatePolicyDefinitions, evaluateStateMachineTransition, executeWithAdapterRetry, isAdapterCircuitOpenError, isReconciliationRequiredError, isRetryableExecutionError } from "@fabricorg/platform";
2
+ import { AdapterCircuitBreakerRegistry, AdapterRegistry, FABRIC_GOVERNANCE_CONTRACT_VERSION, ReconciliationRequiredError, aggregatePolicyOutcomes, assertActionFinalization, assertAdapterCircuitBreakerConfig, assertAdapterOutcomeConsistency, assertAdapterStepDeadlines, assertGovernanceRuntimeEvidence, assertMutationGovernanceContext, canonicalJson, createFabricId, evaluatePolicyDefinitions, evaluateStateMachineTransition, executeWithAdapterRetry, isActorType, isAdapterCircuitOpenError, isReconciliationRequiredError, isRetryableExecutionError } from "@fabricorg/platform";
3
3
  import { performance } from "perf_hooks";
4
4
  import { assertAssemblyRuntimeCompatible } from "@fabricorg/assembly";
5
5
  import { createHash } from "crypto";
@@ -296,6 +296,52 @@ async function appendLifecycleEvent(transaction, factory, invocation, kind) {
296
296
  }, metadata);
297
297
  }
298
298
  //#endregion
299
+ //#region src/agent-proposal.ts
300
+ /** Validate without invoking getters or retaining caller-owned evidence. */
301
+ function snapshotAgentProposal(value) {
302
+ const invalid = () => {
303
+ throw new Error("Invalid agent proposal.");
304
+ };
305
+ if (!value || typeof value !== "object" || Array.isArray(value) || types.isProxy(value)) return invalid();
306
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return invalid();
307
+ const allowed = [
308
+ "confidence",
309
+ "riskTier",
310
+ "agentSessionId",
311
+ "agentRunId",
312
+ "reason",
313
+ "evidence"
314
+ ];
315
+ for (const key of Reflect.ownKeys(value)) {
316
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
317
+ if (typeof key !== "string" || !allowed.includes(key) || !descriptor.enumerable || !Object.hasOwn(descriptor, "value")) return invalid();
318
+ }
319
+ if (value.confidence !== void 0 && (typeof value.confidence !== "number" || !Number.isFinite(value.confidence))) return invalid();
320
+ if (value.riskTier !== void 0 && ![
321
+ "low",
322
+ "medium",
323
+ "high"
324
+ ].includes(value.riskTier)) return invalid();
325
+ for (const key of [
326
+ "agentSessionId",
327
+ "agentRunId",
328
+ "reason"
329
+ ]) {
330
+ const field = value[key];
331
+ if (field !== void 0 && (typeof field !== "string" || field.length > (key === "reason" ? 4096 : 256) || key !== "reason" && field.trim().length === 0)) return invalid();
332
+ }
333
+ const evidence = snapshotApprovalDecision({
334
+ approved: true,
335
+ approverId: "proposal",
336
+ approverType: "agent",
337
+ ...value.evidence !== void 0 ? { evidence: value.evidence } : {}
338
+ }).evidence;
339
+ return {
340
+ ...value,
341
+ ...evidence !== void 0 ? { evidence } : {}
342
+ };
343
+ }
344
+ //#endregion
299
345
  //#region src/command-identity.ts
300
346
  const PARAMETER_DIGEST_ALGORITHM = "fabric-canonical-json-sha256-v1";
301
347
  function digestParameters(parameters) {
@@ -1001,7 +1047,11 @@ function snapshotSubmission(input) {
1001
1047
  const executionReason = scalar("executionReason");
1002
1048
  const idempotencyKey = scalar("idempotencyKey");
1003
1049
  const authorizationBindingId = scalar("authorizationBindingId");
1050
+ const proposal = input.agentProposal;
1051
+ if (proposal !== void 0 && actorType !== "agent") throw new Error("Agent proposal requires an agent actor.");
1052
+ const agentProposal = proposal === void 0 ? void 0 : snapshotAgentProposal(proposal);
1004
1053
  const live = {
1054
+ ...agentProposal !== void 0 ? { agentProposal } : {},
1005
1055
  actionId,
1006
1056
  tenantId,
1007
1057
  spaceId,
@@ -1070,6 +1120,7 @@ function privateSubmission(snapshot) {
1070
1120
  const provenance = provenanceRead ? copyProvenance(provenanceRead) : void 0;
1071
1121
  const authorizationBinding = bindingRead ? copyBinding(bindingRead) : void 0;
1072
1122
  return Object.freeze({
1123
+ ...snapshot.agentProposal !== void 0 ? { agentProposal: snapshot.agentProposal } : {},
1073
1124
  actionId: snapshot.actionId,
1074
1125
  tenantId: snapshot.tenantId,
1075
1126
  spaceId: snapshot.spaceId,
@@ -1166,6 +1217,7 @@ function parametersCopy(snapshot) {
1166
1217
  */
1167
1218
  function liveSubmissionView(snapshot, input) {
1168
1219
  const view = {
1220
+ ...snapshot.agentProposal !== void 0 ? { agentProposal: snapshotAgentProposal(snapshot.agentProposal) } : {},
1169
1221
  actionId: snapshot.actionId,
1170
1222
  tenantId: snapshot.tenantId,
1171
1223
  spaceId: snapshot.spaceId,
@@ -1207,6 +1259,7 @@ function submissionView(snapshot) {
1207
1259
  const provenance = fresh(snapshot.provenance);
1208
1260
  const authorizationBinding = fresh(snapshot.authorizationBinding);
1209
1261
  return {
1262
+ ...snapshot.agentProposal !== void 0 ? { agentProposal: snapshotAgentProposal(snapshot.agentProposal) } : {},
1210
1263
  actionId: snapshot.actionId,
1211
1264
  parameters: parametersCopy(snapshot),
1212
1265
  tenantId: snapshot.tenantId,
@@ -1321,6 +1374,7 @@ const MAX_STAGED_INVOCATION_KEY_LENGTH = 128;
1321
1374
  const MAX_STAGED_INVOCATION_BYTES = 65536;
1322
1375
  const MAX_STAGED_INVOCATION_BATCH_BYTES = 262144;
1323
1376
  const STAGED_INVOCATION_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
1377
+ const STAGED_INVOCATION_PRINCIPAL_PATTERN = /^[a-z][a-z0-9._:-]{0,127}$/;
1324
1378
  /** Validate and normalize one immutable batch before its parent transaction commits. */
1325
1379
  function prepareStagedInvocationBatch(input) {
1326
1380
  if (!Array.isArray(input.requests)) throw new Error("stagedInvocations must be an array.");
@@ -1340,6 +1394,8 @@ function prepareStagedInvocationBatch(input) {
1340
1394
  if (!(input.parentAction.stagesInvocations ?? []).includes(request.actionId)) throw new Error(`Action "${input.parentAction.actionId}" may not stage "${String(request.actionId)}".`);
1341
1395
  const child = input.resolveAction(request.actionId);
1342
1396
  if (!child) throw new Error(`Staged action "${String(request.actionId)}" is not registered.`);
1397
+ const principal = input.parentAction.stagedInvocationPrincipals?.[child.actionId];
1398
+ if (principal !== void 0 && !Object.hasOwn(input.stagedInvocationPrincipals ?? {}, principal)) throw new Error(`Staged invocation principal "${principal}" is not registered with this Platform Host.`);
1343
1399
  const parameters = finalizationJson(request.parameters);
1344
1400
  if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) throw new Error(`stagedInvocations[${index}] parameters must be a JSON object.`);
1345
1401
  if (!child.schema.safeParse(parameters).success) throw new Error(`stagedInvocations[${index}] parameters do not match action "${child.actionId}".`);
@@ -1354,24 +1410,27 @@ function prepareStagedInvocationBatch(input) {
1354
1410
  if (byteLength(canonicalJson({
1355
1411
  key: request.key,
1356
1412
  actionId: child.actionId,
1357
- parameters: durableParameters
1413
+ parameters: durableParameters,
1414
+ ...principal !== void 0 ? { principal } : {}
1358
1415
  })) > 65536) throw new Error(`stagedInvocations[${index}] exceeds ${MAX_STAGED_INVOCATION_BYTES} bytes.`);
1359
1416
  return {
1360
1417
  key: request.key,
1361
1418
  actionId: child.actionId,
1362
1419
  expectedActionVersion: child.version,
1363
1420
  parameters: durableParameters,
1364
- parameterDigest: digestParameters(durableParameters)
1421
+ parameterDigest: digestParameters(durableParameters),
1422
+ ...principal !== void 0 ? { principal } : {}
1365
1423
  };
1366
1424
  });
1367
1425
  for (const [index, request] of normalized.entries()) if (normalized.findIndex((candidate) => candidate.key === request.key) !== index) throw new Error(`stagedInvocations contains duplicate key "${request.key}".`);
1368
1426
  normalized.sort((left, right) => compareText(left.key, right.key) || compareText(left.actionId, right.actionId));
1369
- const batchIdentity = normalized.map(({ key, actionId, expectedActionVersion, parameters, parameterDigest }) => ({
1427
+ const batchIdentity = normalized.map(({ key, actionId, expectedActionVersion, parameters, parameterDigest, principal }) => ({
1370
1428
  key,
1371
1429
  actionId,
1372
1430
  expectedActionVersion,
1373
1431
  parameters,
1374
- parameterDigest
1432
+ parameterDigest,
1433
+ ...principal !== void 0 ? { principal } : {}
1375
1434
  }));
1376
1435
  if (byteLength(canonicalJson(batchIdentity)) > 262144) throw new Error(`stagedInvocations batch exceeds ${MAX_STAGED_INVOCATION_BATCH_BYTES} bytes.`);
1377
1436
  const batchDigest = digestParameters({
@@ -1406,7 +1465,8 @@ function stagedInvocationRequestIdentity(record) {
1406
1465
  expectedActionVersion: record.expectedActionVersion,
1407
1466
  parameters: record.parameters,
1408
1467
  parameterDigest: record.parameterDigest,
1409
- batchDigest: record.batchDigest
1468
+ batchDigest: record.batchDigest,
1469
+ ...record.principal !== void 0 ? { principal: record.principal } : {}
1410
1470
  });
1411
1471
  }
1412
1472
  function cloneStagedInvocationRecord(record) {
@@ -1473,6 +1533,20 @@ const STAGED_ERROR = Object.freeze({
1473
1533
  lookup: "Staged child lookup failed."
1474
1534
  });
1475
1535
  function createGovernedActionHost(options) {
1536
+ const configuredStagedPrincipals = options.stagedInvocationPrincipals;
1537
+ if (configuredStagedPrincipals !== void 0 && (!configuredStagedPrincipals || typeof configuredStagedPrincipals !== "object" || Array.isArray(configuredStagedPrincipals))) throw new Error("stagedInvocationPrincipals must be an object.");
1538
+ const stagedInvocationPrincipals = Object.freeze(Object.fromEntries(Object.entries(configuredStagedPrincipals ?? {}).map(([name, candidate]) => {
1539
+ if (!STAGED_INVOCATION_PRINCIPAL_PATTERN.test(name)) throw new Error(`Invalid staged invocation principal name: ${name}`);
1540
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) throw new Error(`Staged invocation principal "${name}" must be an object.`);
1541
+ const actorId = candidate.actorId;
1542
+ const actorType = candidate.actorType;
1543
+ if (typeof actorId !== "string" || actorId.length === 0) throw new Error(`Staged invocation principal "${name}" actorId must be a non-empty string.`);
1544
+ if (typeof actorType !== "string" || !isActorType(actorType)) throw new Error(`Staged invocation principal "${name}" has invalid actorType.`);
1545
+ return [name, Object.freeze({
1546
+ actorId,
1547
+ actorType
1548
+ })];
1549
+ })));
1476
1550
  if (options.approvalDefaultTtlMs !== void 0 && (!Number.isSafeInteger(options.approvalDefaultTtlMs) || options.approvalDefaultTtlMs <= 0)) throw new Error("approvalDefaultTtlMs must be a positive safe integer in milliseconds.");
1477
1551
  if (options.approvalLifecycleEvents) {
1478
1552
  const approvalStore = asApprovalStore(options.store);
@@ -1506,6 +1580,9 @@ function createGovernedActionHost(options) {
1506
1580
  const configuredActionResolver = options.resolveAction ?? options.registry?.resolveAction;
1507
1581
  if (!configuredActionResolver) throw new Error("Platform Host requires an explicit module registry or resolveAction function.");
1508
1582
  const actionResolver = configuredActionResolver;
1583
+ if (options.registry?.orderedModules) {
1584
+ for (const module of options.registry.orderedModules) for (const action of module.actions ?? []) for (const principal of Object.values(action.stagedInvocationPrincipals ?? {})) if (!Object.hasOwn(stagedInvocationPrincipals, principal)) throw new Error(`Staged invocation principal "${principal}" referenced by action "${action.actionId}" is not registered with this Platform Host.`);
1585
+ }
1509
1586
  const stagedStore = asStagedInvocationStore(options.store);
1510
1587
  const declaresStaging = options.registry?.orderedModules?.some((module) => (module.actions ?? []).some((action) => (action.stagesInvocations?.length ?? 0) > 0)) ?? false;
1511
1588
  if (declaresStaging && (!stagedStore || !asAtomicMutationStore(options.store))) throw new Error("Staged descendant invocations require a store with transactionalStagedInvocations and transactionWithEvents capabilities.");
@@ -1543,7 +1620,8 @@ function createGovernedActionHost(options) {
1543
1620
  if (submission.authorizationBinding) validateAuthorizationBinding(submission, parameterDigest, action.execution?.authorityMoment, now());
1544
1621
  return {
1545
1622
  durableParameters,
1546
- parameterDigest
1623
+ parameterDigest,
1624
+ agentProposal: submission.agentProposal === void 0 ? void 0 : snapshotAgentProposal(options.redactAgentProposal ? options.redactAgentProposal(submission.actionId, submission.agentProposal) : submission.agentProposal)
1547
1625
  };
1548
1626
  };
1549
1627
  const early = declaresAdmission ? void 0 : prepare();
@@ -1558,9 +1636,10 @@ function createGovernedActionHost(options) {
1558
1636
  };
1559
1637
  assertGovernanceRuntimeEvidence(runtimeEvidence);
1560
1638
  const admission = declaresAdmission ? await admitSubmission(action, submission) : void 0;
1561
- const { durableParameters, parameterDigest } = early ?? prepare();
1639
+ const { durableParameters, parameterDigest, agentProposal } = early ?? prepare();
1562
1640
  const invocationInput = {
1563
1641
  id: actionInvocationId,
1642
+ ...agentProposal !== void 0 ? { agentProposal } : {},
1564
1643
  tenantId: submission.tenantId,
1565
1644
  spaceId: submission.spaceId,
1566
1645
  actionId: submission.actionId,
@@ -1614,6 +1693,7 @@ function createGovernedActionHost(options) {
1614
1693
  });
1615
1694
  if (durableInvocation.id !== actionInvocationId && submission.idempotencyKey) {
1616
1695
  const conflict = idempotencyConflict(durableInvocation, {
1696
+ agentProposal,
1617
1697
  actorId: submission.actorId,
1618
1698
  authorizationBindingId: submission.authorizationBindingId,
1619
1699
  actionVersion: action.version,
@@ -2335,21 +2415,24 @@ function createGovernedActionHost(options) {
2335
2415
  }
2336
2416
  if (invocation.actorType === "agent" && options.hitlEvaluator) {
2337
2417
  const hitlParameters = isRecord(parsed.data) ? parsed.data : invocation.parameters;
2418
+ const proposal = invocation.agentProposal;
2338
2419
  const approvalStore = asApprovalStore(options.store);
2339
2420
  if (!approvalStore) return hostOperation(() => failExecution(invocation, "failed", "The configured HITL evaluator requires a store with approval persistence support."));
2340
2421
  let evaluatedApprovalExpiresAt;
2341
2422
  if (!invocation.hitlRoute) {
2342
2423
  const decision = await options.hitlEvaluator({
2424
+ actionInvocationId: invocation.id,
2425
+ invocation,
2343
2426
  actionId: action.actionId,
2344
2427
  actorId: invocation.actorId,
2345
2428
  actorType: invocation.actorType,
2346
2429
  tenantId,
2347
2430
  spaceId,
2348
2431
  parameters: hitlParameters,
2349
- ...numberValue(hitlParameters.confidence) !== void 0 ? { confidence: numberValue(hitlParameters.confidence) } : {},
2350
- ...isRiskTier(hitlParameters.riskTier) ? { riskTier: hitlParameters.riskTier } : {},
2351
- ...stringValue(hitlParameters.agentSessionId) ? { agentSessionId: stringValue(hitlParameters.agentSessionId) } : {},
2352
- ...stringValue(hitlParameters.agentRunId) ? { agentRunId: stringValue(hitlParameters.agentRunId) } : {}
2432
+ ...(proposal?.confidence ?? numberValue(hitlParameters.confidence)) !== void 0 ? { confidence: proposal?.confidence ?? numberValue(hitlParameters.confidence) } : {},
2433
+ ...isRiskTier(proposal?.riskTier ?? hitlParameters.riskTier) ? { riskTier: proposal?.riskTier ?? hitlParameters.riskTier } : {},
2434
+ ...proposal?.agentSessionId ?? stringValue(hitlParameters.agentSessionId) ? { agentSessionId: proposal?.agentSessionId ?? stringValue(hitlParameters.agentSessionId) } : {},
2435
+ ...proposal?.agentRunId ?? stringValue(hitlParameters.agentRunId) ? { agentRunId: proposal?.agentRunId ?? stringValue(hitlParameters.agentRunId) } : {}
2353
2436
  });
2354
2437
  if (decision.approvalExpiresAt !== void 0 && !validApprovalDate(decision.approvalExpiresAt)) return hostOperation(() => failExecution(invocation, "failed", "approvalExpiresAt must be a valid Date."));
2355
2438
  evaluatedApprovalExpiresAt = decision.approvalExpiresAt === void 0 ? void 0 : new Date(decision.approvalExpiresAt);
@@ -2643,6 +2726,7 @@ function createGovernedActionHost(options) {
2643
2726
  parentAction: action,
2644
2727
  requests: rawStagedInvocations,
2645
2728
  resolveAction: actionResolver,
2729
+ stagedInvocationPrincipals,
2646
2730
  redactParameters: options.redactActionParameters,
2647
2731
  now: now()
2648
2732
  });
@@ -3514,6 +3598,7 @@ function createGovernedActionHost(options) {
3514
3598
  parentAction: action,
3515
3599
  requests: stagedRequests,
3516
3600
  resolveAction: actionResolver,
3601
+ stagedInvocationPrincipals,
3517
3602
  redactParameters: options.redactActionParameters,
3518
3603
  redactedKeys: handlerStagedInvocations.map((request) => request.key),
3519
3604
  now: now()
@@ -4084,6 +4169,8 @@ function createGovernedActionHost(options) {
4084
4169
  if (!parent || parent.status !== "completed") throw new Error("Staged parent is not completed.");
4085
4170
  const child = actionResolver(record.actionId);
4086
4171
  if (!child) throw new StagedDispatchRejectionError("Staged action is no longer registered.");
4172
+ const principal = record.principal !== void 0 && Object.hasOwn(stagedInvocationPrincipals, record.principal) ? stagedInvocationPrincipals[record.principal] : void 0;
4173
+ if (record.principal !== void 0 && !principal) throw new StagedDispatchRejectionError("Staged invocation principal is no longer registered.");
4087
4174
  if (child.execution?.authorityMoment === "capture") throw new StagedDispatchRejectionError("Staged action now requires capture-time authority.");
4088
4175
  if (!child.schema.safeParse(structuredClone(record.parameters)).success) throw new StagedDispatchRejectionError("Staged parameters no longer match the registered action.");
4089
4176
  return submitActionInternal({
@@ -4091,8 +4178,8 @@ function createGovernedActionHost(options) {
4091
4178
  parameters: structuredClone(record.parameters),
4092
4179
  tenantId: parent.tenantId,
4093
4180
  spaceId: parent.spaceId,
4094
- actorId: parent.actorId,
4095
- actorType: parent.actorType,
4181
+ actorId: principal?.actorId ?? parent.actorId,
4182
+ actorType: principal?.actorType ?? parent.actorType,
4096
4183
  correlationId: parent.correlationId,
4097
4184
  causationId: parent.id,
4098
4185
  provenance: {
@@ -4106,7 +4193,8 @@ function createGovernedActionHost(options) {
4106
4193
  id: record.id,
4107
4194
  origin: {
4108
4195
  parentInvocationId: parent.id,
4109
- stageKey: record.key
4196
+ stageKey: record.key,
4197
+ ...record.principal !== void 0 ? { principal: record.principal } : {}
4110
4198
  },
4111
4199
  workerId: lease.workerId,
4112
4200
  leaseToken: lease.leaseToken,
@@ -4313,6 +4401,7 @@ function validateAuthorizationBinding(input, parameterDigest, authorityMoment, c
4313
4401
  }
4314
4402
  function idempotencyConflict(existing, incoming) {
4315
4403
  const reasons = [];
4404
+ if (canonicalJson(existing.agentProposal ?? null) !== canonicalJson(incoming.agentProposal ?? null)) reasons.push("agent_proposal");
4316
4405
  if ((existing.idempotencyActorId ?? existing.actorId) !== incoming.actorId) reasons.push("actor");
4317
4406
  if ((existing.idempotencyAuthorizationBindingId ?? existing.authorizationBindingId) !== incoming.authorizationBindingId) reasons.push("authority_binding");
4318
4407
  if (existing.actionVersion !== incoming.actionVersion) reasons.push("action_version");
@@ -4775,7 +4864,7 @@ var MemoryPlatformHostStore = class {
4775
4864
  kind: "existing",
4776
4865
  invocation: existing
4777
4866
  };
4778
- if (!this.stagedInvocations.find((record) => record.id === input.stageId && record.tenantId === invocation.tenantId && record.spaceId === invocation.spaceId && record.parentInvocationId === invocation.stagedOrigin.parentInvocationId && record.key === invocation.stagedOrigin.stageKey && record.actionId === invocation.actionId && record.status === "pending" && record.leaseOwner === input.workerId && record.leaseToken === input.leaseToken && record.leaseExpiresAt !== void 0 && record.leaseExpiresAt > now)) return { kind: "lease_lost" };
4867
+ if (!this.stagedInvocations.find((record) => record.id === input.stageId && record.tenantId === invocation.tenantId && record.spaceId === invocation.spaceId && record.parentInvocationId === invocation.stagedOrigin.parentInvocationId && record.key === invocation.stagedOrigin.stageKey && record.actionId === invocation.actionId && record.principal === invocation.stagedOrigin.principal && record.status === "pending" && record.leaseOwner === input.workerId && record.leaseToken === input.leaseToken && record.leaseExpiresAt !== void 0 && record.leaseExpiresAt > now)) return { kind: "lease_lost" };
4779
4868
  const createdAt = /* @__PURE__ */ new Date();
4780
4869
  const record = {
4781
4870
  ...invocation,
@@ -5618,6 +5707,21 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5618
5707
  ON fabric_platform.action_invocations (approval_expires_at, id)
5619
5708
  WHERE status='waiting_for_approval' AND approval_expires_at IS NOT NULL;
5620
5709
  `
5710
+ },
5711
+ {
5712
+ version: 13,
5713
+ name: "agent_proposal",
5714
+ sql: `ALTER TABLE fabric_platform.action_invocations ADD COLUMN IF NOT EXISTS agent_proposal jsonb;`
5715
+ },
5716
+ {
5717
+ version: 14,
5718
+ name: "staged_invocation_principals",
5719
+ sql: `
5720
+ ALTER TABLE fabric_platform.staged_invocations
5721
+ ADD COLUMN IF NOT EXISTS principal text;
5722
+ ALTER TABLE fabric_platform.action_invocations
5723
+ ADD COLUMN IF NOT EXISTS staged_origin_principal text;
5724
+ `
5621
5725
  }
5622
5726
  ]);
5623
5727
  }
@@ -5629,6 +5733,8 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5629
5733
  const admitted = input.admittedAt !== void 0;
5630
5734
  const admittedColumn = admitted ? "admitted_at," : "";
5631
5735
  const admittedValue = admitted ? "$25," : "";
5736
+ const proposalColumn = input.agentProposal !== void 0 ? "agent_proposal," : "";
5737
+ const proposalValue = input.agentProposal !== void 0 ? `$${admitted ? 26 : 25}::jsonb,` : "";
5632
5738
  let result;
5633
5739
  try {
5634
5740
  result = await this.sql.query(`INSERT INTO fabric_platform.action_invocations
@@ -5636,8 +5742,8 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5636
5742
  parameters,result,correlation_id,causation_id,idempotency_key,
5637
5743
  parameter_digest,parameter_digest_algorithm,idempotency_actor_id,
5638
5744
  idempotency_authorization_binding_id,invocation_provenance,authorization_binding,execution_reason,
5639
- authorization_binding_id,error,runtime_evidence,${admittedColumn}created_at,updated_at)
5640
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10::jsonb,$11,$12,$13,$14,$15,$16,$17,$18::jsonb,$19::jsonb,$20,$21,$22,$23::jsonb,${admittedValue}$24,$24)
5745
+ authorization_binding_id,error,runtime_evidence,${admittedColumn}${proposalColumn}created_at,updated_at)
5746
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10::jsonb,$11,$12,$13,$14,$15,$16,$17,$18::jsonb,$19::jsonb,$20,$21,$22,$23::jsonb,${admittedValue}${proposalValue}$24,$24)
5641
5747
  ON CONFLICT (tenant_id,space_id,action_id,idempotency_key)
5642
5748
  WHERE idempotency_key IS NOT NULL DO UPDATE SET id=fabric_platform.action_invocations.id
5643
5749
  RETURNING *`, [
@@ -5665,9 +5771,11 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5665
5771
  input.error ?? null,
5666
5772
  input.runtimeEvidence ? JSON.stringify(input.runtimeEvidence) : null,
5667
5773
  now,
5668
- ...admitted ? [input.admittedAt] : []
5774
+ ...admitted ? [input.admittedAt] : [],
5775
+ ...input.agentProposal !== void 0 ? [JSON.stringify(input.agentProposal)] : []
5669
5776
  ]);
5670
5777
  } catch (error) {
5778
+ if (input.agentProposal !== void 0 && error?.code === "42703") throw new Error("Agent proposals require PostgreSQL migration 13 (agent_proposal); run ensureSchema().", { cause: error });
5671
5779
  if (admitted && error?.code === "42703") throw new Error("An admitted invocation needs the action_invocations.admitted_at column; run ensureSchema() to apply PostgreSQL migration 6 (invocation_admission) before submitting actions that declare admitSubmission.", { cause: error });
5672
5780
  throw error;
5673
5781
  }
@@ -5678,7 +5786,9 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5678
5786
  const current = input.now ?? /* @__PURE__ */ new Date();
5679
5787
  const admitted = invocation.admittedAt !== void 0;
5680
5788
  const admittedColumn = admitted ? ",admitted_at" : "";
5681
- const admittedValue = admitted ? ",$30" : "";
5789
+ const admittedValue = admitted ? ",$31" : "";
5790
+ const proposalColumn = invocation.agentProposal !== void 0 ? ",agent_proposal" : "";
5791
+ const proposalValue = invocation.agentProposal !== void 0 ? `,$${admitted ? 32 : 31}::jsonb` : "";
5682
5792
  const values = [
5683
5793
  invocation.id,
5684
5794
  invocation.tenantId,
@@ -5705,21 +5815,24 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5705
5815
  invocation.runtimeEvidence ? JSON.stringify(invocation.runtimeEvidence) : null,
5706
5816
  invocation.stagedOrigin.parentInvocationId,
5707
5817
  invocation.stagedOrigin.stageKey,
5818
+ invocation.stagedOrigin.principal ?? null,
5708
5819
  input.stageId,
5709
5820
  input.workerId,
5710
5821
  input.leaseToken,
5711
5822
  current,
5712
- ...admitted ? [invocation.admittedAt] : []
5823
+ ...admitted ? [invocation.admittedAt] : [],
5824
+ ...invocation.agentProposal !== void 0 ? [JSON.stringify(invocation.agentProposal)] : []
5713
5825
  ];
5714
5826
  let result;
5715
5827
  try {
5716
5828
  result = await this.sql.query(`WITH fence AS (
5717
5829
  SELECT stage.id
5718
5830
  FROM fabric_platform.staged_invocations AS stage
5719
- WHERE stage.id=$26 AND stage.tenant_id=$2 AND stage.space_id=$3
5831
+ WHERE stage.id=$27 AND stage.tenant_id=$2 AND stage.space_id=$3
5720
5832
  AND stage.parent_invocation_id=$24 AND stage.stage_key=$25 AND stage.action_id=$4
5721
- AND stage.status='pending' AND stage.lease_owner=$27 AND stage.lease_token=$28
5722
- AND stage.lease_expires_at IS NOT NULL AND stage.lease_expires_at > $29
5833
+ AND stage.principal IS NOT DISTINCT FROM $26
5834
+ AND stage.status='pending' AND stage.lease_owner=$28 AND stage.lease_token=$29
5835
+ AND stage.lease_expires_at IS NOT NULL AND stage.lease_expires_at > $30
5723
5836
  FOR SHARE
5724
5837
  )
5725
5838
  INSERT INTO fabric_platform.action_invocations
@@ -5727,16 +5840,19 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5727
5840
  parameters,result,correlation_id,causation_id,idempotency_key,parameter_digest,
5728
5841
  parameter_digest_algorithm,idempotency_actor_id,idempotency_authorization_binding_id,
5729
5842
  invocation_provenance,authorization_binding,execution_reason,authorization_binding_id,error,
5730
- runtime_evidence,staged_parent_invocation_id,staged_stage_key${admittedColumn},created_at,updated_at)
5843
+ runtime_evidence,staged_parent_invocation_id,staged_stage_key,staged_origin_principal${admittedColumn}${proposalColumn},created_at,updated_at)
5731
5844
  SELECT $1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10::jsonb,$11,$12,$13,$14,$15,$16,$17,
5732
- $18::jsonb,$19::jsonb,$20,$21,$22,$23::jsonb,$24,$25${admittedValue},$29,$29
5845
+ $18::jsonb,$19::jsonb,$20,$21,$22,$23::jsonb,$24,$25,$26${admittedValue}${proposalValue},$30,$30
5733
5846
  FROM fence
5734
5847
  ON CONFLICT (tenant_id,space_id,staged_parent_invocation_id,staged_stage_key)
5735
5848
  WHERE staged_parent_invocation_id IS NOT NULL AND staged_stage_key IS NOT NULL
5736
5849
  DO UPDATE SET id=fabric_platform.action_invocations.id
5737
5850
  RETURNING *`, values);
5738
5851
  } catch (error) {
5739
- if (error?.code === "42703" || error?.code === "42P01") throw new Error("A staged child needs PostgreSQL migration 11 (staged_descendant_invocations); run ensureSchema() before dispatching staged invocations.", { cause: error });
5852
+ const databaseError = error;
5853
+ if (invocation.agentProposal !== void 0 && databaseError?.code === "42703" && typeof databaseError.message === "string" && /\bagent_proposal\b/.test(databaseError.message)) throw new Error("Agent proposals require PostgreSQL migration 13 (agent_proposal); run ensureSchema().", { cause: error });
5854
+ if (databaseError?.code === "42703") throw new Error("A staged child needs PostgreSQL migration 14 (staged_invocation_principals); run ensureSchema() before dispatching staged invocations.", { cause: error });
5855
+ if (databaseError?.code === "42P01") throw new Error("A staged child needs PostgreSQL migration 11 (staged_descendant_invocations); run ensureSchema() before dispatching staged invocations.", { cause: error });
5740
5856
  throw error;
5741
5857
  }
5742
5858
  if (result.rows[0]) {
@@ -5778,33 +5894,39 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5778
5894
  }
5779
5895
  for (const record of records) {
5780
5896
  if (record.tenantId !== first.tenantId || record.spaceId !== first.spaceId || record.parentInvocationId !== first.parentInvocationId || record.batchDigest !== first.batchDigest) throw new Error(`Invalid staged invocation batch for parent ${first.parentInvocationId}.`);
5781
- await this.sql.query(`INSERT INTO fabric_platform.staged_invocations
5782
- (id,tenant_id,space_id,parent_invocation_id,parent_action_id,stage_key,action_id,
5897
+ try {
5898
+ await this.sql.query(`INSERT INTO fabric_platform.staged_invocations
5899
+ (id,tenant_id,space_id,parent_invocation_id,parent_action_id,stage_key,action_id,principal,
5783
5900
  expected_action_version,parameters,parameter_digest,batch_digest,status,child_invocation_id,
5784
5901
  attempt_count,available_at,lease_owner,lease_expires_at,lease_token,last_error,created_at,updated_at)
5785
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21)`, [
5786
- record.id,
5787
- record.tenantId,
5788
- record.spaceId,
5789
- record.parentInvocationId,
5790
- record.parentActionId,
5791
- record.key,
5792
- record.actionId,
5793
- record.expectedActionVersion,
5794
- JSON.stringify(record.parameters),
5795
- record.parameterDigest,
5796
- record.batchDigest,
5797
- record.status,
5798
- record.childInvocationId ?? null,
5799
- record.attemptCount,
5800
- record.availableAt,
5801
- record.leaseOwner ?? null,
5802
- record.leaseExpiresAt ?? null,
5803
- record.leaseToken,
5804
- record.lastError ?? null,
5805
- record.createdAt,
5806
- record.updatedAt
5807
- ]);
5902
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10::jsonb,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)`, [
5903
+ record.id,
5904
+ record.tenantId,
5905
+ record.spaceId,
5906
+ record.parentInvocationId,
5907
+ record.parentActionId,
5908
+ record.key,
5909
+ record.actionId,
5910
+ record.principal ?? null,
5911
+ record.expectedActionVersion,
5912
+ JSON.stringify(record.parameters),
5913
+ record.parameterDigest,
5914
+ record.batchDigest,
5915
+ record.status,
5916
+ record.childInvocationId ?? null,
5917
+ record.attemptCount,
5918
+ record.availableAt,
5919
+ record.leaseOwner ?? null,
5920
+ record.leaseExpiresAt ?? null,
5921
+ record.leaseToken,
5922
+ record.lastError ?? null,
5923
+ record.createdAt,
5924
+ record.updatedAt
5925
+ ]);
5926
+ } catch (error) {
5927
+ if (error?.code === "42703") throw new Error("Staging an invocation needs PostgreSQL migration 14 (staged_invocation_principals); run ensureSchema() before staging invocations.", { cause: error });
5928
+ throw error;
5929
+ }
5808
5930
  }
5809
5931
  }
5810
5932
  async getActionInvocation(id, tenantId, spaceId) {
@@ -6825,7 +6947,8 @@ function toActionRecord(row) {
6825
6947
  ...row.idempotency_authorization_binding_id ? { idempotencyAuthorizationBindingId: String(row.idempotency_authorization_binding_id) } : {},
6826
6948
  ...row.staged_parent_invocation_id && row.staged_stage_key ? { stagedOrigin: {
6827
6949
  parentInvocationId: String(row.staged_parent_invocation_id),
6828
- stageKey: String(row.staged_stage_key)
6950
+ stageKey: String(row.staged_stage_key),
6951
+ ...row.staged_origin_principal ? { principal: String(row.staged_origin_principal) } : {}
6829
6952
  } } : {},
6830
6953
  ...row.invocation_provenance ? { provenance: row.invocation_provenance } : {},
6831
6954
  ...row.authorization_binding ? { authorizationBinding: row.authorization_binding } : {},
@@ -6855,6 +6978,7 @@ function toActionRecord(row) {
6855
6978
  ...row.mutation_footprint ? { mutationFootprint: row.mutation_footprint } : {},
6856
6979
  ...row.execution_principal ? { executionPrincipal: row.execution_principal } : {},
6857
6980
  ...row.runtime_evidence ? { runtimeEvidence: row.runtime_evidence } : {},
6981
+ ...row.agent_proposal != null ? { agentProposal: row.agent_proposal } : {},
6858
6982
  ...row.admitted_at ? { admittedAt: new Date(row.admitted_at) } : {},
6859
6983
  ...row.error ? { error: String(row.error) } : {},
6860
6984
  createdAt: new Date(row.created_at),
@@ -6870,6 +6994,7 @@ function toStagedInvocationRecord(row) {
6870
6994
  parentActionId: String(row.parent_action_id),
6871
6995
  key: String(row.stage_key),
6872
6996
  actionId: String(row.action_id),
6997
+ ...row.principal ? { principal: String(row.principal) } : {},
6873
6998
  expectedActionVersion: Number(row.expected_action_version),
6874
6999
  parameters: row.parameters,
6875
7000
  parameterDigest: String(row.parameter_digest),
@@ -8351,6 +8476,6 @@ async function runEventAppendChecks(subject) {
8351
8476
  };
8352
8477
  }
8353
8478
  //#endregion
8354
- export { APPROVAL_DECIDED_EVENT, APPROVAL_EXPIRED_EVENT, APPROVAL_REQUESTED_EVENT, ActionAdmissionError, ExternalCompletionError, IdempotencyConflictError, MAX_APPROVAL_EVIDENCE_BYTES, MAX_STAGED_INVOCATIONS, MAX_STAGED_INVOCATION_BATCH_BYTES, MAX_STAGED_INVOCATION_BYTES, MAX_STAGED_INVOCATION_KEY_LENGTH, MemoryPlatformHostStore, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, PostgresPlatformHostStore, STAGED_INVOCATION_KEY_PATTERN, SubmissionRefusalError, applyPostgresMigrations, asStagedInvocationStore, canonicalJson, cloneOutboxRecord, cloneStagedInvocationRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, eventAppendChecks, getPlatformHostHealthSnapshot, outboxActorDisclosure, prepareStagedInvocationBatch, runEventAppendChecks, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, runTenantIsolationChecks, stagedInvocationRequestIdentity, tenantIsolationChecks, toEnterpriseEventEnvelope };
8479
+ export { APPROVAL_DECIDED_EVENT, APPROVAL_EXPIRED_EVENT, APPROVAL_REQUESTED_EVENT, ActionAdmissionError, ExternalCompletionError, IdempotencyConflictError, MAX_APPROVAL_EVIDENCE_BYTES, MAX_STAGED_INVOCATIONS, MAX_STAGED_INVOCATION_BATCH_BYTES, MAX_STAGED_INVOCATION_BYTES, MAX_STAGED_INVOCATION_KEY_LENGTH, MemoryPlatformHostStore, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, PostgresPlatformHostStore, STAGED_INVOCATION_KEY_PATTERN, STAGED_INVOCATION_PRINCIPAL_PATTERN, SubmissionRefusalError, applyPostgresMigrations, asStagedInvocationStore, canonicalJson, cloneOutboxRecord, cloneStagedInvocationRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, eventAppendChecks, getPlatformHostHealthSnapshot, outboxActorDisclosure, prepareStagedInvocationBatch, runEventAppendChecks, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, runTenantIsolationChecks, stagedInvocationRequestIdentity, tenantIsolationChecks, toEnterpriseEventEnvelope };
8355
8480
 
8356
8481
  //# sourceMappingURL=index.js.map