Skip to content

witan: migrated memories are undeletable by their author, because a local cfg.author never matches a deployment's preferred_username #267

Description

@gumaerc

Expected Behavior

After migrating a local store to the deployed service with witan migrate merge, I should be able to maintain my own migrated memories through the deployment, including memory_delete on one that should not have been shared.

The migration runbook describes the self-service path as writing "as you, using your own actor's credential", so the rows it creates should belong to the actor who merged them.

Current Behavior

memory_delete no-ops on every migrated memory, because the stored author came from the local store and can never match the deployment's identity:

{
  "slug": "pf-<redacted>-a1b2c3",
  "deleted": false,
  "reason": "authored by 'Carey P Gumaer', not 'gumaerc@mit.edu'; only the author can delete a memory"
}

The two values come from different namespaces and cannot converge:

  • Local stdio writes cfg.author, which resolves from WITAN_AUTHOR, then git config user.name, then $USER. Mine is Carey P Gumaer.
  • A deployment resolves the author from the JWT in _current_author(), which prefers preferred_username, then email, then act-<sub>. Mine is gumaerc@mit.edu.

store_merge preserves each row's original author rather than stamping the caller, so migrated rows keep the local git name. The author check in memory_delete then always fails.

This is not a misconfigured Keycloak profile. My token has name, given_name and family_name all null, but that is irrelevant, because _current_author() never reads those claims. Populating them would not change the outcome.

There is also no client-side workaround: once remote_url is set, _is_local_stdio() is false and cfg.author (so WITAN_AUTHOR) is ignored for this comparison.

Scope: this affects every user who migrates a local store, for every memory in it, permanently. It is not specific to my store. Memories written through the deployment after cutover are authored correctly and delete fine, so it is exactly the migrated history that becomes unmaintainable. That is also the history most likely to contain something that should be pruned, since it was written before the graph was shared.

Steps to Reproduce

  1. Write at least one memory against a local store, so its author is your git user.name.
  2. Register and log in to a deployment: witan target add ol --remote-url … --oidc-issuer … then witan login --target ol.
  3. Confirm the identity mismatch: witan whoami reports gumaerc@mit.edu while the memory's author is Carey P Gumaer.
  4. WITAN_TARGET=ol witan migrate merge ~/.local/share/witan/graph.omni
  5. Call memory_delete(slug=<a migrated slug>, confirm=True). It returns deleted: false with the author-mismatch reason above.

Possible Solution

Stamp author to the caller's resolved identity when rows arrive through store_merge on the per-actor path. This matches what the runbook already promises for that path, and it means a user's migrated history is owned by the same identity that owns everything they write afterwards.

If preserving original attribution is deliberate, then the alternatives are to accept a set of aliases for an actor when checking authorship, or to give memory_delete an explicit admin or self-service override. Either way it would be worth stating in the migration runbook that migrated memories cannot be deleted by their author, since that is currently a surprise discovered after cutover.

Additional Details

A workaround that appears viable but is untested: rewrite author to the deployment identity in the omnigraph export JSONL and re-merge with bumped updated_at, letting newest-wins reconciliation take the corrected rows. That would let a user take ownership of their own history without an operator, but it depends on store_merge accepting an arbitrary author from the row, which is the same behavior causing the bug.

Related: #145 added memory_update / memory_delete specifically for repairing memories, and this makes half of that unavailable to exactly the memories most in need of repair.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions