@fabricorg/platform-host 8.8.0 → 8.9.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.d.ts CHANGED
@@ -203,30 +203,60 @@ export declare class IdempotencyConflictError extends Error {
203
203
  export type ActionAdmissionRefusal = "refused" | "failed" | "timed_out" | "invalid_decision" | "invalid_parameters";
204
204
  /**
205
205
  * Thrown by `submitAction` when a declared admission check did not admit the
206
- * submission. Host wrote nothing for it: no invocation, idempotency key,
207
- * event, policy record or error. The message holds the action id, the
208
- * refusal and, for `refused`, the check's code; never a submitted value or
209
- * anything the check threw.
206
+ * submission. By default Host writes nothing for it. With recordRefusals
207
+ * enabled and an idempotency key, a definitive refusal can be recorded;
208
+ * `recorded` confirms persistence of the terminal refusal. The message holds
209
+ * the action id, the refusal and, for `refused`, the check's fixed code. It omits parameter
210
+ * payloads and caught callback error text.
210
211
  */
211
212
  export declare class ActionAdmissionError extends Error {
212
213
  readonly actionId: string;
213
214
  readonly refusal: ActionAdmissionRefusal;
214
215
  /** The check's own code, present only for `refused`. */
215
216
  readonly refusalCode?: string | undefined;
217
+ readonly recorded: boolean;
216
218
  readonly code: "ACTION_ADMISSION_REFUSED";
217
219
  constructor(actionId: string, refusal: ActionAdmissionRefusal,
218
220
  /** The check's own code, present only for `refused`. */
219
- refusalCode?: string | undefined);
221
+ refusalCode?: string | undefined, recorded?: boolean);
220
222
  }
221
223
  export type SubmissionRefusal = "entitlement" | "authorization";
222
224
  /** A definitive authorization-boundary refusal before an invocation is created. */
223
225
  export declare class SubmissionRefusalError extends Error {
224
226
  readonly actionId: string;
225
227
  readonly refusal: SubmissionRefusal;
228
+ readonly recorded: boolean;
226
229
  readonly code: "ACTION_SUBMISSION_REFUSED";
227
- constructor(actionId: string, refusal: SubmissionRefusal, message: string);
230
+ constructor(actionId: string, refusal: SubmissionRefusal, message: string, recorded?: boolean);
228
231
  }
229
- export type ExternalCompletionRefusal = "still_executing" | "not_found" | "not_awaiting" | "immediate_contract" | "reference_mismatch" | "provider_mismatch" | "invalid_completion" | "result_invalid" | "redaction_failed";
232
+ /** Fixed refusal evidence; no submitted values belong in a descriptor. */
233
+ export type SubmissionRefusalDescriptor = {
234
+ class: "entitlement" | "authorization";
235
+ } | {
236
+ class: "admission";
237
+ refusal: "refused" | "invalid_parameters";
238
+ refusalCode?: string;
239
+ };
240
+ /** Minimal identity and evidence for an insert-only, terminal refusal. */
241
+ export interface RecordSubmissionRefusalInput {
242
+ id: string;
243
+ tenantId: string;
244
+ spaceId: string;
245
+ actionId: ActionId;
246
+ actionVersion: number;
247
+ actorId: string;
248
+ actorType: ActorType;
249
+ authorizationBindingId?: string;
250
+ idempotencyKey: string;
251
+ submissionRefusal: SubmissionRefusalDescriptor;
252
+ parameterDigest?: string;
253
+ parameterDigestAlgorithm?: "fabric-canonical-json-sha256-v1";
254
+ correlationId: string;
255
+ causationId?: string;
256
+ createdAt: Date;
257
+ updatedAt: Date;
258
+ }
259
+ export type ExternalCompletionRefusal = "erased" | "still_executing" | "not_found" | "not_awaiting" | "immediate_contract" | "reference_mismatch" | "provider_mismatch" | "invalid_completion" | "result_invalid" | "redaction_failed";
230
260
  /**
231
261
  * Why a completion was not applied, typed so a webhook handler can answer
232
262
  * the external system correctly: `retryable` means the invocation is still
@@ -292,6 +322,9 @@ export interface HostHitlEvaluatorContext extends AgentActionPolicyContext {
292
322
  invocation: Readonly<ActionInvocationRecord>;
293
323
  }
294
324
  export interface ActionInvocationRecord {
325
+ /** Store-owned erasure marker; callers cannot patch it through Host write types. */
326
+ readonly storedRecordsErased?: true;
327
+ submissionRefusal?: SubmissionRefusalDescriptor;
295
328
  readonly agentProposal?: AgentProposal;
296
329
  id: string;
297
330
  tenantId: string;
@@ -342,7 +375,7 @@ export interface ActionInvocationRecord {
342
375
  externalCompletion?: RecordedExternalCompletion;
343
376
  /** Opaque, non-secret reference used to revalidate delegated execution authority. */
344
377
  authorizationBindingId?: string;
345
- /** Worker claims including the first; approval acceptance sets a minimum of 1. */
378
+ /** Worker claims including the first; inline approval acceptance sets a minimum of 1. Recording preserves the count. */
346
379
  attemptCount: number;
347
380
  /** Latest claim durably deferred in pre-effect governance; permits only the immediately next claim. */
348
381
  deferredBeforeEffectAttempt?: number;
@@ -405,6 +438,7 @@ export declare const MAX_APPROVAL_EVIDENCE_BYTES: number;
405
438
  export declare const APPROVAL_REQUESTED_EVENT: "ApprovalRequested";
406
439
  export declare const APPROVAL_DECIDED_EVENT: "ApprovalDecided";
407
440
  export declare const APPROVAL_EXPIRED_EVENT: "ApprovalExpired";
441
+ export declare const APPROVAL_DECISION_REFUSED_EVENT: "ApprovalDecisionRefused";
408
442
  export interface ApprovalRequestedPayload {
409
443
  route: AgentActionRoute;
410
444
  riskTier: AgentActionRiskTier;
@@ -435,6 +469,10 @@ export interface ActionApprovalDecision {
435
469
  }
436
470
  export interface PersistedActionApprovalDecision extends Omit<ActionApprovalDecision, "decidedAt"> {
437
471
  decidedAt: Date;
472
+ /** Caller-stable identity for the separate recording API; absent on inline and older decisions. */
473
+ requestId?: string;
474
+ /** Claim count when recorded; the next claim is the approved first execution. */
475
+ recordedAtAttempt?: number;
438
476
  }
439
477
  export interface PolicyEvaluationRecord {
440
478
  id: string;
@@ -554,7 +592,7 @@ export interface AdapterInvocationRecord {
554
592
  createdAt: Date;
555
593
  updatedAt: Date;
556
594
  }
557
- export interface CreateActionInvocationInput extends Omit<ActionInvocationRecord, "createdAt" | "updatedAt" | "attemptCount" | "leaseOwner" | "leaseExpiresAt" | "leaseToken" | "stagedOrigin"> {}
595
+ export interface CreateActionInvocationInput extends Omit<ActionInvocationRecord, "createdAt" | "updatedAt" | "attemptCount" | "leaseOwner" | "leaseExpiresAt" | "leaseToken" | "stagedOrigin" | "storedRecordsErased"> {}
558
596
  /** Scope of an adapter checkpoint within its owning action invocation. */
559
597
  export interface AdapterInvocationScope {
560
598
  tenantId: string;
@@ -610,7 +648,17 @@ export interface PlatformHostStore<TDb> {
610
648
  * canonical events, and invocation state must commit atomically.
611
649
  */
612
650
  transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
651
+ /**
652
+ * First row wins for a supplied idempotency key within tenant, space and action id,
653
+ * including the empty-string key. Replays return the existing row unchanged;
654
+ * the store does not classify submission conflicts (Host does). Unkeyed creates
655
+ * with distinct ids insert independently. `invocationIdempotencyChecks` also
656
+ * covers concurrent key arbitration and preservation of `admittedAt` through
657
+ * an update of another field, plus refusal/admitted arbitration when supported.
658
+ */
613
659
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
660
+ /** Insert a refusal or return the key's existing winner unchanged. */
661
+ recordSubmissionRefusal?(input: RecordSubmissionRefusalInput): Promise<ActionInvocationRecord>;
614
662
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
615
663
  /** Resolve Host-owned staged identity within one tenant and space. */
616
664
  getActionInvocationByStagedOrigin?(tenantId: string, spaceId: string, origin: StagedInvocationOrigin): Promise<ActionInvocationRecord | undefined>;
@@ -684,8 +732,10 @@ export interface PlatformHostStore<TDb> {
684
732
  * back when `run` throws.
685
733
  */
686
734
  export interface PlatformHostMutationTransaction<TDb> {
735
+ /** Lock due approval candidates in this transaction, skipping locked invocation rows. */
736
+ lockDueApprovals?(input: ExpireDueApprovalsStoreInput): Promise<ActionInvocationRecord[]>;
687
737
  /** Conditional SQL approval write on the transaction connection; lifecycle events are appended by the caller in this unit of work. */
688
- beginApprovalDecision?(input: Omit<BeginApprovalDecisionInput, "lifecycleEvent">): Promise<ApprovalDecisionTransitionResult>;
738
+ beginApprovalDecision?(input: Omit<BeginApprovalDecisionInput<TDb>, "lifecycleEvent">): Promise<ApprovalDecisionTransitionResult>;
689
739
  readonly db: TDb;
690
740
  /**
691
741
  * Read and lock an invocation until this transaction completes.
@@ -694,9 +744,12 @@ export interface PlatformHostMutationTransaction<TDb> {
694
744
  getActionInvocationForUpdate?(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
695
745
  /**
696
746
  * Read one event by its stable identity inside the transaction.
747
+ * Erasure-capable stores expose storedRecordsErased on rewritten events.
697
748
  * Required by serialized saga parent lifecycle transitions.
698
749
  */
699
- getEvent?(id: string, tenantId: string, spaceId: string): Promise<AssetEventEnvelope | undefined>;
750
+ getEvent?(id: string, tenantId: string, spaceId: string): Promise<(AssetEventEnvelope & {
751
+ readonly storedRecordsErased?: true;
752
+ }) | undefined>;
700
753
  /**
701
754
  * First-write-wins: an event ID the store already holds, in any tenant or space, is a no-op
702
755
  * that keeps the first event. Do not throw, replace or merge it, regardless of
@@ -747,7 +800,7 @@ export interface PlatformHostMutationTransaction<TDb> {
747
800
  * governance evidence cannot share the event/verdict transaction.
748
801
  */
749
802
  appendExternalReconciliation?: GovernancePlatformHostStore<TDb>["appendExternalReconciliation"];
750
- /** Atomically retain an immutable staged batch with the parent mutation. */
803
+ /** Atomically retain a staged batch with the parent mutation; erasure may later rewrite its payloads. */
751
804
  stageInvocations?(records: readonly StagedInvocationRecord[]): Promise<void>;
752
805
  }
753
806
  export type StagedInvocationStatus = "pending" | "dispatched" | "rejected" | "dead_lettered" | "cancelled";
@@ -970,8 +1023,31 @@ export interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
970
1023
  * sequences and timestamps and potentially different payloads.
971
1024
  */
972
1025
  appendEventWithOutbox(event: AssetEventEnvelope, metadata: OutboxEventMetadata): Promise<void>;
1026
+ /**
1027
+ * `outboxRelayChecks`: claim pending rows available at or before `now` with no
1028
+ * unexpired lease; equality at lease expiry is claimable. Concurrent workers
1029
+ * claim a row once between them. A claim sets owner and expiry to the worker
1030
+ * and `now + leaseDurationMs`, increments attempts by one and increases the
1031
+ * row's token. `limit: 1` returns one row when eligible rows exist.
1032
+ * Published and dead-lettered rows are excluded; returned ordering is unspecified.
1033
+ * `outboxRelayChecks` requires numeric lease tokens that increase on each claim,
1034
+ * including reclaim, despite the optional token fields in the general interfaces.
1035
+ */
973
1036
  claimOutbox(input: ClaimOutboxInput): Promise<OutboxRecord[]>;
1037
+ /**
1038
+ * `outboxRelayChecks`: reject a stale token after reclaim or a wrong worker
1039
+ * without changing the row. With the current owner/token, set `published`
1040
+ * and `publishedAt` and clear lease owner/expiry. A previously settled row
1041
+ * rejects another settlement under its former owner/token.
1042
+ */
974
1043
  markOutboxPublished(id: string, workerId: string, publishedAt: Date, leaseToken?: number): Promise<void>;
1044
+ /**
1045
+ * `outboxRelayChecks`: reject a stale token after reclaim or a wrong worker
1046
+ * without changing the row. With the current owner/token, set `pending` and
1047
+ * the supplied `availableAt`, clear lease owner/expiry and retain attempts;
1048
+ * `deadLetter: true` sets `dead_letter`. A previously settled row rejects
1049
+ * another settlement under its former owner/token.
1050
+ */
975
1051
  markOutboxFailed(input: {
976
1052
  id: string;
977
1053
  workerId: string;
@@ -980,6 +1056,13 @@ export interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
980
1056
  availableAt: Date;
981
1057
  deadLetter: boolean;
982
1058
  }): Promise<void>;
1059
+ /**
1060
+ * `outboxRelayChecks`: return false for a wrong worker/token or a lease expired
1061
+ * at or before `now`, leaving expiry unchanged. For the current unexpired
1062
+ * owner/token, return true and set expiry to `now + leaseDurationMs`.
1063
+ * When `renewOutboxLeaseAndRead` is present, the same probes expect undefined
1064
+ * on refusal and the renewed record on success.
1065
+ */
983
1066
  renewOutboxLease(input: {
984
1067
  id: string;
985
1068
  workerId: string;
@@ -987,6 +1070,14 @@ export interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
987
1070
  leaseDurationMs: number;
988
1071
  now?: Date;
989
1072
  }): Promise<boolean>;
1073
+ /** Renew and hydrate the stored envelope atomically for erasure-safe publication. */
1074
+ renewOutboxLeaseAndRead?(input: {
1075
+ id: string;
1076
+ workerId: string;
1077
+ leaseToken: number;
1078
+ leaseDurationMs: number;
1079
+ now?: Date;
1080
+ }): Promise<OutboxRecord | undefined>;
990
1081
  listOutbox(input?: {
991
1082
  tenantId?: string;
992
1083
  spaceId?: string;
@@ -1120,6 +1211,15 @@ export interface OutboxRequeueAuthorizationInput {
1120
1211
  * but cannot claim atomic domain-write/event persistence.
1121
1212
  */
1122
1213
  export interface AtomicMutationPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
1214
+ /**
1215
+ * Optional retry evidence: reject with ConfirmedTransactionRollback(callbackError)
1216
+ * after rollback succeeds. Its cause must be the identical callback error. A provider
1217
+ * that does not supply this evidence retains the existing failure behavior.
1218
+ * A commit error is not evidence that the callback rolled back. Built-in stores
1219
+ * expose evidence for Host's internal handler callback request; ordinary public
1220
+ * callbacks and store-internal transactions retain their original error objects.
1221
+ * Host normalizes confirmation from custom stores at non-handler transaction sites.
1222
+ */
1123
1223
  transactionWithEvents<TResult>(run: (transaction: PlatformHostMutationTransaction<TDb>) => Promise<TResult>): Promise<TResult>;
1124
1224
  }
1125
1225
  export interface ApprovalLifecycleEvent {
@@ -1128,6 +1228,50 @@ export interface ApprovalLifecycleEvent {
1128
1228
  }
1129
1229
  /** Called within the transition transaction. Must be pure and return audit-safe data. Sequence is assigned by the store. */
1130
1230
  export type ApprovalLifecycleEventFactory = (invocation: ActionInvocationRecord, kind: "requested" | "decided" | "expired") => ApprovalLifecycleEvent;
1231
+ export interface RecordApprovalDecisionRequest extends ActionApprovalDecision {
1232
+ /** Non-blank caller-stable identifier, at most 256 characters; not trimmed or regenerated by Host. */
1233
+ requestId: string;
1234
+ }
1235
+ export type RecordApprovalDecisionOutcome = "approved" | "denied" | "unauthorized" | "expired" | "already_decided" | "late_terminal" | "not_waiting" | "unsupported";
1236
+ export interface RecordApprovalDecisionResult {
1237
+ outcome: RecordApprovalDecisionOutcome;
1238
+ actionInvocationId: string;
1239
+ status: ActionInvocationRecord["status"];
1240
+ replayed: boolean;
1241
+ /** Included for approved/denied outcomes, including replays; omitted for non-applied outcomes. */
1242
+ decision?: PersistedActionApprovalDecision;
1243
+ }
1244
+ export interface TransactionalApprovalAuthorization<TDb = unknown> {
1245
+ (db: TDb, invocation: Readonly<ActionInvocationRecord>): Promise<boolean>;
1246
+ }
1247
+ export interface RecordApprovalDecisionStoreInput<TDb = unknown> {
1248
+ actionInvocationId: string;
1249
+ tenantId: string;
1250
+ spaceId: string;
1251
+ now: Date;
1252
+ /** Carries no `recordedAtAttempt`: the store assigns it from the locked row. */
1253
+ decision: Omit<PersistedActionApprovalDecision, "recordedAtAttempt"> & {
1254
+ requestId: string;
1255
+ };
1256
+ /** Result of the compatibility authorization boundary evaluated before the transaction. */
1257
+ authorized: boolean;
1258
+ /**
1259
+ * Optional authority check on this transaction's `db`, after the invocation row is locked
1260
+ * and classified as writable, immediately before the decision write.
1261
+ */
1262
+ authorizeInTransaction?: TransactionalApprovalAuthorization<TDb>;
1263
+ actionKind: "atomic" | "saga" | "unknown";
1264
+ lifecycleEvent?: ApprovalLifecycleEventFactory;
1265
+ /** Called under the invocation lock after any update, with the pre-patch observed row. */
1266
+ attemptEvent?: (invocation: ActionInvocationRecord, outcome: RecordApprovalDecisionOutcome) => ApprovalLifecycleEvent;
1267
+ }
1268
+ export interface RecordApprovalDecisionStoreResult {
1269
+ /** Whether this transaction changed the invocation; false for replays and previously expired rows. */
1270
+ applied: boolean;
1271
+ outcome: RecordApprovalDecisionOutcome;
1272
+ invocation: ActionInvocationRecord;
1273
+ replayed: boolean;
1274
+ }
1131
1275
  export interface ExpireDueApprovalsInput {
1132
1276
  tenantId?: string;
1133
1277
  spaceId?: string;
@@ -1148,7 +1292,7 @@ export interface ParkApprovalInput {
1148
1292
  leaseToken?: number;
1149
1293
  lifecycleEvent?: ApprovalLifecycleEventFactory;
1150
1294
  }
1151
- export interface BeginApprovalDecisionInput {
1295
+ export interface BeginApprovalDecisionInput<TDb = unknown> {
1152
1296
  lifecycleEvent?: ApprovalLifecycleEventFactory;
1153
1297
  actionInvocationId: string;
1154
1298
  tenantId: string;
@@ -1157,15 +1301,26 @@ export interface BeginApprovalDecisionInput {
1157
1301
  leaseOwner: string;
1158
1302
  leaseDurationMs: number;
1159
1303
  now: Date;
1304
+ /**
1305
+ * Optional authority check on this transaction's `db`, after the invocation row is locked
1306
+ * and classified as writable, immediately before the decision write.
1307
+ */
1308
+ authorizeInTransaction?: TransactionalApprovalAuthorization<TDb>;
1160
1309
  }
1161
1310
  export interface ApprovalDecisionTransitionResult {
1162
1311
  applied: boolean;
1163
1312
  invocation?: ActionInvocationRecord;
1313
+ /** True when a configured in-transaction authority check refused the decision. */
1314
+ authorizationDenied?: boolean;
1164
1315
  }
1165
- /** Optional store capability required only when agent HITL or approval resume is used. */
1316
+ /** Approval persistence capabilities used by Host HITL, inline resume and decision recording. */
1166
1317
  export interface ApprovalPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
1318
+ /** Serialize classification, optional events/outbox and the queued/terminal transition in one transaction. */
1319
+ recordApprovalDecision?(input: RecordApprovalDecisionStoreInput<TDb>): Promise<RecordApprovalDecisionStoreResult>;
1167
1320
  /** True only when approval transitions and lifecycle outbox events share a transaction. */
1168
1321
  readonly transactionalApprovalLifecycle?: boolean;
1322
+ /** True only when approval authority callbacks run under the locked row in the decision transaction. */
1323
+ readonly transactionalApprovalAuthorization?: boolean;
1169
1324
  /**
1170
1325
  * Conditionally park an executable invocation only with its matching lease owner/generation
1171
1326
  * (when leased) and no prior approval decision. Persist the deadline supplied in input.
@@ -1195,7 +1350,7 @@ export interface ApprovalPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
1195
1350
  * or expired event/outbox writes and state change must commit in the same atomic unit
1196
1351
  * of work, or roll back together. Required when implementing parkApproval/expireDueApprovals.
1197
1352
  */
1198
- beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
1353
+ beginApprovalDecision(input: BeginApprovalDecisionInput<TDb>): Promise<ApprovalDecisionTransitionResult>;
1199
1354
  }
1200
1355
  /** Optional durable capabilities used when external-governance enrichment is configured. */
1201
1356
  export interface GovernancePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
@@ -1294,6 +1449,10 @@ export interface ActionExecutionAuthorizationInput extends ActionAuthorizationIn
1294
1449
  invocation: Readonly<ActionInvocationRecord>;
1295
1450
  executionReason: ActionExecutionReason;
1296
1451
  }
1452
+ /** Execution authorization input evaluated on the handler transaction's domain handle. */
1453
+ export interface ActionExecutionAuthorizationInTransactionInput<TDb> extends ActionExecutionAuthorizationInput {
1454
+ db: TDb;
1455
+ }
1297
1456
  /** Trusted authorization input for deciding a parked approval. */
1298
1457
  export interface ActionApprovalAuthorizationInput extends ActionAuthorizationInput {
1299
1458
  decision: ActionApprovalDecision;
@@ -1302,6 +1461,10 @@ export interface ActionApprovalAuthorizationInput extends ActionAuthorizationInp
1302
1461
  /** The durable (post-redaction) invocation record as read before the decision transition. */
1303
1462
  invocation: Readonly<ActionInvocationRecord>;
1304
1463
  }
1464
+ /** Approval authorization input evaluated while the invocation row is locked for its decision write. */
1465
+ export interface ActionApprovalAuthorizationInTransactionInput<TDb> extends ActionApprovalAuthorizationInput {
1466
+ db: TDb;
1467
+ }
1305
1468
  /**
1306
1469
  * Input to `resolvePolicies`. Carries the invocation identity and the
1307
1470
  * schema-parsed durable (post-redaction) parameters so a resolver can choose
@@ -1312,7 +1475,7 @@ export interface ActionApprovalAuthorizationInput extends ActionAuthorizationInp
1312
1475
  export interface ResolvePoliciesInput extends ActionExecutionAuthorizationInput {
1313
1476
  declaredPolicyIds: readonly string[];
1314
1477
  }
1315
- export interface PlatformHostAuthorization {
1478
+ export interface PlatformHostAuthorization<TDb = unknown> {
1316
1479
  checkEntitlement(input: ActionAuthorizationInput): Promise<boolean>;
1317
1480
  authorize(input: ActionAuthorizationInput): Promise<boolean>;
1318
1481
  /**
@@ -1320,14 +1483,25 @@ export interface PlatformHostAuthorization {
1320
1483
  * execution. When absent, the Host reuses `authorize` at this boundary.
1321
1484
  */
1322
1485
  authorizeExecution?(input: ActionExecutionAuthorizationInput): Promise<boolean>;
1486
+ /** Optional final execution authority check on the handler transaction, immediately before the effect. */
1487
+ authorizeExecutionInTransaction?(input: ActionExecutionAuthorizationInTransactionInput<TDb>): Promise<boolean>;
1323
1488
  /** Optional distinct authorization boundary for human/system approval decisions. */
1324
1489
  authorizeApproval?(input: ActionApprovalAuthorizationInput): Promise<boolean>;
1490
+ /** Optional final approval authority check under the locked row in the decision transaction. */
1491
+ authorizeApprovalInTransaction?(input: ActionApprovalAuthorizationInTransactionInput<TDb>): Promise<boolean>;
1325
1492
  /**
1326
1493
  * Authorization for `requeueOutboxDeadLetter`. There is no action to fall
1327
1494
  * back to, so when this is absent every requeue is refused as
1328
1495
  * `not_authorized`. A throw propagates and nothing is requeued.
1329
1496
  */
1330
1497
  authorizeOutboxRequeue?(input: OutboxRequeueAuthorizationInput): Promise<boolean>;
1498
+ /**
1499
+ * Erasure operator authorization after validation and before store access. No fallback:
1500
+ * absence or a result other than true raises StoredRecordErasureAuthorizationError.
1501
+ * A thrown hook error propagates unchanged; neither outcome reaches the store.
1502
+ * Receives identifying facts and detached validated targets, without redact or stored payloads.
1503
+ */
1504
+ authorizeStoredRecordErasure?(input: StoredRecordErasureAuthorizationInput): Promise<boolean>;
1331
1505
  }
1332
1506
  export interface DispatchActionInput {
1333
1507
  actionInvocationId: string;
@@ -1497,7 +1671,7 @@ export interface ErrorTextRedactionContext {
1497
1671
  }
1498
1672
  export interface PlatformHostOptions<TDb> {
1499
1673
  store: PlatformHostStore<TDb>;
1500
- authorization: PlatformHostAuthorization;
1674
+ authorization: PlatformHostAuthorization<TDb>;
1501
1675
  /** Preferred explicit catalog assembled from this runtime's Fabric modules. */
1502
1676
  registry?: Pick<ModuleRegistry<TDb>, "resolveAction" | "resolvePolicy" | "resolveStateMachine"> & Partial<Pick<ModuleRegistry<TDb>, "orderedModules">>;
1503
1677
  /** Resolve vertical- or runtime-local actions without mutating the process-wide registry. */
@@ -1532,9 +1706,29 @@ export interface PlatformHostOptions<TDb> {
1532
1706
  * approval resume, exhausted attempts, and marker-write failures are not retried.
1533
1707
  * Policy persistence, obligation listing/resolution/persistence, state-machine checks,
1534
1708
  * the handler transaction, handlers, adapters, and finalization are excluded;
1535
- * their failure/reconciliation/recovery semantics apply, subject to recoveryMaxAttempts.
1709
+ * their separate failure/reconciliation/recovery semantics apply, including handlerRetry
1710
+ * for confirmed handler rollback, subject to recoveryMaxAttempts.
1536
1711
  */
1537
1712
  retryableExecutionMaxAttempts?: number;
1713
+ /** Bounded retries within one execution attempt after confirmed handler rollback. */
1714
+ handlerRetry?: {
1715
+ /** Total transaction tries, including the first; integer 1–10, default 3. One disables retry. */
1716
+ maxAttempts?: number;
1717
+ /** Assert the whole retried unit kept effects in the transaction. Literal true opts in; throws refuse retry. */
1718
+ classify?: (error: unknown, context: {
1719
+ actionId: string;
1720
+ }) => boolean;
1721
+ /** Retry number starts at 1. Default full jitter on 25 ms doubling; clamped to 0–1000 ms. Throws/non-finite stop retry. */
1722
+ delayMs?: number | ((retry: number) => number);
1723
+ /** Called before each delay; attempt is the upcoming try (2..maxAttempts). Sync throws and async rejections are ignored without awaiting. */
1724
+ onRetry?: (info: {
1725
+ actionInvocationId: string;
1726
+ actionId: string;
1727
+ attempt: number;
1728
+ maxAttempts: number;
1729
+ error: unknown;
1730
+ }) => void;
1731
+ };
1538
1732
  /**
1539
1733
  * Positive integer cap on worker claims for resumed leased running invocations
1540
1734
  * including the first (default max(5, retryableExecutionMaxAttempts); Infinity is rejected).
@@ -1550,6 +1744,8 @@ export interface PlatformHostOptions<TDb> {
1550
1744
  services?: FabricRuntimeServices;
1551
1745
  idempotency?: {
1552
1746
  conflictMode?: "audit-only" | "enforce";
1747
+ /** Reserve keyed definitive submission refusals. Requires enforcing identity and store support. */
1748
+ recordRefusals?: boolean;
1553
1749
  onConflict?(conflict: IdempotencyConflict): void;
1554
1750
  onLegacyRecord?(invocation: ActionInvocationRecord): void;
1555
1751
  };
@@ -1581,6 +1777,8 @@ export interface PlatformHostOptions<TDb> {
1581
1777
  approvalDefaultTtlMs?: number;
1582
1778
  /** Atomic approval lifecycle events and outbox writes; defaults to false. */
1583
1779
  approvalLifecycleEvents?: boolean;
1780
+ /** Atomic audit events for refused recording attempts; defaults to false. */
1781
+ approvalDecisionAttemptEvents?: boolean;
1584
1782
  /** Durable evaluator/ruleset version recorded with every HITL decision. */
1585
1783
  hitlPolicyVersion?: string;
1586
1784
  /** Optional portable resolver; provider-specific implementations belong in integration packages. */
@@ -1696,6 +1894,10 @@ export interface PlatformHostOptions<TDb> {
1696
1894
  */
1697
1895
  adapterDeadlineMs?: number;
1698
1896
  }
1897
+ /** Additive capability; handwritten GovernedActionHost implementations retain their existing shape. */
1898
+ export interface ApprovalDecisionRecordingHost {
1899
+ recordApprovalDecision(id: string, tenantId: string, spaceId: string, request: RecordApprovalDecisionRequest): Promise<RecordApprovalDecisionResult>;
1900
+ }
1699
1901
  export interface ApprovalExpiryHost {
1700
1902
  expireDueApprovals(input?: ExpireDueApprovalsInput): Promise<{
1701
1903
  expired: string[];
@@ -1748,19 +1950,99 @@ export interface OutboxRequeueHost {
1748
1950
  requeueOutboxDeadLetter(input: RequeueOutboxDeadLetterInput): Promise<RequeueOutboxDeadLetterResult>;
1749
1951
  }
1750
1952
  //#endregion
1953
+ //#region src/erasure-types.d.ts
1954
+ type StoredRecordErasureTarget = {
1955
+ readonly kind: "invocation";
1956
+ readonly invocationId: string;
1957
+ } | {
1958
+ readonly kind: "event";
1959
+ readonly eventId: string;
1960
+ };
1961
+ interface ErasurePayloadFields {
1962
+ invocation: "parameters" | "result" | "error" | "provenance" | "authorizationBinding" | "authorizationReconciliation" | "adapterReconciliation" | "hitlReason" | "approvalDecision" | "mutationFootprint" | "executionPrincipal" | "runtimeEvidence" | "pendingCompletion" | "externalCompletion" | "pendingStateTransition" | "finalizationCheckpoint" | "approvalExpiry" | "agentProposal" | "submissionRefusal";
1963
+ adapter: "input" | "output" | "error" | "reconciliation";
1964
+ staged: "parameters" | "lastError";
1965
+ policy_evaluation: "outcome";
1966
+ policy_obligation: "description" | "evidenceReferences" | "metadata";
1967
+ execution_attestation: "attestation";
1968
+ external_reconciliation: "reconciliation";
1969
+ event: "payload" | "provenance";
1970
+ outbox: "lastError" | "traceContext" | "payload" | "provenance";
1971
+ outbox_requeue: "reason" | "priorLastError";
1972
+ }
1973
+ type ErasureRecordKind = keyof ErasurePayloadFields;
1974
+ /** Protected nested keys are omitted from the callback; stores restore structure and overwrite payload digests. */
1975
+ type StoredRecordErasureView = { [K in ErasureRecordKind]: {
1976
+ readonly kind: K;
1977
+ readonly id: string;
1978
+ readonly tenantId: string;
1979
+ readonly spaceId: string;
1980
+ readonly invocationId?: string;
1981
+ readonly eventId?: string;
1982
+ readonly eventType?: string;
1983
+ fields: Partial<Record<ErasurePayloadFields[K], unknown>>;
1984
+ }; }[ErasureRecordKind];
1985
+ /** Validated identifying facts sent to the application authorizer; no stored payload or callback. */
1986
+ interface StoredRecordErasureAuthorizationInput {
1987
+ /** Trusted operator identity supplied by the authenticated application session. */
1988
+ readonly actorId: string;
1989
+ readonly actorType: ActorType;
1990
+ readonly tenantId: string;
1991
+ readonly spaceId: string;
1992
+ readonly requestId: string;
1993
+ readonly targets: readonly StoredRecordErasureTarget[];
1994
+ }
1995
+ interface EraseStoredRecordsInput extends StoredRecordErasureAuthorizationInput {
1996
+ /** Target-lock acquisition budget in milliseconds, 1–60000; default 250. */
1997
+ readonly lockTimeoutMs?: number;
1998
+ /** Rewrite work budget in milliseconds, 1–60000; default 5000. */
1999
+ readonly workTimeoutMs?: number;
2000
+ /** Synchronous JSON-data transformation. A thrown error or invalid result rolls back the batch. */
2001
+ readonly redact: (record: StoredRecordErasureView) => StoredRecordErasureView;
2002
+ }
2003
+ type StoredRecordErasureOutcome = "erased" | "already_erased" | "active" | "not_found";
2004
+ interface EraseStoredRecordsResult {
2005
+ targets: Array<StoredRecordErasureTarget & {
2006
+ outcome: StoredRecordErasureOutcome;
2007
+ }>;
2008
+ /** Records processed, including records processed again by repeat erasure. */
2009
+ counts: Partial<Record<ErasureRecordKind, number>>;
2010
+ }
2011
+ interface ErasablePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
2012
+ /**
2013
+ * Unauthenticated storage port, not an authorization boundary; callers must enforce authorization.
2014
+ * Atomic rewrite/marker/audit operation. The audit retains actorId/actorType as identifying metadata.
2015
+ * Invocation reads expose storedRecordsErased after commit.
2016
+ */
2017
+ eraseStoredRecords(input: EraseStoredRecordsInput): Promise<EraseStoredRecordsResult>;
2018
+ }
2019
+ interface StoredRecordErasureHost {
2020
+ /** Throws StoredRecordErasureAuthorizationError (not_authorized) before store access on authorization refusal. */
2021
+ eraseStoredRecords(input: EraseStoredRecordsInput): Promise<EraseStoredRecordsResult>;
2022
+ }
2023
+ export declare const HOST_RECORDS_ERASED_EVENT: "HostRecordsErased";
2024
+ /** Sentinel replacing required payload digests after stored-record erasure. */
2025
+ export declare const ERASED_DIGEST: "erased";
2026
+ //#endregion
1751
2027
  //#region src/host.d.ts
1752
- export declare function createGovernedActionHost<TDb>(options: PlatformHostOptions<TDb>): GovernedActionHost & OutboxRequeueHost & ApprovalExpiryHost;
2028
+ export declare function createGovernedActionHost<TDb>(options: PlatformHostOptions<TDb>): GovernedActionHost & OutboxRequeueHost & ApprovalExpiryHost & ApprovalDecisionRecordingHost & StoredRecordErasureHost;
1753
2029
  //#endregion
1754
2030
  //#region src/memory-store.d.ts
2031
+ /**
2032
+ * Optional domain snapshot/restore binder. The Host handler callback can request
2033
+ * rollback confirmation after a failed callback and successful undo/restore.
2034
+ * Commit failures and providerless internal transactions supply no confirmation.
2035
+ * Ordinary public transaction callbacks retain their original error objects.
2036
+ */
1755
2037
  export interface MemoryPlatformHostTransactionProvider<TDb> {
1756
2038
  snapshot(db: TDb): TDb;
1757
2039
  restore(db: TDb, snapshot: TDb): void;
1758
2040
  }
1759
- export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb>, StagedInvocationPlatformHostStore<TDb> {
2041
+ export declare class MemoryPlatformHostStore<TDb> implements ErasablePlatformHostStore<TDb>, RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb>, StagedInvocationPlatformHostStore<TDb> {
1760
2042
  readonly db: TDb;
1761
2043
  readonly transactionalOutbox: boolean;
1762
2044
  readonly transactionalApprovalLifecycle: boolean;
1763
- private readonly approvalTransactionProvider;
2045
+ readonly transactionalApprovalAuthorization = true;
1764
2046
  readonly transactionalStagedInvocations: boolean;
1765
2047
  transactionWithEvents?: <TResult>(run: (transaction: PlatformHostMutationTransaction<TDb>) => Promise<TResult>) => Promise<TResult>;
1766
2048
  private adapterCommit;
@@ -1781,10 +2063,16 @@ export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatform
1781
2063
  * `private`, as for the store's other internals, is a compile-time guard.
1782
2064
  */
1783
2065
  private readonly outboxRequeues;
2066
+ private readonly erasedStages;
2067
+ private readonly erasureMarkers;
2068
+ private isErased;
2069
+ private assertNotErased;
2070
+ eraseStoredRecords(request: EraseStoredRecordsInput): Promise<EraseStoredRecordsResult>;
1784
2071
  constructor(db: TDb, transactionProvider?: MemoryPlatformHostTransactionProvider<TDb>);
1785
2072
  transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
1786
2073
  private runTransactionWithEvents;
1787
2074
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
2075
+ recordSubmissionRefusal(input: RecordSubmissionRefusalInput): Promise<ActionInvocationRecord>;
1788
2076
  createActionInvocationForStagedLease(input: CreateStagedActionInvocationInput): Promise<CreateStagedActionInvocationResult>;
1789
2077
  private applyStagedBatch;
1790
2078
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
@@ -1793,7 +2081,8 @@ export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatform
1793
2081
  recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
1794
2082
  private runApprovalTransaction;
1795
2083
  parkApproval(input: ParkApprovalInput): Promise<ApprovalDecisionTransitionResult>;
1796
- beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
2084
+ recordApprovalDecision(input: RecordApprovalDecisionStoreInput<TDb>): Promise<RecordApprovalDecisionStoreResult>;
2085
+ beginApprovalDecision(input: BeginApprovalDecisionInput<TDb>): Promise<ApprovalDecisionTransitionResult>;
1797
2086
  expireDueApprovals(input: ExpireDueApprovalsStoreInput): Promise<ActionInvocationRecord[]>;
1798
2087
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
1799
2088
  recordMutationGovernance(actionInvocationId: string, tenantId: string, spaceId: string, context: Pick<ActionInvocationRecord, "mutationFootprint" | "executionPrincipal"> & {
@@ -1824,13 +2113,14 @@ export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatform
1824
2113
  availableAt: Date;
1825
2114
  deadLetter: boolean;
1826
2115
  }): Promise<void>;
1827
- renewOutboxLease(input: {
2116
+ renewOutboxLease(input: Parameters<OutboxPlatformHostStore<TDb>["renewOutboxLease"]>[0]): Promise<boolean>;
2117
+ renewOutboxLeaseAndRead(input: {
1828
2118
  id: string;
1829
2119
  workerId: string;
1830
2120
  leaseToken: number;
1831
2121
  leaseDurationMs: number;
1832
2122
  now?: Date;
1833
- }): Promise<boolean>;
2123
+ }): Promise<OutboxRecord | undefined>;
1834
2124
  listOutbox(input?: {
1835
2125
  tenantId?: string;
1836
2126
  spaceId?: string;
@@ -1972,21 +2262,37 @@ export interface PostgresPlatformHostTransactionContext<TDb> {
1972
2262
  * `pg.PoolClient`. Production applications provide this adapter so domain
1973
2263
  * methods and Host ledger writes share one PostgreSQL transaction.
1974
2264
  */
2265
+ /**
2266
+ * May reject with ConfirmedTransactionRollback(callbackError) after successful rollback
2267
+ * of a failed callback. Providers omitting that evidence get no in-attempt handler retry.
2268
+ * Commit errors must not be represented as confirmed callback rollback. The store exposes
2269
+ * evidence at the Host handler callback request and normalizes it for other consumers.
2270
+ */
1975
2271
  export interface PostgresPlatformHostTransactionProvider<TDb> {
1976
2272
  run<TResult>(run: (context: PostgresPlatformHostTransactionContext<TDb>) => Promise<TResult>): Promise<TResult>;
1977
2273
  }
1978
2274
  /** Durable mutation-pipeline ledger for Databricks Lakebase or standard Postgres. */
1979
- export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb>, StagedInvocationPlatformHostStore<TDb> {
2275
+ export declare class PostgresPlatformHostStore<TDb> implements ErasablePlatformHostStore<TDb>, RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb>, StagedInvocationPlatformHostStore<TDb> {
1980
2276
  readonly db: TDb;
1981
2277
  private readonly sql;
2278
+ private readonly transactionProvider?;
1982
2279
  readonly transactionWithEvents?: AtomicMutationPlatformHostStore<TDb>["transactionWithEvents"];
2280
+ private ownerLocksPersist;
2281
+ private readonly lockedOwners;
1983
2282
  readonly transactionalOutbox: boolean;
1984
2283
  readonly transactionalApprovalLifecycle: boolean;
2284
+ readonly transactionalApprovalAuthorization: boolean;
1985
2285
  readonly transactionalStagedInvocations: boolean;
1986
- constructor(db: TDb, sql: PlatformHostSqlClient, transactionProvider?: PostgresPlatformHostTransactionProvider<TDb>);
2286
+ constructor(db: TDb, sql: PlatformHostSqlClient, transactionProvider?: PostgresPlatformHostTransactionProvider<TDb> | undefined);
2287
+ /** Internal provider entry: non-handler consumers retain their original error objects. */
2288
+ private runTransaction;
2289
+ private refuseErased;
2290
+ private ownerFence;
1987
2291
  ensureSchema(): Promise<void>;
2292
+ eraseStoredRecords(request: EraseStoredRecordsInput): Promise<EraseStoredRecordsResult>;
1988
2293
  transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
1989
2294
  createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
2295
+ recordSubmissionRefusal(input: RecordSubmissionRefusalInput): Promise<ActionInvocationRecord>;
1990
2296
  createActionInvocationForStagedLease(input: CreateStagedActionInvocationInput): Promise<CreateStagedActionInvocationResult>;
1991
2297
  stageInvocations(records: readonly StagedInvocationRecord[]): Promise<void>;
1992
2298
  getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
@@ -1995,7 +2301,9 @@ export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatfo
1995
2301
  recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
1996
2302
  parkApproval(input: ParkApprovalInput): Promise<ApprovalDecisionTransitionResult>;
1997
2303
  expireDueApprovals(input: ExpireDueApprovalsStoreInput): Promise<ActionInvocationRecord[]>;
1998
- beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
2304
+ private lockDueApprovals;
2305
+ recordApprovalDecision(input: RecordApprovalDecisionStoreInput<TDb>): Promise<RecordApprovalDecisionStoreResult>;
2306
+ beginApprovalDecision(input: BeginApprovalDecisionInput<TDb>): Promise<ApprovalDecisionTransitionResult>;
1999
2307
  appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
2000
2308
  recordMutationGovernance(actionInvocationId: string, tenantId: string, spaceId: string, context: {
2001
2309
  footprint: NonNullable<ActionInvocationRecord["mutationFootprint"]>;
@@ -2024,13 +2332,14 @@ export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatfo
2024
2332
  availableAt: Date;
2025
2333
  deadLetter: boolean;
2026
2334
  }): Promise<void>;
2027
- renewOutboxLease(input: {
2335
+ renewOutboxLease(input: Parameters<OutboxPlatformHostStore<TDb>["renewOutboxLease"]>[0]): Promise<boolean>;
2336
+ renewOutboxLeaseAndRead(input: {
2028
2337
  id: string;
2029
2338
  workerId: string;
2030
2339
  leaseToken: number;
2031
2340
  leaseDurationMs: number;
2032
2341
  now?: Date;
2033
- }): Promise<boolean>;
2342
+ }): Promise<OutboxRecord | undefined>;
2034
2343
  listOutbox(input?: {
2035
2344
  tenantId?: string;
2036
2345
  spaceId?: string;
@@ -2115,7 +2424,9 @@ export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatfo
2115
2424
  updateLeasedActionInvocation(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
2116
2425
  renewActionInvocationLease(input: RenewActionInvocationLeaseInput): Promise<boolean>;
2117
2426
  listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
2118
- getEvent(id: string, tenantId: string, spaceId: string): Promise<AssetEventEnvelope | undefined>;
2427
+ getEvent(id: string, tenantId: string, spaceId: string): Promise<(AssetEventEnvelope & {
2428
+ readonly storedRecordsErased?: true;
2429
+ }) | undefined>;
2119
2430
  }
2120
2431
  //#endregion
2121
2432
  //#region src/postgres-migrations.d.ts
@@ -2259,6 +2570,11 @@ export declare function prepareStagedInvocationBatch<TDb>(input: PrepareStagedIn
2259
2570
  export declare function stagedInvocationRequestIdentity(record: StagedInvocationRecord): string;
2260
2571
  export declare function cloneStagedInvocationRecord(record: StagedInvocationRecord): StagedInvocationRecord;
2261
2572
  export declare function asStagedInvocationStore<TDb>(store: PlatformHostStore<TDb>): StagedInvocationPlatformHostStore<TDb> | undefined;
2573
+ /** Placeholder for published payload-covering batch digests replaced by migration 16. */
2574
+ export declare const LEGACY_BATCH_DIGEST = "legacy-batch";
2575
+ /** Replay comparison used by both built-in stores. Compares the full request identity,
2576
+ * skipping only the batch-digest comparison when the stored row carries LEGACY_BATCH_DIGEST. */
2577
+ export declare function stagedInvocationRequestMatches(stored: StagedInvocationRecord, incoming: StagedInvocationRecord): boolean;
2262
2578
  //#endregion
2263
2579
  //#region src/tenant-isolation.d.ts
2264
2580
  export interface TenantIsolationScope {
@@ -2291,13 +2607,13 @@ export interface TenantIsolationSubject<TDb = unknown> {
2291
2607
  }>;
2292
2608
  /**
2293
2609
  * Optional: put the host and store back to a known state before a check.
2294
- * The checks tolerate accumulated state, and each retires any row it
2295
- * creates directly, so this exists for subjects whose store is shared.
2610
+ * The checks tolerate accumulated state, and direct probes use terminal rows
2611
+ * or retire the active rows they create, so this exists for subjects whose store is shared.
2296
2612
  */
2297
2613
  reset?(): Promise<void> | void;
2298
2614
  }
2299
2615
  export interface TenantIsolationCheck {
2300
- id: "fabric.tenancy.invocation-scoped-read.v1" | "fabric.tenancy.idempotency-key-scoped.v1" | "fabric.tenancy.events-scoped.v1" | "fabric.tenancy.worker-claim-scoped.v1" | "fabric.tenancy.staged-invocation-scoped.v1" | "fabric.tenancy.completion-scoped.v1" | "fabric.tenancy.projection-scoped.v1" | "fabric.tenancy.adapter-invocation-read-scoped.v1" | "fabric.tenancy.adapter-invocation-write-scoped.v1";
2616
+ id: "fabric.tenancy.invocation-scoped-read.v1" | "fabric.tenancy.idempotency-key-scoped.v1" | "fabric.tenancy.submission-refusal-scoped.v1" | "fabric.tenancy.events-scoped.v1" | "fabric.tenancy.worker-claim-scoped.v1" | "fabric.tenancy.staged-invocation-scoped.v1" | "fabric.tenancy.completion-scoped.v1" | "fabric.tenancy.projection-scoped.v1" | "fabric.tenancy.adapter-invocation-read-scoped.v1" | "fabric.tenancy.adapter-invocation-write-scoped.v1";
2301
2617
  run(subject: TenantIsolationSubject): Promise<string[]>;
2302
2618
  }
2303
2619
  export interface TenantIsolationResult {
@@ -2312,9 +2628,10 @@ export interface TenantIsolationResult {
2312
2628
  /**
2313
2629
  * The suite a deployment of the host must pass before it claims isolation.
2314
2630
  *
2315
- * Nine checks: an invocation cannot be read, executed, or completed under
2631
+ * Ten checks: an invocation cannot be read, executed, or completed under
2316
2632
  * another tenant's scope; an idempotency key is a tenant's own, so the same
2317
- * key in two tenants is two invocations; a tenant's event stream carries no
2633
+ * key in two tenants is two invocations; optional recorded refusals retain
2634
+ * tenant and space scope, including when ordinary creation encounters a refusal; a tenant's event stream carries no
2318
2635
  * other tenant's events; a worker scoped to one tenant does not claim another's
2319
2636
  * work; staged listing and claiming retain tenant and space scope; an adapter
2320
2637
  * checkpoint cannot be read or written under another tenant, space, or owning
@@ -2401,4 +2718,211 @@ export declare function eventAppendChecks(): readonly EventAppendCheck[];
2401
2718
  */
2402
2719
  export declare function runEventAppendChecks<TDb>(subject: EventAppendSubject<TDb>): Promise<EventAppendResult>;
2403
2720
  //#endregion
2404
- export { canonicalJson };
2721
+ //#region src/erasure.d.ts
2722
+ export declare function createStoredRecordErasureHost<TDb>(store: PlatformHostStore<TDb>, authorization: Pick<PlatformHostAuthorization<TDb>, "authorizeStoredRecordErasure">): StoredRecordErasureHost;
2723
+ //#endregion
2724
+ //#region src/erasure-conformance.d.ts
2725
+ export interface ErasureProbeScope {
2726
+ tenantId: string;
2727
+ spaceId: string;
2728
+ invocationId: string;
2729
+ }
2730
+ export interface ErasureSubject<TDb = unknown> {
2731
+ store: PlatformHostStore<TDb> & Partial<ErasablePlatformHostStore<TDb>> & {
2732
+ listEvents?(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
2733
+ };
2734
+ tenantId: string;
2735
+ /** Test-store fixture access for record kinds not readable through the base store port. */
2736
+ payloadRecords?: {
2737
+ seed(scope: ErasureProbeScope, sentinel: string): Promise<void>;
2738
+ read(scope: ErasureProbeScope): Promise<readonly {
2739
+ kind: ErasureRecordKind;
2740
+ value: unknown;
2741
+ }[]>;
2742
+ };
2743
+ }
2744
+ export interface ErasureCheck {
2745
+ id: string;
2746
+ run(subject: ErasureSubject): Promise<string[]>;
2747
+ }
2748
+ export interface ErasureResult {
2749
+ passed: boolean;
2750
+ checks: Array<{
2751
+ id: string;
2752
+ status: "passed" | "failed" | "skipped";
2753
+ evidence: string[];
2754
+ error?: string;
2755
+ }>;
2756
+ }
2757
+ /** Destructive probes for isolated test stores; leave evidence in fresh probe spaces. */
2758
+ export declare function erasureChecks(): readonly ErasureCheck[];
2759
+ export declare function runErasureChecks<TDb>(subject: ErasureSubject<TDb>): Promise<ErasureResult>;
2760
+ //#endregion
2761
+ //#region src/erasure-errors.d.ts
2762
+ /** Host authorization refusal; contains no target existence or authorizer failure details. */
2763
+ export declare class StoredRecordErasureAuthorizationError extends Error {
2764
+ readonly refusal = "not_authorized";
2765
+ constructor(message: string);
2766
+ }
2767
+ /** A later mutation of an erased record was refused. */
2768
+ export declare class StoredRecordsErasedError extends Error {
2769
+ readonly code = "HOST_RECORDS_ERASED";
2770
+ constructor();
2771
+ }
2772
+ /** Erasure could not lock its targets or finish within the configured budget. */
2773
+ export declare class ErasureBusyError extends Error {
2774
+ readonly reason: "lock_timeout" | "work_timeout";
2775
+ readonly code = "HOST_ERASURE_BUSY";
2776
+ constructor(reason: "lock_timeout" | "work_timeout", options?: ErrorOptions);
2777
+ }
2778
+ //#endregion
2779
+ //#region src/staged-invocation-conformance.d.ts
2780
+ export type StagedContractStore = StagedInvocationPlatformHostStore<unknown> & AtomicMutationPlatformHostStore<unknown>;
2781
+ export interface StagedCreateRotateRaceInput {
2782
+ record: StagedInvocationRecord;
2783
+ workerId: string;
2784
+ leaseToken: number;
2785
+ now: Date;
2786
+ invocation: CreateActionInvocationInput & {
2787
+ stagedOrigin: {
2788
+ parentInvocationId: string;
2789
+ stageKey: string;
2790
+ principal?: string;
2791
+ };
2792
+ };
2793
+ }
2794
+ export interface StagedCreateRotateRaceOutcome {
2795
+ creation: CreateStagedActionInvocationResult;
2796
+ rotatedToken: number | undefined;
2797
+ }
2798
+ /**
2799
+ * A store whose fence can interleave with rotation (PostgreSQL) supplies the
2800
+ * two races with the first operation held open in a transaction, proving the
2801
+ * second waits for it. Without them the contract runs both operations
2802
+ * concurrently, which serializes in the memory store.
2803
+ */
2804
+ export interface StagedContractHarness {
2805
+ store: StagedContractStore;
2806
+ /** Fenced create held uncommitted; a rotation under the same token must wait for it. */
2807
+ raceCreateThenRotate?(input: StagedCreateRotateRaceInput): Promise<StagedCreateRotateRaceOutcome>;
2808
+ /** Rotation held uncommitted; a fenced create under the old token must wait, then create nothing. */
2809
+ raceRotateThenCreate?(input: StagedCreateRotateRaceInput): Promise<StagedCreateRotateRaceOutcome>;
2810
+ }
2811
+ export interface StagedInvocationSubject {
2812
+ makeHarness(): Promise<StagedContractHarness>;
2813
+ }
2814
+ export interface StagedInvocationCheck {
2815
+ id: string;
2816
+ run(subject: StagedInvocationSubject): Promise<string[]>;
2817
+ }
2818
+ export interface StagedInvocationResult {
2819
+ passed: boolean;
2820
+ checks: Array<{
2821
+ id: string;
2822
+ status: "passed" | "failed" | "skipped";
2823
+ evidence: string[];
2824
+ error?: string;
2825
+ }>;
2826
+ }
2827
+ /** Destructive probes for isolated test stores; leave records in fresh probe spaces. */
2828
+ export declare function stagedInvocationChecks(): readonly StagedInvocationCheck[];
2829
+ export declare function runStagedInvocationChecks(subject: StagedInvocationSubject): Promise<StagedInvocationResult>;
2830
+ //#endregion
2831
+ //#region src/outbox-requeue-conformance.d.ts
2832
+ export interface OutboxRequeueSubject {
2833
+ makeStore(): Promise<OutboxRequeuePlatformHostStore<unknown>>;
2834
+ }
2835
+ export interface OutboxRequeueCheck {
2836
+ id: string;
2837
+ run(subject: OutboxRequeueSubject): Promise<string[]>;
2838
+ }
2839
+ export interface OutboxRequeueResult {
2840
+ passed: boolean;
2841
+ checks: Array<{
2842
+ id: string;
2843
+ status: "passed" | "failed" | "skipped";
2844
+ evidence: string[];
2845
+ error?: string;
2846
+ }>;
2847
+ }
2848
+ /** Destructive probes for isolated test stores; leave outbox and audit records under fresh identities. */
2849
+ export declare function outboxRequeueChecks(): readonly OutboxRequeueCheck[];
2850
+ export declare function runOutboxRequeueChecks(subject: OutboxRequeueSubject): Promise<OutboxRequeueResult>;
2851
+ //#endregion
2852
+ //#region src/approval-conformance.d.ts
2853
+ export type ApprovalCheckStore = ApprovalPlatformHostStore<{}> & Partial<AtomicMutationPlatformHostStore<{}>> & RecoverablePlatformHostStore<{}> & OutboxPlatformHostStore<{}>;
2854
+ export interface ApprovalSubject {
2855
+ makeStore(): Promise<ApprovalCheckStore>;
2856
+ }
2857
+ export interface ApprovalCheck {
2858
+ id: string;
2859
+ run(subject: ApprovalSubject): Promise<string[]>;
2860
+ }
2861
+ export interface ApprovalResult {
2862
+ passed: boolean;
2863
+ checks: Array<{
2864
+ id: string;
2865
+ status: "passed" | "failed" | "skipped";
2866
+ evidence: string[];
2867
+ error?: string;
2868
+ }>;
2869
+ }
2870
+ /** Destructive probes for isolated test stores; leave invocation, event and outbox evidence under fresh identities. */
2871
+ export declare function approvalChecks(): readonly ApprovalCheck[];
2872
+ export declare function runApprovalChecks(subject: ApprovalSubject): Promise<ApprovalResult>;
2873
+ //#endregion
2874
+ //#region src/outbox-relay-conformance.d.ts
2875
+ export interface OutboxRelaySubject {
2876
+ makeStore(): Promise<OutboxPlatformHostStore<unknown>>;
2877
+ }
2878
+ export interface OutboxRelayCheck {
2879
+ id: string;
2880
+ run(subject: OutboxRelaySubject): Promise<string[]>;
2881
+ }
2882
+ export interface OutboxRelayConformanceResult {
2883
+ passed: boolean;
2884
+ checks: Array<{
2885
+ id: string;
2886
+ status: "passed" | "failed" | "skipped";
2887
+ evidence: string[];
2888
+ error?: string;
2889
+ }>;
2890
+ }
2891
+ /** Destructive probes for isolated test stores; leave outbox records under fresh identities and spaces. */
2892
+ export declare function outboxRelayChecks(): readonly OutboxRelayCheck[];
2893
+ export declare function runOutboxRelayChecks(subject: OutboxRelaySubject): Promise<OutboxRelayConformanceResult>;
2894
+ //#endregion
2895
+ //#region src/invocation-idempotency-conformance.d.ts
2896
+ export interface InvocationIdempotencySubject {
2897
+ makeStore(): Promise<PlatformHostStore<unknown>>;
2898
+ }
2899
+ export interface InvocationIdempotencyCheck {
2900
+ id: string;
2901
+ run(subject: InvocationIdempotencySubject): Promise<string[]>;
2902
+ }
2903
+ export interface InvocationIdempotencyResult {
2904
+ passed: boolean;
2905
+ checks: Array<{
2906
+ id: string;
2907
+ status: "passed" | "failed" | "skipped";
2908
+ evidence: string[];
2909
+ error?: string;
2910
+ }>;
2911
+ }
2912
+ /** Destructive probes for isolated test stores; leave invocation records under fresh identities and spaces. */
2913
+ export declare function invocationIdempotencyChecks(): readonly InvocationIdempotencyCheck[];
2914
+ export declare function runInvocationIdempotencyChecks(subject: InvocationIdempotencySubject): Promise<InvocationIdempotencyResult>;
2915
+ //#endregion
2916
+ //#region src/transaction-rollback.d.ts
2917
+ /** Evidence from a transaction provider that rollback completed successfully. */
2918
+ export declare class ConfirmedTransactionRollback extends Error {
2919
+ readonly name = "ConfirmedTransactionRollback";
2920
+ readonly code: "TRANSACTION_ROLLBACK_CONFIRMED";
2921
+ constructor(cause: unknown);
2922
+ }
2923
+ /** Recognise rollback evidence across ESM/CommonJS or other package copies. */
2924
+ export declare function isConfirmedTransactionRollback(error: unknown): error is ConfirmedTransactionRollback;
2925
+ /** Inspect up to 16 errors, failing closed on cycles or unreadable properties. Intended for handlerRetry.classify. */
2926
+ export declare function isTransientPostgresTransactionError(error: unknown): boolean;
2927
+ //#endregion
2928
+ export { type ErasablePlatformHostStore, type EraseStoredRecordsInput, type EraseStoredRecordsResult, type ErasurePayloadFields, type ErasureRecordKind, type StoredRecordErasureAuthorizationInput, type StoredRecordErasureHost, type StoredRecordErasureOutcome, type StoredRecordErasureTarget, type StoredRecordErasureView, canonicalJson };