10 interesting stories served every morning and every evening.

Don't be a meat proxy

gruhn.me

Aug 03, 2026

Too of­ten I ask a ques­tion in Slack or leave feed­back un­der a merge/​pull re­quest or ar­gue with friends in a WhatsApp group and get back:

Claude said: [giant re­sponse ver­ba­tim]

Please don’t do this. I mean, I’ve done this. But I’ve been on the re­ceiv­ing end too many times now. This is not adding value. I can talk to Claude my­self. It’s go­ing to be faster and I get to con­trol the con­text. I don’t need a meat proxy in be­tween.

Reading AI out­put is ex­tra ef­fort. It’s ver­bose, fre­quently con­tains all too plau­si­ble non­sense, and is in­creas­ingly jar­gon dense. I re­cently got this sen­tence from Claude:

NATS con­trol-plane events: stream leader elec­tion / R3 quo­rum re-form dur­ing pod churn.

Jesus. I had to lookup al­most every word to make sense of this.

By all means, prompt AI. But don’t just re­lay the out­put. Read it, un­der­stand it, val­i­date it, and then write a re­sponse in your own words (a de­cent cer­tifi­cate that you’ve done the prior steps). Making that ef­fort is value you can add.

Take code re­view in par­tic­u­lar. Shipping some code can be done with close to zero ef­fort now: Copy/paste the ticket de­scrip­tion into Claude Code. Don’t look at the code or read what Claude has writ­ten. If there’s any feed­back from re­view­ers, copy/​paste that into Claude Code as well. If nec­es­sary, it­er­ate.

That works. But who has done the im­ple­men­ta­tion? The re­view­ers did, us­ing Claude Code, and you as a meat proxy.

Qwen Studio

qwen.ai

SQLite Critical CVEs or LLM Slop? | JFrog

research.jfrog.com

Over the past few days, a newly cre­ated GitHub repo (programmervuln/cveadvisory-) pub­lished a batch of SQLite vul­ner­a­bil­ity ad­vi­sories (as part of other 50+ CVEs which we be­lieve are also LLM slop ex­cept from one). NVD quickly flagged these as crit­i­cal, and CISAs ADP agreed. But when JFrog se­cu­rity re­searchers dug in to ver­ify, the claims fell apart:

The cited code did­n’t even ex­ist in those ver­sions or ref­er­enced un­re­lated logic.

When test­ing the PoC pay­loads they did­n’t work (not trig­ger­ing any crash).

None of these CVEs are listed on SQLite’s of­fi­cial ad­vi­sory page (which is a gold stan­dard for track­ing ac­tual vul­ner­a­bil­i­ties).

All ad­vi­sories in this repo seem AI gen­er­ated when test­ing them with Gptzero

Combining all ad­vi­sories into one file trig­gers AI-generated con­tent warn­ings

This made us ques­tion the re­li­a­bil­ity of these CVEs as well as un­der­stand­ing that these CVEs may be LLM slop.

While in­ves­ti­gat­ing one of the CVEs yes­ter­day, CVE-2026 – 51302, we saw that Red Hat ini­tially as­signed it a 10.0 Critical sever­ity score:

Looking at the CVE again to­day, we no­ticed that the score has since been down­graded to 7.6 High.

To ver­ify these re­ports thor­oughly, we es­tab­lished an iso­lated test­ing work­flow:

Source Inspection: We cloned the of­fi­cial sqlite/​sqlite repos­i­tory and checked out the tar­get tags (version-3.41.0, ver­sion-3.51.2, and ver­sion-3.51.3). We com­pared the re­ported vul­ner­a­bil­ity me­chan­ics against the ac­tual source code.

Clean Environment Build: Compiled the of­fi­cial SQLite re­leases di­rectly in­side iso­lated Docker con­tain­ers to pre­vent en­vi­ron­men­tal con­t­a­m­i­na­tion.

PoC Execution: Feed each ad­vi­so­ry’s PoC SQL state­ments ver­ba­tim into the com­piled SQLite bi­na­ries un­der AddressSanitizer (ASan) in­stru­men­ta­tion to de­tect mem­ory bugs.

NVD & Metadata Audit: Evaluated the CPE pat­terns and ad­vi­sory meta­data across NVD and GHSA feeds to cross-check track­ing ac­cu­racy.

Reported Vulnerability: The ad­vi­sory claims a heap use-af­ter-free oc­curs when sqlite3Re­leaseTem­pReg() leaves a dan­gling pointer in regFree1, which is later deref­er­enced by ex­prCom­pute­Operands().

Finding: The pri­mary is­sue here is that ex­prCom­pute­Operands() did­n’t ex­ist in SQLite 3.41. It was added in the mid­dle of 2025 (commits e24f20a, 280559b). Furthermore, the me­chan­ics of sqlite3Re­leaseTem­pReg() do not in­volve heap deal­lo­ca­tion. The func­tion sim­ply re­cy­cles reg­is­ter in­dices into an ar­ray for reuse, mak­ing a UAF im­pos­si­ble by de­sign.

/* expr.c:6562, SQLite 3.41.0 */ void sqlite3Re­leaseTem­pReg(Parse *pParse, int iReg){ if( iReg ){ sqlite3Vd­beRe­leaseReg­is­ters(pParse, iReg, 1, 0, 0); if( pParse->nTem­pReg < ArraySize(pParse->aTempReg) ){ pParse->aTem­pReg[pParse->nTem­pReg++] = iReg; } } }

PoC Testing: The query ran suc­cess­fully with­out trig­ger­ing a crash be­cause the bug does not ex­ist.

Reported Vulnerability: Claims that ExprListDelete() fails to clear back-ref­er­ences in par­ent struc­tures when re­leas­ing child nodes, al­legedly patched in ver­sion 3.51.3.

Finding: There is no ev­i­dence of back-ref­er­ence point­ers in the Expr, Select, or Window struc­tures that could lead to such a state. Most tellingly, a diff be­tween 3.51.2 and 3.51.3 shows ab­solutely no changes to src/​expr.c. The patch” was en­tirely fab­ri­cated.

PoC Testing: The PoC is in­valid SQL and fails at the parser stage, never ac­tu­ally hit­ting the ex­e­cu­tion logic.

Reported Vulnerability: Claims a UAF oc­curs in sqlite3­Ex­prDelete() be­cause a left-hand ex­pres­sion pointer is not cleared, ref­er­enc­ing spe­cific line num­bers in expr.c.

Finding: The cited line num­bers (1012 and 1026) are a com­ment and a mem­ory al­lo­ca­tion call re­spec­tively, nei­ther has any­thing to do with pLeft or dele­tion logic. While the func­tion is called dur­ing OOM er­ror han­dling, it oc­curs at the end of a scope where the pointer is never reused, pre­vent­ing any po­ten­tial UAF.

/* expr.c:1330, SQLite 3.41.0 */ void sqlite3­Ex­prDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3­Ex­prDeleteNN(db, p); }

PoC Testing: Executed suc­cess­fully as a valid SQL query, re­turn­ing ex­pected out­put with zero mem­ory leaks or er­rors.

Reported Vulnerability: Claims json­Parse­Free() leaves dan­gling ref­er­ences that are later ac­cessed by json­BlobE­dit().

Finding: Similar to the first case, json­BlobE­dit() was not pre­sent in the re­ported tar­get ver­sion (3.41.0). It was only in­tro­duced later as part of the JSONB im­ple­men­ta­tion. In the tar­get ver­sion, json­Parse­Free() is used strictly in de­struc­tors where the sur­round­ing struc­ture is im­me­di­ately dis­carded.

PoC Testing: The PoC hits a mal­formed JSON er­ror im­me­di­ately, mean­ing the code never reaches the JSON mod­i­fi­ca­tion logic where the vul­ner­a­bil­ity sup­pos­edly ex­ists.

Reported Vulnerability: Reports a UAF in json­Re­move­Func specif­i­cally at lines 3555 and 3575 of json.c.

Finding: In ver­sion 3.41.0, src/​json.c is only 2706 lines long. The cited line num­bers don’t ex­ist. The ac­tual im­ple­men­ta­tion of the func­tion was found roughly 2000 lines ear­lier, and an au­dit of that code showed no mem­ory man­age­ment flaws.

PoC Testing: The pay­load fails dur­ing JSON pars­ing, leav­ing the mem­ory un­touched.

Reported Vulnerability: Claims sqlite3­Ex­prList­Delete(pOrderBy) frees the or­der­ing list while sub­se­quent code reads pOrderBy->nExpr.

Finding: The sin­gle-ar­gu­ment sig­na­ture re­ported in the ad­vi­sory does not ex­ist. the ac­tual sig­na­ture re­quires a pointer to the data­base con­text (sqlite3 *db). Furthermore, SQLite ex­plic­itly nulls point­ers im­me­di­ately af­ter dele­tion:

/* se­lect.c:3761, SQLite 3.41.0 */ sqlite3­Ex­prList­Delete(db, pPrior->pOrderBy); pPrior->pOrderBy = 0; /* Pointer im­me­di­ately cleared; im­pos­si­ble to deref­er­ence */

PoC Testing: The PoC pay­load ex­e­cuted against a 20-column ORDER BY query processed nor­mally, re­turn­ing sorted re­sults with no is­sues.

The CVE sub­mis­sion process via MITREs pub­lic form lacks any real iden­tity ver­i­fi­ca­tion, mean­ing vir­tu­ally any­one can sub­mit a vul­ner­a­bil­ity de­scrip­tion and pro­pose a CVSS score.

Historically, NIST acted as a re­li­able safety net for this sys­tem, ex­perts at the National Vulnerability Database (NVD) man­u­ally an­a­lyzed, val­i­dated, and en­riched in­com­ing CVEs be­fore giv­ing them a stamp of ap­proval. But that safety net broke in February 2024.

Hit by a mas­sive surge in vul­ner­a­bil­ity re­ports, NIST ef­fec­tively hit pause on deep analy­sis. CISA and other Authorized Data Publishers (ADPs) tried to step in with their own en­rich­ment ef­forts, but the global pipeline is now frag­mented and drown­ing in a mas­sive back­log. Because no step in to­day’s sys­tem ac­tu­ally re­quires a proof-of-con­cept or bug re­pro­duc­tion, a plau­si­ble-sound­ing fake ad­vi­sory can slide right through the pipeline and end up in GHSA, down­stream data­bases, and en­ter­prise scan­ners.

This in­ci­dent demon­strates a sys­temic is­sue with au­to­mated vul­ner­a­bil­ity in­ges­tion. A broader au­dit of 55 ad­vi­sories pub­lished by the same GitHub ac­count re­vealed that 54 were com­pletely fab­ri­cated, while one con­tained a real bug wrapped in un­ver­i­fied CVE meta­data.

Red Flags to Spot Slop CVEs:

Missing Vendor Corroboration: No men­tion of the is­sue on of­fi­cial main­tainer se­cu­rity pages (e.g., sqlite.org/​cves.html).

Absent Commit History: No com­mit hash or pull re­quest linked in ref­er­ence fields.

Metadata Contradictions: Empty CPE prod­uct de­f­i­n­i­tions or ver­sion ranges that con­flict with the ad­vi­sory nar­ra­tive.

Non-existent Code References: Citing func­tions that do not ex­ist in the claimed tar­get ver­sion or line num­bers past EOF.

These LLM slop CVEs can cause or­ga­ni­za­tions to waste time in­ves­ti­gat­ing and patch­ing vul­ner­a­bil­i­ties that do not ac­tu­ally ex­ist, as well as pol­lut­ing vul­ner­a­bil­ity data­bases. In en­vi­ron­ments where Critical vul­ner­a­bil­i­ties are au­to­mat­i­cally pri­or­i­tized or tick­ets are opened based on vul­ner­a­bil­ity scores, such fab­ri­cated CVEs can turn into a real bur­den.

In en­vi­ron­ments where AI is used to au­to­mate vul­ner­a­bil­ity triage and re­me­di­a­tion this be­comes even more con­cern­ing. An AI agent that en­coun­ters a fab­ri­cated CVE may at­tempt to lo­cate the vul­ner­a­ble func­tion, gen­er­ate a patch, or rec­om­mend changes based on code that does not even ex­ist. Instead of help­ing se­cu­rity teams re­me­di­ate real vul­ner­a­bil­i­ties, it can lead them down a com­pletely wrong path, po­ten­tially in­tro­duc­ing un­nec­es­sary changes and wast­ing time.

To avoid be­ing af­fected by this kind of vul­ner­a­bil­ity noise:

Don’t blindly trust newly pub­lished CVEs by un­known/​un­val­i­dated sources.

Investigate such crit­i­cal CVEs to un­der­stand whether the score matches the vul­ner­a­bil­ity.

Check if your en­vi­ron­ment is truly af­fected by the CVE.

Reproduce the re­ported is­sue with the pro­vided PoC when­ever pos­si­ble in a safe en­vi­ron­ment.

We have also for­mally re­ported these find­ings to GHSA, Redhat and NVD to as­sist in the re­me­di­a­tion of these records.

More German than many Germans

mertbulan.com

In 2017, af­ter I fin­ished the third year of my Computer Science stud­ies, I de­cided to do an in­tern­ship in Europe. So while I was ap­ply­ing for the Erasmus Scholarship, I also started look­ing for in­tern­ships. In the end I got the schol­ar­ship, which helped a lot with the visa process, and I also found an in­tern­ship at a com­pany in Hamburg.

I had never been out­side of Turkey be­fore. So I had also never re­ally talked to peo­ple from other coun­tries. What I knew about Germans came mostly from the Turkish peo­ple who moved to Germany in the 60s for work. Those peo­ple came back to Turkey al­most every sum­mer and told us about their life there. Most of what they said was the same as what you can read on the in­ter­net, the stereo­typ­i­cal German.

People who don’t laugh, who are cold and un­friendly, who al­ways fol­low the rules, who speak a lan­guage that sounds too harsh, and so on. And of course, some­one al­ways brings up the Nazis.

Apart from the peo­ple I talked to in the in­ter­views, my first real con­tact was my German flat­mate. Before I ar­rived he showed me the room on Skype and we agreed on it. When I landed in Hamburg, he picked me up from the air­port. That was a great start, and dur­ing my three months there we chat­ted in the kitchen al­most every evening for half an hour.

I had a lot of ques­tions for him and he al­ways an­swered them prop­erly. On the week­ends he picked up his girl­friend and they ei­ther stayed home or went row­ing. Their re­la­tion­ship looked very healthy to me. She was study­ing med­i­cine, so some­times she was work­ing at her desk on a Saturday while my flat­mate played Witcher 3 right next to her. I never heard them ar­gue about any­thing.

Near the end of my in­tern­ship he told me that he and his girl­friend were go­ing to Africa, so I would be alone in the flat for a week. When I asked him what I should do with the keys, he just said to drop them in the mail­box. That much trust af­ter such a short time re­ally sur­prised me.

We had a last din­ner to­gether and I told him things were go­ing well at the com­pany and there was a chance I could come back to Hamburg.

I was lucky with my flat­mate and I was also lucky at work. I had a great team. They taught me new things, gave me re­spon­si­bil­i­ties the other sum­mer in­terns did­n’t get, and in­cluded me in all the team events. The off­site we had out­side the city is some­thing I still re­mem­ber to­day. And I was get­ting all of this while earn­ing min­i­mum wage.

I was re­ally sur­prised by how friendly every­one was. We weren’t just work­ing, we were hav­ing fun. Everything I had heard about Germans un­til that point was gone. It was the best sum­mer of my life.

My lead was happy with my work and of­fered me a job right away. I could work as a free­lancer from Turkey while fin­ish­ing my stud­ies, and if they were happy with my per­for­mance I would get a full-time con­tract. That is what hap­pened.

Coming back

In April 2018 I got my con­tract, even be­fore I fin­ished my stud­ies. The next month some­thing nice hap­pened. My German flat­mate emailed me and asked when I was com­ing back, be­cause he al­ready had a room for me for the sum­mer. The com­pany was go­ing to give me a place to stay, but I could­n’t say no to him. Right af­ter my last exam, be­fore I even had my diploma, I moved to Hamburg at the end of June and started work­ing full time with the same team, liv­ing with the same flat­mate.

On my first day there were can­dies and bal­loons on my desk. Everybody was happy to see me again. One col­league who knew my in­ter­est in Apple gave me a German flag pin he got at WWDC18. He said he tried to swap it for a Turkish flag but could­n’t man­age it. I was al­ready happy with the gift, be­cause it meant he was think­ing about me while he was in California.

When you start liv­ing in Germany you have to reg­is­ter your ad­dress. When I went to the pub­lic of­fice, the clerk told me I had al­ready lived in Hamburg be­fore. I said I had done a sum­mer in­tern­ship a year ear­lier. He just said: Welcome back!

That was the mo­ment I felt like I was com­ing home, not mov­ing to a new coun­try.

The first years

My first months were mostly about find­ing a flat and fig­ur­ing out how things work here. Since my German was­n’t good enough, my col­leagues came with me to flat view­ings af­ter work. When I had a prob­lem with my elec­tric­ity provider, a col­league came along and did all the talk­ing. When I moved to a dif­fer­ent place a year later, a German col­league rented a van and helped me carry every­thing.

At the time, the com­pany was one of the biggest in­ter­net com­pa­nies here, with around 2.000 peo­ple. Sometimes I saw the C-level in the kitchen get­ting their own cof­fee or even wash­ing their own glasses. They had as­sis­tants, but the as­sis­tants helped with work in­stead of act­ing like ser­vants. We also had a CFO who rode a very old bike to the of­fice.

Whenever we had a team event or an off­site, the or­gan­is­ers made sure they knew every­one’s di­etary needs. Vegan, veg­e­tar­ian, ha­lal, no al­co­hol, al­ler­gies. So every­one would have some­thing to eat and drink.

When I was do­ing a good job, my lead kept telling me to take va­ca­tion in­stead of work­ing more. When I was sick, he told me to stay home un­til I felt bet­ter. I did­n’t even need a doc­tor’s note. It took me a while to no­tice this was not only a work thing. You get on a bus or a train here and no­body checks your ticket. I was­n’t used to this level of trust.

Across from our of­fice there was an Italian restau­rant where we went for pizza some­times. The piz­zas were very tasty and huge, and it was the only place that sold half a pizza. At lunch I saw peo­ple in suits eat­ing there, and right at the next table peo­ple from the con­struc­tion site nearby in their work clothes eat­ing the same pizza. Nobody looked at the other table and no­body thought it was worth notic­ing ex­cept me. That is the part that stayed with me. It was com­pletely nor­mal, and it was nor­mal be­cause a man who spent his morn­ing on a build­ing site can af­ford an Italian lunch and eat it like every­one else.

I no­ticed the same thing in the rich dis­tricts of Hamburg. You can walk into one and not feel like you don’t be­long, and the prices in the shops are not that dif­fer­ent from any­where else in the city. Sometimes they are ex­actly the same. The more I saw of that, the more I wanted to stay. I be­lieve in so­cial democ­racy, and this is a coun­try that calls it­self one and mostly be­haves like it.

It did­n’t take long for me to move up at work. I did­n’t feel any dis­crim­i­na­tion, even though peo­ple say Germans pre­fer Germans when it comes to pro­mo­tions. There were al­ready a lot of peo­ple with a mi­gra­tion back­ground at the top. When I ran as a can­di­date in the works coun­cil elec­tion, I got the most votes of any­one, even though there were many Germans run­ning and only around 25% of the com­pany were im­mi­grants like me.

You see the same thing out­side of com­pa­nies. Cem Özdemir, whose par­ents came from Turkey, has been the prime min­is­ter of Baden-Württemberg since May. Sinan Selen, who was born in Istanbul, runs the of­fice for the pro­tec­tion of the con­sti­tu­tion.

Being in the works coun­cil gave me more con­tact with the C-level. Sometimes I found my­self ar­gu­ing with the CTO or the CEO, and later at a com­pany party we would have a beer to­gether and talk about some­thing else. That is when I un­der­stood how flat the man­age­ment is here. I saw the dif­fer­ence later when I worked for an American com­pany, where they made sure you knew you were lower on the lad­der.

I met hun­dreds of Germans at that com­pany and they were al­ways su­per friendly. I say this be­cause years later I still see many of my old col­leagues at dif­fer­ent events, and most of my friends to­day are peo­ple I used to work with. A lot of im­mi­grants com­plain that it is hard to be­come friends with Germans, but that was­n’t my ex­pe­ri­ence.

My land­ing was soft

I should be hon­est about one thing here. I landed softly. I came into a big in­ter­na­tional com­pany where every­one spoke English, in a city like Hamburg, with a salary that let me pick where I live. I have worked with other German com­pa­nies since then, mostly smaller ones, so what I write here is not only about that one place. But the start was much eas­ier for me than it is for most peo­ple. A lot of them ar­rive with none of that, and the coun­try they meet is not the same one I met. Everything I write here is my ex­pe­ri­ence, not a re­port on how it works for every­one.

The lan­guage is part of that. Every story I told above hap­pened in English. The team, the flat­mate, the works coun­cil, the ar­gu­ments with the CEO, all of it. Once I de­cided I was go­ing to stay here for a long time, I started tak­ing German classes, and af­ter the cit­i­zen­ship law changed I put much more ef­fort into it. So the German came from the de­ci­sion to stay. It was not the thing that made me stay.

I never re­ally tried to in­te­grate. It just hap­pened that the way I think about life turned out to be sim­i­lar to how peo­ple here think.

Why I like the rules

Most peo­ple com­plain about the rules in Germany, but I like them. It means some­one, or a group of peo­ple, sat down and thought about that spe­cific thing and de­cided on a stan­dard for every­one. When you have to do some­thing, you don’t feel lost, be­cause you can just look it up. You don’t have to find some­one who knows.

Rules also make nor­mal days eas­ier. Something sim­ple like wait­ing at a red light even when there are no cars takes away the work of de­cid­ing whether to cross. And if every­one does it, you don’t have to worry about some­one sud­denly step­ping into the street. Or the fire safety rule that makes exit doors in pub­lic build­ings open out­wards. You never have to think about pull or push.

There are also un­writ­ten rules, like be­ing on time. For me the log­i­cal thing has al­ways been to aim for 15 min­utes be­fore the agreed time, so if some­thing hap­pens on the way I’m still fine. After go­ing on dates with a lot of Germans, I re­alised they do the same thing. So in­stead of me ar­riv­ing early and wait­ing 15 min­utes, we just meet 15 min­utes ear­lier.

My favourite one is Ruhezeit, the quiet time be­tween 10PM and 6AM, plus Sundays and pub­lic hol­i­days. My sleep is very im­por­tant to me and I’m a light sleeper, so this rule re­ally helps me. Sometimes I had neigh­bours who had par­ties dur­ing those hours, and I did­n’t hes­i­tate to com­plain (with Lärmprotokoll) to my land­lord. Many Germans have told me I’m more German than many Germans. It is prob­a­bly be­cause of ex­am­ples like this one.

The one time a rule was pointed at me in­stead of work­ing for me was my first ap­pli­ca­tion for per­ma­nent res­i­dence. I had just left my first com­pany and I was be­tween jobs, and that was enough to get it re­jected. That was when I learned what a sus­tain­able liveli­hood means to the German au­thor­i­ties. It does­n’t mean the money you have in your ac­count. It means a per­ma­nent con­tract with the pro­ba­tion time al­ready be­hind you. I had sav­ings and it did­n’t count for any­thing.

It was an emo­tional day. But af­ter I calmed down I could see their logic. A bank bal­ance can be gone in a year and a signed con­tract that al­ready sur­vived six months says some­thing a num­ber can’t. It was the same sys­tem I like for every other rea­son, just this time I was on the wrong side of it.

Understanding the coun­try

The longer I lived here, the more I saw my­self spend­ing the rest of my life here. That made me want to read about the coun­try. I’m a heavy reader and I track every book, so here are the ones I read about Germany:

German Men Sit Down To Pee & Other Insights Into German Culture

Germany: Memories of a Nation

The German Genius

Kaput: The End of the German Miracle

Man’s Search for Meaning

Blood and Iron: The Rise and Fall of the German Empire 1871 to 1918

Why the Germans Do it Better: Notes from a Grown-Up Country

Apart from the books, I also watched a lot of doc­u­men­taries, es­pe­cially about the Nazi era.

Like most peo­ple, I did­n’t know that Germany was­n’t one coun­try un­til the 19th cen­tury. It was made of small king­doms, city states and so on. That is why there are so many kinds of bread, beer and sausage, why some parts have dif­fer­ent pub­lic hol­i­days, dif­fer­ent ac­cents and even a dif­fer­ent way of liv­ing.

The German Genius sur­prised me the most. It is about 1.000 pages about Germans who con­tributed to hu­man­ity in dif­fer­ent fields, and I did­n’t know how many things in our daily life ex­ist thanks to them. Some of them had to es­cape the coun­try be­cause of the Nazis and reached their full po­ten­tial some­where else, in coun­tries like the US and the UK. The books also helped me un­der­stand how Germany built an ed­u­cated mid­dle class, how work­ers’ rights and so­cial re­forms hap­pened, and where the rule about no shop­ping on Sundays comes from.

What stayed with me is that this is prob­a­bly the only coun­try in the west­ern world that faced its own his­tory prop­erly, ad­mit­ted the worst things it did, and built a lot of its iden­tity around not re­peat­ing them. You feel that here in small ways, not only in mu­se­ums. In January 2024, af­ter it came out that far right politi­cians had talked about de­port­ing peo­ple who al­ready hold a German pass­port, 50.000 to 80.000 peo­ple filled the streets of my city in one af­ter­noon.

In eight years I have not had a sin­gle case of racism. I know that is­n’t true for every­one, and I know the far right keeps grow­ing.

I don’t think most of those votes are about hat­ing for­eign­ers. Some peo­ple be­lieve the story they get every day, that the coun­try is bro­ken and that im­mi­grants are the prob­lem. You find that story al­most every­where. The rest are an­gry that cer­tain prob­lems here have not been solved for years by the ex­ist­ing par­ties, so they look for an al­ter­na­tive.

For me, Germans are peo­ple who give trust be­fore it is earned. People who are friendly with­out be­ing fake about it. People who make sure every­one is in­cluded, down to what is on the table. People who care about some­one they will never meet. People who know ex­actly what hap­pened here and don’t look away from it.

Making it of­fi­cial

That is why I de­cided to be­come one of them.

The chance came when the traf­fic light coali­tion, which I think was the most pro­gres­sive gov­ern­ment this coun­try has had in decades, changed the cit­i­zen­ship rules and brought the wait­ing time down to five years. I was el­i­gi­ble, so I ap­plied.

People seem to think a German pass­port is handed out eas­ily now. It is­n’t. You have to prove you paid into the so­cial sys­tem for at least five years. You have to pass the cit­i­zen­ship test. You need German at B1 level. You need a sus­tain­able liveli­hood while your ap­pli­ca­tion is run­ning. And most im­por­tantly, you have to ac­cept the de­mo­c­ra­tic val­ues of this coun­try.

For me the process it­self was smooth. I ap­plied on­line by up­load­ing a pile of PDFs. A week later I got a let­ter say­ing my ap­pli­ca­tion had ar­rived, with a few pa­pers to sign, scan and up­load back. Then the wait­ing started. In to­tal it took around 14 months to get the email say­ing my ap­pli­ca­tion was suc­cess­ful and that I could come and col­lect my Einbürgerungsurkunde.

I picked it up this week, at an ap­point­ment that only took 15 min­utes. I am German now.

I be­lieve I have con­tributed some­thing to this so­ci­ety in these eight years and I will keep do­ing it. And I will keep com­plain­ing about every­thing that needs to be bet­ter. Because that is what real Germans do.

Subscribe to my newslet­ter

No spam, no shar­ing to third party. Only you and me.

Devtools must be open source

blog.exe.dev

Five years ago, most soft­ware en­gi­neers I spoke to had no pro­grams they had writ­ten for them­selves. (I was ask­ing this ques­tion a lot as part of try­ing to un­der­stand how Tailscale could fit into en­gi­neers’ lives.) All day, every day, en­gi­neers use pro­grams writ­ten by oth­ers to write pro­grams for oth­ers. Many of us cus­tomized the pro­grams we used, through con­fig files or plu­g­ins or ex­ten­sions, and many of us used the pro­grams we wrote for oth­ers, as users. It was al­ways an un­usual treat to ask some­one what they had writ­ten for them­selves and learn about the be­spoke soft­ware be­hind their blog, or their home au­toma­tion, or their home­lab, in­stead of an off-the-shelf, al­most-the-right-size sta­tic site gen­er­a­tor or Zigbee ap­pli­ance.

This state of things made a lot of sense to me. Over the years I have writ­ten plenty of soft­ware for my­self, and the re­turn on do­ing so was al­ways ques­tion­able. I could only write so much in a day. There were al­ways more im­por­tant things to do (Something Was Wrong At Work), and com­ing back to a pro­ject af­ter a year to do main­te­nance on it was al­ways ex­tra­or­di­nar­ily painful. There were plenty of years in my ca­reer where I had thrown out all my cus­tom soft­ware and used the most bog-stan­dard en­vi­ron­ments I could to pro­duce code. In my early years as an en­gi­neer at Google I did not even own a per­sonal com­puter.

That was then. Things are dif­fer­ent now.

How to Personalize Software

It is as­ton­ish­ingly easy to per­son­al­ize soft­ware to­day. There are two gen­eral cat­e­gories of prompts to an agent that make all of this pos­si­ble:

Download the source for <software> and build it for lo­cal use. Modify <whatever mem­ory your agent uses> to know that any fu­ture changes to this soft­ware mean chang­ing the sources and re­plac­ing the cur­rent ver­sion. Record in ver­sion con­trol the orig­i­nal mo­ti­va­tion be­hind the change.

and, more im­por­tantly:

and, more im­por­tantly:

Set up a nightly cron job that ex­e­cutes the prompt: fetch up­stream changes to the <software> and re­base all lo­cal changes on top of up­stream. Check that the soft­ware works as in­tended and re­place the cur­rent ver­sion.

At the heart of this is the re­al­iza­tion that agents can not only hack up some code for a spe­cific use but also au­to­mat­i­cally man­age the process of syn­chro­niz­ing changes with up­stream re­leases. This means agents change the ROI on cus­tomiz­ing soft­ware on two fronts si­mul­ta­ne­ously: it is much eas­ier to get started per­son­al­iz­ing, and much eas­ier to keep go­ing.

Another as­ton­ish­ing thing about the two prompts above for edit­ing soft­ware is that you can build them right into an agent. As long as the agent is open source, it does not even re­quire pro­gram­ming. The two prompts can be loaded into a skill (i.e., some text in­struc­tions) put some­where dis­cov­er­able to the agent. We built this into Shelley, so now if you want to edit Shelley you don’t even need the pre­am­ble or to con­fig­ure the timer. It takes care of it for you. You can type in a prompt like make Shelley’s UI high-con­trast” and you have per­son­al­ized your agent.

A Worked Personalization Example: Shelley and Meat

I have a per­sonal pro­ject I have been idly toy­ing with for the last month: meat.dev. The prin­ci­ple is that while agents write code, I still read it be­fore push­ing to our se­ri­ous sys­tems. As the un­der­ly­ing mod­els im­prove, what I look for has changed. The hu­mans I have spent twenty years re­view­ing code for have al­ways strug­gled with edge cases: do the er­rors re­port use­ful in­for­ma­tion; are nil-checks han­dled, etc. (We all do it; when writ­ing code, I am one of the worst of­fend­ers.) One of my roles as a re­viewer was look­ing for these de­tails. Over the past six months, I have dis­cov­ered I don’t need to read for edge cases like that any more: mod­els are far more dili­gent than hu­mans at rote cor­rect­ness. Their er­rors are iso­lated to ar­chi­tec­ture, un­ex­pected use cases, vi­sual out­put their test en­vi­ron­ment is not feed­ing back to them, etc. This means most of the lines of code I re­view are not very use­ful. So I wrote a tool that takes diffs and uses LLMs to strip out the unim­por­tant stuff. I al­most never need to see the im­port blocks, or the nil-checks, or the er­ror han­dling any more, so get it off the screen so I can fo­cus on the meat.

I like this tool, but it has two down­sides: first, I like to read my diffs in Shelley with a good UI, not in a ter­mi­nal. Second, it takes a cou­ple of min­utes for an LLM to di­gest and min­i­mize a diff, and I don’t want to wait. So ide­ally I would not run meat on the com­mand line, but have it built into Shelley and have it pre-pro­cess­ing com­mits the mo­ment they are cre­ated. It turns out I can do that with a sin­gle prompt:

Please build meat.dev into Shelley. Install the lat­est ver­sion in the PATH. When a git com­mit is cre­ated by Shelley, start meat pro­cess­ing in the back­ground on the com­mit. Add a tog­gle to the Shelley Diffs view for meat. If the com­mit is still be­ing processed, so the user it is in process.

Please build meat.dev into Shelley. Install the lat­est ver­sion in the PATH. When a git com­mit is cre­ated by Shelley, start meat pro­cess­ing in the back­ground on the com­mit. Add a tog­gle to the Shelley Diffs view for meat. If the com­mit is still be­ing processed, so the user it is in process.

This sin­gle prompt was all it took not just to add meat to Shelley, but to ap­pro­pri­ately pre-process com­mits in the back­ground be­fore I came back to ses­sion to re­view the diff, sav­ing me wait­ing for a model to re­duce the diff. The only un­for­tu­nate choice the model made was us­ing the 🥩 emoji for the tog­gle but­ton.

Imagine the con­vo­luted mis­ery it would be try­ing to plug that into the VS Code ex­ten­sions API! Or try­ing to get it into vimd­iff. It would cer­tainly be pos­si­ble, but the ma­chin­ery to start pre-pro­cess­ing the com­mits as soon as they ap­pear would be nigh-on im­pos­si­ble. I would be bet­ter off im­ple­ment­ing an out-of-band meatd that lis­tened to the file sys­tem and pro­vided a cache for the meat tool that a cus­tomiza­tion API could use, be­cause the points of ex­ten­sion and con­fig­u­ra­tion would not be the right shape.

And that is the fun­da­men­tal dif­fer­ence be­tween clas­sic con­fig­u­ra­tion/​cus­tomiza­tion and agent-dri­ven per­son­al­iza­tion: you can do so much more. The agent will do the hard work of un­der­stand­ing the source and chang­ing it to suit the par­tic­u­lar task you have in mind. The soft­ware we live with is far more pow­er­ful with per­son­al­iza­tion. All you need is the source code.

The Age of Personalized Software

The pre-agent de­vel­op­ment costs meant it was ra­tio­nal for com­plex soft­ware to ship with large con­fig­u­ra­tion files, ex­ten­sion sys­tems, and plu­gin sys­tems. The core code of even a mod­er­ate pro­ject like Vim is huge and baroque, and takes weeks for a hu­man to di­gest. The thought that, on want­ing line num­bers to print by de­fault, an en­gi­neer would learn the code base and add it just for them­selves is un­rea­son­able. Better to de­sign it for shar­ing with oth­ers, which jus­ti­fies the ex­pense of im­ple­ment­ing it by amor­tiz­ing it over many users. As fea­tures in a code base grow, it makes sense to look for com­mon ab­strac­tions where you can break out an ex­ten­sion or plu­gin sys­tem.

Now the ex­pense of learn­ing the code and mak­ing a change has dropped dra­mat­i­cally. Agents do the heavy lift­ing. For a sin­gle user—which im­plies ex­tremely con­strained con­di­tions un­der which the pro­gram runs—a top-end agent can usu­ally now add a fea­ture in a sin­gle shot. For sin­gle-user soft­ware, the need for care­ful code re­view can of­ten be re­placed by does it seem to work?”

The re­sult is that soft­ware that can be per­son­al­ized does­n’t need a plu­gin sys­tem or a con­fig file. Want to change the font size in your text ed­i­tor? Give the agent the source and tell it to. If it is a hard­coded value it will find and edit it. If it’s a hard­coded bitmap font it will down­load an­other and re­place it, or it will use Monobit to make you one! You have in­cred­i­ble ca­pa­bil­i­ties on tap.

Whole Categories of Software Products Need to Be Reinvented

Personal soft­ware ap­plies well to small teams too. Why would an en­gi­neer­ing team pur­chase an ex­tremely con­fig­urable task man­ager (or a CMS or CRM), spend time learn­ing and con­fig­ur­ing it, and con­tort their team to its lim­its, when they can as­sem­ble just the fea­tures they want from com­mon build­ing blocks?

Both the up­front fixed costs and the on­go­ing costs of per­son­al­iz­ing soft­ware have dis­ap­peared.

The blog you are read­ing is be­spoke soft­ware, writ­ten in Shelley, be­cause it was eas­ier to piece to­gether and per­son­al­ize li­braries like Tiptap than it is to try and cus­tomize tra­di­tional soft­ware prod­ucts. For end-user prod­ucts to make sense in a com­pany to­day, they need to be per­son­al­iz­able. Which means we need the source code.

Where Codex and Claude Code Diverge

This same skill-based tech­nique that was ap­plied to Shelley to make it per­son­al­iz­able can be triv­ially ap­plied to other open-source agents like Pi. (So much so that I am left won­der­ing why Pi needs an ex­ten­sion sys­tem built into it. The source code is the ex­ten­sion sys­tem.) It would re­quire a lot more to­kens, but you could do the same to Codex, which is an open-source agent.

Where you would hit a wall, how­ever, is Claude Code. It is closed-source soft­ware, so you don’t get to per­son­al­ize it. There are a lot of old-fash­ioned cus­tomiza­tion hooks in Claude Code. Hopefully, how you want an agent to work fits in their hooks. If not, switch to an agent that lets you per­son­al­ize it.

ISOPOLIS — San Francisco

sf.isopolis.city

load­ing…

© OpenStreetMap con­trib­u­tors © CARTO · neigh­bor­hoods: DataSF

Prevent cognitive debt by manually retyping LLM-generated code — Ankur Sethi's Lab Notebook

ankursethi.com

Despite what I said in April, I’m still us­ing cod­ing as­sis­tants on my per­sonal pro­jects.

Using them to one-shot en­tire fea­tures leaves me un­sat­is­fied and dis­ori­ented, but I do en­joy us­ing them to fast-for­ward through the bor­ing parts of my pro­jects.

However, al­low­ing my cod­ing as­sis­tant to roam free in my pro­jects leaves me with a colos­sal amount of cog­ni­tive debt. I might hate the idea of por­ing over the Django doc­u­men­ta­tion to fig­ure out how to add tag­ging to my web­site, but I still fun­da­men­tally want to un­der­stand how it works. Just be­cause a prob­lem is bor­ing does­n’t mean I want to fully of­fload my un­der­stand­ing of the so­lu­tion to a ma­chine.

Of course, I could re­view every sin­gle line of code the LLM pro­duces. That’s what most de­vel­op­ers are ex­pected to do in this cursed year of 2026. Robots raise PRs, hu­mans re­view them. It’s a brave new world.

But I don’t en­joy re­view­ing AI-generated PRs. Poring over hun­dreds of lines of overly-de­fen­sive, badly-com­mented, sub­tly in­cor­rect code is not fun. I might grudg­ingly do it for an em­ployer—while mak­ing sure said em­ployer be­comes an ex-em­ployer as soon as pos­si­ble—but I’m sure as hell not do­ing it for my per­sonal pro­jects. Personal pro­jects must be fun above all else. The joy of work­ing on per­sonal pro­jects comes from the process, not from the out­come.

So what’s a boy to do? How do I of­fload the bor­ing work to LLMs with­out ced­ing con­trol of my own work and cog­ni­tion to the slop ma­chine?

I’ve come up with a so­lu­tion that’s grossly in­ef­fi­cient and per­haps slightly com­i­cal: I ask my cod­ing as­sis­tant to gen­er­ate code in the chat, then man­u­ally make all the ed­its my­self.

I have these in­struc­tions in all the agents files in my per­sonal pro­jects:

I want to un­der­stand every line of code that goes into this pro­ject. Never cre­ate, edit, move, re­name, or delete pro­ject files un­less I ex­plic­itly ask you to do so. Instead, show me every pro­posed edit in the chat so I can type it in man­u­ally.Do not run com­mands that mod­ify pro­ject files, in­stall de­pen­den­cies, or change repos­i­tory state un­less I ex­plic­itly re­quest that ac­tion. Instead, show me those com­mands in the chat so I can run them man­u­ally.I’m an ex­pe­ri­enced de­vel­oper. Do not ex­plain syn­tax, APIs, pro­gram­ming con­cepts, or im­ple­men­ta­tion de­tails un­less ex­plic­itly asked.

I want to un­der­stand every line of code that goes into this pro­ject. Never cre­ate, edit, move, re­name, or delete pro­ject files un­less I ex­plic­itly ask you to do so. Instead, show me every pro­posed edit in the chat so I can type it in man­u­ally.

Do not run com­mands that mod­ify pro­ject files, in­stall de­pen­den­cies, or change repos­i­tory state un­less I ex­plic­itly re­quest that ac­tion. Instead, show me those com­mands in the chat so I can run them man­u­ally.

I’m an ex­pe­ri­enced de­vel­oper. Do not ex­plain syn­tax, APIs, pro­gram­ming con­cepts, or im­ple­men­ta­tion de­tails un­less ex­plic­itly asked.

Using LLMs this way al­lows me to work faster than not us­ing LLMs at all, but I’m still slower than those who are will­ing to al­low the ma­chine to think for them. Instead of be­ing 10x faster, I’m prob­a­bly only 2x faster. But what I lose out on in terms of speed, I gain in terms of a deeper un­der­stand­ing of my code.

As I man­u­ally type every sin­gle line of LLM gen­er­ated code into my ed­i­tor, I build up a men­tal model of how it works and fits into my ex­ist­ing code­base. If I don’t un­der­stand an API or al­go­rithm, I can stop to look it up, or just ask the LLM to ex­plain it.

Typing the code my­self forces me to slow down, which means I’m more likely to de­tect hal­lu­ci­na­tions or bad de­sign choices the LLM might have made. I can clean up the code as I go, re­or­ga­niz­ing it, refac­tor­ing it, adding com­ments, and gen­er­ally adapt­ing it to my own taste.

Most im­por­tantly, this work­flow al­lows me to build a spa­tial map of my code­base. I know where every bit of func­tion­al­ity lives in the code­base. When I need to make a change, I know ex­actly where I need to make it. It not only helps me work faster within my pro­jects, it also makes it eas­ier for me to bet­ter prompt and in­struct the LLM in the fu­ture.

When I was learn­ing to code as a teenager, ex­pe­ri­enced pro­gram­mers would of­ten tell me to never copy and paste code into my pro­jects. If I was learn­ing from a book, I was ad­vised to copy all the ex­am­ples into my com­puter and make sure I could run them. If I was learn­ing from a blog post or fo­rum an­swer, I was ad­vised to type it out and adapt it to my code­base so I un­der­stood it com­pletely.

Manually typ­ing LLM-generated into my code­base feels like the ex­act same learn­ing process. It might not be the most ef­fi­cient way to work with an LLM, but I value com­pre­hen­sion over pro­duc­tiv­ity. I’ve been do­ing this for a few months now, and it’s been work­ing well for me. I plan to con­tinue us­ing this work­flow for as long as I can.

I fear the soft­ware in­dus­try is tak­ing on a large amount of cog­ni­tive debt that we’ll have to pay back very soon. There will come a time when we no longer un­der­stand how large parts of our dig­i­tal in­fra­struc­ture are put to­gether. I might not per­son­ally be able to change the course of the en­tire in­dus­try, but I can at least make sure I com­pletely un­der­stand the soft­ware I put out into the world. Anything else would be pro­fes­sional mal­prac­tice.

Taylor Farms Has Rewritten Its Cyclospora Statement Four Times in Sixteen Days. It Still Has Not Said What Changed at That Plant After 2013, or Why Two Thousand Negative Tests Should Mean Anything.

www.marlerblog.com

A com­pa­ny’s pub­lic state­ment in the mid­dle of an out­break is not mar­ket­ing. It is ev­i­dence — what the com­pany said it knew, and when, pub­lished to the world at a mo­ment when no­body had the ben­e­fit of hind­sight. I have built cases on those state­ments since 1993. I have been read­ing and sav­ing this one since the day the re­call is­sued, and the six­teen days since are worth lay­ing out end to end, be­cause the words have moved a great deal and the sub­stance un­der­neath them has not moved at all.

Start with the orig­i­nal. On July 17 the com­pany posted a state­ment that opened with the peo­ple who got sick — the ill, their fam­i­lies, and Americans whose trust in pro­duce had been shaken. It said that trust took decades to earn. It said the re­moval of prod­uct was based on in­for­ma­tion FDA had pro­vided the day be­fore. And it said some­thing that has not ap­peared in a sin­gle ver­sion since: that FDAs trace­back was point­ing to a spe­cific in­de­pen­dent farm, de­scribed as less than one per­cent of the United States ice­berg sup­ply, as the po­ten­tial source.

The re­call was July 17. FDA re­ported a pos­i­tive test on July 18. FDA re­tracted that re­sult as a false pos­i­tive on July 19. The July 17 state­ment there­fore ex­plains why the com­pany pulled prod­uct at a mo­ment when no pos­i­tive lab­o­ra­tory re­sult ex­isted any­where in the world, and the rea­son it gives is FDAs trace­back and the epi­demi­ol­ogy. That is a party ad­mis­sion, and noth­ing pub­lished af­ter­ward reaches back and un­says it.

Two days later the same ad­dress served a dif­fer­ent doc­u­ment. The July 19 ver­sion led with the as­ser­tion that FDA had apol­o­gized to the com­pany. Sympathy for the sick moved from the first para­graph to the fourth and got shorter. The re­call was re­cast in the com­pleted past tense and at­trib­uted to an abun­dance of cau­tion. The ac­knowl­edg­ment about the spe­cific farm was gone. I wrote that night about how the vic­tims ate the ev­i­dence in May, and I have not changed my view since.

There was no apol­ogy. I went look­ing for one in FDAs July 19 up­date and what is there is a lab­o­ra­tory cor­rec­tion and a no­ti­fi­ca­tion to the firm — and in the same para­graph, a state­ment that FDA con­tin­ues work­ing with the firm to en­sure prod­uct im­pli­cated in this out­break has been re­moved. The word im­pli­cated sur­vived the false pos­i­tive. The next day FDA answered in pub­lic with­out nam­ing any­body: the false-pos­i­tive sam­ple does not change the ba­sis for the in­ves­ti­ga­tion or the over­whelm­ing epi­demi­o­log­i­cal data sup­port­ing the re­call, and trace­back and out­break data con­tinue to con­verge on shred­ded ice­berg let­tuce from Taylor Farms lo­ca­tions in cen­tral Mexico. Note the plural lo­ca­tions. The com­pany had de­scribed one in­de­pen­dent farm at less than one per­cent of sup­ply and then stopped de­scrib­ing it at all.

By July 24 the page had been rewrit­ten again, this time lead­ing with money — more than two hun­dred mil­lion dol­lars a year in in­de­pen­dently au­dited food safety pro­to­cols — and re­port­ing that sourc­ing and cen­tral-Mex­ico pro­duc­tion had been sus­pended since July 18 and in­de­pen­dent ex­perts com­mis­sioned for a top-to-bot­tom re­view. The apol­ogy claim was sim­ply ab­sent. No cor­rec­tion, no note, no ac­knowl­edg­ment it had ever been there.

On July 30 the com­pany built some­thing new, a Cy­clospora in­for­ma­tion hub at its own ad­dress, and the old news­room link now redi­rects there. It was re­vised again on July 31, and that re­vi­sion cre­ated a prob­lem. The FAQ list of states that re­ceived re­called prod­uct now runs to twenty-eight and in­cludes West Virginia, which FDA added a week ear­lier. The dis­tri­b­u­tion para­graph higher up the same page still lists twenty-seven and still leaves West Virginia out. West Virginia is one of the nine states in the fed­eral out­break.

Now. All of that is about words, and I have spent enough of this out­break on words. Here is the sub­stance the words have never touched, in six­teen days and five ver­sions.

This is not the first time, and the record of it is long. In the sum­mer of 2013, cy­clospo­ri­a­sis sick­ened 631 peo­ple across twenty-five states. Iowa and Nebraska ac­counted for 239 of them, and epi­demi­o­logic and trace­back work by those two states, CDC and FDA tied their restau­rant cases to bagged salad mix pro­duced by Taylor Farms de Mexico in Doctor Mora, Guanajuato, and served at Olive Garden and Red Lobster. I want to be ex­act here, be­cause the num­ber gets mis­used: the Texas cases that sum­mer were tied to cilantro from an un­re­lated pro­ducer, and the cause of more than a hun­dred other ill­nesses was never de­ter­mined. The salad mix link is to Iowa and Nebraska.

FDA then pub­lished an en­vi­ron­men­tal as­sess­ment of the pro­cess­ing plant and five ranches. Investigators an­a­lyzed roughly 835 prod­uct, wa­ter and en­vi­ron­men­tal sam­ples, in­clud­ing more than 269 hu­man fe­cal sam­ples col­lected from san­i­tary fa­cil­i­ties on the ranches, and re­cov­ered the par­a­site from none of them — the as­sess­ment be­gan five weeks af­ter the last known ill­ness. What sur­vives from that doc­u­ment is its sec­ond rec­om­men­da­tion, which told the firm to de­ter­mine whether Cy­clospora is a rea­son­ably likely food safety haz­ard as­so­ci­ated with the Guanajuato leafy green grow­ing re­gion, and if it is, to re-eval­u­ate the wash step. That was November 2013.

There is one more piece of the 2013 record, and it goes di­rectly to the test­ing ques­tion. The com­pany sus­pended ship­ments to the United States on August 9, 2013, and re­sumed them on August 25 with FDAs con­cur­rence. FDA said at the time that its de­ci­sion rested in part on the en­vi­ron­men­tal as­sess­ment and in part on its re­view of a prod­uct sam­pling plan for Cyclospora that Taylor Farms de Mexico had put in place. A sam­pling plan for this par­a­site, re­viewed by a fed­eral agency, as part of the price of re­open­ing a plant — thir­teen years ago. I have gone look­ing for a sin­gle pub­lished re­sult from it and I have not found one.

Reasonably likely haz­ard is not ca­sual lan­guage. It is the vo­cab­u­lary of haz­ard analy­sis, and the com­pa­ny’s own hub says its pro­cess­ing fa­cil­i­ties op­er­ate un­der the FSMA pre­ven­tive con­trols rule — un­der which a haz­ard re­quir­ing a pre­ven­tive con­trol brings mon­i­tor­ing, ver­i­fi­ca­tion and records along with it. Meanwhile FDA’s own fact sheet for farm­ers car­ries a foot­note list­ing where cy­clospo­ri­a­sis is en­demic: Bangladesh, Brazil, Chile, China, Cuba, Dominican Republic, Egypt, Guatemala, Haiti, India, Indonesia, Jordan, Mexico, Morocco, Nepal, Nigeria, Pakistan, Peru, Puerto Rico, Romania, Saudi Arabia, Tanzania, Thailand, Turkey, Venezuela, Viet Nam and Zimbabwe. Mexico is on that list and has been for years.

The ques­tion, then, is not why you did not test. The ques­tion is what your haz­ard analy­sis says about this par­a­site. If you iden­ti­fied it as a rea­son­ably likely haz­ard, pro­duce the pre­ven­tive con­trol, the ver­i­fi­ca­tion ac­tiv­ity and the records. If you con­cluded it was not a rea­son­ably likely haz­ard, ex­plain the ba­sis for that con­clu­sion — thir­teen years af­ter a fed­eral agency told you to make the de­ter­mi­na­tion, in a coun­try that same agency lists as en­demic, at the same plant, grow­ing a ready-to-eat prod­uct with no kill step. I can­not con­struct an an­swer that sur­vives both ver­sions of the ques­tion.

The same fact sheet tells farm­ers to as­sess wa­ter sys­tems and ad­ja­cent land for sources of con­t­a­m­i­na­tion, and it names sewage and sep­tic sys­tems and land ap­pli­ca­tion of waste­water. The hub lists ad­ja­cent land re­view as part of the com­pa­ny’s ranch in­spec­tions. Good. There is a pub­lic swim­ming re­sort roughly eight hun­dred feet from the Doctor Mora plant, and satel­lite im­agery shows it op­er­at­ing there years be­fore the 2013 as­sess­ment was writ­ten. What did the ad­ja­cent land re­view record about it?

Which brings me to the test­ing, and to the num­ber the com­pany has put at the cen­ter of its de­fense. The hub says that as of July 24 FDA had no con­firmed pos­i­tive prod­uct test re­sults, and that the com­pa­ny’s own test­ing — ap­prox­i­mately two thou­sand sam­ples taken in cen­tral Mexico since May — re­turned zero pos­i­tives. I want to be pre­cise about what that does and does not show, and I want to be fair about what the com­pany ac­tu­ally claims.

On wa­ter, the com­pany de­scribes its own pro­gram in seven words: wa­ter sources are tested for in­di­ca­tor or­gan­isms. FDAs fact sheet says that tra­di­tional mi­cro­bial test­ing, mean­ing fe­cal in­di­ca­tors like generic E. co­l­ior fe­cal co­l­iforms, will not iden­tify the pres­ence of this par­a­site. FDA also says — and I will give the agency the rest of its sen­tence — that in­di­ca­tor test­ing may help iden­tify poor wa­ter qual­ity, which may it­self be a sign of hu­man fe­cal con­t­a­m­i­na­tion. Indicators are not use­less. They are a proxy. But a proxy for fe­cal load­ing is not a test for the or­gan­ism, and this or­gan­is­m’s only reser­voir on earth is hu­man fe­ces.

On prod­uct, the com­pany says more. It says it uses the lat­est FDA-validated test­ing method for Cy­clospora, which means FDA’s Bacteriological Analytical Manual Chapter 19b, pub­lished in June 2017 and since ex­tended to ma­tri­ces in­clud­ing ro­maine let­tuce. There is a com­pan­ion method, Chap­ter 19c, pub­lished in 2020, for agri­cul­tural wa­ter — val­i­dated to de­tect roughly six oocysts in ten liters. Both have ex­isted for years. The hon­est state­ment, then, is not that this com­pany never tested for the par­a­site. It is that the wa­ter pro­gram, by the com­pa­ny’s own de­scrip­tion, was never aimed at it, and that the prod­uct test­ing it did do can­not bear the weight now be­ing placed on it.

Here is why. The Canadian Food Inspection Agency in­de­pen­dently ver­i­fied FDAs pro­duce method and pub­lished the re­sults. Leafy greens spiked with two hun­dred oocysts were de­tected ninety-three per­cent of the time. A 2023 mod­el­ing study in the Journal of Food Protection says the same thing in the fed­eral reg­is­ter of the sci­en­tific lit­er­a­ture: these meth­ods have been shown not to al­ways de­tect con­t­a­m­i­na­tion when pre­sent at low lev­els.

Apply that to two thou­sand sam­ples and the num­ber stops be­ing im­pres­sive. It is not ev­i­dence that the prod­uct was clean. It is ev­i­dence that a method with a thirty per­cent de­tec­tion rate, run against an un­known frac­tion of an enor­mous vol­ume of let­tuce, mostly af­ter the con­t­a­m­i­na­tion win­dow had al­ready closed, found noth­ing.

FDA says its trace­back and its out­break data con­verge on shred­ded ice­berg let­tuce from this com­pa­ny’s lo­ca­tions in cen­tral Mexico. The com­pany says its own two thou­sand sam­ples found noth­ing. Both of those can be true at once, and if they are, the con­clu­sion is not that the let­tuce was clean. The con­clu­sion is that the test­ing pro­gram could not find what was in it. Negative re­sults from a pro­gram that can­not de­tect the haz­ard are not ex­on­er­a­tion. They are a de­scrip­tion of the pro­gram.

The com­pa­ny’s po­si­tion is that epi­demi­ol­ogy can iden­tify a po­ten­tial source but that only a pos­i­tive lab­o­ra­tory test can con­firm a spe­cific prod­uct caused ill­ness. Fine — that is a de­fen­si­ble view of proof, and plenty of sci­en­tists hold it. But a stan­dard that strict about pos­i­tives has noth­ing at all to say about neg­a­tives. If a pos­i­tive is the only thing that counts, then two thou­sand neg­a­tives count for noth­ing too, and the com­pany can­not cite them as if they did.

One last item, and it closes the cir­cle back to 2013. The posts says the com­pa­ny’s teams in­vented a wash sys­tem that is tested and ver­i­fied by USDA and de­scribes cus­tom spin dry­ers and con­sis­tent wash-wa­ter chem­istry. That is a wash step, val­i­dated against bac­te­ria, for an or­gan­ism against which no wash step and no chem­i­cal treat­ment has ever been val­i­dated — FDA says in its own voice that chlo­rine and other com­mon an­timi­cro­bial treat­ments are not ef­fec­tive on it. FDA told this fa­cil­ity to re-eval­u­ate its wash step in 2013. Thirteen years later the wash step is on the web­site as a cre­den­tial.

I do not fault a com­pany for de­fend­ing it­self, and I do not fault it for up­dat­ing a page as facts change. What I fault is a record that moves with­out say­ing it moved, while the ques­tions that ac­tu­ally mat­ter stay un­touched un­der­neath it. Five ver­sions in six­teen days, an apol­ogy as­serted and qui­etly dropped, a trace­back ac­knowl­edg­ment re­moved and later re­stored, a state list that an­swers its own ques­tion two ways on one screen — and in all of it, not one sen­tence about what changed at that plant af­ter 2013.

Two com­mit­tees in Congress have asked this com­pany for doc­u­ments by August 10 and August 13. If I had one re­quest to add to theirs, it would be short. Produce the haz­ard analy­sis. Produce the wa­ter test­ing records and say what or­gan­ism they were look­ing for. Produce the ad­ja­cent land re­views for the Doctor Mora ranches. And pro­duce the 2013 file, the one that an­swers whether this par­a­site was ever treated as a rea­son­ably likely haz­ard at a plant in a coun­try FDA calls en­demic. Everything else on that web­site is a claim.

Wind and solar overtake fossil fuels in Germany for the first time ever

www.intellinews.com

More of Germany’s elec­tric­ity came from wind and so­lar power than from fos­sil fu­els for the first time ever in 2025, ac­cord­ing to Carbon Brief’s analy­sis of Energy Institute Statistical Review of World Energy data. Wind and so­lar to­gether gen­er­ated 225 ter­awatt hours (TWh) of elec­tric­ity, 44% of the to­tal, against 217 TWh (43%) from fos­sil fu­els — a mile­stone Germany shares with the EU as a whole, which also saw wind and so­lar over­take fos­sil-fuel gen­er­a­tion for the first time in 2025.

Wind and so­lar gen­er­ated more elec­tric­ity than fos­sil fu­els in Germany for the first time ever in 2025. Source: Energy Institute Statistical Review of World Energy, 2026 / Carbon Brief.

The shift re­flects two decades of rapid growth in so­lar and on­shore wind un­der Germany’s Energiewende” strat­egy, as the coun­try tran­si­tions away from both coal and nu­clear power. Germany aims to in­stall 115 gi­gawatts (GW) of on­shore wind by 2030, and ap­proved a record 20.8 GW of new ca­pac­ity in 2025 alone. Official tar­gets re­quire econ­omy-wide net-zero emis­sions by 2045, an 80% re­new­ables share of elec­tric­ity con­sump­tion by 2030, and a largely cli­mate neu­tral” power sys­tem by 2035.

Germany has to lean on re­new­ables harder than neigh­bours such as France and the UK to hit those goals, pre­cisely be­cause of its nu­clear phase­out — a core plank of the Energiewende that re­mains po­lit­i­cally set­tled de­spite re­cent push­back. Centre-right Chancellor Friedrich Merz de­scribed the phase­out as a strategic mis­take” ear­lier this year, but his gov­ern­ment has ruled out re­turn­ing to con­ven­tional nu­clear power. Coal re­mains the big­ger near-term chal­lenge: Germany still re­lies on it far more than most other European coun­tries, with an of­fi­cial phase­out dead­line of no later than” 2038, though ex­perts be­lieve the coun­try is on track to elim­i­nate coal from its power sup­ply years ahead of that date de­spite pres­sure dur­ing the re­cent en­ergy cri­sis to slow the tran­si­tion.

Renewables now face a dif­fer­ent kind of op­po­si­tion, how­ever: mount­ing re­sis­tance from the far-right Alternative for Germany (AfD), even as the cur­rent coali­tion si­mul­ta­ne­ously pur­sues new gas-fired power plants of its own — leg­is­lated as a bridge tech­nol­ogy, with the plants in­tended to con­vert to run on green hy­dro­gen by 2045 to stay con­sis­tent with the cli­mate-neu­tral­ity tar­get. Very few voices out­side the AfD are call­ing to scrap the coal phase­out al­to­gether, but the gov­ern­ment is due to pub­lish a re­view of its time­lines in August, which will be the next test of how firmly Berlin in­tends to hold the line.

ICE Collected Nearly 1 Million People’s DNA Last Year—Including Young Children

www.wired.com

On March 13, 2025, Hugo Moreno-Mendez ar­rived at the McLennan County Probation Department in Waco, Texas, ex­pect­ing a rou­tine pro­ba­tion check-in. Instead, Immigration and Customs Enforcement of­fi­cers were wait­ing to ar­rest him.

According to a crim­i­nal com­plaint re­viewed by WIRED, of­fi­cers drove Moreno-Mendez to a nearby ICE field of­fice. There, one de­por­ta­tion of­fi­cer af­ter an­other ap­proached him with the same de­mand.

Open your mouth.

One of­fi­cer tried to take his fin­ger­prints and swab the in­side of his cheek for DNA. He re­fused. Then an­other tried. Then a third. Each time, Moreno-Mendez re­fused.

Four days later, Moreno-Mendez was charged with fail­ing to reg­is­ter as a nonci­t­i­zen and re­fus­ing to pro­vide DNA while in fed­eral cus­tody—the lat­ter a mis­de­meanor that, as of 2021, ICE it­self said it was un­aware had ever been ac­cepted for pros­e­cu­tion.

Moreno-Mendez took both counts to trial. On August 18, 2025, a mag­is­trate judge in Waco found him guilty of each and sen­tenced him to time served.

Moreno-Mendez’s case is part of a sweep­ing ex­pan­sion of DNA col­lec­tion from peo­ple held for civil im­mi­gra­tion vi­o­la­tions—a fed­eral cam­paign that, backed by the threat of pros­e­cu­tion, fun­nels the ge­netic pro­files of nearly every­one in ICE cus­tody into an FBI data­base built for crim­i­nal in­ves­ti­ga­tions. New re­search from Georgetown Law’s Center on Privacy and Technology es­ti­mates that the Department of Homeland Security has be­come the largest sin­gle source of new ge­netic pro­files in the na­tion’s crim­i­nal DNA sys­tem, with ICE alone po­ten­tially adding as many as roughly 920,000 pro­files in 2025.

The vast ma­jor­ity of peo­ple in ICE cus­tody have no crim­i­nal con­vic­tion, and re­sid­ing in the US un­doc­u­mented is typ­i­cally a civil, not crim­i­nal, of­fense. Yet once the DNA pro­files of de­tained peo­ple en­ter the FBIs Combined DNA Index System, or CODIS, law en­force­ment agen­cies across the coun­try can com­pare them against ev­i­dence from un­solved crimes—and against crime-scene DNA col­lected years or even decades from now. The phys­i­cal sam­ple, which holds a per­son’s en­tire genome, sits in a fed­eral lab­o­ra­tory in­def­i­nitely.

The ex­pan­sion of DNA col­lec­tion has ex­tended to fam­i­lies held in im­mi­gra­tion de­ten­tion, sparked law­suits over the col­lec­tion of DNA from pro­test­ers and oth­ers who al­lege they should never have been sub­jected to the pro­gram, and drawn con­gres­sional scrutiny af­ter law­mak­ers learned that chil­dren were be­ing swabbed at a fam­ily de­ten­tion cen­ter in Dilley, Texas.

None of the fam­i­lies at Dilley have been con­victed of a crime,” US rep­re­sen­ta­tives Joaquin Castro, Greg Stanton, and Nanette Barragán said in a joint state­ment to WIRED. They do not be­long in a data­base meant for vi­o­lent crim­i­nals, es­pe­cially chil­dren.”

In re­sponse to ques­tions from WIRED, a DHS spokesper­son de­fended DNA col­lec­tion as a bor­der-se­cu­rity and iden­ti­fi­ca­tion mea­sure, say­ing CBP takes sam­ples from peo­ple ar­rested on fed­eral charges and from de­tained nonci­t­i­zens who are sub­ject to fin­ger­print­ing and not oth­er­wise ex­empt. Asked about chil­dren whose pro­files were sub­mit­ted to CODIS, DHS pointed to a sep­a­rate DNA-testing pro­gram used to ver­ify fam­ily re­la­tion­ships. That pro­gram is dis­tinct from the col­lec­tion at the cen­ter of WIREDs re­port­ing. DHS did not ad­dress Georgetown’s es­ti­mate that ICE may have added hun­dreds of thou­sands of pro­files to CODIS in 2025.

For most of the pro­gram’s his­tory, mi­grant DNA col­lec­tion played out at the bor­der, where Customs and Border Protection swabbed peo­ple it took into cus­tody. ICEs own con­tri­bu­tion was mar­ginal. Internal train­ing slides ob­tained by Georgetown through the Freedom of Information Act (FOIA) show ICE col­lected 3,609 DNA sam­ples in fis­cal year 2020 and 16,392 more through mid-May of fis­cal 2021—roughly 20,000 in all. CBP was op­er­at­ing on a dif­fer­ent scale en­tirely: Agency spread­sheets Georgetown ob­tained and an­a­lyzed show it sent the FBI the DNA of at least 1.36 mil­lion peo­ple be­tween October 2020 and the end of 2024, more than a dozen times ICEs rate dur­ing the same time pe­riod.

Georgetown’s new re­port sug­gests the pro­gram en­tered an en­tirely dif­fer­ent phase in 2025. FBI records show the detainee” in­dex of CODIS—the sub-in­dex where DHS-collected pro­files are stored—reached 3,345,692 pro­files by December 2025, grow­ing by roughly 995,000 that year alone. That is more than 2,700 peo­ple a day, every day, for a year.

To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".

10HN is also available as an iOS App

If you visit 10HN only rarely, check out the the best articles from the past week.

Visit pancik.com for more.