Skip to content

feat(memory): optimistic concurrency control on memory.update#90

Merged
jgpruitt merged 5 commits into
mainfrom
jgpruitt/protected-updates
Jun 24, 2026
Merged

feat(memory): optimistic concurrency control on memory.update#90
jgpruitt merged 5 commits into
mainfrom
jgpruitt/protected-updates

Conversation

@jgpruitt

Copy link
Copy Markdown
Collaborator

Add database-managed version + version_hash on every memory and require the prior version_hash on memory.update. A stale or incorrect hash fails the call with CONFLICT and leaves the memory unchanged.

  • DB: new version bigint + version_hash text columns, backfilled in migration 007. compute_memory_version_hash hashes a canonical JSONB envelope of (tree, name, meta, temporal, content) with function-local UTC + ISO,YMD so tstzrange renders deterministically.
  • Triggers: before-insert seeds version=1 and the hash; before-update bumps version and recomputes the hash on logical-payload change, and restores the managed fields otherwise so direct writes can't mutate them. patch_memory takes _prior_version_hash and raises SQLSTATE ME002 on a mismatch.
  • get_memory / search_memory / hybrid_search_memory return version + version_hash.
  • Engine / protocol / client / server: Memory and MemoryResponse carry version + versionHash; memoryUpdateParams requires versionHash; ME002 maps to a CONFLICT AppError.
  • MCP me_memory_update requires version_hash; CLI me memory update requires --version-hash; me memory edit and the web editor submit the fetched versionHash automatically.

@jgpruitt jgpruitt marked this pull request as ready for review June 23, 2026 20:07
@jgpruitt jgpruitt requested a review from cevian June 23, 2026 20:07
jgpruitt added 3 commits June 23, 2026 20:05
Add database-managed version + version_hash on every memory and require
the prior version_hash on memory.update. A stale or incorrect hash fails
the call with CONFLICT and leaves the memory unchanged.

- DB: new version bigint + version_hash text columns, backfilled in
  migration 007. compute_memory_version_hash hashes a canonical JSONB
  envelope of (tree, name, meta, temporal, content) with function-local
  UTC + ISO,YMD so tstzrange renders deterministically.
- Triggers: before-insert seeds version=1 and the hash; before-update
  bumps version and recomputes the hash on logical-payload change, and
  restores the managed fields otherwise so direct writes can't mutate
  them. patch_memory takes _prior_version_hash and raises SQLSTATE
  ME002 on a mismatch.
- get_memory / search_memory / hybrid_search_memory return version +
  version_hash.
- Engine / protocol / client / server: Memory and MemoryResponse carry
  version + versionHash; memoryUpdateParams requires versionHash;
  ME002 maps to a CONFLICT AppError.
- MCP me_memory_update requires version_hash; CLI me memory update
  requires --version-hash; me memory edit and the web editor submit
  the fetched versionHash automatically.
The templated guard for get_memory referenced `bigin` instead of
`bigint`, and the search_memory guard referenced `halfve` instead of
`halfvec`. The guard's drop-then-assert pass parses these argument
strings through Postgres, so the typos failed every migration with
"type does not exist" (42704) before the create-or-replace ran.
memory.update now requires the prior versionHash; the three e2e update
sites (6, 6b, 6c) were still invoking `me update` without it and
exiting non-zero on argument parsing before reaching the server.
@jgpruitt jgpruitt force-pushed the jgpruitt/protected-updates branch from 848964f to 3d2d1f9 Compare June 24, 2026 01:05
@cevian cevian requested review from Copilot and removed request for Copilot June 24, 2026 09:13

@cevian cevian left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small but important comment

Comment thread packages/server/rpc/memory/memory.ts Outdated
jgpruitt and others added 2 commits June 24, 2026 08:01
Co-authored-by: Matvey Arye <cevian@gmail.com>
Signed-off-by: John Pruitt <jgpruitt@gmail.com>
@jgpruitt jgpruitt merged commit c80b912 into main Jun 24, 2026
2 checks passed
@jgpruitt jgpruitt deleted the jgpruitt/protected-updates branch June 24, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants