@totalreclaw/totalreclaw 3.3.1-rc.21 → 3.3.1-rc.22

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.
@@ -49,6 +49,7 @@ import type {
49
49
  } from './extractor.js';
50
50
  import { PROTOBUF_VERSION_V4 } from './subgraph-store.js';
51
51
  import type { SubgraphSearchFact } from './subgraph-search.js';
52
+ import { confirmIndexed, type ConfirmIndexedOptions } from './confirm-indexed.js';
52
53
 
53
54
  // Lazy-load WASM core — mirrors pin.ts pattern.
54
55
  const requireWasm = createRequire(import.meta.url);
@@ -117,6 +118,15 @@ export interface RetypeSetScopeResult {
117
118
  new_scope?: MemoryScope;
118
119
  tx_hash?: string;
119
120
  error?: string;
121
+ /**
122
+ * Set to `true` when the on-chain batch was submitted successfully but the
123
+ * subgraph indexer did not confirm the new fact id within the timeout
124
+ * window (default 30s). The mutation IS on-chain — clients can rely on
125
+ * `tx_hash` for observability — but a follow-up `recall`/`export` may
126
+ * surface stale state for another few seconds. Resolves once the indexer
127
+ * catches up. See `confirm-indexed.ts` for the polling implementation.
128
+ */
129
+ partial?: boolean;
120
130
  }
121
131
 
122
132
  // ---------------------------------------------------------------------------
@@ -142,6 +152,14 @@ interface NormalizedFact {
142
152
  * where this field was silently dropped on the rewrite path.
143
153
  */
144
154
  pinStatus?: PinStatus;
155
+ /**
156
+ * 3.3.1-rc.22 — embedder identity tag. Preserved across retype/set_scope
157
+ * so the source claim's embedder isn't lost on metadata mutation. The
158
+ * stored encrypted_embedding is regenerated by `deps.generateIndices`
159
+ * downstream; the on-claim tag survives the mutation as a forward-compat
160
+ * marker.
161
+ */
162
+ embeddingModelId?: string;
145
163
  }
146
164
 
147
165
  function projectFromDecrypted(decrypted: string): NormalizedFact | null {
@@ -174,6 +192,7 @@ function projectFromDecrypted(decrypted: string): NormalizedFact | null {
174
192
  createdAt: v1.createdAt,
175
193
  expiresAt: v1.expiresAt,
176
194
  pinStatus: v1.pinStatus,
195
+ embeddingModelId: v1.embeddingModelId,
177
196
  };
178
197
  }
179
198
  }
@@ -229,6 +248,7 @@ async function rewriteWithMutation(
229
248
  factId: string,
230
249
  deps: RetypeSetScopeDeps,
231
250
  mutate: (existing: NormalizedFact) => NormalizedFact,
251
+ confirmOpts?: ConfirmIndexedOptions,
232
252
  ): Promise<RetypeSetScopeResult> {
233
253
  const existing = await deps.fetchFactById(factId);
234
254
  if (!existing) {
@@ -279,6 +299,9 @@ async function rewriteWithMutation(
279
299
  // on a pinned fact does NOT silently un-pin it. Without this, a pinned
280
300
  // fact loses its immunity to auto-supersede after any metadata edit.
281
301
  pinStatus: next.pinStatus,
302
+ // 3.3.1-rc.22 — preserve the source claim's embedder tag through
303
+ // retype/set_scope rewrites. Distillation forward-compat.
304
+ embeddingModelId: next.embeddingModelId,
282
305
  });
283
306
  } catch (err) {
284
307
  return {
@@ -349,6 +372,19 @@ async function rewriteWithMutation(
349
372
  tx_hash: txHash,
350
373
  };
351
374
  }
375
+ // Read-after-write: poll the subgraph until the new fact id is indexed
376
+ // and active, OR the timeout (default 30s) elapses. On timeout (or if
377
+ // the WASM bindings are unavailable / subgraph unreachable), surface
378
+ // `partial: true` so the caller knows the chain write succeeded but the
379
+ // indexer has not yet caught up. The confirm step is observational —
380
+ // never fail the whole operation just because confirm step couldn't run.
381
+ let indexed = false;
382
+ try {
383
+ const confirm = await confirmIndexed(newFactId, confirmOpts);
384
+ indexed = confirm.indexed;
385
+ } catch {
386
+ indexed = false;
387
+ }
352
388
  return {
353
389
  success: true,
354
390
  fact_id: factId,
@@ -358,6 +394,7 @@ async function rewriteWithMutation(
358
394
  previous_scope: current.scope,
359
395
  new_scope: next.scope,
360
396
  tx_hash: txHash,
397
+ ...(indexed ? {} : { partial: true }),
361
398
  };
362
399
  } catch (err) {
363
400
  return {
@@ -381,6 +418,7 @@ export async function executeRetype(
381
418
  factId: string,
382
419
  newType: MemoryType,
383
420
  deps: RetypeSetScopeDeps,
421
+ confirmOpts?: ConfirmIndexedOptions,
384
422
  ): Promise<RetypeSetScopeResult> {
385
423
  if (!isValidMemoryType(newType)) {
386
424
  return {
@@ -389,10 +427,15 @@ export async function executeRetype(
389
427
  error: `Invalid new type "${newType}". Must be one of: claim, preference, directive, commitment, episode, summary.`,
390
428
  };
391
429
  }
392
- return rewriteWithMutation(factId, deps, (current) => ({
393
- ...current,
394
- type: newType,
395
- }));
430
+ return rewriteWithMutation(
431
+ factId,
432
+ deps,
433
+ (current) => ({
434
+ ...current,
435
+ type: newType,
436
+ }),
437
+ confirmOpts,
438
+ );
396
439
  }
397
440
 
398
441
  /**
@@ -403,6 +446,7 @@ export async function executeSetScope(
403
446
  factId: string,
404
447
  newScope: MemoryScope,
405
448
  deps: RetypeSetScopeDeps,
449
+ confirmOpts?: ConfirmIndexedOptions,
406
450
  ): Promise<RetypeSetScopeResult> {
407
451
  if (!(VALID_MEMORY_SCOPES as readonly string[]).includes(newScope)) {
408
452
  return {
@@ -411,10 +455,15 @@ export async function executeSetScope(
411
455
  error: `Invalid new scope "${newScope}". Must be one of: ${VALID_MEMORY_SCOPES.join(', ')}.`,
412
456
  };
413
457
  }
414
- return rewriteWithMutation(factId, deps, (current) => ({
415
- ...current,
416
- scope: newScope,
417
- }));
458
+ return rewriteWithMutation(
459
+ factId,
460
+ deps,
461
+ (current) => ({
462
+ ...current,
463
+ scope: newScope,
464
+ }),
465
+ confirmOpts,
466
+ );
418
467
  }
419
468
 
420
469
  // ---------------------------------------------------------------------------
package/skill.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "totalreclaw",
3
- "version": "1.6.2",
3
+ "version": "3.3.1-rc.22",
4
4
  "description": "End-to-end encrypted memory for AI agents — portable, yours forever. XChaCha20-Poly1305 E2EE: server never sees plaintext.",
5
5
  "author": "TotalReclaw Team",
6
6
  "license": "MIT",