@@ -665,7 +665,21 @@ export interface ScatterPoint {
665665 advisoryCount : number
666666}
667667
668- export async function listPackagesForScatter ( qx : QueryExecutor ) : Promise < ScatterPoint [ ] > {
668+ export async function listPackagesForScatter (
669+ qx : QueryExecutor ,
670+ options : { status ?: string } = { } ,
671+ ) : Promise < ScatterPoint [ ] > {
672+ const { status } = options
673+
674+ // 'unassigned' covers packages with no stewardship row (s.id IS NULL) in addition
675+ // to rows explicitly marked unassigned. All other statuses filter via s.status directly.
676+ // The query always uses LEFT JOIN — the filter is applied in the WHERE clause, not the join.
677+ const statusFilter = status
678+ ? status === 'unassigned'
679+ ? `AND (s.status = 'unassigned' OR s.id IS NULL)`
680+ : `AND s.status = $(status)`
681+ : ''
682+
669683 const rows : Array < {
670684 purl : string
671685 name : string
@@ -675,16 +689,17 @@ export async function listPackagesForScatter(qx: QueryExecutor): Promise<Scatter
675689 stewardshipId : string | null
676690 stewardshipStatus : string | null
677691 openVulns : number
678- } > = await qx . select ( `
692+ } > = await qx . select (
693+ `
679694 SELECT
680695 p.purl,
681696 p.name,
682- ROUND(COALESCE(p.impact, 0) * 100)::int AS "criticalityScore",
683- ROUND(COALESCE(r_sc.scorecard_score, 0) * 10)::int AS "healthScore",
684- r_sc.scorecard_score AS "scorecardScoreRaw",
685- s.id::text AS "stewardshipId",
686- s.status AS "stewardshipStatus",
687- COALESCE(ap_counts.cnt, 0) AS "openVulns"
697+ ROUND(COALESCE(p.impact, 0) * 100)::int AS "criticalityScore",
698+ ROUND(COALESCE(r_sc.scorecard_score, 0) * 10)::int AS "healthScore",
699+ r_sc.scorecard_score AS "scorecardScoreRaw",
700+ s.id::text AS "stewardshipId",
701+ s.status AS "stewardshipStatus",
702+ COALESCE(ap_counts.cnt, 0) AS "openVulns"
688703 FROM packages p
689704 LEFT JOIN stewardships s ON s.package_id = p.id
690705 LEFT JOIN LATERAL (
@@ -699,9 +714,12 @@ export async function listPackagesForScatter(qx: QueryExecutor): Promise<Scatter
699714 LIMIT 1
700715 ) r_sc ON true
701716 WHERE p.is_critical = true
717+ ${ statusFilter }
702718 ORDER BY p.impact DESC NULLS LAST, p.purl ASC
703719 LIMIT 2000
704- ` )
720+ ` ,
721+ { status } ,
722+ )
705723
706724 return rows . map ( ( r ) => ( {
707725 purl : r . purl ,
0 commit comments