Skip to content

Any DELETE /fs enqueues a semantic refresh of the deleted item's parent with recursive=True — deleting a top-level directory re-summarizes the entire namespace #3224

Description

@pengfus

Environment

  • OpenViking v0.4.5 (docker); code path unchanged in current main (2026-07-13)

Bug

After any successful DELETE /api/v1/fs (regardless of the API's recursive query param), service/fs_service.py::rm enqueues a semantic refresh anchored at the deleted item's parent directory (_semantic_refresh_parent_uri). The message construction in _enqueue_delete_refresh does not pass recursive:

msg = SemanticMsg(
    uri=root_uri,                        # parent of the deleted item — reasonable anchor
    context_type=context_type,
    ...                                  # recursive not passed!
    changes={"deleted": [deleted_uri]},  # incremental hint is present but unused
)

and SemanticMsg.__init__ defaults recursive: bool = True. The semantic processor therefore performs a full post-order re-walk of the parent's entire subtree, regenerating every directory's L0/L1 via the VLM, even though nothing under the siblings changed.

The blast radius scales with where the deleted item sits:

  • deleting a file in a leaf directory → only that directory (accidentally cheap, which is why this goes unnoticed)
  • deleting a subdirectory of a large directory → all sibling subtrees re-walked
  • deleting a top-level directory → parent is the namespace root → the whole tree

Production impact (measured)

Deleting one small test directory directly under viking://resources on a tree of ~138k files / ~11k directories triggered a silent full re-summarization: ~3.4 VLM calls/sec sustained, 65M+ prompt tokens and ~45k calls over 3.7 hours before we aborted it (projected 10+ hours total). All regenerated content was equivalent to what was already on disk. The job emits no per-node logs, exposes no progress, and cannot be cancelled through any API — the only way to stop it is to stop the server and delete the queue row while stopped.

Reproduction

  1. Create viking://resources/tmp-dir/a.md (any small resource).
  2. DELETE /api/v1/fs?uri=viking://resources/tmp-dir&recursive=true.
  3. Log shows Processing semantic generation for: viking://resources (recursive=True) followed by a full-tree walk (VLM traffic proportional to the whole namespace, not to the deletion).

Expected behavior / suggested fix

_enqueue_delete_refresh should pass recursive=False. The deleted path is already carried in changes={"deleted": [...]}; a non-recursive incremental refresh of the parent correctly drops the deleted entry from the parent's L0/L1, and the processor's existing parent-refresh cascade propagates the update to the namespace root at a cost proportional to path depth (a handful of VLM calls) instead of subtree size.

We have been running this one-line change in production: deleting a top-level directory now produces exactly one viking://resources (recursive=False) incremental refresh (~2 VLM calls), with sibling subtrees untouched.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions