diff --git a/src/lib/claimsLink.ts b/src/lib/claimsLink.ts
index 98816c1..6e8a441 100644
--- a/src/lib/claimsLink.ts
+++ b/src/lib/claimsLink.ts
@@ -27,7 +27,10 @@ export function claimsHref(q: ClaimsQuery): string {
/** The rows behind "claims denied" / "affected". */
export function affectedClaimsHref(kind: string, slice: Slice | null, anchor: string | null): string | null {
if (kind === 'expiring_appeals') {
- return claimsHref({ status: 'denied', appeal: 'not_filed', dl_from: anchor ?? undefined, dl_to: anchor ? addDays(anchor, 14) : undefined });
+ // Without the anchor the 14-day window cannot be expressed, and the link
+ // would open every unfiled denial ever. Show no link instead.
+ if (!anchor) return null;
+ return claimsHref({ status: 'denied', appeal: 'not_filed', dl_from: anchor, dl_to: addDays(anchor, 14) });
}
if (kind === 'slow_payer') {
return slice?.payer ? claimsHref({ payer: slice.payer, status: 'pending' }) : null;
diff --git a/src/screens/CaseScreen.tsx b/src/screens/CaseScreen.tsx
index f9f8762..e57beee 100644
--- a/src/screens/CaseScreen.tsx
+++ b/src/screens/CaseScreen.tsx
@@ -17,7 +17,7 @@ import { ActivityForm } from '../components/ActivityForm';
import { AvaLive } from '../components/AvaLive';
import { Disclosure, FullStory, Recheck, Recommendations, SqlEvidence, Verdict } from '../components/Findings';
import { Briefing, BriefingSkeleton } from '../components/Briefing';
-import { anchorDate, loadBriefing, sliceOf } from '../api/charts';
+import { loadBriefing, sliceOf } from '../api/charts';
import type { Action } from '../api/config';
import { dateTime, num, str } from '../format';
@@ -67,7 +67,14 @@ export function CaseScreen() {
// Chart rows come from six Databricks views through the record-view API. Loaded
// once there are findings to picture; the slice keys decide which weekly line
// and which recovery breakdown are drawn.
- const asOf = str(row?.review_as_of).slice(0, 10) || null;
+ const asOf = str(row?.review_to || row?.review_as_of).slice(0, 10) || null;
+ // The anchor behind "expiring within 14 days". It is the review's own
+ // ceiling date when the reviewer set one, otherwise the lakehouse's latest
+ // service date — read from the stats view, NOT from the briefing: the charts
+ // take seconds to load and a link rendered without the anchor would silently
+ // drop the deadline window and open thousands of rows instead of hundreds.
+ const lake = useQuery(() => client.rows('dni-rv-lakehouse-tables', { limit: 10 }), [], !asOf && hasFindings);
+ const anchor = asOf ?? str(lake.data?.find((r) => str(r.table_name) === 'claims')?.to_date).slice(0, 10) ?? null;
const briefing = useQuery(
() => loadBriefing(client, slice, { kind, asOf }),
[id, slice?.payer, slice?.department, slice?.code, kind, asOf],
@@ -171,7 +178,7 @@ export function CaseScreen() {
{/* ---------- The findings: what happened, how much, what to approve ---------- */}
{hasFindings && (
<>
-
+
{briefing.data ? (
) : (
diff --git a/src/screens/ClaimsScreen.tsx b/src/screens/ClaimsScreen.tsx
index 8e7cccb..6c3cfd0 100644
--- a/src/screens/ClaimsScreen.tsx
+++ b/src/screens/ClaimsScreen.tsx
@@ -69,8 +69,13 @@ export function ClaimsScreen() {
const filtered = filters.length > 0 || !!search;
const key = params.toString();
+ // ORDER BY A UNIQUE COLUMN. Each page is its own query against Spark, and
+ // `service_date` has thousands of ties — with a non-unique sort key the
+ // engine is free to order tied rows differently per execution, so page 2
+ // repeated rows from page 1. `claim_id` is unique and is assigned in date
+ // order, so descending is still newest-first, and every page is disjoint.
const q = useQuery(
- () => client.recordView('dni-rv-claims', { page, limit: PAGE, filters, search, sortBy: 'service_date', sortDir: 'desc' }),
+ () => client.recordView('dni-rv-claims', { page, limit: PAGE, filters, search, sortBy: 'claim_id', sortDir: 'desc' }),
[key],
);
// The platform caps its count at 10,000; the stats view has the exact