fix(vector-sync): address round-6 review — rename shadowed var, add test

- vector_sync route: rename the response dict from `body` to `resp` so it no
  longer shadows the request `body` (maintenance trap)
- scanner: comment the intentional files-vs-text purge timing asymmetry
- tests: add the all-text-types-disabled backstop case (empty allow-set)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-16 01:56:54 +02:00
co-authored by Claude Opus 4.8
parent d0db530ac9
commit 21ce620a84
3 changed files with 25 additions and 3 deletions
+3 -3
View File
@@ -121,16 +121,16 @@ async def purge_doc_types_route(request: Request) -> JSONResponse:
# NOT purged (consent not yet enforced for them) — the scanner backstop
# still catches these, but the caller shouldn't assume full success.
failed = [dt for dt in dict.fromkeys(doc_types) if dt not in purged]
body: dict = {"purged": purged}
resp: dict = {"purged": purged}
if failed:
body["failed"] = failed
resp["failed"] = failed
logger.info(
"Vector-sync purge by admin %s: purged=%s failed=%s",
user_id,
purged,
failed,
)
return JSONResponse(body)
return JSONResponse(resp)
except ProvisioningRequiredError as e:
logger.info("Provisioning required for user %s: %s", user_id, e)
+3
View File
@@ -594,6 +594,9 @@ async def scan_user_documents(
# indexed. The deletion-reconcile below then sees every indexed
# file as "missing" and purges it after the grace period — the
# backstop for the eager purge Astrolabe runs on disable.
# Asymmetry (intentional): files purge up to 1.5x scan_interval
# later than text types, which get immediate one-shot backstop
# deletes via _enqueue_deletes_for_disabled_types.
logger.debug(
"[SCAN-%s] Files disabled by admin for %s; skipping tagged-file discovery",
scan_id,
@@ -73,6 +73,25 @@ async def test_enqueues_deletes_for_disabled_text_type(monkeypatch):
assert all(t.operation == "delete" and t.doc_type == "note" for t in sent)
async def test_all_text_types_disabled_enqueues_all(monkeypatch):
# Admin disabled everything at once (empty allow-set): every text type's
# indexed points are enqueued for deletion in a single call.
_patch_qdrant(
monkeypatch, {"note": ["n1"], "news_item": ["ni1"], "deck_card": ["d1"]}
)
sent: list = []
stream = _producer(AsyncMock(side_effect=lambda t: sent.append(t)))
queued = await _enqueue_deletes_for_disabled_types("alice", stream, frozenset(), 1)
assert queued == 3
assert {(t.doc_type, t.doc_id) for t in sent} == {
("note", "n1"),
("news_item", "ni1"),
("deck_card", "d1"),
}
async def test_noop_when_allowed_is_none(monkeypatch):
# Fail-open: a transient capability read must never trigger deletion.
send = AsyncMock()