plugmem 0.9.0 → 0.11.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 (3) hide show
  1. package/README.md +34 -1
  2. package/index.d.ts +20 -0
  3. package/package.json +7 -7
package/README.md CHANGED
@@ -185,6 +185,21 @@ duplicate or contradict**. If a preflight must not write, use
185
185
  `rememberGuarded`: the database holds one write scope across its similarity
186
186
  check and conditional insertion, so concurrent preflights cannot both pass.
187
187
 
188
+ **`entity` is what makes the guard a guard.** The detector compares the new text
189
+ against that entity's most recent live facts and against nothing else, so a
190
+ `rememberGuarded` call with **no** `entity` has no candidates and always returns
191
+ `status: "stored"` - it does not fail, it simply has nothing to compare against.
192
+ Six identical guarded writes with no entity produce six facts; the same six with
193
+ `entity` produce one and five `blocked`.
194
+
195
+ `checked` on the result says whether a comparison happened at all: `false` is a
196
+ fact stored exactly as `remember` would have stored it. Do not read `status:
197
+ "stored"` as "checked and clear" without it.
198
+
199
+ `similar` carries `{ id, score, reason }` - the ids, not the text. Resolve a
200
+ hit's wording with `get(id)` when you want to show the caller what it collided
201
+ with.
202
+
188
203
  ```typescript
189
204
  const decision = await db.rememberGuarded({
190
205
  text: "the user prefers async-std",
@@ -218,6 +233,7 @@ only moves arguments and results across the boundary.
218
233
  | `rememberMany(args[])` | store a batch: one embedding round-trip, one journal sync |
219
234
  | `revise(id, args)` | close a fact and record its successor |
220
235
  | `forget(id)` | tombstone a fact; resolves with whether it was live |
236
+ | `forgetMany(ids[])` | tombstone a batch: one journal sync, one post-write pass |
221
237
  | `removeTag(tag)` | remove a tag from every current fact while preserving facts/history |
222
238
  | `link(args)` | upsert a typed edge, optionally with `provenance` |
223
239
  | `unlink(args)` | close the current edge; resolves with whether one was open |
@@ -254,6 +270,23 @@ of mixing incompatible vectors. `reembed` is the deliberate transition; it
254
270
  runs on a libuv worker, leaves the JavaScript event loop responsive, keeps reads
255
271
  live and makes concurrent writes reject with `PLUGMEM_BUSY`.
256
272
 
273
+ A mismatch does **not** stop the database opening, on a writer or a read-only
274
+ handle, and loses nothing. What fails is exactly two things: `recall` with a
275
+ `query` and `remember` with `text`. Everything else - `stats`, `get`, `tagsOf`,
276
+ `listTags`, entity/graph recall, `exportPage`, `forget`, `link`, `verify`,
277
+ `maintain`, `checkpoint`, `reembed` - keeps answering. So the content is safe
278
+ and recovery is always available, and a consumer only finds out at its first
279
+ lookup after the change: detect it by making the cheapest text recall and
280
+ watching for the error, rather than from a note of what was configured last
281
+ time.
282
+
283
+ `reembed` is idempotent; it rebuilds ONE database, so a workspace needs a pass
284
+ over every memory in it. On an EMPTY database it still makes one request whose
285
+ input is the empty string - a provider that rejects empty input fails a rebuild
286
+ that had nothing to rebuild. And switching an embedder on over a database built
287
+ without one breaks nothing and warns about nothing: compare `stats().vectors`
288
+ with `stats().facts` to notice the facts that have no vectors yet.
289
+
257
290
  **Read-only handles** (`{ readOnly: true }`) observe another process's writer
258
291
  over a published snapshot. The read verbs answer, the write verbs throw, and two
259
292
  more appear: `generation()` (the pinned snapshot number) and `refresh()` (adopt
@@ -489,7 +522,7 @@ callback in the process. Anything that can do that runs on a libuv worker and
489
522
  returns a promise instead.
490
523
 
491
524
  Promises: `Plugmem.open`, `remember`, `rememberGuarded`, `rememberMany`, `revise`, `recall`,
492
- `forget`, `removeTag`, `listTags`, `link`, `unlink`, `export`, `exportPage`, `verify`, `maintain`,
525
+ `forget`, `forgetMany`, `removeTag`, `listTags`, `link`, `unlink`, `export`, `exportPage`, `verify`, `maintain`,
493
526
  `checkpoint`, every database verb on `WorkspaceMemory`, and every registry
494
527
  verb on `Workspace`.
495
528
 
package/index.d.ts CHANGED
@@ -218,6 +218,16 @@ export interface GuardedRememberOutcome {
218
218
  status: 'stored' | 'blocked'
219
219
  outcome?: RememberOutcome
220
220
  similar: Array<Similar>
221
+ /**
222
+ * Whether the similarity detector had anything to compare against.
223
+ *
224
+ * `false` means the fact was stored WITHOUT a duplicate check: the
225
+ * detector is scoped to the fact's entity, so a call carrying no
226
+ * `entity` has no candidate set and cannot block anything, now or after
227
+ * any number of later writes. Always `true` on a blocked result, which
228
+ * by definition compared something.
229
+ */
230
+ checked: boolean
221
231
  }
222
232
  /** One recalled fact. */
223
233
  export interface RecalledFact {
@@ -721,6 +731,15 @@ export declare class Plugmem {
721
731
  * @throws synchronously in read-only mode.
722
732
  */
723
733
  forget(id: number): Promise<boolean>
734
+ /**
735
+ * Tombstones many facts at once. Equivalent to [`forget`](Plugmem::forget)
736
+ * on each id in order, but under **one** journal sync and **one**
737
+ * post-write policy pass instead of N — the same batching
738
+ * [`rememberMany`](Plugmem::remember_many) does for writes. Resolves with
739
+ * one boolean per id, in the same order, `true` when that id was live.
740
+ * @throws synchronously in read-only mode.
741
+ */
742
+ forgetMany(ids: Array<number>): Promise<boolean[]>
724
743
  /**
725
744
  * Upserts a typed edge `src -rel-> dst`. **Async** for the same reason as
726
745
  * [`forget`](Plugmem::forget). @throws synchronously in read-only mode.
@@ -926,6 +945,7 @@ export declare class WorkspaceMemory {
926
945
  revise(id: number, args: RememberArgs): Promise<RememberOutcome>
927
946
  recall(args?: RecallArgs | undefined | null): Promise<RecallResult>
928
947
  forget(id: number): Promise<boolean>
948
+ forgetMany(ids: Array<number>): Promise<boolean[]>
929
949
  link(args: LinkArgs): Promise<void>
930
950
  unlink(args: LinkArgs): Promise<boolean>
931
951
  get(id: number): Promise<FactSnapshot | null>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plugmem",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Native Node.js addon for plugmem: an embedded bitemporal memory and retrieval engine for local-first applications and agents (remember / recall / revise / forget over one local database).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,11 +43,11 @@
43
43
  "typecheck": "tsc -p tsconfig.json"
44
44
  },
45
45
  "optionalDependencies": {
46
- "plugmem-linux-x64-gnu": "0.9.0",
47
- "plugmem-linux-arm64-gnu": "0.9.0",
48
- "plugmem-darwin-x64": "0.9.0",
49
- "plugmem-darwin-arm64": "0.9.0",
50
- "plugmem-win32-x64-msvc": "0.9.0",
51
- "plugmem-win32-arm64-msvc": "0.9.0"
46
+ "plugmem-linux-x64-gnu": "0.11.0",
47
+ "plugmem-linux-arm64-gnu": "0.11.0",
48
+ "plugmem-darwin-x64": "0.11.0",
49
+ "plugmem-darwin-arm64": "0.11.0",
50
+ "plugmem-win32-x64-msvc": "0.11.0",
51
+ "plugmem-win32-arm64-msvc": "0.11.0"
52
52
  }
53
53
  }