feat: use Nextcloud filename for indexed file title + reconcile on rename
The vector-sync pipeline derived an indexed file's display title from the document's embedded metadata (e.g. a PDF's /Title), falling back to the filename only when absent. That embedded title frequently disagrees with how the user named the file in Nextcloud and is confusing in the astrolabe vector-viz UI (a passive consumer of the `title` payload field). For files, always derive the title from the Nextcloud filename via a shared `file_title_from_path` helper. Notes/deck/news keep their metadata titles. A rename/move in Nextcloud keeps the fileid (doc_id) and content (etag/mtime) but changes the path, so both the dedup claim and the scanner freshness gate skip re-embedding and the stored file_path/title go stale. Add `reconcile_document_path`: a metadata-only set_payload that refreshes file_path + title on the existing real chunks without re-fetch/re-embed. Wire it into both skip paths: - dedup hit (etag unchanged on rename) via claim_existing_index(current_path=...) - scanner incremental skip (etag changed, mtime stable) Both reuse already-fetched payloads, so steady-state scans add no extra round-trip (reconcile is a no-op when the path is unchanged). Refs: Deck #204 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
967298ddbe
commit
bded41de5d
@@ -43,6 +43,7 @@ from nextcloud_mcp_server.vector.scanner import DocumentTask
|
||||
from nextcloud_mcp_server.vector.sharing_state import (
|
||||
claim_existing_index,
|
||||
existing_principals,
|
||||
file_title_from_path,
|
||||
release_document_for_user,
|
||||
)
|
||||
|
||||
@@ -531,7 +532,11 @@ async def _index_document(
|
||||
# in the tenant, claim it for this user (observed-access ACL) and skip
|
||||
# the expensive fetch/parse/embed entirely.
|
||||
if doc_task.etag and await claim_existing_index(
|
||||
doc_task.doc_id, "file", doc_task.etag, doc_task.user_id
|
||||
doc_task.doc_id,
|
||||
"file",
|
||||
doc_task.etag,
|
||||
doc_task.user_id,
|
||||
current_path=doc_task.file_path,
|
||||
):
|
||||
await delete_placeholder_point(
|
||||
doc_id=doc_task.doc_id,
|
||||
@@ -615,7 +620,10 @@ async def _index_document(
|
||||
|
||||
content = result.text
|
||||
file_metadata = result.metadata
|
||||
title = file_metadata.get("title") or file_path.split("/")[-1]
|
||||
# Favour the Nextcloud filename over any embedded document title
|
||||
# (e.g. a PDF's /Title), which often disagrees with how the user
|
||||
# named the file and is confusing in the UI.
|
||||
title = file_title_from_path(file_path)
|
||||
# etag comes from the scanner's tag REPORT (threaded via the
|
||||
# DocumentTask); read_file itself returns no etag. It is the
|
||||
# tenant-wide content-dedup key, so it must be persisted.
|
||||
|
||||
Reference in New Issue
Block a user