🔧 Programmierung 🕛 kürzlich 10 Min Lesezeit
0

How I built a content quality gate that stops bad articles before they publish

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

I run I built earlier applies the same principle to social posts: systematic gates catch what self-review misses reliably. For articles, the gate runs before the publish workflow can touch the file.



The has a similar constraint: structure imposed at ingestion time is easier to maintain than structure enforced by convention.



Title and description length. Titles over 90 characters are an error — Dev.to and Hashnode truncate feed titles beyond that. Descriptions over 200 characters are an error — the meta description budget for Google and Hashnode display.



Word count. This is a warning rather than a hard error because the threshold varies by article archetype. A lightweight at 580 words isn't technically failing a hard constraint, but the flag forces a decision: add a section, or accept the shorter count and justify it. The word count always appears in the summary line regardless, so there's no hiding from it.



Cliché detection. 14 literal phrases are checked case-insensitively against the full body. The list covers diving metaphors, fast-paced-world openers, hyperbolic tech superlatives, and in-this-article throat-clearing — the standard set of AI-assisted writing tics. I won't reproduce all 14 here for an ironic reason I'll cover in "What I'd do differently."



The check is simple String.prototype.includes, not regex, because the phrases are specific enough that false positives aren't a real concern. An article using the typical "world of AI" framing is probably using clichéd structure; the check forcing me to see it is the point.



Fabricated metric detection. Two regex patterns catch the most common forms of fabricated social proof:




CODE
const FABRICATED_METRIC_PATTERNS = [
/\b(\d{2,3},?\d{3,}|\d{4,})\s+(visit|view|readers?|users?|subscribers?)\b/gi,
/\branked #1\b/gi,
/\bmillion(?:s)?\s+of\s+(?:users?|readers?|developers?)/gi,
];






The first pattern catches round numbers followed by social-proof nouns like "visitors", "users", or "subscribers" — numbers presented as fact when the sites are young enough that no credible claim to that kind of traffic exists. The pattern requires a four-digit-or-higher number followed directly by a social-proof noun. It catches claimed traffic figures but not numeric references in code or data discussion.



This check produces an error, not a warning, because fabricated metrics are the one category I genuinely can't allow. The whole premise of the uses a similar "catch before ship" logic at the infrastructure level. The article gate applies it at the content level.



Sentence repetition. Any sentence appearing three or more times in the same article generates a warning. This catches a specific AI-assisted writing failure: a paragraph occasionally gets reformulated twice, and the reformulation ends up identical to the original a few hundred words later. The check normalizes to lowercase and trims whitespace before comparing.






Strict versus lenient mode



The gate has two distinct behaviors depending on how it's called. The applies here: different content tiers have different quality expectations.



The article generation routine runs strict mode on each newly staged file before committing. The publish workflow runs against the specific file being published. The all-articles scan runs periodically to report on historical drift without failing anything.






Title duplicate detection across the repo



When scanning all articles (not single-file mode), the gate runs a cross-article deduplication check. Titles are normalized to lowercase alphanumeric, whitespace collapsed, then compared:




CODE
function detectTitleDuplicates(reports) {
const titles = new Map();
for (const [path, r] of reports) {
if (!r.meta?.title) continue;
const key = r.meta.title.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
const existing = titles.get(key) ?? [];
existing.push(path);
titles.set(key, existing);
}
return [...titles.entries()]
.filter(([, paths]) => paths.length > 1)
.map(([key, paths]) => ({ key, paths }));
}






This catches rephrase cases more than exact duplicates (which would be obvious). "Why I use Turso for my Astro monorepo" and "Using Turso libSQL in an Astro monorepo" normalize to similar-enough strings to surface as candidates. The check doesn't do semantic similarity — it doesn't need to. Structural overlap is enough of a signal to warrant a second look, given how the I built approach content credibility from the site structure side. The lint gate approaches it from the individual article side. Both serve the same goal: content that doesn't embarrass the project in hindsight.






FAQ



Why not use an existing prose linter like alex or write-good?



alex focuses on inclusive language; write-good checks passive voice and weak qualifiers. Neither checks frontmatter structure, tag pools, or fabricated metrics — the pipeline-specific failures I actually need to catch. A domain-specific gate catches domain-specific failures better than a general-purpose tool.



How does the fabricated metric check handle code blocks?



Currently it doesn't exclude them, which is the known gap. Numeric references in code examples occasionally trigger false positives. I review the flagged line location before treating it as a real failure. Pre-processing the body to strip triple-backtick blocks would fix this.



Why warn on internal link count instead of hard-erroring?



Because article type isn't always deterministic from content alone. A 1200-word article might be a pillar or a borderline lightweight. Treating it as a warning preserves the ability to make a judgment call; treating it as a hard error would block edge cases that are genuinely fine.



What happens to historical articles that fail current checks?



Baseline scan mode reports them without failing. Historical content is in a different tier. New articles must pass strict mode; historical articles are known issues reported for visibility, not blocked.






Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 40%
🟡 In Evaluierung 30%
🟢 Keine Auswirkung 16%
Spannende Innovation 14%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
2 Quellen
ChatGPT, Claude, and Grok all went down at once; enterprises need a backup plan
2 Quellen
OpenAI launches GPT-6 Astra
1 Quelle
What JPMorgan does differently with AI that any company can apply
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How I built a content quality gate that stops bad articles before they publish

Thematisch verwandte Begriffe: built, content, quality, gate · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...