Skip to main content

delete_mem

Function delete_mem 

Source
pub fn delete_mem(
    engine: &mut Engine,
    params: MemDeleteParams,
) -> Result<MemDeleteResponse, FullEngineError>
Expand description

Unregister a writable mem at runtime. The unified-engine counterpart to full’s memstead_git_branch::mem_management::delete_mem.

Ordering guarantees mirror full’s:

  1. Pre-mutation checks (input validation, name resolution, allowlist match). Any failure here leaves the engine untouched and performs zero filesystem writes.

  2. Router unregister (snapshot swap via memstead_base::Engine::unregister_writable_mem). After this the mem is no longer visible to readers. The unregister hands back the backend handle so step 3 can drive backend-side cleanup without re-resolving the mount.

  3. Optional disk delete. A failure here is non-fatal: the mem is already unregistered, the leftover artifacts are a follow-up concern, and the response reports files_deleted: false with a typed MEM_FILES_NOT_DELETED warning naming what survived.

    • Folder mount: remove_dir_all(location) removes the mem directory. backend.delete_artifacts() is a no-op (folder backends keep the default impl).
    • Mem-db-backed (git-branch) mount: backend.delete_artifacts() drops refs/heads/<branch_leaf> and prunes __MEMSTEAD:mems/<branch_leaf>/config.json. There is no on-disk directory to rmdir.

    files_deleted: true reflects “every backend-visible artifact for this mem has been removed” — the wire shape is unchanged but the semantic now covers both backends symmetrically.

Operator-mode bypass. When MemDeleteParams::operator_mode is true, Step 2 ([[mem_management.delete]] allowlist match) is skipped. All other steps run identically — including input validation, name resolution, the policy safeguard, router unregister, backend cleanup, and persistence. The flag is set by the transport that established operator intent at boot (today, memstead-mcp --operator-mode) and is not exposed as a wire-shape input.

Policy safeguard. Step 3 (MEM_REFERENCED_BY_POLICY) fires when delete_files: true AND another writable mem has a cross_mem_links grant pointing into the target. The gating is independent of operator_mode: storage destruction would orphan the grant, so the refusal is a hard stop until the grant is revoked. When delete_files: false (router-only unregister), the storage survives and the grant remains valid against it — the check is skipped. This matches the verb split exposed at the CLI layer (mem unregister is the verb that produces delete_files: false; mem delete is the verb that produces delete_files: true).

Hierarchical candidate composition is symmetric with create_mem: the router records the create-time path on each writable entry, and Step 2 below reads it back via [memstead_base::MemRouterSnapshot::mem_path_for_mem] to assemble the same <mem_path>/<name> (or bare <name>) string the create-side composer matched against.