Skip to content

feat: recall across personal memory and Data Rooms - #49

Merged
stormer78 merged 1 commit into
mainfrom
feat/unified-recall
Nov 11, 2026
Merged

stormer78 merged 1 commit into
mainfrom
feat/unified-recall

Conversation

@stormer78

Copy link
Copy Markdown
Contributor

Closes #34.

What it does

  • vta-agent-memory rooms add --room <did> --host <did> [--member <did>] [--label L] (plus rooms remove and rooms list) adds a room to the config for recall to read. The host has to be named because nothing maps a room to its host (rooms/keys/browse: "nothing maps a room to its host").
  • memory_recall reads personal memory and every configured room, then ranks them together. Room records use the same record::relevance × basis weight × status weight scale, so a personal memory and a room record that match equally well score equally.
    • A new sources option narrows where recall looks: personal, rooms, or a room's id or label.
    • Each result carries source (personal with contextId, or room with roomId and label), author, status and basis/confidence.
    • unavailable lists rooms that couldn't be read. Recall carries on without them.
  • memory_get with room: <roomId> reads one room record in full.
  • doctor reports, for each room, how many records are recallable and how many are refused, or why the room is unavailable.

Checking room records

rooms/keys/read reports what the VTA checked about the host. The author's in-body signature is the reader's job, so rooms::verify_body applies the rules of vtc_client::rooms::body::verify_record_body, which is what pnm rooms read uses:

  1. a proof that verifies for assertionMethod, using eddsa-jcs-2022 or ecdsa-jcs-2019;
  2. author is the signer;
  3. the body names the room, key and sealed version it was read from. The sealed version comes from ext.org.openvtc.rooms.sealedAt, because a curation moves a record's version past its body;
  4. on an attributed room, author is the author the host recorded.

A record that fails any of these is left out and reported in refused, the same way a personal memory with a bad signature is. Checks 3 and 4 run before the author's DID is resolved.

An open room's records have no in-body signature. They are recalled, but their author is marked hostReported.

Status works as follows:

  • deprecated records rank at half weight;
  • retracted records and records past their validUntil are left out.

Tests (tests/rooms_recall.rs, 5, plus one server test and two unit tests)

The fake VTA now answers rooms/keys/browse/0.4 and rooms/keys/read/0.2.

  • Acceptance: one recall across personal memory, a sealed room and an open room. It checks the interleaved ranking, source/author/status/basis on each result, that recall returns no bodies, and that recall only ever sends browse and read to rooms.

  • Acceptance: a room record whose signature fails is excluded and reported, in three forms:

    • altered after signing;
    • signed for one key and served at another;
    • signed by someone other than the author the host recorded.

    This holds with a query and with none. A mutation check confirmed the test fails if signature verification is removed.

  • Standing:

    • deprecated records are demoted;
    • retracted and expired records are left out;
    • a curated record (sealed at version 5, now at 6) verifies at its sealed version.
  • An unreachable room is reported as unavailable, and personal recall still answers.

  • sources: ["personal"] makes no room calls. A memory type leaves rooms out, since room records have no type.

  • Server: an unknown source or room is invalid_params before any VTA call.

cargo clippy --all-targets is clean, all existing tests pass, and the eval's hard checks all pass with no metric change: personal ranking moved only by refactoring relevance out of rank.

Decisions worth a look

  • Room authors can be resolved over the network. Personal records stay did:key-only. Room members are often did:webvh, so room records are checked with the SDK's shared resolver (PNM_RESOLVER_URL if set), as pnm does. The DIDs it resolves are those of room members, since the VTA wouldn't open the record otherwise, and resolution happens only after the location and host-author checks. A recall that reads no rooms never builds the resolver.
  • Human or agent author is reported as kind: "unstated". The issue asks for it "from the in-body signature", but SealedRecordBody carries only the signing DID. data-rooms.md §6.1 plans to carry it through attenuated VACs. I'd rather say "unstated" than guess. thisMember says whether the configured member wrote the record.
  • The session-start hook stays personal-only, and so does the CLI recall. Every room adds a browse plus batch reads with up-to-30-second host timeouts, and a slow host must never delay a session. Rooms are recalled through the MCP tool.
  • At most 256 records are read per room per recall, newest first. Rooms are meant to be small, and each record costs a read.
  • Recall never writes to a room. The test asserts that only browse and read are sent to rooms.

Not covered

  • Everything was tested against the loopback fake. Neither a live room nor the VTA's real ACL for rooms/keys/* from an application-role agent identity has been tried; that grant may need adding at enrolment.
  • No eval scenario yet. The harness has no room steps, and adding them is a follow-up.

Version 0.7.0 → 0.8.0.

memory_recall now also reads the Data Rooms configured for recall
(`rooms add`), through the user's VTA (rooms/keys/browse + read), and
ranks room records with personal memories on one scale. Each result
names its source, author, status and basis.

A sealed room record's in-body signature is checked here by the
rules pnm uses: proof verifies, author is the signer, signed location
(at the sealed version) is where it was read, author matches what the
host recorded. A record failing any of them is refused and reported.
Open-room records are marked hostReported. Deprecated records are
demoted; retracted and expired ones left out. An unreadable room is
reported as unavailable without failing recall. Recall never writes to
a room; the session-start hook stays personal-only.

Closes #34

Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
@stormer78
stormer78 merged commit cc8eacd into main Nov 11, 2026
4 checks passed
@stormer78
stormer78 deleted the feat/unified-recall branch November 11, 2026 02:20
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.

Unified recall across personal memory and Data Rooms with per-result provenance

1 participant