From f6b1ce2e214ffd4875e511ad627a85a2dedcdcb6 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:44:48 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`claude/?= =?UTF-8?q?codebase-review-ade6ed`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @BigSimmo. * https://github.com/BigSimmo/Database/pull/510#issuecomment-4951682581 The following files were modified: * `src/app/api/health/route.ts` * `src/app/api/setup-status/route.ts` * `src/lib/answer-verification.ts` * `src/lib/api-rate-limit.ts` * `src/lib/deep-probe-auth.ts` * `src/lib/rag-cache.ts` * `src/lib/rag-extractive-answer.ts` * `src/lib/rag.ts` * `src/lib/security-headers.ts` --- src/app/api/health/route.ts | 10 ++++++++++ src/app/api/setup-status/route.ts | 26 ++++++++++++++++++++++++++ src/lib/answer-verification.ts | 14 +++++++++++++- src/lib/api-rate-limit.ts | 30 ++++++++++++++++++++++++++++-- src/lib/deep-probe-auth.ts | 7 ++++++- src/lib/rag-cache.ts | 17 ++++++++++++++++- src/lib/rag-extractive-answer.ts | 20 ++++++++++++++++++-- src/lib/rag.ts | 19 +++++++++++++++++-- src/lib/security-headers.ts | 8 ++++++++ 9 files changed, 142 insertions(+), 9 deletions(-) diff --git a/src/app/api/health/route.ts b/src/app/api/health/route.ts index 0e2521f50..a7c58800a 100644 --- a/src/app/api/health/route.ts +++ b/src/app/api/health/route.ts @@ -5,6 +5,16 @@ import { allowDeepHealthProbe } from "@/lib/deep-probe-auth"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; +/** + * Reports application configuration and health status. + * + * The `deep=1` query parameter enables an authorized Supabase connectivity + * check. Deep checks are skipped in demo mode or when Supabase is not + * configured. + * + * @param request - The incoming request, including query parameters and deep-check authorization credentials + * @returns A JSON health report with an HTTP 200 status when ready, or 503 when a required check fails + */ export async function GET(request: Request) { const deep = new URL(request.url).searchParams.get("deep") === "1"; const supabaseConfigured = Boolean(env.NEXT_PUBLIC_SUPABASE_URL && env.SUPABASE_SERVICE_ROLE_KEY); diff --git a/src/app/api/setup-status/route.ts b/src/app/api/setup-status/route.ts index 43a965abf..4c16de628 100644 --- a/src/app/api/setup-status/route.ts +++ b/src/app/api/setup-status/route.ts @@ -276,6 +276,12 @@ function setupStatusCacheTtl(payload: SetupStatusPayload) { return payload.indexingActive ? SETUP_STATUS_ACTIVE_CACHE_MS : SETUP_STATUS_IDLE_CACHE_MS; } +/** + * Creates an HTTP response containing the setup status payload and polling metadata. + * + * @param payload - The setup status information to include in the response + * @returns A JSON response with caching and polling headers + */ function setupStatusResponse(payload: SetupStatusPayload) { return NextResponse.json(payload, { headers: { @@ -296,6 +302,12 @@ const COARSE_SETUP_DETAIL: Record = { unknown: "Status unavailable. Operators can see specifics via the health deep probe or server logs.", }; +/** + * Replaces setup check details with generic status-based messages. + * + * @param payload - The setup status payload whose check details should be coarsened + * @returns A setup status payload with sanitized check details + */ function coarseSetupStatusPayload(payload: SetupStatusPayload): SetupStatusPayload { return { ...payload, @@ -303,6 +315,11 @@ function coarseSetupStatusPayload(payload: SetupStatusPayload): SetupStatusPaylo }; } +/** + * Builds the current setup and indexing status payload. + * + * @returns The setup checks, indexing activity state, polling interval, and generation timestamp. + */ async function buildSetupStatusPayload(): Promise { const supabase = supabaseProjectCanBeQueried ? createAdminClient() : null; const unavailable = await readSupabaseAvailability(supabase); @@ -431,6 +448,15 @@ async function readSetupStatusPayload() { } } +/** + * Serves setup and health status for the current project request. + * + * Local requests receive detailed check information. Internet-reachable requests + * receive detailed information only when authorized for deep health probes; + * otherwise, per-check details are generalized. + * + * @returns An HTTP response containing setup status or an unsafe-origin response. + */ export async function GET(request: Request) { const identity = localProjectRequestIdentityPayload(request); if (!identity.localServer.safeLocalOrigin) { diff --git a/src/lib/answer-verification.ts b/src/lib/answer-verification.ts index 77103c0e7..7633eec9b 100644 --- a/src/lib/answer-verification.ts +++ b/src/lib/answer-verification.ts @@ -218,6 +218,12 @@ const actionableNumericSectionKinds = new Set([ "required_actions", ]); +/** + * Determines whether an answer contains actionable numeric content that requires numeric verification. + * + * @param answer - The answer to evaluate + * @returns `true` if the answer contains actionable numeric context and is eligible for verification gating, `false` otherwise. + */ function hasActionableNumericContext(answer: RagAnswer) { if (!answer.grounded || answer.confidence === "unsupported") return false; if (answer.queryClass === "medication_dose_risk" || answer.queryClass === "table_threshold") return true; @@ -239,7 +245,13 @@ function hasActionableNumericContext(answer: RagAnswer) { // `verificationSources` overrides the corpus numbers are checked against. The model path // passes the packed context it actually generated from (answer.sources stays the unpacked // answer-input set for the client/eval boundary); other callers omit it and verify against -// answer.sources as before. +/** + * Verifies numeric figures in an answer against its cited source content and annotates unsupported figures. + * + * @param answer - The answer whose numeric content is verified and updated. + * @param verificationSources - Optional source corpus to use instead of `answer.sources`. + * @returns The updated answer with faithfulness warnings and evidence-gap handling when figures are unsupported. + */ export function applyNumericVerification(answer: RagAnswer, verificationSources?: SearchResult[]): RagAnswer { const sources = verificationSources ?? answer.sources ?? []; const unverified = new Set(); diff --git a/src/lib/api-rate-limit.ts b/src/lib/api-rate-limit.ts index 1c1720090..88199856a 100644 --- a/src/lib/api-rate-limit.ts +++ b/src/lib/api-rate-limit.ts @@ -4,7 +4,11 @@ import { PublicApiError } from "@/lib/http"; import type { RateLimitSubject } from "@/lib/public-api-access"; import type { createAdminClient } from "@/lib/supabase/admin"; -/** Prefer durable RPC rate limits; fall back to per-instance memory when the DB function is unavailable. */ +/** + * Determines whether in-memory rate limiting may be used when durable rate limiting is unavailable. + * + * @returns `true` in local no-auth mode or production, `false` otherwise. + */ export function allowRateLimitInMemoryFallbackOnUnavailable() { return isLocalNoAuthMode() || process.env.NODE_ENV === "production"; } @@ -13,11 +17,23 @@ export function allowRateLimitInMemoryFallbackOnUnavailable() { // when the durable limiter is unavailable. A per-process Map gives N× the intended limit across N // horizontally-scaled instances during a limiter outage — unacceptable for expensive/abusable // paths: `answer` (paid provider generation) and `document_upload` (storage writes + ingestion -// cost). Local-no-auth dev keeps the in-memory fallback for single-instance usability. +/** + * Identifies rate-limit buckets that must fail closed when the limiter is unavailable. + * + * @param bucket - The rate-limit bucket to evaluate + * @returns `true` for the `answer` and `document_upload` buckets, `false` otherwise + */ function failsClosedOnLimiterUnavailable(bucket: ApiRateLimitBucket) { return bucket === "answer" || bucket === "document_upload"; } +/** + * Determines whether anonymous requests may use an in-memory rate limiter when the durable limiter is unavailable. + * + * @param bucket - The rate-limit bucket being evaluated. + * @param allowInMemoryFallbackOnUnavailable - Whether to allow in-memory fallback when the durable limiter is unavailable. + * @returns `true` if in-memory fallback is allowed, `false` otherwise. + */ function allowAnonymousRateLimitFallback(bucket: ApiRateLimitBucket, allowInMemoryFallbackOnUnavailable?: boolean) { // Fail-closed buckets must not fall back to a per-instance limiter in a distributed production // runtime. If the durable limiter is unavailable, fail closed before any expensive work starts. @@ -149,6 +165,16 @@ export async function consumeApiRateLimit(args: { }; } +/** + * Applies a durable rate limit to an owner or anonymous subject. + * + * Anonymous `answer` requests are constrained by both subject-specific and global + * limits. In-memory fallback is disabled for fail-closed buckets unless local + * no-auth mode is enabled. + * + * @param args - Rate-limiting configuration and subject identity. + * @returns The rate-limit decision and window metadata. + */ export async function consumeSubjectApiRateLimit(args: { supabase: SupabaseAdmin; subject: RateLimitSubject; diff --git a/src/lib/deep-probe-auth.ts b/src/lib/deep-probe-auth.ts index 22f903de6..a62492be6 100644 --- a/src/lib/deep-probe-auth.ts +++ b/src/lib/deep-probe-auth.ts @@ -6,7 +6,12 @@ import { env } from "@/lib/env"; // `x-health-deep-token` header. Used by /api/health (deep Supabase probe) and // /api/setup-status (detailed setup checks) so both surfaces gate internal error text and // project posture behind the same secret. Constant-time compare; fails closed when the secret -// is unset or the token length/value differs. +/** + * Determines whether a request is authorized for deep health probe access. + * + * @param request - The request containing the deep probe authorization token + * @returns `true` if the request token matches the configured secret, `false` otherwise. + */ export function allowDeepHealthProbe(request: Request): boolean { const secret = env.HEALTH_DEEP_PROBE_SECRET; if (!secret) return false; diff --git a/src/lib/rag-cache.ts b/src/lib/rag-cache.ts index b9fce6b59..10b59b409 100644 --- a/src/lib/rag-cache.ts +++ b/src/lib/rag-cache.ts @@ -612,6 +612,15 @@ export function packedContextCacheKey( ].join("|"); } +/** + * Adds compact context from adjacent document chunks to the leading search results. + * + * @param supabase - The Supabase client used to retrieve adjacent document chunks + * @param results - Search results to enrich with adjacent context + * @param queryClass - Query classification used to determine how many results to enrich + * @param options - Controls whether cross-document context packing is enabled + * @returns Search results with adjacent context added when matching chunks are available + */ export async function packAdjacentSourceContext( supabase: ReturnType, results: SearchResult[], @@ -696,7 +705,13 @@ export async function packAdjacentSourceContext( // flagged unverified, blanking a correct answer. Overlay the packed adjacent_context onto // the answer-input results (by chunk id) to rebuild the exact verification corpus, WITHOUT // mutating answer.sources itself (the route-boundary client trim and eval byte-identity -// both depend on answer.sources staying unpacked — see answer-client-payload.ts). +/** + * Aligns adjacent source context with packed search results. + * + * @param results - The search results to update. + * @param packed - Search results containing the desired adjacent context. + * @returns Results with matching adjacent context values copied from `packed`. + */ export function attachAdjacentContext(results: SearchResult[], packed: SearchResult[]): SearchResult[] { const adjacentById = new Map(); for (const source of packed) { diff --git a/src/lib/rag-extractive-answer.ts b/src/lib/rag-extractive-answer.ts index 46eb26cd0..c9e00ae44 100644 --- a/src/lib/rag-extractive-answer.ts +++ b/src/lib/rag-extractive-answer.ts @@ -1729,7 +1729,15 @@ function applyProviderLabels(answer: RagAnswer): RagAnswer { // Public wrapper: runs quality finalization, then stamps provider/quality labels so the UI can // disclose source-only (lower-quality) answers and verify-against-sources guidance. -/** Finalize rag answer quality. */ +/** + * Finalizes an extractive RAG answer's quality and provider metadata. + * + * @param answer - The answer to finalize + * @param query - The query the answer addresses + * @param queryClass - The classified query type + * @param verificationSources - Optional sources used to verify numeric claims + * @returns The finalized RAG answer + */ export function finalizeRagAnswerQuality( answer: RagAnswer, query: string, @@ -1739,7 +1747,15 @@ export function finalizeRagAnswerQuality( return applyProviderLabels(finalizeRagAnswerQualityCore(answer, query, queryClass, verificationSources)); } -/** Finalize rag answer quality core. */ +/** + * Finalizes an answer by applying quality checks, gap handling, section cleanup, and numeric verification. + * + * @param answer - The answer to finalize. + * @param query - The user query used to evaluate answer relevance and clinical intent. + * @param queryClass - The classified query type used for quality and fallback decisions. + * @param verificationSources - Optional sources used to verify numeric claims. + * @returns The quality-checked and finalized answer. + */ function finalizeRagAnswerQualityCore( answer: RagAnswer, query: string, diff --git a/src/lib/rag.ts b/src/lib/rag.ts index b4d11feeb..b0bdfa302 100644 --- a/src/lib/rag.ts +++ b/src/lib/rag.ts @@ -3599,7 +3599,12 @@ export async function answerQuestion(query: string, documentId?: string) { return answerQuestionWithScope({ query, documentId, allowGlobalSearch: true }); } -/** Answer question with scope. */ +/** + * Answers a question within the requested search scope, coalescing identical in-flight requests when caching is enabled. + * + * @param args - The question, scope, cache, progress, and request options. + * @returns The generated answer. + */ export async function answerQuestionWithScope(args: AnswerQuestionWithScopeArgs): Promise { const startedAt = Date.now(); const coalescingEnabled = !args.skipCache && env.RAG_ANSWER_CACHE_TTL_MS > 0 && env.RAG_ANSWER_CACHE_SIZE > 0; @@ -3637,7 +3642,17 @@ export async function answerQuestionWithScope(args: AnswerQuestionWithScopeArgs) return pending; } -/** Answer question with scope uncoalesced. */ +/** + * Generates a clinically grounded answer within the requested document scope. + * + * Uses cached or shared answers when available, retrieves supporting evidence, selects an + * answer route, and falls back to extractive or unsupported responses when generation is + * unavailable or fails. + * + * @param args - Query, document scope, routing options, callbacks, and request controls. + * @param startedAt - Timestamp used to calculate total request latency. + * @returns The finalized answer with citations, retrieval diagnostics, and response metadata. + */ async function answerQuestionWithScopeUncoalesced( args: AnswerQuestionWithScopeArgs, startedAt: number, diff --git a/src/lib/security-headers.ts b/src/lib/security-headers.ts index 42777bcb6..800ad20a9 100644 --- a/src/lib/security-headers.ts +++ b/src/lib/security-headers.ts @@ -39,6 +39,14 @@ export type ContentSecurityPolicyOptions = SecurityHeaderFlags & { nonce: string; }; +/** + * Builds a Content Security Policy for the current runtime. + * + * @param isDevelopment - Whether development script permissions should be used. + * @param isLocalHttpRuntime - Whether insecure-request upgrades should be omitted. + * @param nonce - The nonce used to authorize production scripts. + * @returns The Content Security Policy header value. + */ export function buildContentSecurityPolicy({ isDevelopment, isLocalHttpRuntime,