perf(search): narrow the recency window 90d -> 60d
Operator request. Bigger effect than expected.
THREE constants, not one
"90" appeared in three places, and two of them are load-bearing:
universal-search-service.ts UNIVERSAL_SEARCH_WINDOW_DAYS orders scope
quotes-search-service.ts SEARCH_RECENT_WINDOW_DAYS quotes pushdown
quotes-service.ts SEARCH_RECENT_WINDOW_DAYS exported; shared
with the /quotes page + archive
The last two must stay equal — the /quotes page renders "Show recent
(last N days)" from the exported constant while the server filters on
the private one, so moving them apart desyncs the label from the
behaviour with no error anywhere. All three moved together. Universal
search calls searchQuotes without `includeOlder`, so it inherits the
quotes window; changing only the universal constant would have left
global search reading 60 days of orders and 90 days of quotes behind a
single "last 60 days" label.
The UI label reads windowDays straight off the service, so it follows.
MEASURED
Order candidate set collapses — the window was carrying far more than
the linear slice it looks like:
90d -> 5,394 orders / 16,640 items / 6,696ms scope scan
60d -> 972 orders / 3,307 items / 1,606ms scope scan
Cold search "tiaan": 17-22s -> 4.6s measured. That is most of the
mitigation the TTL bump was papering over, so the long-deferred pushdown
rewrite is now worth less than it was this morning.
Quotes genuinely drop, and it is real rather than a regression: Tiaan's
own quotes go 22 -> 6 between a 90- and 60-day window, because that
band is where most of his quotes sit. Verified against PB directly.
ALSO
Pinned the clock in the age-chip test. It asserted "4d" against a
fixture dated four days before the wall clock, so it expired the day
the date rolled past — it failed on this run for exactly that reason.
This commit is contained in:
parent
c22e9d1bd6
commit
d55e54680b
4 changed files with 12 additions and 6 deletions
|
|
@ -96,7 +96,7 @@ import type { Quote, QuoteItem } from "@/lib/types";
|
||||||
* compute it independently from `SEARCH_RECENT_WINDOW_DAYS`, so
|
* compute it independently from `SEARCH_RECENT_WINDOW_DAYS`, so
|
||||||
* envoy clock skew or process restart never desyncs the label.
|
* envoy clock skew or process restart never desyncs the label.
|
||||||
*/
|
*/
|
||||||
const SEARCH_RECENT_WINDOW_DAYS = 90;
|
const SEARCH_RECENT_WINDOW_DAYS = 60;
|
||||||
function searchRecentCutoff(now: Date = new Date()): string {
|
function searchRecentCutoff(now: Date = new Date()): string {
|
||||||
return new Date(
|
return new Date(
|
||||||
now.getTime() - SEARCH_RECENT_WINDOW_DAYS * 24 * 60 * 60 * 1000,
|
now.getTime() - SEARCH_RECENT_WINDOW_DAYS * 24 * 60 * 60 * 1000,
|
||||||
|
|
|
||||||
|
|
@ -285,7 +285,7 @@ export function completedRecentCutoff(now: Date = new Date()): string {
|
||||||
* two surfaces agree on what "recent" means. Same single source of
|
* two surfaces agree on what "recent" means. Same single source of
|
||||||
* truth as `COMPLETED_RECENT_WINDOW_DAYS` for the new tabs.
|
* truth as `COMPLETED_RECENT_WINDOW_DAYS` for the new tabs.
|
||||||
* ========================================================================== */
|
* ========================================================================== */
|
||||||
export const SEARCH_RECENT_WINDOW_DAYS = 90;
|
export const SEARCH_RECENT_WINDOW_DAYS = 60;
|
||||||
export function searchRecentCutoff(now: Date = new Date()): string {
|
export function searchRecentCutoff(now: Date = new Date()): string {
|
||||||
return new Date(
|
return new Date(
|
||||||
now.getTime() - SEARCH_RECENT_WINDOW_DAYS * 24 * 60 * 60 * 1000,
|
now.getTime() - SEARCH_RECENT_WINDOW_DAYS * 24 * 60 * 60 * 1000,
|
||||||
|
|
|
||||||
|
|
@ -118,8 +118,14 @@ describe("daysAgoIso — the 90-day scope window", () => {
|
||||||
expect(daysAgoIso(0, now)).toBe("2026-10-14T00:00:00.000Z");
|
expect(daysAgoIso(0, now)).toBe("2026-10-14T00:00:00.000Z");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("defaults to the 90-day window constant the UI reports", () => {
|
it("defaults to the window constant the UI reports", () => {
|
||||||
expect(UNIVERSAL_SEARCH_WINDOW_DAYS).toBe(90);
|
// 90 → 60 on 2026-10-15 at the operator's request. If this
|
||||||
|
// assertion is failing after an intentional change, update the
|
||||||
|
// number AND the comment above it — the value is duplicated in
|
||||||
|
// quotes-search-service (private) and quotes-service (exported,
|
||||||
|
// shared with the /quotes page and its archive), and the three
|
||||||
|
// MUST move together or the page label desyncs from the filter.
|
||||||
|
expect(UNIVERSAL_SEARCH_WINDOW_DAYS).toBe(60);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
* ============================================================================
|
* ============================================================================
|
||||||
* SCOPE
|
* SCOPE
|
||||||
* ============================================================================
|
* ============================================================================
|
||||||
* Bounded to a recent window (UNIVERSAL_SEARCH_WINDOW_DAYS, currently 90)
|
* Bounded to a recent window (UNIVERSAL_SEARCH_WINDOW_DAYS, currently 60)
|
||||||
* on the collections that grow without bound (orders, quotes). The
|
* on the collections that grow without bound (orders, quotes). The
|
||||||
* bounded reference collections (suppliers, companies, customers, reps,
|
* bounded reference collections (suppliers, companies, customers, reps,
|
||||||
* stock items, both PO flavours) are searched in full — a supplier or
|
* stock items, both PO flavours) are searched in full — a supplier or
|
||||||
|
|
@ -73,7 +73,7 @@ type AdminPocketBase = Awaited<ReturnType<typeof getAdminPocketBase>>;
|
||||||
* client as `windowDays` so the UI can say "last 90 days" instead of
|
* client as `windowDays` so the UI can say "last 90 days" instead of
|
||||||
* leaving the operator guessing whether a miss means "aged out".
|
* leaving the operator guessing whether a miss means "aged out".
|
||||||
*/
|
*/
|
||||||
export const UNIVERSAL_SEARCH_WINDOW_DAYS = 90;
|
export const UNIVERSAL_SEARCH_WINDOW_DAYS = 60;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rendered hits per group. `total` is always the uncapped count.
|
* Rendered hits per group. `total` is always the uncapped count.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue