On the morning of 30 June 2026, between 09:53 and 13:42, a sweep ran over the
articles on this blog. The repo had opened on 31 March 2026, and in the three
months since, the automated content pipeline had accumulated posts full of
fabricated figures presented as measurements, invented scenes told as lived
experience, and command output that never came from a terminal. Six commits
cleared them. Into the fourth batch's commit message went this line — no Turkish
diacritics, because I write commit messages in ASCII: "TUM 576 makale de-fab
tamamlandi (pilot+4 batch)", meaning all 576 articles de-fabbed.
Four months later, this week, I put that sentence on a scale. The sweep really
had worked: it deleted 3,222 Turkish lines. But "complete" was a scope claim, and
the scope was never written down anywhere. Written down, it would have said:
455 of 901 Turkish files; zero of 901 English files.
So the numbers can be reproduced, the measurement went into the repo as a script:
scripts/measure-defab-coverage.mjs. Every figure below comes from the 990dee53
tree on origin/main, read on 17 October 2026.
First, the limit of my own criterion
This is the easiest place in the article to attack, so let me open it myself.
The sweep's rule was not a single thing. The pilot commit's message names four
classes: fake numbers, fake command output, piles of anecdotes, repeated credits.
Four months later I can mechanically trace only one of those four backwards — the
percent sign. Of the 3,222 Turkish lines the sweep deleted, only 553 (17.2%)
contain a percent sign; the remaining 83% are sentences no regex recognises on
its own.
So the 474 below is a probe pushed through one of four doors. The scope finding is
entirely independent of that criterion, and far sharper, because it needs no
language analysis at all: you ask git which files changed, and git answers.
The sweep itself
Six commits: a pilot (09:53), four batches (10:19–10:55) and a second wave
(13:42). According to the script's count, the sweep touched 455 Turkish article
files. The number of English files it touched: zero.
When the sweep started the archive held 1,802 .mdx files — 901 Turkish, 901
English; by the time it finished two new articles had landed, making it 902 and
- The blog has been bilingual from the start and every article has a twin. The sweep never opened half the archive.
Where does "576" come from? The honest answer is that I cannot reproduce it today.
The pilot commit's message calls itself "~576 de-fab isinin dogrulanmis ilk
partisi" — the verified first batch of ~576 de-fab work — so a candidate set was
computed that morning. The code that computed it is not in the repo. The only
figure I can verify in hindsight is the one git tells me: 455 files modified.
I could say I failed to notice the gap that day, but that would be half a
confession. The real failure is not the oversight; it is that the scope was
never recorded. The commit messages have numbers ("140/140 render OK", "net -52
satir"), they have a quality claim ("cerrahi, oz korundu" — surgical, substance
preserved), they even have method. No scope. Four months later the person reading
that message — and that person was me — reads "all articles cleaned".
First boundary: language
All 455 Turkish articles have an English twin; the script found every one. 408
of those twins have not changed since the day of the sweep. I looked at the last
change to each of the 47 that did: 31 are fix(translate) commits, 16 are
fix(content). Those 47 files were touched for translation or content repair —
not one of them for fabrication cleanup.
The question the script puts to the twins is narrow: is there a percentage the
sweep deleted from the Turkish text that is gone from Turkish today but still
present in the English twin? The answer: 474 numbers, across 213 articles.
A concrete case, because an abstract number makes nobody uncomfortable. Under
career there is an article titled "The AI Premium is Real: Engineers with AI
Skills Earn 12-56% More". The sweep deleted every percentage from its Turkish
body; today not a single percent-marked figure remains there. The English twin's
body has nine: 12%, 15%, 20%, 25%, 40%, 56%, 70%, 80%, 90%. The twin's last change
was 26 June 2026 — four days before the sweep — and it was a sharing-flag flip.
Both pages return 200 this morning. The same claim, deleted in one language,
published in the other. To a search engine these are two documents; to a reader
they are the "corrected" and the "uncorrected" version of one article.
This figure is easy to over-read, so let me write down both of its limits. The
script verifies that the number appears somewhere in the English file, not
that it sits in the same sentence. And the percent pattern also reaches inside
code blocks and tables: of eleven cases I sampled at random from the 474, two
carried no claim at all (a file-listing line reading ├── res/: 12.3 MB (18.9%),
and a cell in a comparison table). So 474 is not a clean count of fabrications; it
is a count of "percentages the sweep removed from Turkish that still stand in
English".
The other direction deserves the same honesty: only 213 of the 455 articles
produced such a number. There are two reasons the other 242 did not. The line the
sweep deleted in that article may contain no percentage at all — and 83% of the
lines do not. Or the deleted percentage still appears somewhere else in the
Turkish text, in which case the "gone from Turkish" condition fails and the case
drops out. So 213 is not the whole set; it is the part the criterion can prove
comfortably.
Second boundary: what counted
Let us read the sweep's rule from its own commit message again. The pilot says:
fake numbers posing as measurements become qualitative, fake command output
becomes a comment, "anekdot yiginini 1-2'ye indir" — trim the pile of
anecdotes down to one or two — and repeated credits get simplified.
For anecdotes the rule is reduction, not deletion. Four months later I remembered
this as "I cleared out the fabricated anecdotes". The rule never said that.
The measurement: in 188 of the 455 Turkish articles the sweep passed through,
an invented client/project narrative pattern is still standing today — 311
occurrences in total.
Let me set one sentence from that AI premium article side by side, before and
after the sweep. Before:
Bir müşteri projesinde, bankanın iç dokümanlarını kullanarak otomatik yanıt
sistemi kurarken, RAG mimarisi sayesinde halüsinasyon oranını ciddi şekilde
düşürdük ve ilgili bilgilere erişim süresini milisaniyelere indirdik.
On a client project, building an automatic answering system from a bank's
internal documents, the RAG architecture brought the hallucination rate down
considerably and cut access time to the relevant information **down to
milliseconds.
What is published today:
…halüsinasyon oranını ciddi şekilde düşürdük ve ilgili bilgilere erişim
süresini belirgin biçimde kısalttık.
…brought the hallucination rate down considerably and **shortened* access time
to the relevant information noticeably.*
Two words changed. The measurement-shaped "down to milliseconds" went; the bank
stayed, the client project stayed, the first-person plural stayed. The part that
made the sentence falsifiable was deleted and the part that made it invented
stayed published.
It would suit my argument to paint the sweep as blind here, but the record says
otherwise. In the same file, the second wave removed an invented bank scene
outright from a different bullet: "Bir bankanın iç platformunda ise… çağrı
sürelerini kayda değer ölçüde azalttık" — and on a bank's internal platform we
cut call times considerably — was rewritten as "Aynı mantık müşteri desteğinde
de işliyor… kısaltabiliyor", the same logic works in customer support… it can
shorten. The first-person claim went and the bank went with it. Two bullets, one
file, one morning, two different outcomes.
The sweep was not blind; it was uneven. And the most dangerous thing about an
uneven sweep is that its report looks even: the word "complete" puts both bullets
in the same bag.
Third boundary: title and address
The Turkish title of that same article still reads "%12-56 Daha Fazla Alıyor". Its
slug is ...-12-56-daha-fazla-aliyor. The figure the sweep deleted from the body
sits in the title and in the address — in both languages.
The sweep is not to blame here, because the cause is technical: a published
article's slug does not change. Social posts, RSS readers and external links all
point at that address. The title can be corrected; correcting the address is a far
more expensive job than correcting. So the claim deleted from the body is
fossilised in the article's permanent identity.
What comes out of this has less to do with scope than with order: a claim must be
verified before it reaches the title. The
title gate
came later on this blog, and that article counted the residue left in the archive
by gates that cannot be applied retroactively. This is the cheapest and most
permanent form of the same problem.
The surface the sweep never owned
Now the part that bothers me most. While the sweep was pulling fabrication out of
the archive, another piece of automation was putting it in.
On 9 May 2026 a FAQ system entered the repo. Its commit message states the intent
plainly: to raise site traffic, "etik + risk-yok yontemler" — ethical, no-risk
methods — were wanted, and "fake yorum yerine AI-generated FAQ + Schema.org
markup", AI-generated FAQ with Schema.org markup instead of fake comments, was
the pick. The system appends four AI-written question-answer pairs to the end of
every article, both as a visible accordion and as FAQPage structured data.
Where that stands today: 681 Turkish and 624 English articles carry the block.
Inside them, 5,218 answers in total (2,723 Turkish, 2,495 English).
How many narrate invented experience? For this question I did not write a new
detector; writing my own would have meant tuning the criterion in my own favour.
Instead the repo's own pre-publication filter
(scripts/lib/content-safety.mjs, sitting here since 17 August 2026) was run
against the published answers. A few of the patterns it looks for:
ben/biz + kullandım|kurdum|yaşadım|gördüm|ölçtüm…
benim deneyimimde | bir keresinde | geçen ay|hafta|yıl
bir müşteri/proje/ERP…de + çalışırken|kurarken|geliştirirken…
I|we + used|built|deployed|implemented|experienced|measured…
The result: 1,045 answers (229 Turkish, 816 English) would not survive my own
filter. 564 articles have at least one answer in that state. Here is one, from
under a live career article:
In my experience, the only thing that lasts in the tech world is
real, lived experience.
I did not write that, and my name is underneath it. It sits in a code block rather
than in a quotation because quoting it as prose makes this article fail the same
gate — the validator flagged the draft, and the only thing that got it through was
moving the sentence somewhere the filter does not read.
The fix has been inside the repo for two months and going forward it is fairly
strict: generate-faq.ts runs all four generated answers through the filter,
drops the ones that trip it, and cancels the whole block if fewer than three safe
answers remain. Backward it has never been run — the blocks injected before the
filter existed have not been rescanned once. The class got fixed in my pipeline
and not in my archive.
Let me not read that sentence too generously: the filter arrived on 17 August, and
since then exactly four blocks have been injected (two on 17 August, two on 15
October). Strict going forward, yes — but tested on four blocks so far. The 1,045
in the archive are there today.
And a correction before I fall into my own trap: the sweep was not blind to
this area. The six de-fab commits changed 310 faq lines on the Turkish side. The
detector did look there, and it did clean some answers. What was missing is not
field of view but ownership: the sweep was a one-off job, while the FAQ
generator was a running pipeline. A class cleared on 30 June was being regenerated
by another script in the same repo from 1 July onward. Of 1,419 total faq
injections, 470 happened after the day of the sweep: 368 in July, 100 in
August, the most recent on 15 October 2026.
I end up in the same place as the gate article I published five months ago, with
one difference: there I counted a gate that had never been run over the archive.
Here it turns out that half the archive — the English half — has never been
through any gate at all.
The target itself is gone
I am glad the source got opened for this section, because writing it from memory
would have produced something false.
The FAQ system was built for the "FAQ rich result" that Google used to show in
search results; the commit subject even claims a CTR gain. So, the Google Search
Central changelog. The 8 May 2026 entry, titled "Deprecating the FAQ rich result
feature", says: "This feature will no longer appear in Google Search starting May
7, 2026." The 15 June 2026 entry announces the documentation's removal: "The FAQ
rich result feature is no longer shown in Google Search results, as announced in
the changelog entry in May 2026."
Put the dates side by side. The feature left search on 7 May 2026. The
announcement came on 8 May. The system was committed on 9 May 2026 at 15:40 —
a day after the feature's death was announced, a pipeline went up to win it.
There is more, and it is older: the changelog's 14 September 2023 entry says the
FAQ documentation was updated "to state that the feature is only shown for
well-known, authoritative government and health websites." The rich result had
been limited to recognised government and health sites since 2023. A personal
technical blog was never on that list.
Open the address of that old FAQ structured data page today and it 301-redirects
to its own removal notice.
One distinction should not be skipped: what died is Google's display, not the
markup. FAQPage is still a valid schema.org type and its definition is still
there: "A FAQPage is a WebPage presenting one or more 'Frequently asked
questions'." The JSON-LD on my pages is not broken; only the mechanism that
rewarded it is gone. If I do delete the blocks, what I lose will not be technical
either: the visible accordion and the four answers a reader takes from it
disappear, and nothing breaks.
What is left? 5,218 machine-written question-answer pairs, 1,045 of them in a
voice my own filter rejects, published with no measurable search gain. Google's
spam policy page offers a definition for this kind of production: "Scaled content
abuse is when many pages are generated for the primary purpose of manipulating
search rankings and not helping users", with "Using generative AI tools or other
similar tools to generate many pages without adding value for users" among the
examples. My case does not sit squarely inside that definition — the blocks were
added to existing pages, no new pages were generated, the articles themselves are
original. But the intent side is uncomfortably close: the production was for
ranking.
I will not settle the deletion question in this article. Some answers genuinely
give a reader something — there are answers that tidy up a definition from the
article or put a number back in context. But none of them is a sentence I wrote,
and 1,045 of them narrate, by my own rules, a life that is not mine. The scope
came first, because the mistake four months ago was exactly deciding without
measuring.
Why my corrections never arrive one at a time
Measuring the scope produced one more distribution as a by-product, and frankly it
explains the thesis better than anything else. The script classifies every
post-publication change to Turkish article files. The spread: 3,077 changes are
a sharing flag only, 966 are frontmatter only, 49 are the FAQ block only,
and 950 genuinely touch the body.
Those 950 body changes spread across 630 articles — nearly half the 1,345
Turkish articles in my archive have had their body changed after publication. In
43 commits. Of those 43, 25 touch a single article, which is a majority by count;
but those 25 commits account for only 25 of the 950 changes. The other 925
come from 18 bulk passes: a 180-file de-fab wave, batches of 140 and 135, a
114-file repair of truncated articles, a 110-file third batch, a 97-file cleanup
of internal-link placeholders, a 52-file final batch. The full list is in the
script's output.
So 97.4% of my correction effort comes from bulk passes. What that says is
uncomfortable and, I think, true: I do not catch errors, I catch error classes.
Spotting one wrong thing in one article and going back for it is a three-percent
behaviour. The upside is obvious — a single sweep repairs the bodies of 180
articles. The downside comes from the same mechanism: an error that does not form
a class stays published forever, because the only thing that would have seen it
was a class sweep, and that sweep did not count it as a class.
A methodology note is owed on these figures. My first classifier counted 1,189
body changes; the script in the repo says 950. I can split the gap into three
rules, each of which can be switched off in the script one at a time: turn off the
import line rule and it reads 1,135 — mechanical residue from April's SVG→PNG
cover conversion; turn off the faq line rule too and it reads 1,184; turn off
the blank line rule as well and it reads exactly 1,189. The first version of my
measuring instrument mistook changing a cover format for correcting an article.
One case, on its own
One last measurement, because after numbers this large a single case has something
to say. Of the 681 Turkish articles with a FAQ block, how many have answers that
are not in Turkish? One. Which one? The article published two days ago, the one
that measured my own habit of re-fixing fixes — that one.
The 15 October injection wrote English question-answer pairs into the Turkish file
and refers to me in the third person: "How does the author determine whether a
'fix' commit actually holds…"
It is live right now, under the heading "Sıkça Sorulanlar", in English. A single
case out of 681 hardly counts as a pattern. But I was working in the same repo
both while writing that article and while taking the measurements for this one,
and for two days it went unseen. I have learned to measure my own archive; not yet
to read it.
What happens from here
Four items, all cheap. The list stays short because writing a long one substitutes
for doing the work.
Put the scope of a sweep in the same place as the claim. Where "all 576
articles" went, "455 of 901 Turkish files; 0 English" would have prevented a
four-month-long false memory. A scope sentence is the cheapest and most valuable
line in a commit message.
When you add a gate, run it over the archive once. Building a gate forward is
easy and satisfying: one conditional, and everything after it is clean. Running it
backward is a dull bulk job and nothing reminds you of it. The FAQ filter has
guarded the pipeline for two months and has never scanned the archive once; 1,045
is the size of that gap. Adding a gate should carry the question "how many
published items violate this rule?" as part of the work.
In a bilingual archive, the unit of measurement should be the pair rather than
the file. Every claim exists in two copies. Any sweep that measures in one
language skips half of them by definition.
When wiring up automation, verify the target still exists. The cost is one
document read. Beyond fabrication, that is what the FAQ pipeline taught me: five
minutes of checking a source could have made five months of production
unnecessary.
One more thing I noticed while writing: those 474 numbers are still live as you
read this sentence. Ending this article without a date would repeat the mistake of
four months ago — the English archive goes through the filter next, and the result
gets written up separately.
Conclusion
The real output of a cleanup job is not the cleaned files but the definition:
which class, where, under which rule. The files are already sitting in git
history; the definition, if unwritten, evaporates and the most optimistic sentence
takes its place. In my case: "complete".
Earlier I counted my own fix commits and
measured
which of them failed to hold; that measurement lived inside the code and
deliberately excluded the src/content/ directory. The link rot in published
articles got its own count
as well. This third measurement sits in the gap between the two: my code had been
audited and my articles had been audited, but the scope of the audit had not.
The most confident word in a cleanup report is usually the least audited one. If
you write "complete" without writing beside it what stayed outside, the only thing
that will remind you four months later is measuring your own archive again.
Top comments (0)