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

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.

ISOPOLIS — San Francisco

sf.isopolis.city

load­ing…

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

Security Verification

www.ft.com

For help please visit help.ft.com. We apol­o­gise for any in­con­ve­nience.

The fol­low­ing in­for­ma­tion can help our sup­port team to re­solve this is­sue.

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.

GitHub - wie-project/kakehashi: Userspace macOS translation layer for Linux ARM64

github.com

Userspace ma­cOS ARM64 → Linux aarch64 trans­la­tion layer (CLI-first, no JIT).

Load Darwin Mach-O on Linux aarch64, map a free­stand­ing lib­Sys­tem, trans­late BSD syscalls, and run real guests (clang probes, 7-Zip 7zz, curl, threads).

What works

Verified on Docker/Colima and UTM (Linux aarch64). Install once:

cargo in­stall kake­hashi # or from a check­out: cargo in­stall –path crates/​kh-cli –force

kh bot­tle en­sure kh in­stall 7zip # Darwin 7zz → guest /usr/local/bin/7zz kh in­stall curl # Darwin curl → guest /usr/local/bin/curl

Relative -o / archive paths re­solve against the host CWD of the kh process (create par­ent dirs your­self, or rely on auto-mkdir for O_CREAT). Through the bot­tle, /Volumes/linux/… bridges to the host root (/ → host /).

7-Zip (7zz)

# Version / help kh run 7zz — kh run 7zz — –help

# Create archive (cwd-relative) kh run 7zz — a demo.7z README.md kh run 7zz — t demo.7z kh run 7zz — l demo.7z kh run 7zz — x -o./out demo.7z

# Multi-thread com­press (correctness gate) kh run 7zz — a -t7z -m0=lzma2 -mx=5 -mmt=4 mt.7z README.md kh run 7zz — t mt.7z # ex­pect: Everything is Ok, exit 0

Docker helpers (artifacts un­der host .tmp/kh-out/):

./scripts/docker-7zz.sh –help ./scripts/docker-7zz.sh a /Volumes/linux/out/demo.7z /Volumes/linux/src/README.md ls -lh .tmp/kh-out/demo.7z

KAKEHASHI_HYPERCALL=1 ./scripts/docker-7zz.sh a -t7z -m0=lzma2 -mx=5 -mmt=4 \ /Volumes/linux/out/mt.7z /Volumes/linux/src/README.md ./scripts/docker-7zz.sh t /Volumes/linux/out/mt.7z

curl

# Banner (G1) kh run curl — –version

# HTTP GET → file (G3 / G5). Parents for -o are cre­ated when miss­ing. kh run curl — -sS -o .tmp/kh-out/body http://​ex­am­ple.com/ # ex­pect: exit 0, ~559 bytes, HTML con­tains Example Domain” wc -c .tmp/kh-out/body head -c 80 .tmp/kh-out/body; echo

# HTTP to std­out kh run curl — -sS http://​ex­am­ple.com/ | head -c 80; echo

# HTTPS GET (G4) — OpenSSL + bot­tle CA (from host or curl.se down­load) kh run curl — -sS -o .tmp/kh-out/https-body https://​ex­am­ple.com/ wc -c .tmp/kh-out/https-body

# Negative: bad / self-signed cert must fail (rc ≠ 0) kh run curl — -sS -o /dev/null https://​self-signed.badssl.com/; echo exit:$?

Docker helpers:

./scripts/docker-curl.sh –version ./scripts/docker-curl.sh -sS -o /Volumes/linux/out/body http://​ex­am­ple.com/ ./scripts/docker-curl.sh -sS -o /Volumes/linux/out/https-body https://​ex­am­ple.com/ ls -lh .tmp/kh-out/body .tmp/kh-out/https-body

# Trace-first probe logs → .tmp/kh-curl-probe/ ./scripts/docker-curl-probe.sh –version

# Option ma­trix (large tiers) → .tmp/kh-curl-options/ ./scripts/docker-curl-options.sh tier1 ./scripts/docker-curl-options.sh tier9 – 10 ./scripts/docker-curl-options.sh all # tier1..10

Harmless noise on many runs:

kh: open fail ENOENT(openat) path=/​etc/​ssl/​openssl.cnf — OpenSSL op­tional con­fig; HTTP/HTTPS still work via the seeded CA bun­dle.

WARN … skip dylib … Security/CoreFoundation — Apple frame­works not in the bot­tle; soft stubs cover the load path.

un­re­solved strong sym­bol; bound to named miss­ing tram­po­line — sym­bols not hit on the happy path.

Details and gates: docs/​curl.md.

Also green

Not a prod­uct claim (yet)

Full curl fea­ture set (POST bod­ies, prox­ies, HTTP/3 end-to-end, every scheme), real Apple Security.framework, git / CLT, GUI, code­sign. Next prod­uct slice: git via kh in­stall xcode-tools — see docs/​git.md.

Crates

The guest dylib is ven­dored at crates/​kh-run­time/​re­sources/​lib­Sys­tem.B.dylib and com­piled into the run­time with in­clude_bytes!. Publishing kh-run­time ships the dylib; end users do not need a sep­a­rate down­load.

Requirements

Rust 1.88+

Linux aarch64 for live kh run / kh trace

Page sizes: 4 KiB (containers) and 16 KiB (Asahi-class)

Optional: curl/​wget + tar for kh in­stall 7zip / kh in­stall curl

Install

cargo in­stall kake­hashi # or from a check­out: cargo in­stall –path crates/​kh-cli

kh bot­tle en­sure kh in­stall 7zip kh in­stall curl

Bottle lay­out

Default root: ~/.local/share/kakehashi/bottle/ (override with KAKEHASHI_DATA_DIR / KAKEHASHI_ROOT).

Performance (honest)

Kakehashi runs guest code na­tively on the CPU. The tax is the syscall bound­ary (TLS switch, alt stack, NEON save/​re­store, Rust dis­patch) × how chatty the guest is — not an in­struc­tion em­u­la­tor.

Measured gap

On Ubuntu aarch64 bare-metal (UTM), multi-file 7zz archive (-t7z -m0=lzma2 -mx=5 -mmt=4, ~8k files / ~240 MiB tree):

On com­pres­sion-heavy, few-file sam­ples the gap is of­ten much smaller (~×1.1 – 1.2). The large multi-file gap is dom­i­nated by path walk + per-syscall bound­ary, not wrong LZMA.

Hypercall is on by de­fault for all guest threads. Opt out with KAKEHASHI_HYPERCALL=0 only for de­bug (residual svc→brk / SIGTRAP).

Why ~×5 is still use­ful in CI

The prod­uct goal for CI is not as fast as na­tive ma­cOS,” but run Darwin CLI/tools on cheap Linux aarch64 run­ners in­stead of scarce, ex­pen­sive ma­cOS ca­pac­ity.

GitHub Actions hosted run­ners (private-repo over­age rates, USD per minute; see Actions run­ner pric­ing):

ma­cOS stan­dard is roughly ×10–×12 the Linux ar­m64 minute rate be­fore any wall-time dif­fer­ence. Even if a job runs ×5 slower un­der kh on Linux ar­m64 than the same work on a ma­cOS run­ner, bill­able cost can still be lower be­cause the ma­cOS minute is an or­der of mag­ni­tude more ex­pen­sive (illustrative: 5 × $0.005 ≈ $0.025 vs 1 × $0.062). Public-repo free min­utes and self-hosted Linux am­plify that fur­ther; ma­cOS hosted ca­pac­ity also tends to queue longer and (on GitLab SaaS) is Premium/Ultimate / beta-gated.

When ma­cOS run­ners still win: GUI, code­sign/​no­ta­riza­tion, Xcode UI tests, or any work­load that is not a pure CLI Darwin bi­nary un­der free­stand­ing lib­Sys­tem.

Gates, not benches: CI cor­rect­ness is cargo test / smoke / 7zz -mmt=4, not match na­tive wall clock.” Perf work is tracked in docs/​roadmap.md.

Quick start (Docker / Colima on Apple Silicon)

docker build -t kake­hashi:dev -f Dockerfile.dev . docker run –rm -v $PWD”:/src -w /src kake­hashi:dev \ cargo test –workspace –exclude kh-lib­sys­tem

# Full smoke (build + clippy + test + mi­cro run) ./scripts/docker-smoke.sh

Build

cargo build -p kake­hashi –release cargo test –workspace –exclude kh-lib­sys­tem cargo clippy –workspace –exclude kh-lib­sys­tem –all-targets — -D warn­ings

# Maintainers: re­fresh em­bed af­ter free­stand­ing ABI changes cargo build -p kh-lib­sys­tem –release –target aarch64-ap­ple-dar­win ./scripts/stage-libsystem.sh # → crates/​kh-run­time/​re­sources/​lib­Sys­tem.B.dylib

lib­Sys­tem dis­cov­ery: –libsystem → KAKEHASHI_LIBSYSTEM → paths next to kh → crate re­sources/ → em­bed­ded bytes in kh-run­time.

Testing map

.tmp/, .kh/, and tar­get/ are git­ig­nored.

Guest path ↔ host path (Docker helpers)

Bottle bridges the Linux FS as /Volumes/linux/…:

Scripts

License

Apache License 2.0. See LICENSE.txt and NOTICE.

This pro­ject is not de­rived from Darling. Do not ven­dor pro­pri­etary Apple SDKs or blobs.

How the Words We Teach English Language Learners Changed

pudding.cool

Look through the words scat­tered around this page. Every one of them is among the most com­monly used words in the English lan­guage.

They come from a 2023 list of about 2,800 words, shown to cover over 90% of gen­eral English use, in­tended for peo­ple learn­ing the lan­guage.

This 2023 list is an up­date of an ear­lier one, made in 1953, which iden­ti­fied about 2,300 words as the es­sen­tial vo­cab­u­lary to every­day life at the time.

Between the two lists, 70 years apart, about 600 words were dropped, and over 1,100 were added. The rest re­mained as is.

Some of the changes make im­me­di­ate sense: Telegraph dropped out; com­puter was added, along with web­site and blog. Tobacco was re­placed by cig­a­rette. Motherhood be­came mom, and dad was added too, though fa­ther­hood was never on the list to be­gin with. The world changed and vo­cab­u­lary surely fol­lowed.

But also: ap­ple did­n’t make the new list. Neither did fork, soap, um­brella or leaf, for ex­am­ple. It’s not that these things van­ished from every­day life, but many hands-on words be­came less cen­tral to the core vo­cab­u­lary. Dog stayed; goat and don­key did­n’t. Bread stayed; bread­mak­ing in­gre­di­ents—flour and wheat—dropped. Cook is on the new list. Boil, bake, and fry are not.

And many of the words that were added, such as mort­gage, cor­po­ra­tion, ap­pro­pri­ate, analy­sis, fairly, and de­spite, don’t look any­thing like the ones that were dis­carded. In fact, they are mostly ab­stract con­cepts that don’t look like any­thing at all.

A

Added to 2023 list

A

Removed from 1953 list

A

In both lists

From Goat to Despite

How the Words We Teach English Language Learners Changed, and What That Says About Us

By Jasmine Nackash

These essential vo­cab­u­lary” lists are called the General Service List (1953) and the New General Service List (2013, re­vised in 2023).

They were de­signed as teach­ing tools for peo­ple learn­ing English as a sec­ond lan­guage, built from real-world us­age data and ex­ten­sively tested. The aim was a vo­cab­u­lary list with as few words and as much cov­er­age of every­day English us­age. That cov­er­age is high, over 90% for the 2023 list1 and about 84% for the 1953 list.2 To ac­count for that much of the lan­guage, they had to track a sig­nif­i­cant por­tion of what­ever peo­ple were ac­tu­ally read­ing and say­ing. A word earned its place by ap­pear­ing of­ten enough, across enough con­texts, to be hard to avoid for the av­er­age per­son in an English-speaking so­ci­ety. Open the word lists panel on the right to browse through all the en­tries in both lists.

While these were prac­ti­cal tools, built to cap­ture which words peo­ple need most, the an­swer also dou­bles as a snap­shot of or­di­nary life, 70 years apart: what peo­ple were ex­pected to en­gage with, and had to deal with, in their daily lives.

Treating the lists as an in­di­rect record of day-to-day life, I went through the dif­fer­ences be­tween them from a few an­gles: what the words were about, how tan­gi­ble were they, and to which parts of speech they be­longed.

I started by us­ing a com­mon lin­guis­tics re­search tool3 that sorted all of the words by mean­ing. It as­signed each word to one of 21 sub­ject cat­e­gories, based on typ­i­cal us­age: Food and Farming, the Body and the Self, Government and Public, Language and Communication, and so on. Together, they sug­gested what kind of world each list was built for.

Data source: all words run through the UCREL Semantic Analysis System (USAS).

The cat­e­gories that shrank are mostly those that have to do with the im­me­di­ate, phys­i­cal world, while the gains are those fur­thest from it.

To bet­ter see this, the cat­e­gories can be ori­ented spa­tially. Some cat­e­gories de­scribe you: your body and emo­tions. Some de­scribe what’s im­me­di­ately around you: food, ob­jects, and the nat­ural world. Others name sys­tems you par­tic­i­pate in: gov­ern­ment, in­sti­tu­tions, so­ci­ety, and cul­ture. And some have no lo­ca­tion at all: ab­stract con­cepts, rea­son­ing, and processes. When we look at the data grouped by phys­i­cal scope, the pat­tern of change seems to point in a spe­cific di­rec­tion.

The Self: Emotion | The Body and the Individual

Local/Immediate: Substances, Materials, Objects and Equipment | Food and Farming | Life and Living Things | Architecture, Housing and the Home | World and Environment

Institutional: Money and Commerce in Industry | Government and Public | Education | Science and Technology

Social/Communicative: Social Actions, States, and Processes | Movement, Location, Travel and Transport | Language and Communication | Entertainment, Sports and Games | Arts and Crafts

Universal/Abstract: General and Abstract Terms | Psychological Actions, States and Processes | Numbers and Measurement | Names and Grammar | Time

In hind­sight, the shift makes sense. By 1957, four years af­ter the orig­i­nal list was pub­lished, white-col­lar work­ers out­num­bered blue-col­lar for the first time in US his­tory. And by 2000, fewer than one in four work­ers did man­ual la­bor. The stuff peo­ple en­coun­tered in their daily lives, what they needed to talk about, and the sys­tems they had to nav­i­gate all changed.

The vo­cab­u­lary lists, built from the lan­guage of their re­spec­tive eras, tracked those changes. The shifts re­flect a life that moved fur­ther from its own mak­ing: less tied to tools, an­i­mals, food, and the body; more tied to na­tional or global in­sti­tu­tions, cat­e­gories, sys­tems, and ideas.

The new vo­cab­u­lary—mort­gage, leg­is­la­tion, per­spec­tive, in­volve­ment, im­prove­ment, as­sump­tion, eval­u­a­tion—are words you can’t weigh, point to, or hold in your hand. These words shape your life, but they do it with­out oc­cu­py­ing phys­i­cal space.

To bet­ter un­der­stand whether there was a shift in vo­cab­u­lary de­scrib­ing the phys­i­cal world, I com­pared each word to a data­base that rates its tan­gi­bil­ity on a scale of 1 to 5 (called a concreteness rat­ing4”). A rat­ing of 5 means you can ex­pe­ri­ence the word di­rectly with your senses, while a rat­ing of 1 means you can’t.

The highly con­crete end dropped the most: from 21% of the to­tal in 1953 down to 14% in 2023.

Kernel den­sity es­ti­ma­tion, band­width 0.08 · Data source: Brysbaert et al. (2014)

This shift mat­ters be­cause ab­stract and con­crete words are processed by our brains in dif­fer­ent ways. When you read axe, your brain does­n’t just de­code let­ters, it reaches for some­thing: an im­age, a weight, or a ges­ture. The word ac­ti­vates both a ver­bal la­bel and a sen­sory trace. Psychologists call this dual cod­ing:5 Concrete words travel through two chan­nels, ver­bal and sen­sory; ab­stract words travel through one. Two chan­nels mean two re­trieval path­ways, which is why con­crete words are stickier,” eas­ier to hold in a line of thought and faster to re­call. Abstract words, on the other hand, are purely ver­bal, and have to be un­der­stood through lan­guage alone.

To put it an­other way: Concrete words are eas­ier for us to process be­cause they are bun­dled with a web of as­so­ci­a­tions, tac­tile ex­pe­ri­ences, and mem­o­ries that an­chor their mean­ing. Here’s a more de­tailed view of the shift away from con­crete lan­guage:

Data source: Brysbaert Concreteness rat­ings for 40 thou­sand gen­er­ally known English word lem­mas. The dataset pro­vided 99.8% cov­er­age of the words in both lists. 6 words not in the dataset are not in­cluded in this chart: as, di­a­log, eng­lish, gai­ety, mad­den, old-fash­ioned.

While con­crete words have sen­sory ground­ing to carry their mean­ing, ab­stract words rely on other parts of speech to spec­ify, soften, or sharpen what they mean. That help tends to come from one par­tic­u­lar cor­ner of the lan­guage: ad­verbs.

The 2023 list con­tains more words over­all (2,809 vs. 2,284). All changes men­tioned in the text re­flect each cat­e­go­ry’s share of its list, not raw counts. Data source: NLTK (Natural Language Toolkit), with man­ual cor­rec­tion of mis­la­beled words.

Axe does­n’t need an ad­verb to mod­ify it; you know what it is. But ac­cept­able, rel­e­vant, and ad­e­quate come with con­di­tions, qual­i­fi­ca­tions, and de­grees that need to be spelled out. Adverbs do pre­cisely that: lan­guage to cal­i­brate lan­guage. Look through all the ad­verbs that were added:

ab­solutely­ac­tu­allya­longsideany­more­ap­par­entlyap­prox­i­matelyau­to­mat­i­cally­badly­barely­ba­si­cally­briefly­care­ful­lyc­er­tain­ly­clear­ly­close­ly­complete­ly­con­se­quent­ly­con­stant­ly­cur­rent­ly­deeply­def­i­nite­ly­d­if­fer­ent­ly­di­rect­ly­dra­mat­i­cal­lyeasi­ly­ef­fec­tive­lyen­tire­lye­qual­lyeven­tu­al­lyex­act­lyex­treme­ly­fair­ly­faith­ful­ly­fi­nal­ly­firm­ly­first­ly­forever­fre­quent­ly­ful­ly­fur­ther­more­gen­er­al­ly­gent­ly­grad­u­al­ly­great­ly­heav­i­ly­hence­high­ly­hope­ful­ly­im­me­di­ate­ly­in­creas­ing­lyini­tial­ly­large­lylit­er­al­ly­main­ly­mere­ly­month­ly­most­ly­nat­u­ral­lyn­ear­byn­ear­lynec­es­sar­i­lyn­ev­er­the­less­new­ly­nor­mal­ly­ob­vi­ous­ly­oc­ca­sion­al­ly­o­rig­i­nal­ly­over­sea­spar­tic­u­lar­ly­part­lyper­fect­lyper­son­al­ly­pos­si­bly­po­ten­tial­ly­pre­cise­lypre­sum­ablypre­vi­ous­lypri­mar­i­lyprob­a­blyprop­er­lyquick­lyqui­et­lyrapid­lyrarelyre­al­lyrea­son­ablyre­cent­lyre­gard­less­reg­u­lar­lyrel­a­tive­lyre­spec­tive­ly­roughl­y­sec­ondl­y­se­ri­ouslysig­nif­i­cantlysim­i­larlysim­plyslightlyslowlysome­what­specif­i­cally­strongly­sub­se­quently­suc­cess­fully­sud­denly­surely­surpris­ing­ly­to­tal­lytru­lytwice­typ­i­cal­lyul­ti­mate­lyun­for­tu­nate­lyusu­al­lyvir­tu­al­ly­widely

Most of the ad­verbs spec­ify de­gree, fre­quency, cer­tainty, and ex­tent. Some hedge (somewhat, partly, rel­a­tively, pos­si­bly, ap­prox­i­mately). Others as­sert (absolutely, def­i­nitely, en­tirely, ex­actly, pre­cisely). They’re all do­ing the same kind of work: Take a state­ment and tell you how much of it is true, how of­ten, and how cer­tain. It’s as if the world now re­quires you to be more pre­cise about every­thing.

Bread sur­vived both lists. Flour, wheat, har­vest and bake did­n’t. The word for what sus­tains us re­mained es­sen­tial, while the words for how we’d make it weren’t. That might be the most hon­est sum­mary of what hap­pened.

The world that made the 2023 list is more reg­u­lated, more con­nected, and in many ways more ca­pa­ble than the one be­hind the 1953 list. It’s a world fur­ther than our kitchen or home, reach­ing across economies, in­sti­tu­tions, and democ­ra­cies.

Today’s vo­cab­u­lary re­flects a life that is­n’t self-con­tained, but rather more sys­temic. It’s not so much about what’s within ar­m’s reach, but more about the larger world we nav­i­gate through. That sort of long-dis­tance con­nec­tion re­quires a par­tic­u­lar kind of lan­guage: ex­pan­sive, ab­stract, and pre­cise. And lan­guage, it turns out, can’t help it­self. It keeps track.

Methods & Notes

I com­pared two promi­nent vo­cab­u­lary lists for English learn­ers: the General Service List (GSL, 1953; 2,284 words) and the New General Service List (NGSL 1.2, 2023; 2,809 words). I la­beled words ap­pear­ing on both lists as remained” (1,656), words only on the 1953 list as removed” (628), and words only on the 2023 list as added” (1,153).

The GSL words came from the Simple English Wiktionary GSL. The NGSL words came from the of­fi­cial NGSL 1.2 file (“alphabetized and lem­ma­tized for re­search”). The NGSL uses lem­mas (one en­try per word fam­ily); the GSL some­times lists in­flected forms as sep­a­rate head­words. These lists track word forms deemed worth teach­ing based on fre­quency and use­ful­ness, not ab­stract con­cepts. For ex­am­ple, the word be­ing is on the GSL as its own head­word and was not in­cluded in the NGSL, But this does­n’t mean the con­cept of ex­is­tence left the lan­guage. In the NGSL it falls un­der be, which is on both lists.

Both lists were built for teach­ing, but ex­ter­nal re­search sug­gests each cov­ers a large share of every­day lan­guage use. About 84% of gen­eral English for the GSL and about 90% for the NGSL, de­pend­ing on the text and how words are counted. I did not re-run those cor­pus analy­ses my­self. I take the pub­lished ma­te­ri­als as given and rely on cov­er­age fig­ures from the list au­thors and from fol­low-up stud­ies (including an in­de­pen­dent check on American English by Stoeckel, 2019 — see foot­notes). That’s why the dif­fer­ences be­tween the lists felt worth ex­am­in­ing as more than a cur­ricu­lum up­date, with the caveat that nei­ther list is a neu­tral cen­sus of cul­ture.

All tagged words: re­mained, re­moved, and added, with se­man­tic tags, con­crete­ness rat­ings, and part-of-speech la­bels are in this pub­lic spread­sheet. You can also browse the word lists in the word-list panel on the right side of this page.

Each word was tagged with the UCREL Semantic Analysis System (USAS), us­ing the 21 top-level cat­e­gories. USAS also as­signs much finer sub-cat­e­gories (there are hun­dreds), but I stayed at the top level so the charts could show broad shifts with­out split­ting the words into overly gran­u­lar bins.

I chose not to cor­rect mis­la­bels. For ex­am­ple, ham­mer, nail, and wax are all tagged General and Abstract Terms”, but in USASs finer tags, they read as ac­tions (“to ham­mer,” to nail,” to wax”), not ob­jects. Out of con­text, many of these words go mul­ti­ple ways, and it did­n’t feel right to over­ride that case by case; USAS is an es­tab­lished lin­guis­tic frame­work, and swap­ping in my own judg­ment would mix two dif­fer­ent stan­dards.

For the sec­ond chart, I grouped USASs 21 cat­e­gories into five scope” do­mains (self, lo­cal, in­sti­tu­tional, so­cial, ab­stract). That group­ing is my ed­i­to­r­ial choice, not part of USAS. It came from notic­ing a spa­tial qual­ity to the trends seen across the 21 cat­e­gories.

Concreteness rat­ings come from Brysbaert et al. (2014). I used these as-is. Six words weren’t in the data­base and were left out of the con­crete­ness charts: as, di­a­log, eng­lish, gai­ety, mad­den, and old-fash­ioned.

Parts of speech were tagged with NLTK, sim­pli­fied to five cat­e­gories. Here I did in­ter­vene, but only when a word was clearly mis­la­beled (132 words, 3.8% of the list; mostly ad­jec­tives mis­la­beled as nouns). When a word can act as more than one part of speech de­pend­ing on con­text, I left the tag as-is and de­ferred to NLTK as the es­tab­lished frame­work, us­ing the pri­mary, most com­mon la­bel. Here I also used an LLM strictly to help flag po­ten­tial er­rors in NLTKs out­put.

Both lists rank words by fre­quency, then ap­ply learner-fo­cused cu­ra­tion. Michael West’s 1953 list es­pe­cially re­flects pe­riod ped­a­gogy. He fa­vored gen­eral-pur­pose vo­cab­u­lary over emo­tional or highly spe­cific words, not just what­ever ap­peared most of­ten (Therova, 2020, sum­ma­riz­ing West, 1953, pp. ix–x). Some of what looks like 1950s life” may also be how mid-cen­tury ESL teach­ing fil­tered the lan­guage. I still treat the lists as a por­trait of every­day English be­cause both cover a large share of run­ning text and speech that goes well be­yond the class­room.

On NGSLs ~90% cov­er­age: Browne, Culligan & Phillips, NGSL pro­ject. See also: A New General Service List: The Better Mousetrap We’ve Been Looking for?, Browne (2014); and An Examination of the New General Service List, Stoeckel (2019). ⏎

On GSLs ~84% cov­er­age: A gen­eral ser­vice list of English words with se­man­tic fre­quen­cies, West (1953); The New General Service List: A core vo­cab­u­lary for EFL stu­dents and teach­ers, Cambridge ELT (2018). ⏎

UCREL: Semantic Analysis System (USAS). ⏎

Concreteness rat­ings for 40 thou­sand gen­er­ally known English word lem­mas, Brysbaert, M., Warriner, A. B., & Kuperman, V. (2014). Behavior Research Methods, 46, 904 – 911. ⏎

Why are pic­tures eas­ier to re­call than words? Paivio, A., Rogers, T.B. & Smythe, P.C. Psychon Sci 11, 137 – 138 (1968). ⏎

Developers are attached to tools because tools encode trust

stackoverflow.blog

About six years ago, we ran a piece about IDEs where the gist was that IDEs were get­ting to be so pow­er­ful and ca­pa­ble that it was a mar­vel that any­body used Vim or Emacs like a cave­man. While yes, it was a provoca­tive ar­ti­cle, it got a lot of de­vel­op­ers pretty riled up. Comments came from both sides, both from folks trash­ing the ar­ti­cle for not un­der­stand­ing how de­vel­op­ers work and from those de­vel­op­ers who preach the good news of Emacs all day. But mostly there was a great dis­cus­sion about why these tools were ac­tu­ally use­ful.

For a novice, Vim and Emacs can seem like un­in­tu­itive ter­mi­nal pro­grams that re­quire mem­o­riza­tion of se­cret key­strokes to use (and es­cape). But for the ex­pe­ri­enced user, it can feel as nat­ural as think­ing. One com­ment pointed to The Pragmatic Programmer by David Thomas and Andrew Hunt, which ex­plained that de­vel­op­ers—crafts­men that they are (or were)—need sharp tools” that feel like an ex­ten­sion of their hand. Vim and Emacs, in their in­fi­nite cus­tomiz­abil­ity, can be molded to fit your ex­act hand and work­flow. Taking the time to build pro­fi­ciency and trust in your tools, and well as hack­ing them to fit you, pays deep div­i­dends.

In this age of agen­tic en­gi­neer­ing, the new tools are ter­mi­nals you talk to in nat­ural lan­guage. A cod­ing agent lacks the pre­ci­sion and speci­ficity of a de­vel­oper writ­ing well-crafted code, but it can out­put whole ap­pli­ca­tions in a frac­tion of the time. The ques­tion that still echoes to­day is whether those out­puts can be trusted. Our last Developer Survey found that the more de­vel­op­ers used AI, the less they trusted it—us­age rose from 76% to 84%, but trust fell from 40% to 29%.

The tools them­selves are new and their ca­pa­bil­i­ties are in con­stant flux. If your kitchen knife kept chang­ing shape, weight, and edge, you’d have to re­learn it every time; that’s a hard tool to build trust in. But it also points to a flaw in how you use that tool, the process around it, and the way the tool re­in­forces the process. You trust your fa­vorite knife, IDE, paint­brush, or what­ever be­cause of the trust you’ve built with it, and the process around it.

In this ar­ti­cle, we’ll look at how tools build trust­wor­thy processes, the ways that tool changes high­light but can’t fix bro­ken processes, and where tool­ing and cul­ture can work to­gether to build new trust.

Developer tool­ing op­er­ates and evolves along­side soft­ware de­vel­op­ment as a whole, but also with in­di­vid­ual de­vel­op­ers. If you start work­ing and learn­ing in a ter­mi­nal, per­haps in a day when IDEs or graphic in­ter­faces did­n’t ex­ist, then the way that you un­der­stand cre­at­ing code in­cludes those ter­mi­nals and ter­mi­nal text ed­i­tors. Adding in an IDE would re­quire not just learn­ing a new tool, but refac­tor­ing your process of writ­ing code.

If mov­ing from the ter­mi­nal to the IDE is a hard process shift (or as some would say, un­nec­es­sary), then mov­ing from ei­ther to an agen­tic cod­ing tool is harder. One of my ret­i­cences for em­brac­ing some of the AI pro­gram­ming is be­cause I’m faster with my IDE be­cause I know how that works,” said Tricia Gee, a de­vel­oper pro­duc­tiv­ity ad­vo­cate. I’ve seen the same thing when I’ve worked with peo­ple who know Vim and Emacs very well. You could use the refac­tor­ing tools in IntelliJ IDEA. They’re like, yes, but that re­quires a learn­ing curve. I’ve spent so long us­ing what­ever tool it is. My fin­gers know what to do. Understanding a tool very well, no mat­ter what it is, be­comes a lot of un­con­scious com­pe­tence.”

Building that mus­cle mem­ory, that tacit knowl­edge of how soft­ware op­er­ates on a code level, lets de­vel­op­ers trust their tools to help pro­duce and im­prove their code. AI agents, mean­while, are faster, more opaque, and less pre­dictable. You use am­bigu­ous lan­guage to cre­ate soft­ware in­stead of code. Code is a pre­cise state­ment of a so­lu­tion,” said Bjarne Stoustrup, the cre­ator of C++. English is a lousy lan­guage for ex­press­ing things that have to be un­am­bigu­ous.” A trusty tool is pre­dictable, re­li­able. You don’t have to it­er­ate re­peat­edly with Emacs or Vim.

With most de­vel­oper tools, like an IDE, con­tainer­iza­tion tool, or sta­tic an­a­lyzer, you know where the bound­aries are. They have their role and don’t step out­side it. But AI is find­ing its way into all parts of the SDLC tool­chain. Which means the re­duced trust de­vel­op­ers have in AI ap­plies to the en­tirety of the process. Code may be faster to pro­duce, but val­i­dat­ing it, get­ting it to a point where de­vel­op­ers can trust that it won’t cause ex­pen­sive pro­duc­tion fail­ures, of­ten takes longer.

Agentic cod­ing tools change the na­ture of the soft­ware de­vel­op­ment process. The tools that arose around the pre­vi­ous process—lin­ters, au­to­mated unit tests, CI/CD, etc.—may not work in their cur­rent form with this changed process.

Those tools en­coded the process, but they weren’t the process it­self. A great CI/CD tool did­n’t mean you shipped faster. A great IDE did­n’t mean you wrote bet­ter code. An is­sue track­ing sys­tem with story points did­n’t mean you es­ti­mated ef­fort well. Some part of the process ex­isted as cul­ture, as the be­hav­iors and norms of the peo­ple build­ing soft­ware. New tools of­ten mean chang­ing the or­ga­ni­za­tional cul­ture.

This story will be fa­mil­iar to any­one who works in siz­able en­gi­neer­ing orgs. New tools, what­ever their promise, can fail when they don’t fit into ex­ist­ing cul­tures and processes. Successful tools re­quire shift­ing the cul­ture and processes in a way that de­vel­op­ers ac­cept and un­der­stand. Y’all love build­ing things and solv­ing prob­lems, so tools that don’t help you do that bet­ter get ig­nored.

Agentic cod­ing gained rapid adop­tion be­cause it let de­vel­op­ers solve prob­lems faster. But it ex­posed a lot of flaws in ex­ist­ing processes when code be­came nearly triv­ial to cre­ate. There had al­ways been an is­sue with un­clear and shift­ing re­quire­ments, but now solv­ing a prob­lem re­quires tightly defin­ing what both problem” and solve” mean.

Code may be (nearly) free, but val­i­dat­ing it is­n’t. The new bot­tle­neck has be­come code re­view. The old joke was that if you want a PR ap­proved quickly, change 100 lines. Coding agents change hun­dreds of lines of code in an in­stant, and send mas­sive diffs across to hu­mans to re­view (or rub­ber­stamp). LLM-as-a-judge is evolv­ing as a scal­able so­lu­tion here, but en­gi­neer­ing ways to trust that an AI can re­view code that an AI wrote takes work.

In that same light, run­ning code is also not free. You’ve got the cost of in­fra­struc­ture, which in the cloud-na­tive era is a fac­tor of the com­pute, mem­ory, and traf­fic vol­umes your ap­pli­ca­tion in­curs. You’ve got the cost of your hosted de­pen­den­cies and APIs. And, you’ve got the cost of fail­ures, the hard­est thing to bud­get for: down­time, se­cu­rity breaches, and op­por­tu­nity costs. Tools that pro­duce soft­ware that does­n’t (or can’t) con­sider these costs might not be worth it. And they put a strain on the process you built that used to pro­duce trust­wor­thy, re­li­able soft­ware.

For a lot of folks, the SDLC has started to look bro­ken thanks to agen­tic cod­ing. Naturally, these folks are look­ing to new tool­ing to re­pair those cracks: AI SREs, au­to­mated code re­view, mem­ory and con­text man­agers, con­trol plane and har­ness im­prove­ments, and so on. These are all solid ad­di­tions to the tool­ing in an AI-enabled soft­ware or­ga­ni­za­tion. But tool­ing alone will not fix things, es­pe­cially if the cul­ture and process stay the same. A bro­ken process with bet­ter tools (that folks may not use) is still bro­ken.

In the old SDLC, prod­uct man­agers would come up with fea­ture and func­tion re­quire­ments based on their re­search, cus­tomer con­ver­sa­tions, and com­peti­tor un­der­stand­ing. Architects would spec out the soft­ware based on their years of ex­pe­ri­ence and un­der­stand­ing of the ex­ist­ing tech stack. Engineers would build it and re­view com­mits based on their knowl­edge of code logic and the ex­ist­ing code­base. QA would re­view and try to break the soft­ware based on their ex­pe­ri­ence with how soft­ware breaks. Once the soft­ware was de­ployed to pro­duc­tion, DevOps and SREs would mon­i­tor and man­age the per­for­mance and re­sources used based on their pre­vi­ous ex­pe­ri­ence.

You built trust in this sys­tem by work­ing with peo­ple, un­der­stand­ing how they thought, and lim­it­ing the ways that any one in­di­vid­ual or tool could go rogue and dev­as­tate the sys­tem. Building trust in an AI-enabled SDLC needs these same things: work­ing with peo­ple and en­sur­ing they are re­spon­si­ble and ac­count­able, shar­ing work­ing processes and it­er­at­ing on them, and min­i­miz­ing the chance for mis­takes.

The first step is to en­sure that we en­shrine hu­mans as the re­spon­si­ble par­ties and flag where AI made con­tri­bu­tions. Everybody talks about human-in-the-loop,” but as Charity Majors, CTO of Honeycomb, pointed out, Human-in-the-loop sounds like a pity in­vite. I made the loop, I own the loop, I’m the only rea­son that loop ex­ists. It is MY f***ing loop!” The per­son push­ing the com­mit owns that code. The peo­ple ap­prov­ing those PRs own that ap­proval. If you broke prod on a Friday be­fore AI, you did­n’t blame your IDE. If you break it now, the prob­lem does­n’t lie with the agent; it lies be­tween the key­board and chair.

Collaboration in the age of AI can be a harder and stranger thing. Agents let you ex­pand the idea of what a full­stack de­vel­oper is, do­ing every­thing from prod­uct re­quire­ments to DevOps in a cod­ing agent. Developers can very eas­ily be­come a silo of one. You don’t have to, say, check in with your de­signer about the de­sign be­cause you just got an agent to build the de­sign,” said Jaime DeLanghe, chief prod­uct of­fi­cer at Slack, and you don’t have to work with an­other en­gi­neer in a spe­cific do­main to un­der­stand their code base be­cause you just ask the agent the ques­tion. You could go way down this path and cre­ate a mas­sive PR.”

Some folks have sug­gested prompt­ing agents in a shared room, so every­one can com­ment and mod­ify the process. Others have sug­gested that every PR in­clude tran­scripts of the prompt­ing process. This view into the con­ver­sa­tion with an agent might even give greater in­sight into how that code came about. It’s so cool to be able to open up a PR and ac­tu­ally see how the de­vel­oper was think­ing and how they were prob­lem solv­ing,” said Dane Knecht, chief tech­nol­ogy of­fi­cer at Cloudflare.

Where the old process used ac­cess con­trols, au­dit trails and diffs, and CI/CD checks to limit the blast ra­dius of any mis­take, the new process needs to re­move chance be­fore the code is writ­ten. That means en­sur­ing every­thing you want the code to do is ex­plic­itly stated in the prompt. You can use spec.md files for this, but any­thing not spec­i­fied might now get built. If you leave any­thing up to chance, it will be left up to chance,” said Scott Hanselman, VP of Developer Community at Microsoft. I got this lit­tle ring light app to build, and I’m on x64. I wanted it to work on ARM, so I needed to tell it, Make me an ARM ver­sion.’ If I did­n’t do it, it would­n’t have hap­pened.”

Of course, you can’t cram every­thing you need into a clever prompt (nor should you). You’d end up re­peat­ing your­self a lot and al­most cer­tainly miss­ing a few things that ex­ist as tacit com­pany knowl­edge. Lots of smart peo­ple are out there think­ing about pro­vid­ing bet­ter con­text to your agents and giv­ing them long-term and short-term mem­o­ries. The trick is giv­ing your agents the right con­text that your code needs. Normally, this would be the sea­son­ing that se­nior devs get over time. But agents need you to cap­ture that knowl­edge some­where (like Stack Internal), ver­ify it, and serve the right bits up as con­text when needed.

So you’ve got the world’s best prompt. You gave your agent the right con­text, and it built some­thing that passed peer re­view and got pushed to prod. Your next check on the sys­tem is to never build that piece of func­tion­al­ity again. You’ve got a per­fectly good soft­ware com­po­nent; don’t lose it, reuse it. The DRY (don’t re­peat your­self) prin­ci­ple is our main prin­ci­ple,” said Laly Bar-Ilan, Chief Scientist at Bit. AI to­day is in­her­ently WET (write every­thing twice). This de­vel­oper tells it, Okay, gen­er­ate a but­ton,’ and it gladly does so, and then an­other de­vel­oper in an­other team asks it, and then there’s an­other but­ton in the code base.”

The biggest hack to build­ing trust with AI agents, though, might be to know when not to use them. Even with all the above guardrails on your process, there’s still a bit of a dice roll in­volved with AI by dint of its na­ture. If you have a per­fectly good non-de­ter­min­is­tic so­lu­tion in place, why rein­vent the wheel? We are try­ing to ap­ply non-de­ter­min­is­tic sys­tems to a lot of sce­nar­ios where you should have de­ter­min­is­tic code,” said Anil Dash. LLMs are bad at that thing, and so why are we try­ing to use them as the ham­mer on all these things that ain’t nails? The hum­ble bash script that has been run­ning for six years is fine.”

We used to have trust built-in thanks to the peo­ple and tools we worked with. That trust came from pre­dictabil­ity: You knew what they could do, you knew where their strengths and weak­nesses were, and could you ex­pect that your ex­pe­ri­ence with them on Monday would match up with your ex­pe­ri­ence with them Tuesday. The prob­a­bilis­tic na­ture of AI, as well as the speed at which im­prove­ments and changes hap­pen, throws all that out the win­dow. Process im­prove­ments can help en­gi­neer trust back into de­vel­op­ment.

In the good old days, we built processes around peo­ple, and we trusted those processes be­cause we trusted the peo­ple we worked with. We built tools that we trusted to man­age the process, and they acted as an ex­ten­sion of our­selves and the peo­ple we worked with.

With AI, we’re able to au­to­mate a lot of those processes. The good news is that work gets done faster. The bad news is that we don’t trust it when it’s done. The tools are new, the peo­ple are mov­ing to more high-level roles, and we still need to build trust. With a more de­lib­er­ate, ex­plic­itly-de­fined work­flow that pre­serves hu­man judge­ment, we can start to build trust in the new sys­tems.

Successful teams won’t be the ones that gen­er­ate the most code. They’ll be the ones build­ing feed­back loops, gold stan­dard knowl­edge that pro­vides the best con­text, and tools that align your process with your work­flows.

SwiftUI After 7 Years: A Story of Mediocrity

ykvm.com

Seven years af­ter its block­buster 2019 an­nounce­ment, SwiftUI was sup­posed to be the ma­ture, pro­duc­tion-grade fu­ture of cross-plat­form UI de­vel­op­ment on all Apple plat­forms. Instead, SwiftUI feels like a per­pet­ual beta, even in 2026. In this deep dive, I break down why the ini­tial ex­cite­ment has given way to deep pro­fes­sional frus­tra­tion for se­nior en­gi­neers. I an­a­lyze the sys­temic is­sues with per­for­mance and lay­out pre­dictabil­ity, the chaotic state of SwiftUI’s ever-chang­ing data flow, and the frus­trat­ing lack of back­ward com­pat­i­bil­ity that forces de­vel­op­ers into a night­mare of shims and workarounds.

Through real-world ex­am­ples—in­clud­ing Apple’s own SwiftUI tu­to­r­ial (which is bro­ken) and a head-to-head per­for­mance com­par­i­son with UIKit (guess who wins)—I demon­strate how SwiftUI trades pre­cise en­gi­neer­ing for an il­lu­sion of con­ve­nience.

Beyond the code, this video ex­plores a broader, more con­cern­ing shift in Cupertino: a tran­si­tion away from the un­com­pro­mis­ing crafts­man­ship of the orig­i­nal era of Cocoa, Aqua, and Auto Layout to­ward a mod­ern cor­po­rate cul­ture of good enough” prod­ucts. If you are tired of mak­ing ex­cuses for bro­ken fea­tures, fight­ing lay­out bugs, and do­ing Apple’s QA work for them, this per­spec­tive is for you.

Links

Landmarks (Apple’s bro­ken SwiftUI tu­to­r­ial)

Undocumented Self._printChanges() method (and other de­bug­ging tricks)

SwiftUI Only Makes It Easy to Develop Bad Apps

SwiftUI Group Still(?) Considered Harmful (another ex­am­ple of SwiftUI’s hid­den gotchas)

Video Transcript

Intro

Okay, let’s get on with it.

This is go­ing to be a longer piece about SwiftUI, what’s wrong with it, and why I don’t be­lieve it’s get­ting bet­ter any time soon. The past seven years haven’t turned SwiftUI into a real, pro­duc­tion-grade UI frame­work: It still suf­fers from long-stand­ing is­sues with lay­out con­sis­tency and per­for­mance.

But you don’t have to take my word for it; you can see for your­self in Apple’s of­fi­cial, first-party SwiftUI tu­to­r­ial. Just down­load the com­plete demo pro­ject at the link be­low and run it on your Mac.

I’ll get back to this par­tic­u­lar case later in this video. But let’s start with a short ret­ro­spec­tive.

SwiftUI was an­nounced back in 2019—and to much fan­fare. I was there and wit­nessed it my­self. Apple promised to end the era of fight­ing Auto Layout and re­build­ing the app every time you make the tini­est of change.

Instead, you were go­ing to get de­clar­a­tive syn­tax, the sin­gle source of truth, built-in an­i­ma­tion, in­stant pre­views, and cross-plat­form reusabil­ity of your code. To me, it sounded too good to be true.

As it turned out, it was.

By this point, the ini­tial ex­cite­ment has­n’t just faded. It’s given way to a grow­ing sense of deep pro­fes­sional frus­tra­tion.

And af­ter seven years, the ex­cuse that SwiftUI is still a young frame­work,” well, it’s just dead. In this in­dus­try, seven years is like an eter­nity. It’s roughly the time be­tween this and this, and it’s more than the time be­tween the first iPhone and the iOS 7 re­design. By com­par­i­son, SwiftUI feels like it’s in a per­pet­ual beta state. Every new fea­ture comes with a fine-print foot­note. Every lay­out fix breaks two more things you did­n’t even touch. And hon­estly? I’m tired of mak­ing ex­cuses for all this in my own pro­jects.

Why SwiftUI Exists

But be­fore we have a look at SwiftUI’s spe­cific strengths and weak­nesses—mostly weak­nesses—let’s see why SwiftUI even ex­ists.

It’s not so much that Apple wanted to give you great dev tools, but be­cause it sort of had to. Apple had to re­spond to the pres­sure from the com­pe­ti­tion. By the mid-2010s, Facebook’s React be­came de facto stan­dard on the web, and soon React Native and Google’s Flutter started their con­quest of mo­bile plat­forms. Both frame­works are re­ac­tive and de­clar­a­tive.

From the per­spec­tive of any busi­ness, build­ing na­tive apps started to look less and less ap­peal­ing. Instead, they could use the same code­base on iOS and Android while also bor­row­ing com­po­nents from their own web­sites.

I be­lieve there was one more rea­son, and it is the Mac App Store. When was the last time you opened it? And when was the last time you in­stalled a new na­tive app on your Mac? Yeah, same thing here.

The iOS App Store was the key step in Apple’s tran­si­tion to ser­vices busi­ness, thanks to its 30% fee on every trans­ac­tion. But on the Mac, many apps only worked in the browser, or as web apps in Electron wrap­pers.

SwiftUI was sup­posed to solve both of these prob­lems: keep de­vel­op­ers within the na­tive ecosys­tem to build new apps, and make it eas­ier to port ex­ist­ing ones to the Mac.

Reactive data flows, de­clar­a­tive lay­out, and cross-plat­form sup­port were the key sell­ing points of SwiftUI. Did Apple de­liver on them? Let’s have a closer look.

Data Flow

One of the biggest pain points that con­tin­ues to bother se­nior en­gi­neers, my­self in­cluded, is the data flow. On pa­per, the sin­gle source of truth sounds like a dream. In prac­tice, the re­al­ity is a con­fus­ing mess of prop­erty wrap­pers, macros, and ever-chang­ing sup­port­ing frame­works.

We started with @State, @Binding, and ObservedObjects. Then Apple re­al­ized the per­for­mance was dis­as­trous and SwiftUI was re-ren­der­ing views all the time. That’s when it in­tro­duced the Observation frame­work and the @Observable macro. They tried to solve the prob­lem with com­piler tricks, but it clearly was­n’t enough so the lay­out en­gine con­tin­ued its guess­ing games.

In SwiftUI, you can never know for sure how many times a view will up­date and, when it does, why it chose to. Even us­ing the un­doc­u­mented de­bug­ging APIs does­n’t give you the full pic­ture.

Data flow in SwiftUI is in­deed re­ac­tive—but some­times I wish it was­n’t, be­cause it’s re­ac­tive in all the wrong ways. It of­ten re­acts to changes it should ig­nore, and it ig­nores the changes you ac­tu­ally care about. To me, SwiftUI’s re­ac­tiv­ity is a black box: It makes achiev­ing pre­dictable be­hav­ior al­most im­pos­si­ble.

Layout System

That brings us to the ar­chi­tec­tural side of things. Let’s talk about SwiftUI’s lay­out sys­tem. If you’ve spent any time build­ing non-triv­ial in­ter­faces, you know the frus­tra­tion with SwiftUI. Its lay­out en­gine is in­cred­i­bly un­pre­dictable. It is built on the idea of size ne­go­ti­a­tion, and all this sounds log­i­cal in a keynote, but it feels like a night­mare when you try to build a float­ing view or a cus­tom side­bar.

And speak­ing of cus­tom side­bars. That demo pro­ject from the SwiftUI tu­to­r­ial has a very stan­dard, non-cus­tom one. You build the pro­ject with the lat­est Xcode and launch the app on the lat­est ma­cOS—only to get this. The first time I no­ticed it was over two years ago, and since then, noth­ing has changed.

Ah, sorry, one thing has changed. Thanks to Liquid Glass, the but­tons now also have dif­fer­ent sizes—though it’s hardly a SwiftUI prob­lem.

What is a SwiftUI prob­lem is the over­all fragility of UI lay­outs. They fall apart in the most un­ex­pected ways and at the most un­for­tu­nate mo­ments. You can see it in the very real, pro­duc­tion apps like UTM. It’s a fan­tas­tic piece of en­gi­neer­ing, but its re­liance on SwiftUI some­times makes it feel like an early pro­to­type.

In the end, you find your­self wrap­ping every­thing in a GeometryReader. And this is the ul­ti­mate ad­mis­sion of de­feat. Once you use the GeometryReader, you’ve lost the de­clar­a­tive ben­e­fit en­tirely. Now you have to cal­cu­late co­or­di­nates man­u­ally, with even more ver­bosity than in Auto Layout (which is ironic). And the worst thing is that you might need to rewrite all your co­or­di­nate math in the very next up­date, just be­cause SwiftUI’s lay­out sys­tem has changed again.

API Stability & Feature Parity

Moving on to API sta­bil­ity and fea­ture par­ity—or the lack thereof. If you look at any mod­ern SwiftUI code­base, you’ll find it full of those if #available checks, to the point where it’s al­most com­i­cal—ex­cept it’s ac­tu­ally em­bar­rass­ing. Someone was talk­ing about writ­ing less code and bet­ter code, back in 2019. And what do we have seven years in?

Let’s say you want to dis­miss the key­board on scroll, the same way it worked since iOS 7. Sorry, but you need iOS 16 to do this in SwiftUI.

Okay, maybe you want to let your users cus­tomize the win­dow tool­bar, just as they could since 2001 (or some­thing like that). Well, SwiftUI re­ceived this breakthrough” fea­ture only a few years ago.

And then there’s the most ba­sic task: dis­play­ing im­ages you fetched from the net­work. Well, you bet­ter write your own fetcher, be­cause AsyncImage was in­tro­duced only in iOS 15.

But if you want to also cache those im­ages, I’ve got bad news for you: You can’t do it at all be­cause right now, in July 2026, this API is still in beta.

For all these sce­nar­ios, de­vel­op­ers usu­ally come up with their own hacks and workarounds. And when Apple fi­nally de­liv­ers the API that ex­isted in AppKit or UIKit for decades, you have to main­tain mul­ti­ple im­ple­men­ta­tions.

But even if the API you use was in­tro­duced in the very first ver­sion of SwiftUI, there’s a good change it’s been re­named or re­placed with a sim­i­lar one. One ex­am­ple is the NavigationView. It was known for be­ing su­per buggy. And it seems that in­stead of fix­ing it, Apple de­cided to re­place the en­tire com­po­nent with the NavigationStack. But this, again, means that you have to keep sep­a­rate branches, for newer and older ver­sions.

So, is that less code” or better code?” You tell me be­cause I kind of don’t know.

This con­stant API turnover re­sults in de­vel­op­ment hell. Instead of de­clar­ing the UI struc­ture once, we have to write shims and patches for com­pat­i­bil­ity, and then we have to hope that they would­n’t break apart in the next up­date. We’re ba­si­cally do­ing Apple’s QA work for them.

All these prob­lems should’ve been solved in 2019—okay, maybe 2020. Yet even af­ter seven years, SwiftUI has­n’t achieved fea­ture par­ity with the legacy” frame­works. SwiftUI is just run­ning around in cir­cles, and we have to run along just to stay in the same place.

But you know what? None of this would’ve been such a big prob­lem—but only if Apple did­n’t pre­tend that SwiftUI is rock-solid and built for ages. This would­n’t have been a prob­lem if you could just write code call­ing the lat­est APIs, and then back-de­ploy it to older ver­sions of iOS. Yes, you’d still have to refac­tor and phase out old code more fre­quently. But at least the cur­rent ver­sion would work con­sis­tently on all de­vices.

It is the way mod­ern UI works on Android: Jetpack Compose is just a pack­age that you get and up­date through a de­pen­dency man­ager. Then it’s sim­ply bun­dled with your ex­e­cutable and can be used on de­vices as old as 2014—all while de­liv­er­ing the ex­act same UI.

Performance

Let’s talk about per­for­mance. This is where you can’t fool any­one—even though Apple still tries by only show­ing SwiftUI run­ning on the lat­est hard­ware. But the fact is, SwiftUI’s per­for­mance is just not up to the stan­dard, no mat­ter how many times Apple has promised to im­prove it. It is not what I ex­pect from a first-class frame­work” run­ning on a premium plat­form.”

For ex­am­ple, here’s my own head-to-head com­par­i­son of UIKit and SwiftUI. The test is a sim­ple im­age gallery used in the pre­vi­ous ver­sion of my play­ground app.

Why pre­vi­ous? Because I have since re­built the en­tire app us­ing the ul­ti­mate cross-plat­form frame­work. But that’s a story for an­other time.

So, de­spite all the per­for­mance hacks, like de­cod­ing im­ages on back­ground threads, scrolling the SwiftUI grid con­sis­tently feels much less smooth. Needless to say, if you have to keep in mind some ob­scure op­ti­miza­tion se­crets just to make it work, all the ini­tial sim­plic­ity of SwiftUI goes out the win­dow.

It’s only one of the tests I per­formed, and I de­lib­er­ately used an older iPhone for it. But it should­n’t make any dif­fer­ence, be­cause if you need an M5 Pro Max su­per chip just to show a bunch of JPEGs, there’s some­thing se­ri­ously wrong with your en­tire ar­chi­tec­ture. That’s not how you build high-qual­ity soft­ware; it just does­n’t work like that.

Cross-Platform Myth

This brings us to the fi­nal promise of SwiftUI—its cross-plat­form sup­port. I watched a few old SwiftUI keynotes, and to be fair, I did­n’t hear the words write once, run any­where” in any of them—it’s usu­ally learn those tools once, and then ap­ply them every­where.”

There’s but one prob­lem. What you learned about SwiftUI on iOS is rarely ap­plic­a­ble to lay­outs on the Mac. That is, un­less you want to end up with UIs that feel alien, like those iPad apps that Apple brought to the Mac (yeah, these apps).

Yes, the core SwiftUI con­cepts, like data flow and com­po­si­tional lay­out, are roughly the same. But the spe­cific com­po­nents you use, and the way you con­fig­ure them, are of­ten very dif­fer­ent. Not to men­tion, the very same views can have in­con­sis­tent im­ple­men­ta­tion across plat­forms.

In other words, UI de­sign for a 6-inch phone and 27-inch desk­top is not the same. Who would’ve thought?

In my ex­pe­ri­ence, SwiftUI’s learn once, ap­ply any­where” of­ten turns into learn once, learn twice, ap­ply some­where, de­bug every­where.”

That is, of course, if you’re in­ter­ested in build­ing UIs that look na­tive and pro­fes­sional. If not, SwiftUI can ac­tu­ally give you re­sults that will do” or re­sults that are good enough.”

Philosophical Shift

And ac­tu­ally, I view this good enough” thing as the biggest prob­lem here. I be­lieve it serves as a sign of a ma­jor shift in Apple’s en­tire ap­proach to soft­ware de­vel­op­ment. With SwiftUI, we’ve en­tered an era where some­thing that mostly works” is con­sid­ered ad­e­quate. Or an era where cov­er­ing only 90% of use cases is con­sid­ered a suc­cess. The ex­pec­ta­tions of pro­duc­tion-grade qual­ity and sta­bil­ity gave way to so-called ve­loc­ity—which is a word you use when you want to ship garbage, only do it faster.

In the days of Cocoa, that was un­think­able. In the early days of Mac OS X, that would’ve been a dis­as­ter. Can you imag­ine a SwiftUI ver­sion of that orig­i­nal Aqua keynote? Imagine for a sec­ond that in­stead of liquid” but­tons that look so good you’d want to lick them,” Jobs pre­sented flick­er­ing side­bars and jump­ing but­tons. He would’ve been roasted.

But now, it seems that we’re set­tling for good enough” prod­ucts and it will do” men­tal­ity. This is the stan­dard of crafts­man­ship I’m not ready to ac­cept.

And it’s not just a sin­gle frame­work is­sue. It’s a sys­temic shift. First, one com­pany starts a trend on moving fast and break­ing things.” Gradually, more de­vel­op­ers join it; not all of them move fast, but ship­ping bro­ken things be­comes nor­mal­ized, even in first-party apps and sys­tem com­po­nents.

For in­stance, Apple Music has for years had this bug where edit­ing the queue would make the track list jump and then play an en­tirely wrong song.

TestFlight crops the se­lec­tion with no padding.

The Settings app on the iPad shows crash re­ports like this, and even though I took this screen­shot back in January, it has­n’t been fixed up un­til now.

The Home Screen shows du­pli­cate icons for the same app. And it makes the sta­tus bar jump back and forth. And it shows out­lines for icons that should­n’t be dis­played.

And even pro­fes­sional apps like Logic Pro now ship with miss­ing lo­cal­iza­tion. You know, those pro­fes­sional apps that are sup­posed to be the bench­mark of qual­ity and sta­bil­ity.

I can go on for a long time.

While not all of these ex­am­ples use SwiftUI, they demon­strate the level of qual­ity that Apple con­sid­ers acceptable” now. I did­n’t have to dig deep to find them; these are the things that I per­son­ally saw in the past few months.

So with these ex­am­ples in mind, it’s not sur­pris­ing that the flag­ship sys­tem frame­work makes it nearly im­pos­si­ble to build an app that’s not bro­ken in at least one way.

On Apple plat­forms in par­tic­u­lar, this shift be­gan around 2018, with those alien” apps I al­ready men­tioned. It’s when Project Marzipan, later re­named Catalyst, first en­abled UIKit code to be reused on the Mac. Tech re­view­ers tore apart the re­sults, and here’s more screen­shots.

But in­stead of do­ing the home­work, Apple dou­bled-down on the idea of cross-plat­form de­vel­op­ment, with SwiftUI. And this brand-new, com­pletely untested frame­work only in­tro­duced more is­sues with per­for­mance, sta­bil­ity, and vi­sual ap­peal.

I con­clude that low­er­ing the bar for qual­ity was a choice, not a ne­ces­sity. I refuse to ac­cept that choice. And that is why I can’t trust SwiftUI even af­ter seven years.

Summary

As a bot­tom line, and to an­swer the ques­tion from the be­gin­ning, what is ac­tu­ally wrong with SwiftUI?

If you weigh in all the prob­lems that haven’t been fixed in the seven years of its ex­is­tence, the an­swer is,

Everything.

Or at least every­thing that’s im­por­tant for build­ing sta­ble, per­for­mant, and main­tain­able sys­tems.

The story of SwiftUI is a story of medi­oc­rity and falling stan­dards. We’re of­fered to trade pre­dictable pre­ci­sion for an il­lu­sion of con­ve­nience. And then we’re forced to ei­ther spend the time de­bug­ging the frame­work, or ship bro­ken apps as is.

As a se­nior en­gi­neer, I find nei­ther of these op­tions ap­peal­ing. I don’t re­spect the it will do” mind­set, and I be­lieve that users de­serve bet­ter than good enough.”

SwiftUI is not truly bad. It’s mediocre. And that, in my opin­ion, is much, much worse.

So for now, I still pre­fer the legacy” UI frame­works.

Afterthought

The idea of this piece came to me even be­fore I started this chan­nel. For years, I’ve been ob­serv­ing SwiftUI’s strug­gle to be­come a solid re­place­ment for AppKit and UIKit—in other words, to be­come what Apple promised it to be, all the way back in 2019.

For years, I’ve been test­ing SwiftUI’s new it­er­a­tions in the hopes that the prob­lems that plague it will fi­nally get fixed.

But as the time goes by, SwiftUI’s not be­com­ing bet­ter in a fun­da­men­tal way. It’s just as half-baked as it was seven years ago, and apps built with SwiftUI mostly turn out just as un­re­mark­able.

But SwiftUI’s strug­gle is not the only thing I’ve been ob­serv­ing. I’ve also been ob­serv­ing soft­ware en­gi­neers who sin­cerely be­lieved that if a fea­ture built with SwiftUI works right here and right now, then their job is done. Unless they choose the in­fe­rior tools on pur­pose, I don’t re­ally blame them.

Well, maybe a lit­tle, be­cause you can’t ig­nore the long-term cost of main­te­nance with­out pay­ing the price.

Anyway, in­di­vid­ual en­gi­neers aren’t usu­ally the ones who pay it; their em­ploy­ers are. But in the times when busi­nesses are ob­sessed with re­plac­ing hu­mans with AI agents, it’s hard to ex­pect the qual­ity of their prod­ucts to im­prove. And be­cause these are also the same busi­nesses that view soft­ware de­vel­op­ment as a com­mod­ity or lin­ear pro­duc­tion, they typ­i­cally want to ship fast” in­stead of right.” We can al­ready see the re­sults of this ap­proach, and we’re go­ing to see more in the fu­ture.

Outro

That’s it for to­day’s Code Bird video, but I am very in­ter­ested in your opin­ion, es­pe­cially if you dis­agree with me. I would love to read your com­ments down be­low.

Give this video a thumbs-up if you feel it de­serves one. Subscribe to the chan­nel for more en­gi­neer­ing con­tent.

I’ll see you in the next video. Until then, make your tools fly.

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.