fix(prefetch): recurse parts-catalogs trees to full depth
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
isLeafLinkPath flagged EVERY pcat node as a leaf (any pcat: linkPath), so the backfill worker fetched a mid-group folder's "parts" — a 1-level drill that only revealed its sub-groups — and never recursed. Deep pcat trees (whose top level is ~100% folders) were left one level shallow: no parts seeded, so the new tree part-counts stayed 0 and the cross-tree catalog search (DB-only) found nothing on a freshly decoded vehicle. Exactly why serkan's Ford Mondeo looked like an empty catalog. Use the captured hasSubgroups flag: a pcat node is a parts leaf only when it is NOT a known parent group. Folders now queue a children job and the existing recursion (queueCategoryJob → processChildren → getChildren) drills to full depth (MAX_DEPTH=5), seeding parts at every leaf. The rolling backfill rescan warms existing shallow vehicles wave by wave; new decodes warm deep via the reactive schedulePrefetch. Rate limiter + PCAT_PACE + backlog guard keep it bounded (all env-tunable to ramp). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -247,7 +247,7 @@ export class PrefetchWorkerService implements OnModuleInit, OnModuleDestroy {
|
||||
await this.queueCategoryJob(child, vehicleId, source, 1);
|
||||
queued++;
|
||||
}
|
||||
} else if (this.isLeafLinkPath(cat.linkPath, cat.source)) {
|
||||
} else if (this.isLeafLinkPath(cat.linkPath, cat.source, cat.hasSubgroups)) {
|
||||
// Leaf — check if parts already fetched
|
||||
const [partCheck] = await this.db
|
||||
.select({ id: parts.id })
|
||||
@@ -488,14 +488,20 @@ export class PrefetchWorkerService implements OnModuleInit, OnModuleDestroy {
|
||||
// ==================== Helpers ====================
|
||||
|
||||
private async queueCategoryJob(
|
||||
cat: { id: string; linkPath: string | null; source: string; unavailable: boolean },
|
||||
cat: {
|
||||
id: string;
|
||||
linkPath: string | null;
|
||||
source: string;
|
||||
unavailable: boolean;
|
||||
hasSubgroups?: boolean | null;
|
||||
},
|
||||
vehicleId: string,
|
||||
source: string,
|
||||
depth: number,
|
||||
): Promise<void> {
|
||||
if (cat.unavailable) return;
|
||||
|
||||
if (this.isLeafLinkPath(cat.linkPath, cat.source)) {
|
||||
if (this.isLeafLinkPath(cat.linkPath, cat.source, cat.hasSubgroups)) {
|
||||
// Leaf — check if already has parts
|
||||
const [partCheck] = await this.db
|
||||
.select({ id: parts.id })
|
||||
@@ -543,12 +549,25 @@ export class PrefetchWorkerService implements OnModuleInit, OnModuleDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
private isLeafLinkPath(linkPath: string | null, source: string): boolean {
|
||||
private isLeafLinkPath(
|
||||
linkPath: string | null,
|
||||
source: string,
|
||||
hasSubgroups?: boolean | null,
|
||||
): boolean {
|
||||
if (!linkPath) return false;
|
||||
// EMEX: Vehicle.aspx group nodes are parents to drill; Unit.aspx (hierarchical
|
||||
// tree) and QuickDetails.aspx (legacy flat) leaves carry parts.
|
||||
if (source === "emex") return !linkPath.includes("Vehicle.aspx");
|
||||
if (source === "parts-catalogs") return linkPath.startsWith("pcat:"); // pcat: prefix = leaf
|
||||
// parts-catalogs: EVERY node has a pcat: linkPath, so the old "pcat: prefix =
|
||||
// leaf" rule mis-flagged every mid-group folder as a leaf — the worker fetched
|
||||
// its "parts" (a 1-level drill that just revealed sub-groups) and never
|
||||
// recursed, leaving deep pcat trees a single level shallow (no parts → empty
|
||||
// part counts, dead cross-tree search). Use the captured hasSubgroups flag
|
||||
// instead: a node is a parts leaf only when it is NOT a known parent group, so
|
||||
// folders queue a children job and the recursion drills to full depth. Unknown
|
||||
// flag (null, rare pre-migration rows) → treated as leaf, preserving the old
|
||||
// 1-level behaviour for those.
|
||||
if (source === "parts-catalogs") return hasSubgroups !== true;
|
||||
// PL24 leaf indicators
|
||||
return (
|
||||
linkPath.includes("/bom/") ||
|
||||
|
||||
Reference in New Issue
Block a user