@fabricorg/platform-host 7.0.0 → 7.1.1

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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { ActorType, ActionId, ActionStatus, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ModuleRegistry, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
1
+ import { ActorType, ActionId, ActionStatus, EvidencePacketReference, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ModuleRegistry, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
2
2
  import { AssemblyLockfile } from '@fabricorg/assembly';
3
3
 
4
4
  /** Version of the vendor-neutral health/readiness contract. */
@@ -185,6 +185,20 @@ declare class IdempotencyConflictError extends Error {
185
185
  readonly code: "IDEMPOTENCY_CONFLICT";
186
186
  constructor(conflict: IdempotencyConflict);
187
187
  }
188
+ type ExternalCompletionRefusal = "still_executing" | "not_found" | "not_awaiting" | "immediate_contract" | "reference_mismatch" | "provider_mismatch" | "invalid_completion" | "result_invalid";
189
+ /**
190
+ * Why a completion was not applied, typed so a webhook handler can answer
191
+ * the external system correctly: `retryable` means the invocation is still
192
+ * being finalized and the same callback will be accepted once it parks, so
193
+ * answer with something the sender retries; anything else is permanent and
194
+ * a retry will get the same refusal.
195
+ */
196
+ declare class ExternalCompletionError extends Error {
197
+ readonly refusal: ExternalCompletionRefusal;
198
+ readonly code: "EXTERNAL_COMPLETION_REFUSED";
199
+ constructor(refusal: ExternalCompletionRefusal, message: string);
200
+ get retryable(): boolean;
201
+ }
188
202
  interface PendingAssetEvent {
189
203
  eventType: string;
190
204
  subjectType: string;
@@ -216,6 +230,14 @@ interface ActionInvocationRecord {
216
230
  authorizationReconciliation?: AuthorizationReconciliationOutcome;
217
231
  /** Durable evidence when an adapter returned an ambiguous outcome requiring reconciliation. */
218
232
  adapterReconciliation?: AdapterReconciliationOutcome;
233
+ /**
234
+ * A handoff the host is waiting on. While present the invocation is
235
+ * `running` without a lease: it is not stuck, it is somebody else's turn,
236
+ * and the recovery worker must not re-execute it.
237
+ */
238
+ pendingCompletion?: PendingExternalCompletion;
239
+ /** The completion an external system delivered, kept so a repeat is recognised and a contradiction is caught. */
240
+ externalCompletion?: RecordedExternalCompletion;
219
241
  /** Opaque, non-secret reference used to revalidate delegated execution authority. */
220
242
  authorizationBindingId?: string;
221
243
  attemptCount: number;
@@ -290,6 +312,57 @@ interface ExternalReconciliationRecord extends ExternalReconciliation {
290
312
  tenantId: string;
291
313
  spaceId: string;
292
314
  }
315
+ interface PendingExternalCompletion {
316
+ provider: string;
317
+ adapterType: string;
318
+ operation: string;
319
+ adapterInvocationId: string;
320
+ externalReference: string;
321
+ acceptedAt: Date;
322
+ /** Past this instant the host moves the invocation to reconciliation. */
323
+ dueAt?: Date;
324
+ /**
325
+ * Set when the invocation finished executing and parked. A handoff is
326
+ * recorded before the remaining steps run, so until this is set a
327
+ * completion has nothing settled to settle into; it is asked to retry.
328
+ */
329
+ parkedAt?: Date;
330
+ }
331
+ /**
332
+ * What an external system reports when it finishes work the host accepted.
333
+ *
334
+ * Matched to the invocation by `externalReference`, never by guesswork: a
335
+ * completion that names a reference the invocation is not waiting on is
336
+ * refused, because completing the wrong invocation is worse than dropping a
337
+ * callback.
338
+ */
339
+ interface ExternalCompletion {
340
+ externalReference: string;
341
+ outcome: "completed" | "failed";
342
+ /** Merged over the handler's result on completion. */
343
+ result?: Record<string, unknown>;
344
+ error?: string;
345
+ provider?: string;
346
+ evidenceReferences?: EvidencePacketReference[];
347
+ observedAt: Date | string;
348
+ }
349
+ interface RecordedExternalCompletion extends ExternalCompletion {
350
+ recordedAt: Date;
351
+ /**
352
+ * Canonical digest of provider, reference, outcome, result, error, and
353
+ * evidence. A repeat with the same digest is the same news; a repeat with
354
+ * the same outcome and a different digest is changed evidence, and is a
355
+ * contradiction like a flipped outcome. Observation time is left out,
356
+ * since a redelivery legitimately carries a new one.
357
+ */
358
+ digest: string;
359
+ }
360
+ interface ReconcileOverdueCompletionsInput {
361
+ tenantId?: string;
362
+ spaceId?: string;
363
+ limit?: number;
364
+ now?: Date;
365
+ }
293
366
  type AdapterInvocationStatus = "running" | "succeeded" | "failed" | "ambiguous";
294
367
  interface AdapterReconciliationOutcome {
295
368
  kind: "adapter_outcome_ambiguous";
@@ -330,7 +403,7 @@ interface PlatformHostStore<TDb> {
330
403
  transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
331
404
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
332
405
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
333
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
406
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
334
407
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
335
408
  createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
336
409
  getAdapterInvocation(id: string): Promise<AdapterInvocationRecord | undefined>;
@@ -364,7 +437,7 @@ interface PlatformHostMutationTransaction<TDb> {
364
437
  nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
365
438
  listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
366
439
  getEntityState?(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
367
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
440
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
368
441
  updateLeasedActionInvocation?(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
369
442
  }
370
443
  type OutboxStatus = "pending" | "published" | "dead_letter";
@@ -496,6 +569,12 @@ interface ListActionInvocationsInput {
496
569
  spaceId?: string;
497
570
  statuses?: readonly ActionStatus[];
498
571
  updatedBefore?: Date;
572
+ /** Only invocations holding a pending external completion. */
573
+ awaitingCompletion?: boolean;
574
+ /** Only pending completions due at or before this instant. Implies `awaitingCompletion`. */
575
+ completionDueBefore?: Date;
576
+ /** Only invocations no worker holds a lease on. */
577
+ unleased?: boolean;
499
578
  limit?: number;
500
579
  }
501
580
  interface ClaimActionInvocationsInput {
@@ -506,7 +585,20 @@ interface ClaimActionInvocationsInput {
506
585
  spaceId?: string;
507
586
  now?: Date;
508
587
  }
509
- type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>;
588
+ /**
589
+ * What the host writes back to an invocation.
590
+ *
591
+ * Store obligations for `pendingCompletion`, which a custom store must honour
592
+ * or the recovery worker will re-run an external handoff:
593
+ * - a patch that sets `pendingCompletion` together with `status: "running"`
594
+ * parks the invocation and must clear its lease;
595
+ * - a patch that sets `pendingCompletion` without a status records the handoff
596
+ * and must leave the lease alone;
597
+ * - a patch with `pendingCompletion: undefined` clears it;
598
+ * - `claimActionInvocations` must never claim a running invocation without a
599
+ * lease, which is what a parked invocation is.
600
+ */
601
+ type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation" | "pendingCompletion" | "externalCompletion">>;
510
602
  interface UpdateLeasedActionInvocationInput {
511
603
  id: string;
512
604
  tenantId: string;
@@ -609,6 +701,8 @@ interface SubmitActionResult {
609
701
  error?: string;
610
702
  reconciliation?: AuthorizationReconciliationOutcome;
611
703
  adapterReconciliation?: AdapterReconciliationOutcome;
704
+ /** Present while the invocation waits for an external system to complete it. */
705
+ pendingCompletion?: PendingExternalCompletion;
612
706
  /** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
613
707
  consistency?: "authoritative-now" | "provisional-until-reconciled";
614
708
  hitlRoute?: AgentActionRoute;
@@ -621,6 +715,8 @@ interface ExecuteActionResult {
621
715
  error?: string;
622
716
  reconciliation?: AuthorizationReconciliationOutcome;
623
717
  adapterReconciliation?: AdapterReconciliationOutcome;
718
+ /** Present while the invocation waits for an external system to complete it. */
719
+ pendingCompletion?: PendingExternalCompletion;
624
720
  /** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
625
721
  consistency?: "authoritative-now" | "provisional-until-reconciled";
626
722
  hitlRoute?: AgentActionRoute;
@@ -645,6 +741,12 @@ interface PlatformActionWorkerOptions<TDb> {
645
741
  signal?: AbortSignal;
646
742
  onError?: (error: unknown, invocation?: ActionInvocationRecord) => void;
647
743
  telemetry?: PlatformHostTelemetry;
744
+ /**
745
+ * Sweep overdue external handoffs each cycle. Defaults to on. Turn it off
746
+ * for a store without the governance seam, where the sweep would refuse
747
+ * on every cycle, and run the sweep elsewhere.
748
+ */
749
+ sweepOverdueCompletions?: boolean;
648
750
  }
649
751
  interface PlatformActionWorkerCycleResult {
650
752
  claimed: number;
@@ -746,6 +848,20 @@ interface GovernedActionHost {
746
848
  resumeApprovedInvocation(actionInvocationId: string, tenantId: string, spaceId: string, decision: ActionApprovalDecision): Promise<ExecuteActionResult>;
747
849
  recordExecutionAttestation(actionInvocationId: string, tenantId: string, spaceId: string, attestation: ExecutionAttestation): Promise<void>;
748
850
  recordExternalReconciliation(actionInvocationId: string, tenantId: string, spaceId: string, reconciliation: ExternalReconciliation): Promise<void>;
851
+ /**
852
+ * Complete an invocation an adapter handed off, by the reference the
853
+ * external system was given. Idempotent for a repeated identical
854
+ * completion; a contradictory one moves the invocation to reconciliation.
855
+ */
856
+ completeExternalInvocation(actionInvocationId: string, tenantId: string, spaceId: string, completion: ExternalCompletion): Promise<ExecuteActionResult>;
857
+ /**
858
+ * Move handoffs past their deadline to `reconciliation_required`, so a
859
+ * callback that never comes is a finding and not a silent wait. The
860
+ * pending handoff is kept, so a late completion can still land.
861
+ */
862
+ reconcileOverdueCompletions(input?: ReconcileOverdueCompletionsInput): Promise<{
863
+ overdue: string[];
864
+ }>;
749
865
  }
750
866
 
751
867
  declare function createGovernedActionHost<TDb>(options: PlatformHostOptions<TDb>): GovernedActionHost;
@@ -772,7 +888,7 @@ declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostSto
772
888
  private runTransactionWithEvents;
773
889
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
774
890
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
775
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
891
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
776
892
  recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
777
893
  beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
778
894
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
@@ -884,7 +1000,7 @@ declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostS
884
1000
  transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
885
1001
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
886
1002
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
887
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
1003
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
888
1004
  recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
889
1005
  beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
890
1006
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
@@ -1051,4 +1167,4 @@ interface CreateDurableSagaParentLifecycleOptions<TDb> {
1051
1167
  */
1052
1168
  declare function createDurableSagaParentLifecycle<TDb>(options: CreateDurableSagaParentLifecycleOptions<TDb>): HostSagaParentLifecycle;
1053
1169
 
1054
- export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationPatch, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type AdapterReconciliationOutcome, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type AuthorizationBinding, type AuthorizationGoverningMoment, type AuthorizationReconciliationOutcome, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type CreateDurableSagaParentLifecycleOptions, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type HostCompensationRecord, type HostSagaParentApprovalInput, type HostSagaParentCancellationInput, type HostSagaParentCompletionInput, type HostSagaParentFailureInput, type HostSagaParentLifecycle, type HostSagaParentProgressInput, type HostSagaParentProgressRecord, type IdempotencyConflict, IdempotencyConflictError, type InvocationProvenance, type InvocationSource, type KnownActionExecutionReason, type ListActionInvocationsInput, MemoryPlatformHostStore, type MemoryPlatformHostTransactionProvider, type NamespacedAttributes, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, type PendingAssetEvent, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostHealthCounts, type PlatformHostHealthOptions, type PlatformHostHealthQuery, type PlatformHostHealthSnapshot, type PlatformHostHealthStatus, type PlatformHostHealthStore, type PlatformHostLifecycleTelemetry, type PlatformHostMetricName, type PlatformHostMetricTelemetry, type PlatformHostMetricType, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostReadinessReason, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PlatformHostTelemetry, type PlatformHostTelemetryAttribute, type PlatformHostTelemetryEventName, type PlatformHostTelemetryHook, type PlatformHostTelemetryInput, type PlatformHostTelemetryRecord, type PlatformHostWorkerHealthInput, type PolicyEvaluationRecord, type PolicyObligationRecord, type PostgresMigration, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type RecoverablePlatformHostStore, type RenewActionInvocationLeaseInput, type SubmitActionInput, type SubmitActionResult, type UpdateLeasedActionInvocationInput, applyPostgresMigrations, canonicalJson, cloneOutboxRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, getPlatformHostHealthSnapshot, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };
1170
+ export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationPatch, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type AdapterReconciliationOutcome, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type AuthorizationBinding, type AuthorizationGoverningMoment, type AuthorizationReconciliationOutcome, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type CreateDurableSagaParentLifecycleOptions, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalCompletion, ExternalCompletionError, type ExternalCompletionRefusal, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type HostCompensationRecord, type HostSagaParentApprovalInput, type HostSagaParentCancellationInput, type HostSagaParentCompletionInput, type HostSagaParentFailureInput, type HostSagaParentLifecycle, type HostSagaParentProgressInput, type HostSagaParentProgressRecord, type IdempotencyConflict, IdempotencyConflictError, type InvocationProvenance, type InvocationSource, type KnownActionExecutionReason, type ListActionInvocationsInput, MemoryPlatformHostStore, type MemoryPlatformHostTransactionProvider, type NamespacedAttributes, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, type PendingAssetEvent, type PendingExternalCompletion, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostHealthCounts, type PlatformHostHealthOptions, type PlatformHostHealthQuery, type PlatformHostHealthSnapshot, type PlatformHostHealthStatus, type PlatformHostHealthStore, type PlatformHostLifecycleTelemetry, type PlatformHostMetricName, type PlatformHostMetricTelemetry, type PlatformHostMetricType, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostReadinessReason, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PlatformHostTelemetry, type PlatformHostTelemetryAttribute, type PlatformHostTelemetryEventName, type PlatformHostTelemetryHook, type PlatformHostTelemetryInput, type PlatformHostTelemetryRecord, type PlatformHostWorkerHealthInput, type PolicyEvaluationRecord, type PolicyObligationRecord, type PostgresMigration, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type ReconcileOverdueCompletionsInput, type RecordedExternalCompletion, type RecoverablePlatformHostStore, type RenewActionInvocationLeaseInput, type SubmitActionInput, type SubmitActionResult, type UpdateLeasedActionInvocationInput, applyPostgresMigrations, canonicalJson, cloneOutboxRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, getPlatformHostHealthSnapshot, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ActorType, ActionId, ActionStatus, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ModuleRegistry, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
1
+ import { ActorType, ActionId, ActionStatus, EvidencePacketReference, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ModuleRegistry, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
2
2
  import { AssemblyLockfile } from '@fabricorg/assembly';
3
3
 
4
4
  /** Version of the vendor-neutral health/readiness contract. */
@@ -185,6 +185,20 @@ declare class IdempotencyConflictError extends Error {
185
185
  readonly code: "IDEMPOTENCY_CONFLICT";
186
186
  constructor(conflict: IdempotencyConflict);
187
187
  }
188
+ type ExternalCompletionRefusal = "still_executing" | "not_found" | "not_awaiting" | "immediate_contract" | "reference_mismatch" | "provider_mismatch" | "invalid_completion" | "result_invalid";
189
+ /**
190
+ * Why a completion was not applied, typed so a webhook handler can answer
191
+ * the external system correctly: `retryable` means the invocation is still
192
+ * being finalized and the same callback will be accepted once it parks, so
193
+ * answer with something the sender retries; anything else is permanent and
194
+ * a retry will get the same refusal.
195
+ */
196
+ declare class ExternalCompletionError extends Error {
197
+ readonly refusal: ExternalCompletionRefusal;
198
+ readonly code: "EXTERNAL_COMPLETION_REFUSED";
199
+ constructor(refusal: ExternalCompletionRefusal, message: string);
200
+ get retryable(): boolean;
201
+ }
188
202
  interface PendingAssetEvent {
189
203
  eventType: string;
190
204
  subjectType: string;
@@ -216,6 +230,14 @@ interface ActionInvocationRecord {
216
230
  authorizationReconciliation?: AuthorizationReconciliationOutcome;
217
231
  /** Durable evidence when an adapter returned an ambiguous outcome requiring reconciliation. */
218
232
  adapterReconciliation?: AdapterReconciliationOutcome;
233
+ /**
234
+ * A handoff the host is waiting on. While present the invocation is
235
+ * `running` without a lease: it is not stuck, it is somebody else's turn,
236
+ * and the recovery worker must not re-execute it.
237
+ */
238
+ pendingCompletion?: PendingExternalCompletion;
239
+ /** The completion an external system delivered, kept so a repeat is recognised and a contradiction is caught. */
240
+ externalCompletion?: RecordedExternalCompletion;
219
241
  /** Opaque, non-secret reference used to revalidate delegated execution authority. */
220
242
  authorizationBindingId?: string;
221
243
  attemptCount: number;
@@ -290,6 +312,57 @@ interface ExternalReconciliationRecord extends ExternalReconciliation {
290
312
  tenantId: string;
291
313
  spaceId: string;
292
314
  }
315
+ interface PendingExternalCompletion {
316
+ provider: string;
317
+ adapterType: string;
318
+ operation: string;
319
+ adapterInvocationId: string;
320
+ externalReference: string;
321
+ acceptedAt: Date;
322
+ /** Past this instant the host moves the invocation to reconciliation. */
323
+ dueAt?: Date;
324
+ /**
325
+ * Set when the invocation finished executing and parked. A handoff is
326
+ * recorded before the remaining steps run, so until this is set a
327
+ * completion has nothing settled to settle into; it is asked to retry.
328
+ */
329
+ parkedAt?: Date;
330
+ }
331
+ /**
332
+ * What an external system reports when it finishes work the host accepted.
333
+ *
334
+ * Matched to the invocation by `externalReference`, never by guesswork: a
335
+ * completion that names a reference the invocation is not waiting on is
336
+ * refused, because completing the wrong invocation is worse than dropping a
337
+ * callback.
338
+ */
339
+ interface ExternalCompletion {
340
+ externalReference: string;
341
+ outcome: "completed" | "failed";
342
+ /** Merged over the handler's result on completion. */
343
+ result?: Record<string, unknown>;
344
+ error?: string;
345
+ provider?: string;
346
+ evidenceReferences?: EvidencePacketReference[];
347
+ observedAt: Date | string;
348
+ }
349
+ interface RecordedExternalCompletion extends ExternalCompletion {
350
+ recordedAt: Date;
351
+ /**
352
+ * Canonical digest of provider, reference, outcome, result, error, and
353
+ * evidence. A repeat with the same digest is the same news; a repeat with
354
+ * the same outcome and a different digest is changed evidence, and is a
355
+ * contradiction like a flipped outcome. Observation time is left out,
356
+ * since a redelivery legitimately carries a new one.
357
+ */
358
+ digest: string;
359
+ }
360
+ interface ReconcileOverdueCompletionsInput {
361
+ tenantId?: string;
362
+ spaceId?: string;
363
+ limit?: number;
364
+ now?: Date;
365
+ }
293
366
  type AdapterInvocationStatus = "running" | "succeeded" | "failed" | "ambiguous";
294
367
  interface AdapterReconciliationOutcome {
295
368
  kind: "adapter_outcome_ambiguous";
@@ -330,7 +403,7 @@ interface PlatformHostStore<TDb> {
330
403
  transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
331
404
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
332
405
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
333
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
406
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
334
407
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
335
408
  createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
336
409
  getAdapterInvocation(id: string): Promise<AdapterInvocationRecord | undefined>;
@@ -364,7 +437,7 @@ interface PlatformHostMutationTransaction<TDb> {
364
437
  nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
365
438
  listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
366
439
  getEntityState?(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
367
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
440
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
368
441
  updateLeasedActionInvocation?(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
369
442
  }
370
443
  type OutboxStatus = "pending" | "published" | "dead_letter";
@@ -496,6 +569,12 @@ interface ListActionInvocationsInput {
496
569
  spaceId?: string;
497
570
  statuses?: readonly ActionStatus[];
498
571
  updatedBefore?: Date;
572
+ /** Only invocations holding a pending external completion. */
573
+ awaitingCompletion?: boolean;
574
+ /** Only pending completions due at or before this instant. Implies `awaitingCompletion`. */
575
+ completionDueBefore?: Date;
576
+ /** Only invocations no worker holds a lease on. */
577
+ unleased?: boolean;
499
578
  limit?: number;
500
579
  }
501
580
  interface ClaimActionInvocationsInput {
@@ -506,7 +585,20 @@ interface ClaimActionInvocationsInput {
506
585
  spaceId?: string;
507
586
  now?: Date;
508
587
  }
509
- type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>;
588
+ /**
589
+ * What the host writes back to an invocation.
590
+ *
591
+ * Store obligations for `pendingCompletion`, which a custom store must honour
592
+ * or the recovery worker will re-run an external handoff:
593
+ * - a patch that sets `pendingCompletion` together with `status: "running"`
594
+ * parks the invocation and must clear its lease;
595
+ * - a patch that sets `pendingCompletion` without a status records the handoff
596
+ * and must leave the lease alone;
597
+ * - a patch with `pendingCompletion: undefined` clears it;
598
+ * - `claimActionInvocations` must never claim a running invocation without a
599
+ * lease, which is what a parked invocation is.
600
+ */
601
+ type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation" | "pendingCompletion" | "externalCompletion">>;
510
602
  interface UpdateLeasedActionInvocationInput {
511
603
  id: string;
512
604
  tenantId: string;
@@ -609,6 +701,8 @@ interface SubmitActionResult {
609
701
  error?: string;
610
702
  reconciliation?: AuthorizationReconciliationOutcome;
611
703
  adapterReconciliation?: AdapterReconciliationOutcome;
704
+ /** Present while the invocation waits for an external system to complete it. */
705
+ pendingCompletion?: PendingExternalCompletion;
612
706
  /** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
613
707
  consistency?: "authoritative-now" | "provisional-until-reconciled";
614
708
  hitlRoute?: AgentActionRoute;
@@ -621,6 +715,8 @@ interface ExecuteActionResult {
621
715
  error?: string;
622
716
  reconciliation?: AuthorizationReconciliationOutcome;
623
717
  adapterReconciliation?: AdapterReconciliationOutcome;
718
+ /** Present while the invocation waits for an external system to complete it. */
719
+ pendingCompletion?: PendingExternalCompletion;
624
720
  /** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
625
721
  consistency?: "authoritative-now" | "provisional-until-reconciled";
626
722
  hitlRoute?: AgentActionRoute;
@@ -645,6 +741,12 @@ interface PlatformActionWorkerOptions<TDb> {
645
741
  signal?: AbortSignal;
646
742
  onError?: (error: unknown, invocation?: ActionInvocationRecord) => void;
647
743
  telemetry?: PlatformHostTelemetry;
744
+ /**
745
+ * Sweep overdue external handoffs each cycle. Defaults to on. Turn it off
746
+ * for a store without the governance seam, where the sweep would refuse
747
+ * on every cycle, and run the sweep elsewhere.
748
+ */
749
+ sweepOverdueCompletions?: boolean;
648
750
  }
649
751
  interface PlatformActionWorkerCycleResult {
650
752
  claimed: number;
@@ -746,6 +848,20 @@ interface GovernedActionHost {
746
848
  resumeApprovedInvocation(actionInvocationId: string, tenantId: string, spaceId: string, decision: ActionApprovalDecision): Promise<ExecuteActionResult>;
747
849
  recordExecutionAttestation(actionInvocationId: string, tenantId: string, spaceId: string, attestation: ExecutionAttestation): Promise<void>;
748
850
  recordExternalReconciliation(actionInvocationId: string, tenantId: string, spaceId: string, reconciliation: ExternalReconciliation): Promise<void>;
851
+ /**
852
+ * Complete an invocation an adapter handed off, by the reference the
853
+ * external system was given. Idempotent for a repeated identical
854
+ * completion; a contradictory one moves the invocation to reconciliation.
855
+ */
856
+ completeExternalInvocation(actionInvocationId: string, tenantId: string, spaceId: string, completion: ExternalCompletion): Promise<ExecuteActionResult>;
857
+ /**
858
+ * Move handoffs past their deadline to `reconciliation_required`, so a
859
+ * callback that never comes is a finding and not a silent wait. The
860
+ * pending handoff is kept, so a late completion can still land.
861
+ */
862
+ reconcileOverdueCompletions(input?: ReconcileOverdueCompletionsInput): Promise<{
863
+ overdue: string[];
864
+ }>;
749
865
  }
750
866
 
751
867
  declare function createGovernedActionHost<TDb>(options: PlatformHostOptions<TDb>): GovernedActionHost;
@@ -772,7 +888,7 @@ declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostSto
772
888
  private runTransactionWithEvents;
773
889
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
774
890
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
775
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
891
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
776
892
  recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
777
893
  beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
778
894
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
@@ -884,7 +1000,7 @@ declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostS
884
1000
  transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
885
1001
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
886
1002
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
887
- updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation">>): Promise<void>;
1003
+ updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
888
1004
  recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
889
1005
  beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
890
1006
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
@@ -1051,4 +1167,4 @@ interface CreateDurableSagaParentLifecycleOptions<TDb> {
1051
1167
  */
1052
1168
  declare function createDurableSagaParentLifecycle<TDb>(options: CreateDurableSagaParentLifecycleOptions<TDb>): HostSagaParentLifecycle;
1053
1169
 
1054
- export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationPatch, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type AdapterReconciliationOutcome, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type AuthorizationBinding, type AuthorizationGoverningMoment, type AuthorizationReconciliationOutcome, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type CreateDurableSagaParentLifecycleOptions, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type HostCompensationRecord, type HostSagaParentApprovalInput, type HostSagaParentCancellationInput, type HostSagaParentCompletionInput, type HostSagaParentFailureInput, type HostSagaParentLifecycle, type HostSagaParentProgressInput, type HostSagaParentProgressRecord, type IdempotencyConflict, IdempotencyConflictError, type InvocationProvenance, type InvocationSource, type KnownActionExecutionReason, type ListActionInvocationsInput, MemoryPlatformHostStore, type MemoryPlatformHostTransactionProvider, type NamespacedAttributes, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, type PendingAssetEvent, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostHealthCounts, type PlatformHostHealthOptions, type PlatformHostHealthQuery, type PlatformHostHealthSnapshot, type PlatformHostHealthStatus, type PlatformHostHealthStore, type PlatformHostLifecycleTelemetry, type PlatformHostMetricName, type PlatformHostMetricTelemetry, type PlatformHostMetricType, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostReadinessReason, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PlatformHostTelemetry, type PlatformHostTelemetryAttribute, type PlatformHostTelemetryEventName, type PlatformHostTelemetryHook, type PlatformHostTelemetryInput, type PlatformHostTelemetryRecord, type PlatformHostWorkerHealthInput, type PolicyEvaluationRecord, type PolicyObligationRecord, type PostgresMigration, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type RecoverablePlatformHostStore, type RenewActionInvocationLeaseInput, type SubmitActionInput, type SubmitActionResult, type UpdateLeasedActionInvocationInput, applyPostgresMigrations, canonicalJson, cloneOutboxRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, getPlatformHostHealthSnapshot, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };
1170
+ export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationPatch, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type AdapterReconciliationOutcome, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type AuthorizationBinding, type AuthorizationGoverningMoment, type AuthorizationReconciliationOutcome, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type CreateDurableSagaParentLifecycleOptions, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalCompletion, ExternalCompletionError, type ExternalCompletionRefusal, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type HostCompensationRecord, type HostSagaParentApprovalInput, type HostSagaParentCancellationInput, type HostSagaParentCompletionInput, type HostSagaParentFailureInput, type HostSagaParentLifecycle, type HostSagaParentProgressInput, type HostSagaParentProgressRecord, type IdempotencyConflict, IdempotencyConflictError, type InvocationProvenance, type InvocationSource, type KnownActionExecutionReason, type ListActionInvocationsInput, MemoryPlatformHostStore, type MemoryPlatformHostTransactionProvider, type NamespacedAttributes, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, type PendingAssetEvent, type PendingExternalCompletion, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostHealthCounts, type PlatformHostHealthOptions, type PlatformHostHealthQuery, type PlatformHostHealthSnapshot, type PlatformHostHealthStatus, type PlatformHostHealthStore, type PlatformHostLifecycleTelemetry, type PlatformHostMetricName, type PlatformHostMetricTelemetry, type PlatformHostMetricType, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostReadinessReason, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PlatformHostTelemetry, type PlatformHostTelemetryAttribute, type PlatformHostTelemetryEventName, type PlatformHostTelemetryHook, type PlatformHostTelemetryInput, type PlatformHostTelemetryRecord, type PlatformHostWorkerHealthInput, type PolicyEvaluationRecord, type PolicyObligationRecord, type PostgresMigration, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type ReconcileOverdueCompletionsInput, type RecordedExternalCompletion, type RecoverablePlatformHostStore, type RenewActionInvocationLeaseInput, type SubmitActionInput, type SubmitActionResult, type UpdateLeasedActionInvocationInput, applyPostgresMigrations, canonicalJson, cloneOutboxRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, getPlatformHostHealthSnapshot, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };