fix: a review window needs a baseline — say which one, refuse ones that have none

- charter: a window starting before the data or longer than 12 weeks is split
  (last 6 weeks vs the 8 before); REVIEWED always names the compared periods,
  never the requested span or the whole table
- Run review: shows the data's span, previews the exact recent and baseline
  periods, blocks a window whose baseline would fall before the first claim,
  and sends 'data as of' only when no window end is given

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Yashas 2026-09-17 12:26:49 +05:30
parent 91002b11c4
commit 77cf90e40b

View File

@ -1,7 +1,9 @@
import { useState } from 'react'; import { useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Brain, CalendarRange, Database, Radar } from 'lucide-react'; import { Brain, CalendarRange, Database, Radar } from 'lucide-react';
import { useZino } from '../api/provider'; import { useQuery, useZino } from '../api/provider';
import { addDays } from '../api/charts';
import { str } from '../format';
import { ACT, LAKEHOUSE, QUIET_MORNING_AS_OF, WORKFLOW } from '../api/config'; import { ACT, LAKEHOUSE, QUIET_MORNING_AS_OF, WORKFLOW } from '../api/config';
import { Button, Card, ErrorNote, Input, Label } from '../components/core'; import { Button, Card, ErrorNote, Input, Label } from '../components/core';
import { shortDate } from '../format'; import { shortDate } from '../format';
@ -28,14 +30,29 @@ export function RunReviewScreen() {
const [from, setFrom] = useState(''); const [from, setFrom] = useState('');
const [to, setTo] = useState(''); const [to, setTo] = useState('');
// The data's own span, so a window cannot be set where there is nothing to
// compare: a start before the first claim leaves no baseline, and a run on
// such a window would have to improvise one.
const stats = useQuery(() => client.rows('dni-rv-lakehouse-tables', { limit: 10 }), []);
const claimsStats = stats.data?.find((r) => str(r.table_name) === 'claims');
const dataFrom = str(claimsStats?.from_date).slice(0, 10) || null;
const dataTo = str(claimsStats?.to_date).slice(0, 10) || null;
// The window Ava will actually use, so the reviewer sees it before pressing Run. // The window Ava will actually use, so the reviewer sees it before pressing Run.
const effectiveTo = to || asOf; const effectiveTo = to || asOf;
const weeks = from && effectiveTo ? Math.round((new Date(effectiveTo).getTime() - new Date(from).getTime()) / 604800000) : null;
const split = weeks != null && weeks > 12;
const recentFrom = split && effectiveTo ? addDays(effectiveTo, -41) : from || (effectiveTo ? addDays(effectiveTo, -41) : '');
const baseFrom = recentFrom ? addDays(recentFrom, -56) : '';
const baseTo = recentFrom ? addDays(recentFrom, -1) : '';
const dateErr = const dateErr =
from && effectiveTo && from > effectiveTo from && effectiveTo && from > effectiveTo
? 'The window must start before it ends.' ? 'The window must start before it ends.'
: to && asOf && to > asOf : to && asOf && to > asOf
? '"Window to" cannot be after "data as of".' ? '"Window to" cannot be after "data as of".'
: null; : dataFrom && baseFrom && baseFrom < dataFrom
? `The 8-week baseline before ${shortDate(recentFrom)} needs data from ${shortDate(baseFrom)}, but the data begins ${shortDate(dataFrom)}. Start the window on or after ${shortDate(addDays(dataFrom, 56))}.`
: null;
async function run(custom: boolean) { async function run(custom: boolean) {
setBusy(custom ? 'custom' : 'now'); setBusy(custom ? 'custom' : 'now');
@ -45,7 +62,8 @@ export function RunReviewScreen() {
// reviewer set, so a plain run is a genuinely empty submission. // reviewer set, so a plain run is a genuinely empty submission.
const data: Record<string, string> = {}; const data: Record<string, string> = {};
if (custom) { if (custom) {
if (asOf) data.review_as_of__review = asOf; // "Window to" is the ceiling; "data as of" only matters when no window end is given.
if (asOf && !to) data.review_as_of__review = asOf;
if (from) data.review_from__review = from; if (from) data.review_from__review = from;
if (to) data.review_to__review = to; if (to) data.review_to__review = to;
} }
@ -121,6 +139,7 @@ export function RunReviewScreen() {
<p className="mt-0.5 text-sm text-muted"> <p className="mt-0.5 text-sm text-muted">
Replay a past morning, or point the review at a specific period. Leave a date blank to Replay a past morning, or point the review at a specific period. Leave a date blank to
use the default. use the default.
{dataFrom && dataTo ? ` Data available ${shortDate(dataFrom)} – ${shortDate(dataTo)}, ${dataTo.slice(0, 4)}.` : ''}
</p> </p>
</div> </div>
</div> </div>
@ -150,11 +169,12 @@ export function RunReviewScreen() {
<> <>
Ava will compare{' '} Ava will compare{' '}
<span className="font-semibold text-ink"> <span className="font-semibold text-ink">
{from ? shortDate(from) : effectiveTo ? '6 weeks before' : 'the last 6 weeks'} {recentFrom ? `${shortDate(recentFrom)} – ${shortDate(effectiveTo)}` : 'the last 6 weeks'}
{from || effectiveTo ? ` – ${effectiveTo ? shortDate(effectiveTo) : 'latest data'}` : ''}
</span>{' '} </span>{' '}
against the 8 weeks before it against{' '}
{asOf ? `, treating ${shortDate(asOf)} as the latest date` : ''}. <span className="font-semibold text-ink">{baseFrom ? `${shortDate(baseFrom)} – ${shortDate(baseTo)}` : 'the 8 weeks before'}</span>
{effectiveTo ? `, ignoring anything after ${shortDate(effectiveTo)}` : ''}.
{split ? ` A window longer than 12 weeks has no baseline of its own, so its last 6 weeks are compared with the 8 before them.` : ''}
</> </>
)} )}
</p> </p>