twin memory

Erasure & receipts

Forget erases items, sessions or threads with every copy and everything learned from them, and returns a receipt counting what went.

/v1/memory/forget hard-deletes from one end user's memory. It is not a soft delete or a hidden flag. The words are gone from storage, from the index and from everything that was built from them.

Name what goes

Give any mix of these lists, up to 500 ids each:

FieldNames
itemsItems by the id you gave them.
sessionsEvery message of a session, across all its days.
threadsThreads by id (th_…), as search returns them.
eventsEvents by id (ev_…), as add returns them.

A request that names nothing is refused with 422.

What is removed

An item is said once and copied many times. Forget reaches each copy:

  • the stored item itself;
  • the passages cut from its conversation, their word index entries and their vectors;
  • its mentions of people and things;
  • the records read from it, and the values and lines built from those records;
  • every version of an added item;
  • every page that quoted any of it, such as known, which is built again from what remains;
  • anything of it still waiting to land.

Two rules make this exact:

  • A record that rests on a forgotten turn goes whole. If a record cites three messages and you forget one, the record goes. It is a claim the remaining messages were never shown to support. The same holds for every record read from a window of the conversation that held the forgotten message. When a forget takes records, the rest of the conversation is read again later without it. An expiry that takes records does the same.
  • What is left is filed again. A conversation that lost a message is cut into passages again from what remains. A conversation with nothing left goes whole.

After the rows are deleted, storage itself is cleaned: pages freed by the delete are overwritten with zeros, the word index is merged so no segment keeps the forgotten terms, and the write-ahead log is emptied.

Tombstones

Each forgotten event id is remembered, with nothing of what it said, so that a copy still on its way in cannot land it again after the forget returns. If you later add the same item on purpose, that lifts the tombstone and the item is added again, as a new event.

The receipt

Forget answers with a receipt: counts of what it removed, and each table's row count before and after.

{
  "events": 1,
  "threads_emptied": 1,
  "lessons": 0,
  "ledger": 1,
  "records": 0,
  "corrections": 0,
  "actions": 0,
  "assertions": 0,
  "unowned_vectors": 0,
  "log_emptied": true,
  "tables": {
    "events": { "before": 4, "after": 3 },
    "threads": { "before": 3, "after": 2 },
    "passages": { "before": 3, "after": 2 },
    "mentions": { "before": 13, "after": 11 },
    "facts": { "before": 0, "after": 0 },
    "vectors": { "before": 0, "after": 0 },
    "codes": { "before": 0, "after": 0 },
    "parties": { "before": 2, "after": 2 },
    "withdrawals": { "before": 0, "after": 0 },
    "passages_fts": { "before": 3, "after": 2 },
    "facts_fts": { "before": 0, "after": 0 },
    "files": { "before": 18, "after": 19 }
  },
  "inbox": 0,
  "versions": 2,
  "queue": 0
}
FieldMeaning
eventsHow many stored events the request named and erased.
threads_emptiedConversations with nothing left, removed whole.
ledgerStored items deleted.
recordsRecords deleted because they rested on a forgotten turn.
assertionsValue lines deleted, the ones history returns.
correctionsCorrections that applied to deleted records.
lessons, actionsDerived lines of other kinds that rested on a forgotten turn. Usually 0 for content you add.
unowned_vectorsVectors no remaining passage or record owns, deleted.
log_emptiedtrue when the write-ahead log was emptied after the delete.
tablesEach table's row count for this end user, before and after.
inboxItems still waiting to land that were dropped.
versionsVersions of added items erased.
queueCopies dropped from the delivery queue. null if the queue could not be reached; the erasure stands either way, and you can call again.

files can rise: the tombstone is a new file, and pages are written again from what remains.

When nothing matched, the receipt is short: {"events": 0, "inbox": 0, "versions": 0, "queue": 0}.

Keep the receipt with your record of the request. It is what you can show a user or an auditor. See Handling erasure requests.

After a forget

  • status reports the item as unknown.
  • versions reports state: "forgotten" with one line saying when.
  • lineage finds nothing for it.

Cost and time

Forget makes no model call. Its time grows with the size of that end user's whole history, because what remains is filed and built again. It is meant for erasure requests, not for routine cleanup on every turn. For data that should only live for a while, use expiry.

Erase a whole end user

To delete everything for one end user, delete the end user from the console's End users page. That removes the end user's whole database and anything still queued for them, in one step.

On this page