Skip to content
3 changes: 3 additions & 0 deletions docs/branch-review-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,14 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD
| 2026-07-13 | origin/codex/rag-canary-completion | d1b7647bde73e7d0558472ad6aa19c3b49d94639 | branch-cleanup | Retained for open PR #612 and active worktree activity. | Fresh GitHub open-PR query and moving-head observation; deletion prohibited. |
| 2026-07-13 | origin/main | 528a1752f41cd29a518ca9341c93c724030173ae | branch-cleanup | Protected base branch retained. | Final refreshed origin/main snapshot before the ledger PR. |
| 2026-07-14 | PR #629 / codex/eval-canary-quota-handling | 8fe1be6d0c58c60afeeb82f720b03c90ce57c2cf | review-followup | One P2 structured-error retry defect confirmed and fixed on `codex/eval-canary-structured-errors`. | GitHub connector thread inspection; `tests/eval-utils.test.ts` 14/14; focused ESLint and Prettier. |
| 2026-07-14 | codex/global-answer-reliability | 01d2749978d4e8f3b4ac508e068ec7b8d331f816 | release-readiness / answer generation, source governance, progress, and document access | No unresolved P0-P2 findings after fixing demo-path governance parity, preserving feedback-token binding during the `origin/main` rebase, and binding legacy-summary feedback to the delivered governed answer. Ready for hosted PR checks. | `npm run verify:pr-local` (2,223 passed, 1 skipped; production build and offline RAG evaluation passed); focused Chromium answer regressions (4/4 passed); focused answer and route regressions (124/124 passed). |
| 2026-07-14 | claude/repo-next-steps-e53523 | 3f7d6d76f597f2a0311af1052480f84b68ecc259 | launch-readiness and RAG-performance follow-up | Branch changes were already squash-merged by PR #513. Fresh review found one P1 governance inconsistency (Singapore app/worker processing omitted from the PIA's cross-border account) and three P2 follow-ups: degraded-answer SLO overcounting, a second blocking shared-cache miss diagnostic query, and stale launch/RAG backlog status. No source fix was applied in this review. | `git diff --check c3828ceb9f3812abeebc1b653361fc254dda9f5e..3f7d6d76f597f2a0311af1052480f84b68ecc259`; focused Vitest 92/92; `npm run eval:rag:offline` 36 fixtures and 59/59 contract tests; `npm run verify:cheap` passed runtime, action pins, sitemap, type scale, lint, typecheck, and 1,672 passed/1 skipped tests. Provider-backed Supabase/OpenAI, browser, release, drift, and live retrieval-quality checks were not run. |
| 2026-07-14 | codex/rag-performance-followups | 5502fd498ea2069f810795a8659f98ab3abf8c80 | release-readiness review | The local release review found no P0-P2 defect after correcting one stale PIA statement; the later hosted review follow-up is recorded below. The scoped RAG round-trip, SLO, retention, privacy, and documentation changes were ready for PR handoff. Highest residual risk is the known live hybrid-RPC latency tail; model experiments remain blocked by provider quota and legal execution remains operator/counsel work. | Rebased onto `origin/main`; runtime and full Prettier check; ESLint; TypeScript; Vitest 2,213 passed/1 skipped; Next.js production build (636 pages) plus client-bundle secret scan; offline RAG 36 fixtures and 277/277 contract tests; `git diff --check`. Live retention jobs 13/16 were already verified during this workstream. |
| 2026-07-14 | PR #632 / codex/rag-performance-followups | aa264e92c44b42fdcceeac6292011ba51169b862 | review-followup | One P2 SLO-classification defect was confirmed: the broad source-only `degraded` flag also included healthy extractive answers. Fixed by persisting and counting a separate `provider_generation_degraded` flag derived only from `generation_fallback`. | GitHub connector plus UTF-8 thread-aware review inspection; focused ESLint; 45/45 targeted Vitest tests; TypeScript; offline RAG 36 fixtures and 277/277 contract tests; `git diff --check`. |
| 2026-07-14 | PR #632 / codex/rag-performance-followups | 07cac8f4e094bf4b5ccd264feb6420fbd4e35e2b | review-followup | CodeRabbit's APP 1/5 governance contradiction was confirmed and corrected; Railway's pending DPA and Singapore processor basis are now explicit checklist/status items. The optional cache-miss granularity suggestion was not adopted because it would undo the reviewed single-read cold-miss design or require a broader schema/RPC change. | GitHub review-thread inspection; focused Prettier and `git diff --check` passed. Local production-readiness inspection reported the expected missing provider env; the Railway production-context check had already passed on this workstream. |
| 2026-07-14 | PR #632 / codex/rag-performance-followups | 0c792b8c10516c85d18832fc96562dd70a671b5f | review-followup | One P1 privacy-disclosure defect was confirmed: OpenAI retrieval embedding can receive query text even when answer synthesis remains source-only. Fixed the PIA and public `/privacy` copy to distinguish retrieval-embedding egress from model-backed synthesis egress, with focused copy coverage. | GitHub connector review-thread inspection; focused privacy UI test, ESLint, TypeScript, Prettier, production-readiness, and `git diff --check`. |
| 2026-07-14 | PR #632 / codex/rag-performance-followups | a2eb6db0efbef983e1b3242261d5cc6b2b9d839d | review-followup | One late P2 rollout-compatibility defect was confirmed: the provider-fallback SLO would omit recent rows written before `provider_generation_degraded` existed. Fixed the count predicate to include the new flag or legacy `generation_fallback:` reasons while continuing to exclude intentional extractive routes. | GitHub connector review-thread inspection; focused answer-SLO test, ESLint, TypeScript, Prettier, and `git diff --check`. |
| 2026-07-14 | PR #634 / codex/global-answer-reliability | 588c34c3d455c367e6aa38dc9fce64191678631b | review-followup | One late P2 quota-bypass defect was confirmed: streamed full-document summaries consumed only the general answer quota. Fixed the route to enforce the stricter `document_summarize` quota before starting the stream or provider work while retaining the general answer ceiling. | GitHub connector review-thread inspection; focused private-access route suite 116/116; ESLint; TypeScript; Prettier; `git diff --check`. |
| 2026-07-14 | codex/specifiers-design | c3e7024e15d2157bbc0b989276324cc6ad3eea5c | Specifiers UI, clinical decision-support, accessibility, and release-readiness review | One P2 WCAG contrast defect was reproduced and fixed across the builder, comparison, and map accent eyebrows. No remaining high-confidence defect was found in the changed scope; residual risk is clinical/manual governance of the original specifier summaries. | Focused Vitest 18/18; focused Chromium desktop/mobile 2/2 with serious/critical axe WCAG A/AA scanning and overflow checks; `npm run check:production-readiness:ci` READY; `npm run verify:cheap` 2,210 passed/1 skipped; `npm run verify:pr-local` 2,213 passed/1 skipped plus production build and client-bundle secret scan; `git diff --check`. Full advisory `verify:ui` exceeded the local 10-minute execution window; provider-backed checks were not run. |
| 2026-07-14 | PR #633 / codex/specifiers-design | 03daca3bfdf86517b9956f3c7d91be27d9f1a751 | Review follow-up and failed UI regression | Eight distinct P2 behaviors across nine review threads were confirmed and fixed: initial selection normalization, duplicate query removal, clinical applicability mapping, canonical Specifiers routing, severity-neutral base wording, diagnostic-section ordering, base/specifier compatibility, and severe psychotic-features wording. The failed app-menu keyboard test was a stale order assertion and now covers the inserted Specifiers item. | Focused Vitest 6/6; focused Chromium 4/4; scoped ESLint and TypeScript; CI-mode production readiness READY; production build and client-bundle secret scan passed. Hosted required checks passed on the refreshed `main` merge before the final compatibility fixes; provider-backed Supabase/OpenAI checks were not run. |
| 2026-07-14 | PR #634 / codex/global-answer-reliability | b411329ec5f181661e5d49276c398440aa928fa2 | review-followup | One late P2 fast-context defect was confirmed: Australian tier ordering could push a higher-ranked supplementary passage outside the four-chunk routine fast budget. Fixed by preserving the retrieval-ranked, crowding-capped candidate budget before applying the order-only Australian preference within that set. | GitHub connector review-thread inspection; focused RAG context-budget suite 22/22; ESLint; TypeScript; Prettier; `git diff --check`. |
90 changes: 22 additions & 68 deletions src/app/api/answer/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@ import { buildSmartRagApiPlan } from "@/lib/smart-rag-api";
import { clinicalQueryModeSchema, queryClassForClinicalMode, queryForClinicalMode } from "@/lib/clinical-query-mode";
import { resolveSearchScope, searchScopeFiltersSchema } from "@/lib/search-scope";
import { resolveRetrievalAccessScope } from "@/lib/owner-scope";
import {
hasDangerSourceGovernanceWarning,
sourceGovernanceRefusalAnswer,
sourceGovernanceWarnings,
} from "@/lib/source-governance";
import { sourceGovernanceWarnings } from "@/lib/source-governance";
import { parseJsonBody } from "@/lib/validation/body";
import { toClientAnswerPayload } from "@/lib/answer-client-payload";
import {
answerDegradedModeSignal,
buildGovernedAnswerClientResponse,
buildGovernedDemoAnswerClientResponse,
} from "@/lib/answer-response";
import { answerServerTimingEntries, buildServerTimingHeader } from "@/lib/server-timing";
import { createAdminClient } from "@/lib/supabase/admin";
import { captureServerException } from "@/lib/observability/error-capture";
import { logAnswerDiagnostics } from "@/lib/answer-telemetry";
import { nonProductionSupabaseDemoFallbackReason } from "@/lib/supabase/errors";
import * as serverAuth from "@/lib/supabase/auth";
import type { RagAnswer } from "@/lib/types";
import { answerFeedbackMetadata } from "@/lib/answer-feedback-token";

export const runtime = "nodejs";
Expand All @@ -46,15 +45,6 @@ type AnswerRequestBody = z.infer<typeof answerSchema>;
const emptyScopeAnswer =
"The selected filters did not match any indexed documents, so I cannot generate an answer for that scope.";

function answerDegradedModeSignal(answer?: Pick<RagAnswer, "degradedMode" | "answerQualityTier" | "fallbackReason">) {
if (answer?.degradedMode) return answer.degradedMode;
const active = answer?.answerQualityTier === "source_only";
return {
active,
reason: active ? (answer?.fallbackReason ?? "source_only") : null,
};
}

function buildDemoAnswerPayload(body: AnswerRequestBody, fallbackReason?: string) {
const answer = demoAnswer(body.query, body.documentId, body.documentIds);
const answerFocusQuery = queryForClinicalMode(body.query, body.queryMode);
Expand All @@ -65,14 +55,14 @@ function buildDemoAnswerPayload(body: AnswerRequestBody, fallbackReason?: string
routeMode: answer.routingMode,
retrievalStrategy: "hybrid",
});
return {
...answer,
responseMode: smartApiPlan.displayMode,
smartApiPlan,
demoMode: true,
degradedMode: fallbackReason ? { active: true, reason: fallbackReason } : answerDegradedModeSignal(answer),
...(fallbackReason ? { fallbackMode: "non_production_demo", fallbackReason } : {}),
};
return buildGovernedDemoAnswerClientResponse(
{
...answer,
responseMode: smartApiPlan.displayMode,
smartApiPlan,
},
fallbackReason,
);
}

export async function POST(request: Request) {
Expand Down Expand Up @@ -137,59 +127,23 @@ export async function POST(request: Request) {
queryMode: answerBody.queryMode,
signal: request.signal,
});
const warnings = sourceGovernanceWarnings({
results: answer.sources ?? [],
relevance: answer.relevance ?? answer.smartPanel?.relevance ?? null,
const governedResponse = buildGovernedAnswerClientResponse(answer);
logAnswerDiagnostics({
supabase,
query: answerBody.query,
ownerId: access.ownerId,
answer: governedResponse.telemetryAnswer,
});
const shouldUseSourceGovernanceRefusal =
answer.grounded !== false && answer.confidence !== "unsupported" && answer.responseMode !== "evidence_gap";
if (shouldUseSourceGovernanceRefusal && hasDangerSourceGovernanceWarning(warnings)) {
// Build the refusal explicitly — never spread ...answer here, or the original
// (refused) sources/smartPanel/smartApiPlan would still reach the client and
// defeat the refusal. Keep only the safe "unsupported" contract fields, matching
// the empty-scope branch above.
void logAnswerDiagnostics({
supabase,
query: answerBody.query,
ownerId: access.ownerId,
answer: {
...answer,
grounded: false,
confidence: "unsupported",
sources: [],
responseMode: "evidence_gap",
fallbackReason: "source_governance_refusal",
routingReason: [answer.routingReason, "source_governance_refusal"].filter(Boolean).join("; "),
},
});
return NextResponse.json({
answer: sourceGovernanceRefusalAnswer,
grounded: false,
confidence: "unsupported",
citations: [],
sources: [],
degradedMode: answerDegradedModeSignal(answer),
scope: { ...scope, queryMode: answerBody.queryMode },
sourceGovernanceWarnings: warnings,
...answerFeedbackMetadata(interactionId, sourceGovernanceRefusalAnswer),
});
}

logAnswerDiagnostics({ supabase, query: answerBody.query, ownerId: access.ownerId, answer });

// Durations only — see server-timing.ts for the trust-boundary constraint.
const serverTiming = buildServerTimingHeader(
answerServerTimingEntries(answer.latencyTimings, Date.now() - routeStartedAt),
);
return NextResponse.json(
{
// Boundary trim only — governance warnings and diagnostics above
// consumed the full answer (see answer-client-payload.ts).
...toClientAnswerPayload(answer),
degradedMode: answerDegradedModeSignal(answer),
...governedResponse.payload,
scope: { ...scope, queryMode: answerBody.queryMode },
sourceGovernanceWarnings: warnings,
...answerFeedbackMetadata(interactionId, answer.answer),
...answerFeedbackMetadata(interactionId, governedResponse.payload.answer),
},
serverTiming ? { headers: { "Server-Timing": serverTiming } } : undefined,
);
Expand Down
Loading