From 1113011eada083c9d247029aa2568e27a04c4fe4 Mon Sep 17 00:00:00 2001 From: SMTP Relay & Email - Free Send <60409540+msgwing@users.noreply.github.com> Date: Mon, 17 Aug 2026 22:50:22 +0200 Subject: [PATCH] fix(ci): make the radar check the candidate is a directory at all The run of 2026-08-17 queued a database client and a collection of n8n workflow templates. Both passed because their README contains the word "email" somewhere, which is true of most repositories and says nothing about whether the project is a curated list. Two gates instead. A candidate must look like a directory - at least 40 entry-shaped lines, `- [name](https://...)` - and must carry a mail or email *heading*, not the word loose in the prose. The matched heading is now what the queued issue reports, so a reviewer sees which section the entry would go in. Checked against real READMEs: free-for-dev 1287 entries and a heading, passes. Chat2DB 0 entries, rejected. awesome-n8n-templates 2 entries, rejected. awesome-selfhosted has 1261 entries and passes this gate, and is still caught by the eligibility gate above it, which is the right order. --- .github/workflows/listings-radar.yml | 33 ++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/listings-radar.yml b/.github/workflows/listings-radar.yml index f423144..90c2684 100644 --- a/.github/workflows/listings-radar.yml +++ b/.github/workflows/listings-radar.yml @@ -143,13 +143,32 @@ jobs: continue; } - // The list has to have a section this belongs in. A general - // awesome-list with no mail, SMTP or email section is not a - // rejection of the project - it is simply the wrong list, and - // submitting anyway is how a maintainer learns to ignore you. - const section = ['smtp', 'email', 'e-mail', 'mail', 'transactional'] - .find(w => lower.includes(w)); - if (!section) { rejected++; continue; } + // Is it a curated list at all? This gate was missing entirely on + // the run of 2026-08-17, which queued a database client and a + // collection of n8n workflow templates - both of them repos whose + // README happens to contain the word "email", which is true of + // most repos and says nothing. A directory looks like a + // directory: dozens of entry-shaped lines. + const entries = (readme.match(/^[ ]*[-*] \[[^\]]+\]\(https?:\/\//gm) || []).length; + if (entries < 40) { + core.info(`${r.full_name}: only ${entries} list entries - not a directory.`); + rejected++; + continue; + } + + // And it has to have a section this belongs in - a *heading*, + // not the word somewhere in the prose. A general list with no + // mail section is not a rejection of the project, it is simply + // the wrong list, and submitting anyway is how a maintainer + // learns to ignore you. + const heading = readme.match( + /^#{1,4}[ ]+.*(e-?mail|smtp|mail|transactional).*$/im); + if (!heading) { + core.info(`${r.full_name}: ${entries} entries but no mail section.`); + rejected++; + continue; + } + const section = heading[0].replace(/^#+\s*/, '').trim().slice(0, 60); // What kind of list is it? Having a mail section is not enough, // and this is where the first run went wrong: it queued