@abloatai/humans 0.48.0 → 0.50.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.
Files changed (106) hide show
  1. package/dist/client.d.ts +6 -0
  2. package/dist/humans.d.ts +1 -1
  3. package/dist/local/RuntimeContext.d.ts +1 -1
  4. package/dist/local/SyncClient.d.ts +1 -1
  5. package/dist/local/SyncClient.js +3 -3
  6. package/dist/local/client/createModelProxy.d.ts +7 -1
  7. package/dist/local/client/createModelProxy.js +146 -39
  8. package/dist/local/client/options.d.ts +1 -1
  9. package/dist/local/client/reactiveEngine.js +69 -7
  10. package/dist/local/client/resourceTypes.d.ts +1 -1
  11. package/dist/local/client/resourceTypes.js +1 -1
  12. package/dist/local/client/storeCluster.d.ts +3 -0
  13. package/dist/local/client/storeCluster.js +4 -2
  14. package/dist/local/client/storeLifecycle.d.ts +2 -0
  15. package/dist/local/client/storeLifecycle.js +1 -0
  16. package/dist/local/client/wsMutationExecutor.d.ts +4 -1
  17. package/dist/local/client/wsMutationExecutor.js +26 -2
  18. package/dist/local/context.js +5 -1
  19. package/dist/local/interfaces/index.d.ts +3 -1
  20. package/dist/local/mutators/UndoManager.d.ts +1 -1
  21. package/dist/local/mutators/UndoManager.js +1 -1
  22. package/dist/local/query/client.js +15 -0
  23. package/dist/local/query/types.d.ts +14 -0
  24. package/dist/local/stores/syncAction.d.ts +1 -1
  25. package/dist/local/stores/syncAction.js +1 -1
  26. package/dist/local/sync/ConnectionManager.d.ts +1 -1
  27. package/dist/local/sync/ConnectionManager.js +1 -1
  28. package/dist/local/sync/OnDemandLoader.d.ts +3 -0
  29. package/dist/local/sync/OnDemandLoader.js +15 -2
  30. package/dist/local/sync/SyncWebSocket.d.ts +1 -1
  31. package/dist/local/sync/SyncWebSocket.js +1 -1
  32. package/dist/local/sync/commitFrames.d.ts +1 -1
  33. package/dist/local/sync/commitFrames.js +1 -1
  34. package/dist/local/sync/contextPorts.d.ts +1 -1
  35. package/dist/local/sync/contextPorts.js +1 -1
  36. package/dist/local/sync/credentialLifecycle.d.ts +1 -1
  37. package/dist/local/sync/credentialLifecycle.js +1 -1
  38. package/dist/local/sync/wsFrameHandlers.d.ts +1 -1
  39. package/dist/local/sync/wsFrameHandlers.js +1 -1
  40. package/dist/local/transactions/databaseCommitOutbox.d.ts +1 -1
  41. package/dist/local/transactions/localMutation.d.ts +1 -1
  42. package/dist/local/transactions/localMutation.js +1 -1
  43. package/dist/local/transactions/mutations/MutationQueue.d.ts +2 -2
  44. package/dist/local/transactions/mutations/MutationQueue.js +4 -4
  45. package/dist/local/transactions/mutations/batchProcessing.d.ts +1 -1
  46. package/dist/local/transactions/mutations/commitApi.d.ts +1 -1
  47. package/dist/local/transactions/mutations/commitLane.d.ts +1 -1
  48. package/dist/local/transactions/mutations/commitPayload.d.ts +2 -1
  49. package/dist/local/transactions/mutations/commitPayload.js +8 -0
  50. package/dist/local/transactions/mutations/commitTransport.d.ts +1 -1
  51. package/dist/local/transactions/mutations/commitTransport.js +1 -1
  52. package/dist/local/transactions/mutations/durableCommitRestore.d.ts +1 -1
  53. package/dist/local/transactions/mutations/durableCommitRestore.js +1 -1
  54. package/dist/local/transactions/mutations/durableWriteStore.d.ts +4 -4
  55. package/dist/local/transactions/mutations/durableWriteStore.js +3 -3
  56. package/dist/local/transactions/mutations/localMutation.d.ts +1 -1
  57. package/dist/local/transactions/mutations/mutationPersistence.d.ts +1 -1
  58. package/dist/local/transactions/mutations/pendingDrain.d.ts +2 -2
  59. package/dist/local/transactions/mutations/pendingDrain.js +1 -1
  60. package/dist/local/transactions/mutations/replayValidation.d.ts +13 -1
  61. package/dist/local/transactions/mutations/replayValidation.js +3 -2
  62. package/dist/local/transactions/reconnectDrain.d.ts +1 -1
  63. package/dist/react/useSyncStatus.d.ts +1 -1
  64. package/dist/react/useSyncStatus.js +1 -1
  65. package/package.json +2 -2
  66. package/src/Ablo.ts +1 -1
  67. package/src/client.ts +7 -0
  68. package/src/humans.ts +1 -1
  69. package/src/local/RuntimeContext.ts +1 -1
  70. package/src/local/SyncClient.ts +3 -3
  71. package/src/local/client/createModelProxy.ts +236 -55
  72. package/src/local/client/options.ts +1 -1
  73. package/src/local/client/reactiveEngine.ts +81 -4
  74. package/src/local/client/resourceTypes.ts +1 -1
  75. package/src/local/client/storeCluster.ts +12 -2
  76. package/src/local/client/storeLifecycle.ts +3 -0
  77. package/src/local/client/wsMutationExecutor.ts +43 -1
  78. package/src/local/context.ts +5 -1
  79. package/src/local/interfaces/index.ts +7 -5
  80. package/src/local/mutators/UndoManager.ts +1 -1
  81. package/src/local/query/client.ts +17 -0
  82. package/src/local/query/types.ts +16 -1
  83. package/src/local/stores/syncAction.ts +1 -1
  84. package/src/local/sync/ConnectionManager.ts +1 -1
  85. package/src/local/sync/OnDemandLoader.ts +20 -3
  86. package/src/local/sync/SyncWebSocket.ts +1 -1
  87. package/src/local/sync/commitFrames.ts +1 -1
  88. package/src/local/sync/contextPorts.ts +1 -1
  89. package/src/local/sync/credentialLifecycle.ts +1 -1
  90. package/src/local/sync/wsFrameHandlers.ts +1 -1
  91. package/src/local/transactions/databaseCommitOutbox.ts +1 -1
  92. package/src/local/transactions/localMutation.ts +1 -1
  93. package/src/local/transactions/mutations/MutationQueue.ts +4 -4
  94. package/src/local/transactions/mutations/batchProcessing.ts +1 -1
  95. package/src/local/transactions/mutations/commitApi.ts +1 -1
  96. package/src/local/transactions/mutations/commitLane.ts +1 -1
  97. package/src/local/transactions/mutations/commitPayload.ts +10 -1
  98. package/src/local/transactions/mutations/commitTransport.ts +1 -1
  99. package/src/local/transactions/mutations/durableCommitRestore.ts +2 -2
  100. package/src/local/transactions/mutations/durableWriteStore.ts +4 -4
  101. package/src/local/transactions/mutations/localMutation.ts +1 -1
  102. package/src/local/transactions/mutations/mutationPersistence.ts +1 -1
  103. package/src/local/transactions/mutations/pendingDrain.ts +2 -2
  104. package/src/local/transactions/mutations/replayValidation.ts +3 -2
  105. package/src/local/transactions/reconnectDrain.ts +1 -1
  106. package/src/react/useSyncStatus.ts +1 -1
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import type { SchemaRecord, Schema } from '@abloatai/transaction/schema/schema';
12
12
  import type { ParticipantKind } from '@abloatai/transaction/types/participant';
13
+ import type { EffectiveAuthority } from '@abloatai/transaction/auth';
13
14
  import type { Logger } from '@abloatai/transaction/logger';
14
15
  import type { AuthCredentialSource } from '@abloatai/transaction/auth/credentialSource';
15
16
  import type { CredentialProvider } from '@abloatai/transaction/auth/apiKey';
@@ -23,6 +24,7 @@ export interface IdentitySeed {
23
24
  /** The resolved account scope; null until known. */
24
25
  readonly accountScope: string | null;
25
26
  readonly syncGroups: readonly string[];
27
+ readonly authority: EffectiveAuthority;
26
28
  }
27
29
  export interface StoreLifecycle {
28
30
  /**
@@ -169,6 +169,7 @@ export function startStoreLifecycle(deps) {
169
169
  participantKind,
170
170
  accountScope,
171
171
  syncGroups: resolvedSyncGroups,
172
+ authority: resolved.authority,
172
173
  });
173
174
  if (resolved.refreshScheduler) {
174
175
  _refreshScheduler = resolved.refreshScheduler;
@@ -7,6 +7,8 @@
7
7
  import type { ReadDependency, TrackDependency } from '@abloatai/transaction/coordination/schema';
8
8
  import type { MutationExecutor, MutationOperation } from '../interfaces/index.js';
9
9
  import type { CommitAck } from '../sync/commitFrames.js';
10
+ import type { CommitReceiptWire } from '@abloatai/transaction/wire/commit';
11
+ import { type ReadSetContext } from '@abloatai/transaction/internal/read-set';
10
12
  /**
11
13
  * Creates the default mutation executor, which sends each change as a `commit`
12
14
  * frame over the sync engine's own WebSocket. The engine owns its socket, so
@@ -23,5 +25,6 @@ import type { CommitAck } from '../sync/commitFrames.js';
23
25
  * generation below exists only for direct, one-shot executor consumers.
24
26
  */
25
27
  export declare function createDefaultMutationExecutor(getWs: () => {
28
+ sendCommitReceipt?: (operations: readonly MutationOperation[], clientTxId: string, timeoutMs?: number, reads?: readonly ReadDependency[] | null, track?: readonly TrackDependency[] | null) => Promise<CommitReceiptWire>;
26
29
  sendCommit?: (operations: readonly MutationOperation[], clientTxId: string, timeoutMs?: number, reads?: readonly ReadDependency[] | null, track?: readonly TrackDependency[] | null) => Promise<CommitAck>;
27
- } | null): MutationExecutor;
30
+ } | null, readSetContext?: ReadSetContext): MutationExecutor;
@@ -4,6 +4,8 @@
4
4
  * commit time because it does not exist yet when the executor is created. A
5
5
  * client wires this up automatically unless you supply your own executor.
6
6
  */
7
+ import { recordWebSocketCommitReceipt, } from '@abloatai/transaction/internal/read-set';
8
+ import { commitAckSchema } from '@abloatai/transaction/wire/commit';
7
9
  import { AbloError, AbloConnectionError } from '@abloatai/transaction/errors';
8
10
  // ── Default mutation executor (wire: `commit` frame over WebSocket) ──────
9
11
  /**
@@ -21,10 +23,10 @@ import { AbloError, AbloConnectionError } from '@abloatai/transaction/errors';
21
23
  * this key before its first attempt and owns reuse across retries. The fallback
22
24
  * generation below exists only for direct, one-shot executor consumers.
23
25
  */
24
- export function createDefaultMutationExecutor(getWs) {
26
+ export function createDefaultMutationExecutor(getWs, readSetContext) {
25
27
  async function commit(operations, options) {
26
28
  const ws = getWs();
27
- if (!ws?.sendCommit) {
29
+ if (!ws || (!ws.sendCommit && !ws.sendCommitReceipt)) {
28
30
  throw new AbloConnectionError('SyncWebSocket not ready for commit. The engine must finish bootstrap ' +
29
31
  'before mutations can be sent.', { code: 'ws_not_ready' });
30
32
  }
@@ -33,6 +35,28 @@ export function createDefaultMutationExecutor(getWs) {
33
35
  ? crypto.randomUUID()
34
36
  : `tx_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`);
35
37
  try {
38
+ if (ws.sendCommitReceipt) {
39
+ const receipt = await ws.sendCommitReceipt(operations, clientTxId, undefined, options?.reads, options?.track);
40
+ recordWebSocketCommitReceipt(readSetContext, {
41
+ receipt,
42
+ operations,
43
+ reads: options?.reads,
44
+ track: options?.track,
45
+ });
46
+ return commitAckSchema.parse({
47
+ status: receipt.status,
48
+ statusAt: receipt.statusAt,
49
+ lastSyncId: receipt.lastSyncId,
50
+ ...(receipt.correlationId ? { correlationId: receipt.correlationId } : {}),
51
+ ...(receipt.notifications ? { notifications: receipt.notifications } : {}),
52
+ ...(receipt.missingIds ? { missingIds: receipt.missingIds } : {}),
53
+ });
54
+ }
55
+ if (!ws.sendCommit) {
56
+ throw new AbloConnectionError('SyncWebSocket commit transport is unavailable.', {
57
+ code: 'ws_not_ready',
58
+ });
59
+ }
36
60
  return await ws.sendCommit(operations, clientTxId, undefined, // use sendCommit's built-in 15s default; no per-call override
37
61
  options?.reads, options?.track);
38
62
  }
@@ -71,7 +71,11 @@ const _fallback = {
71
71
  config: emptyConfig,
72
72
  getModelMetadata: () => undefined,
73
73
  mutationExecutor: {
74
- commit: () => Promise.resolve({ lastSyncId: 0, status: 'confirmed' }),
74
+ commit: () => Promise.resolve({
75
+ status: 'confirmed',
76
+ statusAt: '1970-01-01T00:00:00.000Z',
77
+ lastSyncId: 0,
78
+ }),
75
79
  executeCreate: () => Promise.resolve(),
76
80
  executeUpdate: () => Promise.resolve(null),
77
81
  executeDelete: () => Promise.resolve(),
@@ -142,7 +142,7 @@ import type { MutationOptions } from '@abloatai/transaction/resources/mutationOp
142
142
  * `claim` are deliberately absent: both are resolved on the client before a write
143
143
  * is staged, so neither reaches this layer.
144
144
  */
145
- export type WriteOptions = Pick<MutationOptions, 'readAt' | 'onStale' | 'idempotencyKey' | 'label' | 'fenceToken'>;
145
+ export type WriteOptions = Pick<MutationOptions, 'readAt' | 'onStale' | 'idempotencyKey' | 'label' | 'fenceToken' | 'claimRef'>;
146
146
  /** A single mutation within a batch. Its `options` travel with it so the server
147
147
  * can cache and replay the operation for idempotent retries. */
148
148
  export interface MutationOperation {
@@ -162,6 +162,8 @@ export interface MutationOperation {
162
162
  * the wire at once.
163
163
  */
164
164
  transactionId?: string;
165
+ /** Server-issued claim identity the operation is attributed to. */
166
+ claimId?: string | null;
165
167
  readAt?: number | null;
166
168
  onStale?: OnStaleMode | null;
167
169
  /**
@@ -168,7 +168,7 @@ export declare class UndoScope<S extends Schema> {
168
168
  * Run `work` after every previously-enqueued scope operation has settled,
169
169
  * in invocation order. The internal `tail` always resolves (failures are
170
170
  * swallowed *for the chain only*) so one rejected mutator can't wedge the
171
- * queue; the original settlement is still surfaced to this call's caller.
171
+ * queue; the original confirmation is still surfaced to this call's caller.
172
172
  */
173
173
  private enqueue;
174
174
  /**
@@ -315,7 +315,7 @@ export class UndoScope {
315
315
  * Run `work` after every previously-enqueued scope operation has settled,
316
316
  * in invocation order. The internal `tail` always resolves (failures are
317
317
  * swallowed *for the chain only*) so one rejected mutator can't wedge the
318
- * queue; the original settlement is still surfaced to this call's caller.
318
+ * queue; the original confirmation is still surfaced to this call's caller.
319
319
  */
320
320
  enqueue(work) {
321
321
  const result = this.tail.then(work, work);
@@ -12,6 +12,7 @@
12
12
  * repeating the fetch and error-handling boilerplate.
13
13
  */
14
14
  import { z } from 'zod';
15
+ import { modelListEvidenceSchema } from '@abloatai/transaction/wire';
15
16
  import { translateHttpError } from '@abloatai/transaction/errors';
16
17
  import { classifyRecovery } from '@abloatai/transaction/errorCodes';
17
18
  import { withAuthHeaders } from '@abloatai/transaction/auth/credentialSource';
@@ -33,6 +34,16 @@ const QueryResultSchema = z
33
34
  const QueryBatchResultSchema = z
34
35
  .object({
35
36
  results: z.array(QueryResultSchema),
37
+ evidence: z.array(z.array(modelListEvidenceSchema)).optional(),
38
+ errors: z.array(z.object({
39
+ index: z.number().int().nonnegative(),
40
+ model: z.string(),
41
+ type: z.string(),
42
+ code: z.string(),
43
+ message: z.string(),
44
+ request_id: z.string().optional(),
45
+ event_id: z.string(),
46
+ })).optional(),
36
47
  })
37
48
  .loose();
38
49
  /**
@@ -129,6 +140,10 @@ export async function postQuery(options, batch) {
129
140
  });
130
141
  return { results: batch.queries.map(() => []) };
131
142
  }
143
+ for (const failure of parsed.data.errors ?? []) {
144
+ runtime.logger.warn(`Could not load ${failure.model} — ${failure.message} (code: ${failure.code}, ref: ${failure.request_id ?? failure.event_id}). No results were returned for slot ${failure.index}.`);
145
+ runtime.logger.debug('[postQuery.error] query slot failure', failure);
146
+ }
132
147
  return parsed.data;
133
148
  }
134
149
  finally {
@@ -15,6 +15,7 @@
15
15
  */
16
16
  export type { WherePrimitive, WhereOp, WhereClause, LoadWhere, } from '@abloatai/transaction/resources/where';
17
17
  import type { WhereClause } from '@abloatai/transaction/resources/where';
18
+ import type { ModelListEvidence } from '@abloatai/transaction/wire';
18
19
  /** A single structured fetch request. */
19
20
  export interface Query {
20
21
  /**
@@ -76,6 +77,18 @@ export interface QueryBatchResult {
76
77
  * before use.
77
78
  */
78
79
  results: unknown[];
80
+ /** Per-result-slot evidence for the primary rows in that slot. */
81
+ evidence?: readonly (readonly QueryReadEvidence[])[];
82
+ /** Per-slot failures that previously looked identical to an empty result. */
83
+ errors?: readonly {
84
+ index: number;
85
+ model: string;
86
+ type: string;
87
+ code: string;
88
+ message: string;
89
+ request_id?: string;
90
+ event_id: string;
91
+ }[];
79
92
  /**
80
93
  * The server watermark observed after the batch ran. Model reads expose this
81
94
  * as `stamp`, and callers thread it into `commits.create({ readAt })` so the
@@ -83,3 +96,4 @@ export interface QueryBatchResult {
83
96
  */
84
97
  lastSyncId?: number;
85
98
  }
99
+ export type QueryReadEvidence = ModelListEvidence;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The persisted local action record consumed by `SyncActionStore`. It is a
3
3
  * client materialization artifact, not a transaction-layer wire shape: the
4
- * authoritative broadcast vocabulary is the settlement core's delta wire
4
+ * authoritative broadcast vocabulary is the confirmation core's delta wire
5
5
  * schema, while this one adds the local `__class` discriminator IndexedDB uses.
6
6
  */
7
7
  import { z } from 'zod';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The persisted local action record consumed by `SyncActionStore`. It is a
3
3
  * client materialization artifact, not a transaction-layer wire shape: the
4
- * authoritative broadcast vocabulary is the settlement core's delta wire
4
+ * authoritative broadcast vocabulary is the confirmation core's delta wire
5
5
  * schema, while this one adds the local `__class` discriminator IndexedDB uses.
6
6
  */
7
7
  import { z } from 'zod';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): the
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): the
3
3
  * connection state machine is plain, mobx-free plumbing an agent needs as much
4
4
  * as a browser does. This path re-exports it so existing importers stay
5
5
  * unchanged; the reactive store mirrors its transitions through
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): the
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): the
3
3
  * connection state machine is plain, mobx-free plumbing an agent needs as much
4
4
  * as a browser does. This path re-exports it so existing importers stay
5
5
  * unchanged; the reactive store mirrors its transitions through
@@ -78,6 +78,7 @@ export interface FetchOptions<T> {
78
78
  }
79
79
  export declare class OnDemandLoader {
80
80
  private readonly opts;
81
+ private readonly readEvidence;
81
82
  private readonly inFlight;
82
83
  /**
83
84
  * Query keys with a background confirm currently in flight. Distinct from
@@ -125,6 +126,8 @@ export declare class OnDemandLoader {
125
126
  * deduped on the (modelName, where, orderBy, limit) tuple.
126
127
  */
127
128
  fetch<T>(modelName: string, options?: FetchOptions<T>): Promise<Model[]>;
129
+ /** Exact evidence retained for a row returned by a server-confirmed fetch. */
130
+ getReadEvidence(row: object): number | undefined;
128
131
  private runFetch;
129
132
  /**
130
133
  * Read a query's rows from local storage only — pool first, then IndexedDB
@@ -49,6 +49,7 @@ function snapshotDoesNotAdvanceModel(data, model) {
49
49
  }
50
50
  export class OnDemandLoader {
51
51
  opts;
52
+ readEvidence = new WeakMap();
52
53
  inFlight = new Map();
53
54
  /**
54
55
  * Query keys with a background confirm currently in flight. Distinct from
@@ -135,6 +136,10 @@ export class OnDemandLoader {
135
136
  .catch(() => undefined);
136
137
  return work;
137
138
  }
139
+ /** Exact evidence retained for a row returned by a server-confirmed fetch. */
140
+ getReadEvidence(row) {
141
+ return this.readEvidence.get(row);
142
+ }
138
143
  async runFetch(modelName, typename, ModelClass, clauses, options, queryKey) {
139
144
  // `{ type: 'complete' }` is the only way to force a server round-trip:
140
145
  // read-after-write certainty. Every other read is local-first.
@@ -217,7 +222,8 @@ export class OnDemandLoader {
217
222
  * revalidation kicked off after an `'unknown'` local hit.
218
223
  */
219
224
  async fetchFromNetwork(modelName, typename, clauses, options) {
220
- const networkRows = await this.queryNetwork(modelName, clauses, options);
225
+ const network = await this.queryNetwork(modelName, clauses, options);
226
+ const networkRows = network.rows;
221
227
  const networkModels = networkRows
222
228
  // Strict: a row the server returned whose type name this client never
223
229
  // registered is a genuine schema collision (the pushed schema differs
@@ -225,6 +231,12 @@ export class OnDemandLoader {
225
231
  // dropping the row and failing downstream as `entity_not_found`.
226
232
  .map((raw) => this.hydrateOne(raw, typename, { strict: true }))
227
233
  .filter((m) => m !== null);
234
+ const evidenceById = new Map(network.evidence.map((entry) => [entry.id, entry.stamp]));
235
+ for (const model of networkModels) {
236
+ const stamp = evidenceById.get(model.id);
237
+ if (stamp !== undefined)
238
+ this.readEvidence.set(model, stamp);
239
+ }
228
240
  if (networkModels.length > 0) {
229
241
  this.opts.objectPool.addBatch(networkModels, ModelScope.live);
230
242
  // Background IDB write — don't block the caller. Expanded children are
@@ -435,6 +447,7 @@ export class OnDemandLoader {
435
447
  runtime: this.opts.runtime,
436
448
  }, { queries: [query] });
437
449
  const rows = Array.isArray(result.results[0]) ? result.results[0] : [];
450
+ const evidence = result.evidence?.[0] ?? [];
438
451
  // Normalize: wire rows lack `__typename` when the server elides it.
439
452
  const normalized = rows.map((row) => {
440
453
  if (row && typeof row === 'object' && !('__typename' in row)) {
@@ -453,7 +466,7 @@ export class OnDemandLoader {
453
466
  if (options?.expand && options.expand.length > 0) {
454
467
  this.hydrateExpanded(modelName, normalized, options.expand);
455
468
  }
456
- return normalized;
469
+ return { rows: normalized, evidence };
457
470
  }
458
471
  /**
459
472
  * Hydrate nested expanded rows. Resolves each relation's target
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The reactive engine's connection to the sync server: the settlement core's
2
+ * The reactive engine's connection to the sync server: the confirmation core's
3
3
  * duplex transport ({@link WsTransport}, ADR 0016) plus everything that turns
4
4
  * the stream into a local, watchable copy — wire-delta validation, the resume
5
5
  * cursor and its persistence-gated ack discipline, incremental sync and
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The reactive engine's connection to the sync server: the settlement core's
2
+ * The reactive engine's connection to the sync server: the confirmation core's
3
3
  * duplex transport ({@link WsTransport}, ADR 0016) plus everything that turns
4
4
  * the stream into a local, watchable copy — wire-delta validation, the resume
5
5
  * cursor and its persistence-gated ack discipline, incremental sync and
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): the
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): the
3
3
  * commit-path frame builders are stateless wire helpers. This path re-exports
4
4
  * them so existing importers stay unchanged. The core's `buildCommitFrame`
5
5
  * takes the structural `CommitFrameOperation` slice, which this package's
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): the
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): the
3
3
  * commit-path frame builders are stateless wire helpers. This path re-exports
4
4
  * them so existing importers stay unchanged. The core's `buildCommitFrame`
5
5
  * takes the structural `CommitFrameOperation` slice, which this package's
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The runtime context, sliced into the ports the settlement core's transport
2
+ * The runtime context, sliced into the ports the confirmation core's transport
3
3
  * takes. The core is injected, never service-located (ADR 0016), while this
4
4
  * package resolves its shared dependencies through `getContext()` — so these
5
5
  * adapters bridge the two: each method reads the context at call time, which
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The runtime context, sliced into the ports the settlement core's transport
2
+ * The runtime context, sliced into the ports the confirmation core's transport
3
3
  * takes. The core is injected, never service-located (ADR 0016), while this
4
4
  * package resolves its shared dependencies through `getContext()` — so these
5
5
  * adapters bridge the two: each method reads the context at call time, which
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): keeping
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): keeping
3
3
  * a long-lived socket's credential fresh is connection plumbing an agent needs
4
4
  * as much as a browser does. This path re-exports it so existing importers
5
5
  * stay unchanged.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): keeping
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): keeping
3
3
  * a long-lived socket's credential fresh is connection plumbing an agent needs
4
4
  * as much as a browser does. This path re-exports it so existing importers
5
5
  * stay unchanged.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): the
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): the
3
3
  * inbound frame dispatch is the receiving half of the wire protocol, and the
4
4
  * handlers already worked against the minimal `WsSession` port rather than
5
5
  * the transport object. This path re-exports it so existing importers stay
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Moved to the settlement core with the duplex transport (ADR 0016): the
2
+ * Moved to the confirmation core with the duplex transport (ADR 0016): the
3
3
  * inbound frame dispatch is the receiving half of the wire protocol, and the
4
4
  * handlers already worked against the minimal `WsSession` port rather than
5
5
  * the transport object. This path re-exports it so existing importers stay
@@ -1,5 +1,5 @@
1
1
  import type { DurableWriteStore } from '@abloatai/transaction/durableWrites';
2
- import type { PendingWrite } from '@abloatai/transaction/transactions/settlement/pendingWrite';
2
+ import type { PendingWrite } from '@abloatai/transaction/transactions/confirmation/pendingWrite';
3
3
  export interface CommitOutboxDatabase {
4
4
  sealTransactionRecord(record: PendingWrite, consumedRecordIds: readonly string[]): Promise<unknown>;
5
5
  getPersistedTransactions(): Promise<readonly unknown[]>;
@@ -3,7 +3,7 @@ type EmitLocalMutation = (event: string, payload: unknown) => void;
3
3
  /**
4
4
  * Human-side optimistic-write adapter.
5
5
  *
6
- * Settlement retains ordering and receipts; this adapter owns the local
6
+ * Confirmation retains ordering and receipts; this adapter owns the local
7
7
  * pre-image ledger and announces apply/rollback work to the materialiser.
8
8
  */
9
9
  export declare function createLocalMutationPort(emit: EmitLocalMutation): LocalMutationPort;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Human-side optimistic-write adapter.
3
3
  *
4
- * Settlement retains ordering and receipts; this adapter owns the local
4
+ * Confirmation retains ordering and receipts; this adapter owns the local
5
5
  * pre-image ledger and announces apply/rollback work to the materialiser.
6
6
  */
7
7
  export function createLocalMutationPort(emit) {
@@ -19,7 +19,7 @@ import { type LogPositionPort } from '../../logPosition.js';
19
19
  import type { WriteOptions } from '../../interfaces/index.js';
20
20
  import type { StaleNotification, ReadDependency, TrackDependency } from '@abloatai/transaction/coordination/schema';
21
21
  import { type MutationInput, type QueuedMutation, type UserContext } from './commitPayload.js';
22
- import { type CommitOutboxScope } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
22
+ import { type CommitOutboxScope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
23
23
  import type { DurableWriteStore } from './durableWriteStore.js';
24
24
  import { type LocalMutationPort } from './localMutation.js';
25
25
  import { type CommitTransaction } from './commitLane.js';
@@ -124,7 +124,7 @@ export declare class MutationQueue extends EventEmitter {
124
124
  /**
125
125
  * Small race buffer for authoritative echoes that arrive before the queued
126
126
  * mutation receipt. The forward and WAL stream are independent channels, so
127
- * either can win without changing the settlement result.
127
+ * either can win without changing the confirmation result.
128
128
  */
129
129
  private recentDeltaCorrelations;
130
130
  /**
@@ -25,7 +25,7 @@ import { entityKey, mergeUpdateData, takeUnsentCreateForModel, findCreateBarrier
25
25
  import { DeltaConfirmationTracker } from './deltaConfirmation.js';
26
26
  import { deserializePersistedTransaction, isNonReplayablePersistedRow, pendingMutationRecordId, legacyPendingMutationRecordSchema, pendingMutationRecordSchema, persistedMutationSchema, } from './replayValidation.js';
27
27
  import { deserializeLegacyPendingMutation, loadPersistedTransactions, persistQueuedTransaction, removePersistedTransaction, settlePersistedFailure, } from './mutationPersistence.js';
28
- import { createCommitEnvelopeMember, createDurableCommitEnvelope, commitEnvelopeRecordId, durableCommitEnvelopeSchema, } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
28
+ import { createCommitEnvelopeMember, createDurableCommitEnvelope, commitEnvelopeRecordId, durableCommitEnvelopeSchema, } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
29
29
  import { stableStringify } from '@abloatai/transaction/utils/json';
30
30
  import { createLocalMutationPort, } from './localMutation.js';
31
31
  import { dispatchCommitBounded, parseMutationCommitResult, persistDurableCommitAcceptance, removeDurableCommit, sealDurableCommit, } from './commitTransport.js';
@@ -38,7 +38,7 @@ import { handleFailure } from './failureHandling.js';
38
38
  import { handleConflict as resolveConflict, isPermanentError as classifyPermanentError, isDefinitiveRejection as classifyDefinitiveRejection } from './failurePolicy.js';
39
39
  import { takeNextExecutionBatch as selectExecutionBatch, takePendingDrainBatch as selectPendingDrainBatch } from './executionSelection.js';
40
40
  import { scheduleProcessing as scheduleProcessingExternal } from './processingScheduler.js';
41
- import { drainPendingSettlements, } from './pendingDrain.js';
41
+ import { drainPendingConfirmations, } from './pendingDrain.js';
42
42
  import { restoreDurableCommits as restoreDurableCommitsExternal } from './durableCommitRestore.js';
43
43
  export class MutationQueue extends EventEmitter {
44
44
  // Keep one hour of clock/network margin inside the server's 24-hour ledger.
@@ -92,7 +92,7 @@ export class MutationQueue extends EventEmitter {
92
92
  /**
93
93
  * Small race buffer for authoritative echoes that arrive before the queued
94
94
  * mutation receipt. The forward and WAL stream are independent channels, so
95
- * either can win without changing the settlement result.
95
+ * either can win without changing the confirmation result.
96
96
  */
97
97
  recentDeltaCorrelations = new Map();
98
98
  /**
@@ -1082,7 +1082,7 @@ export class MutationQueue extends EventEmitter {
1082
1082
  return;
1083
1083
  this.isProcessing = true;
1084
1084
  try {
1085
- await drainPendingSettlements(this.pendingDrainContext);
1085
+ await drainPendingConfirmations(this.pendingDrainContext);
1086
1086
  }
1087
1087
  finally {
1088
1088
  this.isProcessing = false;
@@ -5,7 +5,7 @@ import type { MutationStore } from './MutationStore.js';
5
5
  import type { OptimisticUpdateEntry } from './localMutation.js';
6
6
  import type { StaleNotification } from '@abloatai/transaction/coordination/schema';
7
7
  import type { MutationCommitResult } from '@abloatai/transaction/wire/commit';
8
- import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
8
+ import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
9
9
  export interface BatchProcessingContext {
10
10
  readonly runtime: RuntimeContext;
11
11
  readonly config: MutationQueueConfig;
@@ -1,5 +1,5 @@
1
1
  import type { ReadDependency, TrackDependency } from '@abloatai/transaction/coordination/schema';
2
- import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
2
+ import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
3
3
  import type { CommitTransaction } from './commitLane.js';
4
4
  import type { SealDurableCommitInput } from './commitTransport.js';
5
5
  export interface CommitApiContext {
@@ -1,7 +1,7 @@
1
1
  import type { RuntimeContext } from '../../RuntimeContext.js';
2
2
  import type { ReadDependency, TrackDependency, OnStaleMode, StaleNotification } from '@abloatai/transaction/coordination/schema';
3
3
  import type { MutationCommitResult } from '@abloatai/transaction/wire/commit';
4
- import type { DurableCommitEnvelope, DurableCommitOperation } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
4
+ import type { DurableCommitEnvelope, DurableCommitOperation } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
5
5
  import type { SealDurableCommitInput } from './commitTransport.js';
6
6
  export interface CommitTransaction {
7
7
  id: string;
@@ -12,7 +12,7 @@ import type { RuntimeContext } from '../../RuntimeContext.js';
12
12
  import { MutationOperationType } from '@abloatai/transaction/types';
13
13
  import type { OnStaleMode } from '@abloatai/transaction/coordination/schema';
14
14
  import type { MutationOptions, WriteOptions } from '../../interfaces/index.js';
15
- import type { CommitEnvelopeMember } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
15
+ import type { CommitEnvelopeMember } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
16
16
  export interface UserContext {
17
17
  userId: string;
18
18
  organizationId: string;
@@ -130,6 +130,7 @@ export interface WriteOperationFields {
130
130
  readAt?: number | null;
131
131
  onStale?: OnStaleMode | null;
132
132
  fenceToken?: number | null;
133
+ claimId?: string;
133
134
  options?: Pick<MutationOptions, 'idempotencyKey' | 'label'>;
134
135
  }
135
136
  /**
@@ -110,6 +110,8 @@ export function hasStaleWriteOptions(options) {
110
110
  /** Options whose identity/audit semantics forbid merging two caller writes. */
111
111
  export function hasCommitCoalescingBarrier(options) {
112
112
  return (hasStaleWriteOptions(options) ||
113
+ options?.claimRef != null ||
114
+ options?.fenceToken != null ||
113
115
  typeof options?.idempotencyKey === 'string' ||
114
116
  typeof options?.label === 'string');
115
117
  }
@@ -134,6 +136,12 @@ export function applyWriteOptions(op, transaction) {
134
136
  if (writeOptions.fenceToken !== undefined) {
135
137
  operation.fenceToken = writeOptions.fenceToken;
136
138
  }
139
+ if (writeOptions.claimRef != null) {
140
+ operation.claimId =
141
+ typeof writeOptions.claimRef === 'string'
142
+ ? writeOptions.claimRef
143
+ : writeOptions.claimRef.id;
144
+ }
137
145
  if (writeOptions.idempotencyKey != null || writeOptions.label !== undefined) {
138
146
  operation.options = {
139
147
  ...(writeOptions.idempotencyKey != null
@@ -2,7 +2,7 @@ import type { RuntimeContext } from '../../RuntimeContext.js';
2
2
  import type { MutationExecutor } from '../../interfaces/index.js';
3
3
  import type { ReadDependency, TrackDependency } from '@abloatai/transaction/coordination/schema';
4
4
  import { type MutationCommitResult } from '@abloatai/transaction/wire/commit';
5
- import { type CommitOutboxScope, type DurableCommitEnvelope, type DurableCommitOperation } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
5
+ import { type CommitOutboxScope, type DurableCommitEnvelope, type DurableCommitOperation } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
6
6
  import type { DurableWriteStore } from './durableWriteStore.js';
7
7
  export interface CommitTransportContext {
8
8
  readonly runtime: RuntimeContext;
@@ -1,6 +1,6 @@
1
1
  import { AbloConnectionError, AbloError, AbloIdempotencyError, } from '@abloatai/transaction/errors';
2
2
  import { mutationCommitResultSchema, } from '@abloatai/transaction/wire/commit';
3
- import { createDurableCommitEnvelope, commitEnvelopeRecordId, durableCommitEnvelopeSchema, } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
3
+ import { createDurableCommitEnvelope, commitEnvelopeRecordId, durableCommitEnvelopeSchema, } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
4
4
  export async function sealDurableCommit(ctx, input, pendingMutationRecordId) {
5
5
  const sourceMutationIds = [...new Set(input.sourceMutationIds ?? [])];
6
6
  const envelope = createDurableCommitEnvelope({
@@ -1,6 +1,6 @@
1
1
  import type { RuntimeContext } from '../../RuntimeContext.js';
2
2
  import type { CommitTransaction } from './commitLane.js';
3
- import type { CommitOutboxScope } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
3
+ import type { CommitOutboxScope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
4
4
  import type { DurableWriteStore } from './durableWriteStore.js';
5
5
  export interface DurableCommitRestoreContext {
6
6
  readonly config: {
@@ -1,5 +1,5 @@
1
1
  import { AbloIdempotencyError, AbloValidationError } from '@abloatai/transaction/errors';
2
- import { durableCommitEnvelopeSchema } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
2
+ import { durableCommitEnvelopeSchema } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
3
3
  export async function restoreDurableCommits(ctx) {
4
4
  if (!ctx.config.enablePersistence)
5
5
  return new Set();
@@ -1,14 +1,14 @@
1
1
  /**
2
- * The durable-write port moved to the settlement core (ADR 0016): it is a
2
+ * The durable-write port moved to the confirmation core (ADR 0016): it is a
3
3
  * contract over commit envelopes and holds no local rows. Re-exported here so
4
4
  * the existing `transactions/mutations/durableWriteStore` import path keeps
5
5
  * resolving for the queue, the outbox, and the client options.
6
6
  *
7
7
  * The port and its config live in the core's `durableWrites` module (a behavior
8
8
  * contract, not a persisted shape); the records that cross it are owned by
9
- * `transactions/settlement/pendingWrite`.
9
+ * `transactions/confirmation/pendingWrite`.
10
10
  */
11
11
  export { durableWriteStoreSchema, durableWritesConfigSchema, } from '@abloatai/transaction/durableWrites';
12
12
  export type { DurableWriteStore, DurableWritesConfig, } from '@abloatai/transaction/durableWrites';
13
- export { pendingWriteSchema } from '@abloatai/transaction/transactions/settlement/pendingWrite';
14
- export type { PendingWrite } from '@abloatai/transaction/transactions/settlement/pendingWrite';
13
+ export { pendingWriteSchema } from '@abloatai/transaction/transactions/confirmation/pendingWrite';
14
+ export type { PendingWrite } from '@abloatai/transaction/transactions/confirmation/pendingWrite';