fix(12): WR-02 rotate matchPax8Companies eligibility ordering and raise the limit to prevent starvation
This commit is contained in:
parent
cb8ae85737
commit
76a652ddfd
1 changed files with 26 additions and 9 deletions
|
|
@ -186,7 +186,12 @@ export async function matchPax8Companies(opts?: {
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
}): Promise<Pax8CompanyMatchResult> {
|
}): Promise<Pax8CompanyMatchResult> {
|
||||||
const startedAt = Date.now();
|
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 dryRun = opts?.dryRun ?? false;
|
||||||
|
|
||||||
const result: Pax8CompanyMatchResult = {
|
const result: Pax8CompanyMatchResult = {
|
||||||
|
|
@ -198,17 +203,29 @@ export async function matchPax8Companies(opts?: {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
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>(
|
const eligible = await postgresClient.query<EligibleCompany>(
|
||||||
`SELECT id::text, name
|
`SELECT c.id::text, c.name
|
||||||
FROM pax8_companies
|
FROM pax8_companies c
|
||||||
WHERE is_deleted = false
|
LEFT JOIN pax8_company_match_review r
|
||||||
AND match_method IS DISTINCT FROM 'manual'
|
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 (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM pax8_company_match_review r
|
SELECT 1 FROM pax8_company_match_review r2
|
||||||
WHERE r.pax8_company_id = pax8_companies.id
|
WHERE r2.pax8_company_id = c.id
|
||||||
AND r.resolved_at IS NOT NULL
|
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 $1`,
|
||||||
[limit]
|
[limit]
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue