Studio: remove dead RAG code (AST-confirmed)

Remove code with no live references, each confirmed dead via AST reference
analysis (no production callers and no importers), not just text search:

- chunk_belongs_to_document plus its dedicated tests and the now-orphaned
  _insert_chunk test helper. The preview-target route already does a
  single-query membership check and deliberately never called this helper.
- ingestion-progress.tsx and use-ingestion-events.ts (its only importer).
  Superseded by the aggregate ingestion toast stack; zero importers.
- Unreferenced tests/fixtures/rag-preview sample files and their generator.

No behavior change. The only non-deletion edits reword two comments that
referenced the removed helper.
This commit is contained in:
Daniel Han 2026-05-31 09:35:39 +00:00
commit f3bbd53afa
8 changed files with 6 additions and 284 deletions

View file

@ -95,24 +95,3 @@ def document_for_subject_or_404(
# Docs must belong to a KB or a thread (DB CHECK enforces XOR on insert);
# a row satisfying neither is corrupt — treat as 404.
raise HTTPException(status_code = 404, detail = _NOT_FOUND_DETAIL)
def chunk_belongs_to_document(chunk_id: str, document_id: str) -> bool:
"""True iff `chunk_id` exists in `rag_chunks` for `document_id`.
Used by `/preview-target?chunk_id=...` after the caller has
already established subject authorization for `document_id`. Does
NOT perform authorization itself: callers MUST call
`document_for_subject_or_404(document_id, ...)` first, otherwise a
valid `chunk_id` from another subject's document would leak via a
`True` return.
"""
if not chunk_id or not document_id:
return False
with get_connection() as conn:
row = conn.execute(
"SELECT 1 FROM rag_chunks WHERE id = ? AND document_id = ?",
(chunk_id, document_id),
).fetchone()
return row is not None

View file

@ -1458,10 +1458,10 @@ def get_document_preview_target(
)
# One connection enforces membership AND fetches the row in a single query.
# A separate `chunk_belongs_to_document` call would open a second SQLite
# connection and open a TOCTOU window — if the chunk is deleted between the
# two calls, the fetch returns None and the route 500s (D1.1). Cross-document
# collapses to the same 404 — never 400 (would leak doc existence).
# A separate membership check would open a second SQLite connection and a
# TOCTOU window — if the chunk is deleted between the two calls, the fetch
# returns None and the route 500s (D1.1). Cross-document collapses to the
# same 404 — never 400 (would leak doc existence).
with get_connection() as conn:
chunk_row = conn.execute(
"""

View file

@ -1,7 +1,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Tests for document_for_subject_or_404 and chunk_belongs_to_document.
"""Tests for document_for_subject_or_404.
Authorization rules under test (contracts.md §1 / §2, Risk #1):
@ -13,7 +13,6 @@ Authorization rules under test (contracts.md §1 / §2, Risk #1):
- KB with NULL owner_user_id is NOT accessible (legacy row guard).
- Both not-found and not-authorized return HTTP 404 with identical detail to
prevent document-existence leaking.
- chunk_belongs_to_document only returns True when chunk.document_id matches.
"""
from __future__ import annotations
@ -24,10 +23,7 @@ import pytest
from fastapi import HTTPException
import storage.studio_db as studio_db
from core.rag.authorization import (
chunk_belongs_to_document,
document_for_subject_or_404,
)
from core.rag.authorization import document_for_subject_or_404
# ── Fixtures ──────────────────────────────────────────────────────────
@ -88,16 +84,6 @@ def _insert_thread_doc(
)
def _insert_chunk(conn, chunk_id: str, doc_id: str, chunk_index: int = 0) -> None:
conn.execute(
"""
INSERT INTO rag_chunks (id, document_id, chunk_index, text, token_count)
VALUES (?, ?, ?, ?, ?)
""",
(chunk_id, doc_id, chunk_index, "some chunk text", 20),
)
# ── KB-document authorization ─────────────────────────────────────────
@ -224,49 +210,3 @@ def test_empty_subject_raises_404(tmp_path, monkeypatch):
with pytest.raises(HTTPException) as exc_info:
document_for_subject_or_404(doc_id, "")
assert exc_info.value.status_code == 404
# ── chunk_belongs_to_document ─────────────────────────────────────────
def test_chunk_belongs_returns_true_for_matching_doc(tmp_path, monkeypatch):
"""chunk_belongs_to_document returns True when chunk.document_id matches."""
_reset_db(tmp_path, monkeypatch)
doc_id, kb_id, chunk_id = _uid(), _uid(), _uid()
with studio_db.get_connection() as conn:
_insert_kb(conn, kb_id, owner = "alice")
_insert_kb_doc(conn, doc_id, kb_id)
_insert_chunk(conn, chunk_id, doc_id)
assert chunk_belongs_to_document(chunk_id, doc_id) is True
def test_chunk_belongs_returns_false_for_wrong_doc(tmp_path, monkeypatch):
"""chunk_belongs_to_document returns False when chunk belongs to a different document."""
_reset_db(tmp_path, monkeypatch)
kb_id = _uid()
doc_a, doc_b, chunk_id = _uid(), _uid(), _uid()
with studio_db.get_connection() as conn:
_insert_kb(conn, kb_id, owner = "alice")
_insert_kb_doc(conn, doc_a, kb_id, "a.pdf")
_insert_kb_doc(conn, doc_b, kb_id, "b.pdf")
_insert_chunk(conn, chunk_id, doc_a)
# chunk is doc_a's; probing doc_b → False.
assert chunk_belongs_to_document(chunk_id, doc_b) is False
def test_chunk_belongs_returns_false_for_missing_chunk(tmp_path, monkeypatch):
"""chunk_belongs_to_document returns False for a nonexistent chunk_id."""
_reset_db(tmp_path, monkeypatch)
doc_id, kb_id = _uid(), _uid()
with studio_db.get_connection() as conn:
_insert_kb(conn, kb_id, owner = "alice")
_insert_kb_doc(conn, doc_id, kb_id)
assert chunk_belongs_to_document("ghost-chunk-id", doc_id) is False
def test_chunk_belongs_returns_false_for_empty_inputs(tmp_path, monkeypatch):
"""chunk_belongs_to_document returns False for empty inputs without DB access."""
_reset_db(tmp_path, monkeypatch)
assert chunk_belongs_to_document("", "some-doc") is False
assert chunk_belongs_to_document("some-chunk", "") is False
assert chunk_belongs_to_document("", "") is False

View file

@ -1,77 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
import { Progress } from "@/components/ui/progress";
import { cn } from "@/lib/utils";
import { useIngestionEvents } from "../hooks/use-ingestion-events";
const STAGE_LABELS: Record<string, string> = {
queued: "Queued",
parse: "Parsing document",
caption_images: "Captioning images",
extract_images: "Extracting images",
load_model: "Loading embedder",
chunk: "Chunking text",
embed: "Embedding chunks",
done: "Indexing complete",
};
export function IngestionProgress({
jobId,
className,
}: {
jobId: string;
className?: string;
}) {
const event = useIngestionEvents(jobId);
if (!event) {
return (
<div className={cn("text-xs text-muted-foreground", className)}>
Starting
</div>
);
}
if (event.type === "error") {
return (
<div className={cn("text-xs text-destructive", className)}>
{event.error}
</div>
);
}
if (event.type === "cancelled") {
return (
<div className={cn("text-xs text-muted-foreground", className)}>
Cancelled
</div>
);
}
if (event.type === "complete") {
const chunks = event.num_chunks;
return (
<div className={cn("text-xs text-muted-foreground", className)}>
1 document and {chunks} chunk{chunks === 1 ? "" : "s"} indexed
</div>
);
}
const stage =
"stage" in event && event.stage ? (event.stage as string) : "queued";
const progress =
"progress" in event && typeof event.progress === "number"
? event.progress
: 0;
const label = STAGE_LABELS[stage] ?? stage;
return (
<div className={cn("flex flex-col gap-1.5", className)}>
<div className="flex items-center justify-between gap-3 text-xs text-muted-foreground">
<span className="truncate">{label}</span>
<span className="shrink-0 tabular-nums">{Math.round(progress * 100)}%</span>
</div>
<Progress value={Math.round(progress * 100)} className="h-1" />
</div>
);
}

View file

@ -1,19 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
import { useEffect } from "react";
import { useRagStore } from "../stores/rag-store";
/** Subscribe to a job's SSE; returns latest event, null skips. */
export function useIngestionEvents(jobId: string | null) {
const event = useRagStore((s) =>
jobId ? (s.jobs[jobId] ?? null) : null,
);
const subscribeJob = useRagStore((s) => s.subscribeJob);
useEffect(() => {
if (jobId) subscribeJob(jobId);
}, [jobId, subscribeJob]);
return event;
}

View file

@ -1,93 +0,0 @@
"""Generate tests/fixtures/rag-preview/sample.pdf deterministically.
Run once: python tests/fixtures/rag-preview/make_fixture_pdf.py
Requires no third-party deps builds a minimal valid single-page PDF
using only stdlib so the fixture can be regenerated in any environment.
The output is committed alongside this script so tests load it directly.
"""
import os
import struct
import zlib
from pathlib import Path
OUTPUT = Path(__file__).parent / "sample.pdf"
def _compress(data: bytes) -> bytes:
return zlib.compress(data, level = 9)
def _pdf() -> bytes:
# Minimal one-page PDF 1.4: header, catalog, pages, page, content
# stream, xref, trailer.
page_text = b"BT /F1 12 Tf 72 720 Td (RAG preview fixture - page 1) Tj ET"
compressed = _compress(page_text)
stream_len = len(compressed)
objects: list[bytes] = []
def obj(n: int, body: bytes) -> bytes:
return f"{n} 0 obj\n".encode() + body + b"\nendobj\n"
# 1: Catalog
objects.append(obj(1, b"<< /Type /Catalog /Pages 2 0 R >>"))
# 2: Pages
objects.append(obj(2, b"<< /Type /Pages /Kids [3 0 R] /Count 1 >>"))
# 3: Page
objects.append(
obj(
3,
(
b"<< /Type /Page /Parent 2 0 R "
b"/MediaBox [0 0 612 792] "
b"/Contents 4 0 R "
b"/Resources << /Font << /F1 5 0 R >> >> >>"
),
)
)
# 4: Content stream
objects.append(
obj(
4,
(
f"<< /Length {stream_len} /Filter /FlateDecode >>".encode()
+ b"\nstream\n"
+ compressed
+ b"\nendstream"
),
)
)
# 5: Font
objects.append(
obj(
5,
b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
)
)
header = b"%PDF-1.4\n%\xe2\xe3\xcf\xd3\n"
body = b""
offsets: list[int] = []
for o in objects:
offsets.append(len(header) + len(body))
body += o
xref_offset = len(header) + len(body)
n = len(objects)
xref = f"xref\n0 {n + 1}\n".encode()
xref += b"0000000000 65535 f \n"
for off in offsets:
xref += f"{off:010d} 00000 n \n".encode()
trailer = (
f"trailer\n<< /Size {n + 1} /Root 1 0 R >>\n"
f"startxref\n{xref_offset}\n%%EOF\n"
).encode()
return header + body + xref + trailer
if __name__ == "__main__":
pdf_bytes = _pdf()
OUTPUT.write_bytes(pdf_bytes)
print(f"Written {len(pdf_bytes)} bytes to {OUTPUT}")

Binary file not shown.

View file

@ -1,8 +0,0 @@
This is a test document for RAG preview fixtures.
Section 1: Introduction
The operating margin rose to 18.2% in Q3, driven by improved efficiency.
Section 2: Details
Additional supporting evidence and analysis is contained here.
Page 1 of 1.