fix(12): WR-02 rotate matchPax8Companies eligibility ordering and raise the limit to prevent starvation

This commit is contained in:
lorentz 2026-07-11 07:22:25 -04:00
parent cb8ae85737
commit 76a652ddfd

View file

@ -186,7 +186,12 @@ export async function matchPax8Companies(opts?: {
dryRun?: boolean;
}): Promise<Pax8CompanyMatchResult> {
const startedAt = Date.now();
const limit = opts?.limit ?? 1000;
// WR-02 default raised well above any near-term PAX8/Autotask company
// count (validated at 118 companies; generous headroom for growth) and
// the eligibility ORDER BY below rotates fairness so accumulating
// review-flagged rows can no longer permanently starve alphabetically
// later companies even if this limit is ever hit.
const limit = opts?.limit ?? 10000;
const dryRun = opts?.dryRun ?? false;
const result: Pax8CompanyMatchResult = {
@ -198,17 +203,29 @@ export async function matchPax8Companies(opts?: {
};
try {
// WR-02: ORDER BY name is a static cursor — once flagged-for-review
// companies accumulate (their matched_at stays NULL indefinitely; see
// recordConflict), they keep re-occupying the same slots in every run's
// top-N by name, and once eligible rows exceed `limit`, everything
// sorting alphabetically after that point is starved. Ordering instead
// by "last time this row was actually considered" (the open review's
// detected_at, falling back to matched_at, falling back to the epoch
// for never-yet-scanned rows) rotates fairness: least-recently-attempted
// rows always sort first, so a permanently-open review row sinks behind
// any row that hasn't been reconsidered as recently.
const eligible = await postgresClient.query<EligibleCompany>(
`SELECT id::text, name
FROM pax8_companies
WHERE is_deleted = false
AND match_method IS DISTINCT FROM 'manual'
`SELECT c.id::text, c.name
FROM pax8_companies c
LEFT JOIN pax8_company_match_review r
ON r.pax8_company_id = c.id AND r.resolved_at IS NULL
WHERE c.is_deleted = false
AND c.match_method IS DISTINCT FROM 'manual'
AND NOT EXISTS (
SELECT 1 FROM pax8_company_match_review r
WHERE r.pax8_company_id = pax8_companies.id
AND r.resolved_at IS NOT NULL
SELECT 1 FROM pax8_company_match_review r2
WHERE r2.pax8_company_id = c.id
AND r2.resolved_at IS NOT NULL
)
ORDER BY name
ORDER BY COALESCE(r.detected_at, c.matched_at, 'epoch'::timestamptz) ASC
LIMIT $1`,
[limit]
);