Getting my TOTP data out of Twilio's Authy app thanks to the GDPR
blogccasion
blog.tomayac.com
2026-10-17 13:21:12
As every responsible Internet user, I use two-factor authentication (2FA) for my important accounts. For a long time, I depended on Google's Authenticator app, but because early versions of the app weren't backed up to the cloud (not a problem anymore) and because as a Google Android dogfooder I sw...
As every responsible Internet user, I use
two-factor authentication
(2FA) for my important accounts. For a long time, I depended on Google's
Authenticator
app, but because early versions of the app weren't backed up to the cloud (not a problem anymore) and because as a Google Android dogfooder I switch devices frequently, I turned to Twilio's
Authy
, which at the time already supported cloud backup and cross device synchronization. Authy has both iOS and Android apps, and also offered a desktop app, but for whatever reason they shut down the desktop app three years ago.
Now every time I needed a token, I had to get one of my phones out. Annoying, but not annoying enough for me to actually switch away from Authy. I have 33 accounts in there, and unfortunately Authy offers no export option. For a while, you could hack your way to your data by installing an old version of their desktop app and sniffing the network traffic, but they eventually patched that loophole. Modern Android and iOS versions (for good reason) also make it incredibly hard to sniff mobile traffic, plus I have corporate devices that prevent me from installing the required apps and certificates.
So my data was locked into Authy, with my choices being to just be lazy and stick with it, or bite the bullet and set up 2FA again for each account. Guess what I did! Correct, I entered each account one by one, turned off 2FA, set it up agai… Haha, LOL, of course I did not. I stuck with Authy and walked to one of my phones like a Neanderthal every time I needed a token.
Until I remembered that under the European Union's 🇪🇺
General Data Protection Regulation
(GDPR), I have the right to request my personal data from any service provider, including Authy. If you live in the EU, you have, too. Here's the request I sent to Twilio (
privacy@twilio.com
) to get my TOTP data out of Authy:
Dear Twilio Privacy Team,
I am a resident of [Your EU country] and a user of the Authy application. Under the EU General Data Protection Regulation, I am exercising my right of access (Article 15) and my right to data portability (Article 20) with respect to the personal data you process about me.
Please provide a complete copy of all personal data associated with my Authy account, identified by:
I specifically request that your response include the stored authenticator data for my account, namely the encrypted TOTP token seed values together with any associated salts, initialization parameters, and key-derivation parameters required to decrypt them, and, for each token, the issuer or account name, the number of digits, the period, and the algorithm. Please also specify the encryption scheme used to protect the token seeds, including the cipher and mode, the key-derivation function, its iteration count, and the hash function. The token seeds are stored encrypted under a password known only to me, and I am asking for that encrypted data as you hold it, so that I can decrypt it myself.
Under Article 20, please provide the token data in a structured, commonly used, and machine-readable format, for example JSON.
Please confirm receipt of this request and respond within one month, as required by Article 12(3). If you consider any part of this request unfounded or excessive, please explain your reasoning for each element rather than declining as a whole.
Thank you.
Kind regards,
[Your name]
They came back quickly, asking for the following verification details:
All current and past email addresses associated with the Authy account.
All current and past phone numbers associated with the Authy account.
A confirmation code sent through text message to the number linked to the account, which should be sent back with the reply.
I responded with the requested information, and a few weeks later they sent me a link to a secure file transfer on
twilio.sendsafely.com
and let me download two CSV files with the data. One was an
Authy Personal Information Request - Exported Tokens (1).csv
file with the columns
name
,
encrypted_seed
,
salt
, and
iv
. The
name
is just the name of the token I had chosen. The others are explained below.
encrypted_seed
: The actual TOTP secret (the seed used to generate 2FA codes), encrypted so it's unreadable in plain text.
salt
: Random data mixed in when deriving the encryption key from the encryption password (prevents precomputed "rainbow table" attacks and ensures the same password doesn't always produce the same key).
iv
: The random value (initialization vector) fed into the cipher itself, ensuring that encrypting the same seed twice (even with the same key) produces different ciphertext each time.
The other file,
Authy Personal Information Request - Authy Personal Information (2).csv
, was a text file (despite the
.csv
extension) with CSV-ish metadata about my account and its associated tokens.
,,,,,
User Information,,,,,
Phone number(s),"(+49) [REDACTED]
",,,,
E-mail (primary and secondary),"[REDACTED], [REDACTED]",,,,
"Last Sync (The last time one of your devices communicated to Authy)
-Time is in UTC","Oct 10, 2026 - 06:37
",,,,
"Used at (The last time you verified an Authy TOTP token)
-Time is in UTC","Jun 01, 2018 - 10:27
",,,,
"Created (When the Authy user was created)
-Time is in UTC","Jul 06, 2017",,,,
,,,,,
Devices linked to the Authy user,,,,,
Name,Created,Device Creation IP,User agent,Device ID,Last sync
Android,"Sep 30, 2019",[REDACTED],Dalvik/2.1.0 (Linux; U; Android 10; Pixel 3a Build/QQ1A.190919.002) Mobile,[REDACTED],"Sep 18, 2021"
[SNIP]
Android,"Jun 23, 2026",[REDACTED],Dalvik/2.1.0 (Linux; U; Android 17; Pixel 11 Pro Fold Build/CD1A.260612.002) Mobile,[REDACTED],"Oct 10, 2026"
,,,,,
Authy native tokens,,,,,
ID,Name,Email,Cellphone,Member/Owner,
[REDACTED],Twilio,[REDACTED],[REDACTED],Member,
,,,,,
Authenticator tokens,,,,,
Name,Logo,Created at,Updated at,,
GitHub:tomayac,GitHub,"Jul 17, 2025","Jul 17, 2025",,
[SNIP]
I threw both files at Claude and asked it to create me a
TOTP Vault PWA
that going forward I can use on all of my devices, desktop or mobile, with the TOTP data backed up to a private GitHub repo. After a few iterations back and forth with the LLM, I can now scan QR codes and add new TOTP tokens seamlessly using the
Barcode Detector API
. The app is fully offline capable thanks to
Service Workers
. It looks almost like a native app because I use
Window Controls Overlay
. Each TOTP line has a guessed (but overrideable) icon provided by
Icon Horse
. And it is
my
PWA with features tailored to my needs, like always sorting entries by most recently used, a search input that clears after copying the token, plus, of course, token import and export functionality for all possible providers and standards:
Bitwarden / Vaultwarden:
Unencrypted JSON for importing data in
Bitwarden
/
Vaultwarden
. I use Vaultwarden as a backup on my devices.
otpauth links:
An unencrypted text file with one
otpauth://
link per line, for apps like
Ente Auth
.
Encrypted vault
(not really a standard, but what I use for my backups): A CXF document inside a
JSON Web Encryption
envelope, locked with my password. Yes, the below screenshot is redacted to not show any sensitive TOTP data like the actual account names or the token values (though the latter is really just me being a
tin foil hat
, it's totally unnecessary).
It's kind of sad that I had to use the
GDPR
sledgehammer to get my own TOTP data out of Twilio's Authy, but at least now I have full control over it, and I'm, once more, thankful that the GDPR exists. I would also like to credit Authy for dealing very professionally and promptly with my data request.
Chrome and Edge are removing XSLT: what breaks and what does not
What's going with the pointer arithmetic here? Why is it indexing
out-of-bounds?
The first thing to notice is that m2c doesn't really take into account
that arithmetic on pointers in C is multiplied by the size of the element.
And obviously, spE10 is the root of some array. So corrected, this reads:
We saw yesterday how we should rewrite the iteration back to a for loop,
but also, most likely, the pointer arithmetic here came from
strength
reduction
; the compiler took a multiplication operation and rewrote it
to a “weaker” operation (subtraction) since that's typically cheaper,
at the cost of making the values dependent, an easy trade. So we can
rewrite it back into multiplication:
and now it's easy to see that the loop should read:
for (i = 0; i < 0x80; ++i) {
spE10[i] = 0;
}
and then, of course, the array should get a better name.
Sometimes the loop counter will go backwards while the pointer will go
forwards, which is also completely normal, especially if there's side
effects. The compiler will reverse one but not the other.
Microsoft and CMU Team Up to Train Early Career Software Engineers
In between classes on machine learning and software engineering, Jace Watson isn't heading back to his dorm or finding a quiet place to study somewhere on Carnegie Mellon University's campus.
That's because Watson isn't even in Pittsburgh. He's in Seattle, working at his full-time job as a software engineer at Microsoft and taking classes through the
Preceptorship for AI-accelerated Software Engineering (PRAISE) program
, which CMU and Microsoft launched to train early career software engineers for the rapidly changing computer science landscape.
"When I started undergraduate, it was the beginning of AI being something that everybody had access to on their own computers. As I got closer to graduation, it started becoming clear how big AI tools would be in the workforce, but using AI wasn't a huge part of my education," Watson said. "When I joined Microsoft, these tools were part of my day-to-day, and I wanted to make sure I knew how to fully take advantage of them, which is why I sought out the additional education opportunity through CMU and Microsoft."
CMU and Microsoft launched the Preceptorship for AI-accelerated Software Engineering (PRAISE) program to train early career software engineers for the rapidly changing computer science landscape.
The CMU/Microsoft PRAISE program offers early career Microsoft employees a chance to take online courses in CMU's Kenneth C. Griffin School of Computer Science while receiving hands-on mentorship at the company. At Microsoft, selected early career engineers, or preceptees, work with senior engineering preceptors to build AI-accelerated software engineering skills through structured guidance, mentorship and application to their day-to-day Microsoft work. Participants can also enroll in SCS classes focused on software engineering and artificial intelligence.
"This partnership with Microsoft is about providing the Griffin School of Computer Science's high-quality computer science learning to people who aren't in the traditional education system but are seeking guidance to navigate a rapidly changing landscape," said
SCS Dean Martial Hebert
. "SCS and Microsoft recognize that we all have a part to play in supporting and readying the nation's workforce, and the CMU/Microsoft PRAISE program is an innovative step in that direction."
The idea for the program came about following CMU alumnus Mark Russinovich's (ENG 1989, 1994) visit to SCS in October 2025. The chief technology officer, deputy chief information security officer and technical fellow for Microsoft Azure spoke about how AI tools help senior engineers, but noted that the same level of benefit isn't available for junior engineers.
"AI changes the work, but it doesn't eliminate the need for junior engineers or for human judgment and accountability," Russinovich said. "By combining Microsoft's engineering experience with CMU's academic expertise, PRAISE offers a model we're proud to lead and hope others in industry and academia will adopt."
From that discussion, SCS and Microsoft began considering how education could help junior engineers overcome the challenges of using AI in the workplace.
"It used to be that early career software engineers would do a lot of tasks that would build up their expertise," said
Michael Hilton
, a teaching professor in CMU's
Software and Societal Systems Department
(S3D). "Combining forces between academics and practitioners allows us to bring our expertise together and create solutions that draw on computer science research while standing up to the daily realities of software development."
This semester, Microsoft employees enrolled in the CMU PRAISE certificate program are taking Machine Learning in Production and Preceptorship in AI-Augmented Software Engineering I. These classes train students on how to incorporate machine learning into the software they write and to use AI tools while developing that software.
"That judgment for when to use AI should be viewed as ongoing education, which is why we're partnering with Carnegie Mellon University on curriculum as part of the PRAISE program," Microsoft wrote in their announcement of the partnership. "The intent is to set students up for success in the workplace and accelerate preceptees with formal curricula to complement the guidance from the preceptor on how to build and deliver with confidence."
In the spring semester, students will take DevOps: Engineering for Secure Development and Deployment and the second half of the Preceptorship in AI-Augmented Software Engineering course sequence. These courses can be applied to a master's degree in software engineering, allowing students to further their learning at SCS. CMU hopes to grow the program and add more students to the certificate program, perhaps one day opening the door to other industry partners.
"I am tremendously excited about the impact this program will have on junior engineers at Microsoft," said
Jonathan Aldrich
, an S3D professor who directs the PRAISE certificate program. "With so many companies worldwide faced with upheaval due to AI in software development, I believe this program will become a template for rapidly leveling up new developers across the industry."
Au Jus on the Upper West Side had a Marshal’s sign posted on its window in the lead-up to its official closure. Photo by Sara Lewin Lebwohl.
By Gus Saltonstall
The owner of a former barbecue restaurant on the Upper West Side has been indicted for wage theft, Manhattan District Attorney Alvin Bragg announced on Thursday.
Patrick Griffin, 71, was indicted for allegedly stealing at least $8,000 in wages from five of his employees, according to the DA’s office.
Au Jus, the Oklahoma-style barbecue chain, had three New York City locations, including at 2621 Broadway, on the corner of West 99th Street. All three are now closed.
“As alleged, Patrick Griffin, owner of the popular Au Jus restaurant, took advantage of his workers and stole their hard-earned wages while they provided physically demanding labor,” Bragg said in a news release. “Griffin was allegedly vacationing in Europe while his employees were begging him for their money that they earned and need to support their families.”
Au Jus’s
Upper West Side location closed
in September of 2025, after the front door was boarded and a Marshal’s Notice was posted on the front door. The neighborhood outpost opened in 2020.
Griffin allegedly engaged in a “pattern of wage theft against his workers” beginning in January 2025, and ignored messages and blocked phone numbers when those employees followed up for their payment, according to the Manhattan DA’s office.
Depictions of Texts from Workers to Griffin. Courtesy of the Manhattan DA’s Office.
“Griffin told a former employee that he would not be paid unless he and his coworkers returned to work at the restaurant. When the worker returned to work, Griffin continued withholding his wages, and the worker was forced to leave again,” the Manhattan DA’s office wrote. “In another instance, Griffin demanded that a worker sign a document that falsely claimed he did not have government-issued identification. When the worker refused to sign the false document, Griffin withheld his wages.”
After the unsuccessful attempts to recover the wages, employees reported Griffin’s conduct to the Worker Protection Hotline, which led to the Manhattan District Attorney investigation.
Griffin is officially charged with grand larceny in the third degree by wage theft, scheme to defraud in the first degree, and failure to pay wages in accordance with the labor law.
Subscribe to West Side Rag’s FREE email newsletter
here
. And you can Support the Rag
here.
Leave a comment
Please limit comments to 150 words and keep them civil and relevant to the article at hand.
Comments are closed after six days
. Our primary goal is to create a safe and respectful space where a broad spectrum of voices can be heard. We welcome diverse viewpoints and encourage readers to engage critically with one another’s ideas, but never at the expense of civility. Disagreement is expected—even encouraged—but it must be expressed with care and consideration. Comments that take cheap shots, escalate conflict, or veer into ideological warfare detract from the constructive spirit we aim to cultivate.
A detailed statement on comments and WSR policy can be read
here
.
Most of my losing bets, in both business and investing, were driven by
narrative
reasoning: s
hort compelling stories about the world that sound smart.
“Marijuana is about to be legalized in Canada. This is a rare opportunity to invest at the ground floor of a new industry.”
“I’m going to invest in a cobalt mining company because they won a contract with Tesla.”
Before we launched
Spellbook
, we thought: “Let’s launch Shopify for Lawyers, because hourly billing lawyers care more about getting business than efficiency”
We love stories. Narratives are like a virus and a mind-altering drug. When they hit our ears we feel: “Ah! That makes sense”. They add clarity in an overwhelming world. And then we feel compelled to share the story with others. The clarity felt good and we want to share that feeling. More importantly, sharing the story makes us feel smart.
This contagiousness makes narrative reasoning extremely dangerous. Because simple stories often make horrible bets.
Concise stories don’t work well to drive action in the real world, because the real world is so
multi-causal.
There are hundreds, or even millions of factors that cause a bet to have a good outcome.
Imagine the best chess AI engine in the world: for any board state, it has to consider hundreds moves, and then a huge number of branching futures. Great chess engines can’t simply use narrative reasoning like: “a good offense is the best defense” to win. These engines are more like spreadsheets: massive matrices of numbers and probabilities. They can make moves that are impossible for us to comprehend using language-based reasoning.
The worst part? Real life is
way
more complex than chess.
From this we can conclude that the
most optimal
way of strategizing about the world is definitely not by using a short sequence of words.
Raw reality is not very
legible
. That is, it’s not simply structured and easily comprehensible by us. Although narratives make us comfortable, they’re not enough to capture the essence of reality. Reality is messy.
One of the most impactful things I’ve ever read is Venkatesh Rao’s “
A Big Little Idea Called Legibility
”. It talks about how we are drawn to orderly, legible systems—but how those systems often fail. We even tear up messy, working systems, replace them with nice orderly systems, and see the order fail terribly. We put too much value on legibility. Let’s call this
legibility bias.
For instance, in the image below there is a legible “scientific forest” and an illegible organic forest. “Scientific forests” were a failure, even though their legible structure made us feel confident in the approach. Messy illegible forests remain successful.
Why does legibility bias persist across society, even when we are aware of it? One answer is: it soothes people. We are conditioned from kindergarten onwards to believe that there is a crisp, clear structure to the world. That there are crisp
reasons why things happen.
In the world of startups, that illusion is demolished if you stick at it long enough. But large organizations “cast the illusion” of legibility to soothe and create a sense of order among employees, while those in the inner circle of upper management face messy reality head-on.
Also in organizations, communication bandwidth means that you need crude, simple stories to get the ship headed in the right direction. Simple stories are a necessary evil in management. But big decisions at the top of an organization are not
actually
being made this way. Simple stories are a tool to motivate and direct people in approximately the right direction.
If someone has spent years at a large company, and has not been in the “inner circle” of management—it is easy to see how they might confuse the tool that is being used to motivate them with the process in which effective decisions are actually being made.
People misunderstand the utility of simple stories. They’re more of a management tool, a political tool, a motivation tool, and a marketing tool than a
decision making tool
.
Good bet making is about “finding alpha”. That is, betting on opportunities that others have underestimated. Since humans have a strong
bias for legibility
, highly legible bets get bandwagoned.
For example: “Since marijuana just got legalized in Canada, I’m going to buy $WEED stock to get in at the ground floor of a new industry”
Here’s how that worked out:
Even if these narratives
are
correct, they are too visible to markets and get quickly over-bought. In other words: The stock price gets too high before you make your bet. Or too many competitors get to the business idea before you. Or too many musicians make similar sounding songs. This reasoning works across any competitive domain.
A really good place to find bets that are underestimated is in the illegible.
If stories don’t work, how do we survive at all in a world so complex and multi-causal? Well, simple stories can work for basic survival: “I need to eat to survive”.
But to find good bets that others don’t see, we need to leave crisp stories behind and think more like a chess engine. We need to digest raw hyper-dimensional reality. But how do we do that without putting our situation into a 100,000 x 100,000 spreadsheet?
The first answer is:
intuition
.
We already have 86 billion neurons in our brain that are doing something similar to a chess engine. We can’t see exactly how it works, but it can send us much more valuable signals about the world than narratives do. If we digest enough data, our brain starts pattern matching automatically. Pattern matching is how we position ourselves to throw a basketball and recognize our friends faces. Those are not things we think about in words.
Our brains are really good at pattern matching without using words.
Running fast using intuition to make decisions can be extraordinarily effective.
But what if our intuition is bad? What if our intuition differs from that of our team?
That’s a lot of words to say: “trust your gut!”. But what if you haven’t developed intuition? Or what if your intuition disagrees with the intuition of your team?
There is a slightly more legible approach that I’ve found effective:
Look at your past bets and ask yourself: what are the 10-20 attributes that mattered? List them out, and then go through each of your winning and losing bets, noticing which attributes they had.
We did this for all the product feature bets we made at Spellbook, and were able to correlate 16 attributes with what made a successful product bet. And many were surprising.
Almost none of our correlated attributes had to do with the narrative of the feature itself. We discovered a bunch of other things that mattered:
Can a lawyer get value from the feature instantly with absolutely zero configuration?
Was someone on the team so inspired to build something that they “started without permission”?
Is the feature “whole” rather than a stepping stone to get somewhere else?
Can the feature be fully prototyped in 2 weeks?
We ended up with a framework that is a middle ground between legible, narrative based reasoning and intuition. And the best part is we could objectively score prospective bets in this framework.
It brings us a little closer to reasoning like a chess engine. These signals increased our hit rate significantly when we used to not hit at all.
For years we had been listening to the gospel: “talk to your customers! Build what they ask for!” This was helpful, but it had an catastrophic blindspot that was causing us to make losing bets for years.
We were missing an entire universe of patterns outside of the tunnel vision of stories.
This approach also helped dramatically improve my performance in investing.
When I started noodling in active investing almost 20 years ago, I relied on narrative “reasons” and news headlines to make bets. My active portfolio produced neutral returns for nearly 10 years (adjusted for inflation, that’s a big loss). Those narratives simply didn’t capture the thousands of factors that impacted stock price. And if they did: well everyone else was jumping on the same bandwagon and pushing up the buy price where the bet became too expensive to make sense.
Over the last 9 years I switched to a pattern matching approach. My active portfolio has performed ~20x better than my passive portfolio over that period.
To improve my ability to pattern match, I really like to “soak” in data. I read lots of charts and try to make written predictions on them regularly. I check back on how my predictions fared. Eventually making trades started to feel like throwing a basketball. My brain started to develop a deep intuition for technical and fundamental signals, and how they combine to make a “swish”.
Pattern matching is not hard. Our brains are wired to do it. The hard part is being independent-minded enough to believe your own conclusions.
To do that, you need to escape the universe of simple stories we are surrounded by. Stories are the threads that hold society together. We are fish and stories are our water. Repeating popular stories grants us head nods and social acceptance.
For example, “You can’t beat the market, dollar-cost average into index funds!” is the kind of viral story that will earn you nods of approval from millennials and upvotes on Reddit.
Pattern matching, on the other hand, can drive you to make moves like an advanced chess engine. Moves that others find alien and incomprehensible.
If your bets don’t generate some confused looks, they’re probably too obvious, and thus overdone.
“To believe that what is true for you in your private heart, is true for all men,—that is genius” —Ralph Waldo Emerson,
Self-Reliance
‘AI’ is not a neutral tool. It is a tool of a society that has given up. By its developers’ own admission, ‘AI’ is meant to enable control of population that subverts, and overpowers, all existing political apparatuses, and which, by design, is meant to substitute people’s capacity to make their judgements. If anyone is deluded in their misplaced optimism, it’s the ‘AI’ users and promoters who think they can plug themselves into this massive thing and use it to their advantage,
without being dominated by it
, not us who recognise that ‘AI’ can (and must) be abolished. If we muster
just a fraction
of the faith that ‘AI’ boosters allocate to ‘AI’, and put this faith into a revolutionary project instead, that would be enough to change the world. We just need to convincingly argue for such a (re)allocation.
In short, working towards ‘AI’ abolition is working towards liberation. But what exactly do we mean by that?
Abolition means working towards a liberatory alternative.
Abolition as a political project is most famously associated with the abolition of slavery. The political project of abolition identifies an
oppressive institution
that it wants to eradicate (in this example, slavery); and importantly, also, the project of abolition suggests a
positive worldview
(in this example, a vision of the future where humans treat each other equally and do not dehumanize and enslave each other). Taking an abolitionist perspective is
not
(or at least not primarily) being
against
an oppressive institution; taking an abolitionist perspective is being
in favour of a liberatory alternative
to an oppressive institution.
Other abolitionist projects follow this logic, too: prison abolition works towards restorative justice
as an alternative
to the carceral system; police abolition works towards nonviolent public safety
as an alternative to
the police (and/or policing) state; family abolition words towards community care
as an alternative
to normatively imposed heteropatriarchal nuclear family structures.
As AI abolitionists, we place ourselves in the context of other liberatory struggles against oppressive institutions and in favor of humane alternatives. AI abolition works towards
a revolution from the left
as an alternative to
global technofascism
.
Many proponents of the abolitionist movements mentioned above – abolition of slavery, prisons, police, and family – come to the conclusion that their abolitionist project is not possible within a capitalist system. The same is true for AI abolition. We believe that the abolition of AI is only possible if it goes hand in hand with the abolition of capitalism.
At this point in the text, since, as the famous saying goes, “it is easier to imagine the end of the world than the end of capitalism” (
Frederic Jameson
), it is worth reminding ourselves that not only are alternatives
imaginable
; they are also
feasible
and
realistic
, as for the most of human history — for the absolutely longest time of our human existence on earth — we humans lived without slavery; lived without prisons; lived without police; lived in communities without cisheteropatriarchal norms; and lived without AI.
While we argue about what “AI” really means, real harm is being done.
Whole books and articles have been written, and will be written, about “what exactly” AI is. While these discussions are interesting, they are also beyond the point for our abolitionist purpose here; arguing about competing definitions of AI is distracting our eyes from the actual prize:
an urgently needed revolution from the left
. The good news is that we do not need to go through all of the small print in order to start working towards that
positive worldview
. This is also reflective of reality: since “AI” means different things to different people, you are invited to join the struggle — no matter if you are fighting against…
AI as a set of technologies;
AI as marketing term rooted in eugenics;
AI as a product with for-profit promises that are failing to materialize;
AI as a misconception of what computers can do;
AI as a cultural practice of outsourcing our thinking;
AI as floating signifier;
AI as a political argument for the extraction and appropriation of vast material resources;
and the list continues.
What all of these definitions of AI have in common is that
enormous harm is being done
in the name of
“AI”
.
[here could be inserted the typical laundry list of: the planet, the data privacy, the enshittification, the resources, the acceleration of work, the inhumane working conditions for data labellers, the damage to education, the detrimental psychological effects on people, the gigantic natural resources consumed, the gigantic dual use notjustpotentialbutactualuse see warfare in Gaza and elsewhere, the makingpeopledependentonithencelessawareof the issues, etc.]
Of course, technology is never neutral. And we do not buy into singularity narratives into “AI” bringing human beings closer to God, or the Devil, or both. So, what makes AI
not
just “yet another technology, and why don’t you go abolish the telephone and the printer if you hate technology so much?”, is
the enormous scale at which the term is being used to do harm in the name of some diffuse technooptimist future
. The harm done in the name of AI is much, much, much larger than any of the supposed benefits brought about by AI. And do not fool yourself at this point (just like we do not want to fool you): it is not enough to try to figure out how to “mitigate the harms while exploiting the benefits”. We can see that all of the harms done in the name of AI are integral part of AI; and are integral parts of capitalism. As such, there is no ethical AI, and never will be; and there is no AI abolition under capitalism.
You can take action, now.
It is easy to feel overwhelmed by the magnitude of the issues. Feeling overwhelmed, however, is not the same as being paralyzed. Even when you feel overwhelmed, you still have the agency to act. We collected here a list of actions you can take, from the smallest to the most involved, sorted more or less by magnitude of efforts needed.
Tips to improve your wellbeing
You can abolish AI in your own life. Starting today.
Most importantly: find your people. And support each other. None of this can be carried by one single individual; we all need community to support and sustain us.
Stay with the trouble: In a dehumanizing world, embrace the human experience.
Ask yourself, not “AI”.
Ask other people, not “AI”.
Find out more about the topic: learn & disseminate knowledge about the narratives that make AI seem “inevitable” or “unavoidable” even as these same narratives serve to perpetuate oppression, slavery, de-skilling, authoritarianism and ecological breakdown on a planetary scale.
Find analogue activities to replace your volunteering your time feeding the BigDumbRobot (aka, do more of what you actually enjoy, instead of scrolling through Instagram or conversing with ChatGPT)
Re-skill and up-skill yourself by phasing out tech crutches (like on-the-road access to your emails, 24/7 online availability for communication, GPS navigation) by working on your planning, organizing, navigation and community-building skills
Find like-minded people, gather in real life, and organize together
Stand up and speak up: instead of being part of the discursive normalization, be part of the critical voices who ask foundational questions
Stretching exercise: “reach up and out”. Reach up to the people you can reach that are the highest up in the decision making hierarchy at your workplace, in your community. And reach out to the people that are not (yet) part of your social environment: talk to acquaintances, strangers, the media.
Organize demonstrations and strikes (see Pull the Plug in the UK)
Organize conferences (see Cables of Resistance in Germany)
Start building resources for a difficult future (community and survival skills)
Direct action: start blocking and dismantling instruments of oppression
“AI” is human cultural practice.
When we ask to abolish AI, we are not asking to abolish numbers.
The models that be
may peacefully continue to exist in hypergeometric space, as they have for time eternal, independently of our human dis/usage of them.
When we ask to abolish AI, we ask to abolish what has become (from a 2026 standpoint), over the last few years, a prevalent cultural practice whose most salient feat is its overwhelming uncritical adoption (which, as we explain below, is not a fluke, but willfully engineered into AI systems).
“AI” is the cultural practice of outsourcing our thinking.
What people that praise “AI” for its possibilities “for the benefit of humanity” (solving the climate crisis, eradicating racism, curing cancer, and render the working class superfluous through automation) miss out on is a simple reality check of scales and proportions. All of the enticing future promises so far have largely failed to materialize — quite on the contrary, “AI” is often driving the opposite of what the salvation promise is claiming, i.e., fueling the climate crisis, exacerbating racialized violence, facilitating the mental and physical suffering and death of billions, and trapping enormous segments of the population in increasingly meaningless and agencyless work. And at the same time (here the scale comes in!), if we weigh every single human’s participation in the BigDumbRobotInc. equally, the overwhelming majority of us humans nowadays is using “AI” for one single purpose: to outsource our thinking.
You can abolish AI in your own life. Starting today.
You may feel disempowered to act “against” anything as big as the BigDumbRobot (as cultural practice). Speaking of AI abolition can feel liberating — but also daunting. You can, however, start today to abolish AI in your own life, and then let the waves ripple outwards towards the lives of other people. Here is an incomplete list of feasible steps to take, sorted more or less by magnitude of efforts needed.
Stay with the trouble. In a dehumanizing world, embrace the human experience.
ask yourself, not “AI”.
ask people, not “AI”.
read more about the topic (insert some resources here); learn & disseminate knowledge
find analogue activities to replace your volunteering your time feeding the BigDumbRobot (aka, do more of what you actually enjoy, instead of scrolling through instagram)
re-skill and upskill yourself by phasing out tech crutches (like on-the-road access to your emails, 24/7 online availability for communication, GPS navigation) by working on your planning, organizing, navigation etc. skills
find like-minded people, gather in real life, and organize together
stand up and speak up: instead of being part of the discursive normalization, be part of the critical voices who ask foundational questions
stretching exercise: reach up and out. Reach up to the people
you
can reach that are the highest up in the decision making hiearchy at your workplace, in your community. And reach out to the people that are not (yet) part of your social environment: talk to acquaintances, strangers, the media.
organize demonstrations (see Pull the Plug in the UK)
organize conferences (see Cables of Resistance in Germany)
start building resources for a difficult future (community and survival skills)
direct action
sabotage
strike
Refuse to accept that comfort is the ultimate goal.
How a $1 million sandbox challenge led us to a vulnerability in Linux networking, repeatable host-memory disclosure, and ultimately a full guest-to-host escape.
Part 00: Intro
On August 18, 2026, Vercel announced a
$1 million challenge
inviting researchers to break the isolation boundary of its Sandbox product (total prize pool). The announcement came just weeks after OpenAI had
disclosed a remarkable security incident
: AI agents running inside restricted evaluation environments had found ways around their network isolation, compromised internal infrastructure, and eventually breached systems at Hugging Face. The agents weren't supposed to have internet access in the first place.
But there was an important distinction.
Escaping a sandbox's network restrictions is one thing. Escaping the virtual machine itself and reaching the host is another.
Vercel's challenge explicitly invited researchers to attempt both. We were interested in the latter. (Although we ended up finding vulnerabilities that also allow the former - more on those findings in a later post)
The question was simple:
how much could an untrusted guest influence the host kernel without ever exploiting KVM itself?
We took the challenge, put our research infrastructure to work, and within three days discovered a primitive buried in Linux networking that allowed guest-controlled checksum metadata to rewrite an IPv4 header
after the kernel had already validated it
.
What initially looked like a 32-byte host-memory disclosure would eventually become a full guest-to-host escape in our own KVM and many many other Hypervisor environments. And the beautiful part about it was that the vulnerability wasn't even in the hypervisor, it was in the Linux networking stack.
Vercel later described it as the program's most important report
, and its final tally recorded just one Critical finding. That Critical was what is now pwnescape. Together with a separate network-escape report, we had accomplished both network and host escape goals. Its important to emphasize Vercel's sandbox was already hardened beyond normal industry standards and had no misconfigurations we could spot. Although the vulnerability originated in the Linux kernel and wasn't a Vercel-specific flaw or misconfiguration, Vercel deserves tremendous credit for how they handled it. They moved quickly to protect their customers, launched their own independent research, identified and notified other affected hypervisor and sandbox providers, and worked closely with us to coordinate disclosure and fixes across the industry. Their efforts helped protect not just Vercel's customers, but the wider ecosystem.
This is the story of CVE-2026-99999, a Critical rated Linux kernel vulnerability leading to KVM escape.
Research
We used Omega-Pwn, pwn.ai's experimental research harness combining our custom security architecture and automation with elements of
OmegaClaw
, developed by researchers at SingularityNET and BGI Labs for this ambitious project. Compared to traditional LLM harnesses, it enabled longer research horizons, persistent campaign state, parallel collaborative investigations, and the accumulation of hypotheses, failed experiments, and evidence across complex research sessions.
Humans led the research, framing the hard questions, engineering workflows, and directing investigations.
GPT-5.6 Sol
served as the primary reasoning engine for source-level analysis, exploring attack paths, and challenging assumptions. Omega-Pwn bridged human intuition and contextual insight with the analytical capabilities of advanced LLMs.
As far as we know, PwnEscape exposes an entirely new class of attacks in Linux networking: untrusted checksum metadata can rewrite security-sensitive packet fields after the kernel has already validated and acted on them, undermining assumptions across the networking stack far beyond the original VM escape.
Part 01: A deferred checksum and a mutable IPv4 header
The accepted Linux fix is upstream as
6785011f8b16
,
ipv4: validate checksum_start before completing checksum
.
This is the first installment of
PwnEscape
. We are going to spend most of it inside
sk_buff
, checksum metadata, and IPv4 fragmentation, because that is where the actual failure happened.
Figure 1. The vulnerable component is the host networking stack. “KVM escape” describes the guest/host security boundary crossed in our isolated proof, not the source file that contained the bug.
01A / We went looking beyond the hypervisor
Our
previous kvmCTF research
was about KVM's shadow-MMU behavior: an intricate interaction among mappings, reverse maps, and memory lifetime. This campaign began with a broader hypothesis. The security of a sandbox depends on much more than its hypervisor. A guest interacts with an entire host operating system, including device emulation, virtual networking, packet filters, memory allocators, and the APIs that glue those pieces together.
For pwn, that suggested an efficient research strategy: map the reachable boundary, search for places where untrusted state gets promoted to trusted state, and challenge the assumptions at
every later consumer
, not just at the initial parser. We used GPT5-6-Sol-assisted source inspection with human set the scope and decide what actually constitutes evidence. The particularly interesting question at this time was:
Can an asynchronous or deferred operation modify packet bytes after the kernel has already made security-relevant decisions about those same bytes?
Linux checksum offload offered exactly that possibility.
02 /
CHECKSUM_PARTIAL
is a promise to write later
Linux does not always compute transport checksums immediately. Instead, it can carry a packet in a state where the checksum still needs to be completed. The relevant
sk_buff
bookkeeping includes:
This is normal, documented functionality. On the transmit side, a network device or the software helper
skb_checksum_help()
can calculate the checksum and store the result at the designated field. In well-formed TCP/UDP traffic, that field belongs to the transport checksum. In the ordinary kernel path, the metadata is supposed to describe the packet that actually exists. See the
kernel checksum-offload documentation
.
The critical point is that these values are
not just descriptive metadata
. They authorize a subsequent write into packet memory. If less-trusted software can influence them, their validity must survive every operation between admission and completion.
An
sk_buff
also has multiple notions of where packet data begins:
The distinction between the
frame-relative view
and the
network-header-relative view
is important. A packet can arrive with Ethernet and additional link-layer headers still in its linear data. Later, those headers are removed or skipped for L3 processing. Merely checking that a checksum start falls far enough into the original frame is not the same as proving that it follows the IPv4 header after normalization.
Figure 2. The accepted packet's link-layer context is not the final IPv4 context. The issue is a mismatch of stored metadata and the current network-header boundary, not that the physical allocation magically moves. Our original reports cover the exact packet geometry; this figure focuses on the broken invariant.
The input-side comparison was not enough
The first public patch series makes the entry-path defect especially clear. In
__virtio_net_hdr_to_skb()
, the historical minimum-header check used
skb_transport_offset(skb)
, an offset relative to the current
skb->data
view. That protects against a checksum start that is trivially too early in that view. It does
not
by itself establish how far the start is from the network header when the packet contains additional link-layer structure.
The original reported hardening therefore proposed an additional
network-relative
comparison:
Those two inequalities are not interchangeable. The distinction is the essence of the L2/L3 coordinate mismatch. The patch review grew beyond this first formulation because nested headers, IP options, IPv6, and differing ingress callers require more careful validation than a single optimistic fixed offset.
Our original input-side patch
and
Willem de Bruijn's later proposed broader input validation
provide the source-level history.
For the eventual IPv4 consumer, the accepted guard expresses a particularly useful invariant. With
N = skb->network_header
,
H = ip_hdrlen(skb)
,
C = skb->csum_start
, and nonnegative checksum offset
O
, the eventual output location is
W = C + O
. Requiring
C >= N + H
before completion implies
W >= N + H
. The guard therefore prevents this completion from writing
into the IPv4 header
. It does
not
prove that
W
is the correct field within TCP or UDP; that is a separate protocol-validity question.
This is the first trust failure:
checksum metadata from a less-trusted origin crossed into host packet processing without being constrained against the header that later code would actually use.
03 / The header was checked. Then the header changed.
The most interesting part is the order of operations.
Host ingress sees and parses an IPv4 packet with an ordinary header. Fragment processing and routing can operate on that state. Later, output fragmentation reaches the pending checksum. In the historical code,
ip_do_fragment()
completed the checksum before obtaining the IPv4 header pointer and using the header length. The pre-fix ordering in
net/ipv4/ip_output.c
was effectively:
skb_checksum_help()
is not inherently unsafe. It becomes unsafe here because malformed metadata allows its write to overlap bytes that were
already parsed as an IPv4 header
.
The header field that gives the leak its shape is IPv4
ihl
, a 4-bit count of 32-bit words. The first byte of a normal IPv4 packet contains version and IHL. In our controlled research geometry, it could change from
0x45
(IPv4, five words = 20 bytes) to
0x4f
(IPv4, fifteen words = 60 bytes), without changing the version nibble.
Figure 3. A two-byte header mutation can leave the packet looking like IPv4 while dramatically changing the header-length interpretation.
0x4500
and
0x4f00
are the before/after first words observed in the research case.
Static IHL readout
Packet view
First byte
IHL
Interpreted IPv4 header length
Parsed state
0x45
5 words
20 bytes
After deferred write
0x4f
15 words
60 bytes
The IPv4 version nibble remains
4
; only the four-bit header-length interpretation changes.
The earlier stages had not endorsed a 60-byte header. They had made decisions on a 20-byte header. But the later consumer read an updated field as though it were authoritative.
This is a
time-of-check/time-of-use problem in the semantic sense
, but not the usual race between threads. The execution can be fully deterministic. The “time” separating validation and use is the sequence of legitimate networking operations, with an attacker-influenced deferred write in between.
A simplified control-flow trace
This is an example of vulnerability-oriented path diagram, not a claim that every network configuration takes precisely these exact hooks, although we have found numerous other methods to invoke these vulnerable paths.
04 / Where the 32 bytes actually came from
This part is easy to explain poorly. Linux packet buffers need not contain all packet bytes as one contiguous linear object. An
sk_buff
has a
linear head
plus possible non-linear fragment data. After the relevant reassembly, the research case's
logical linear data length
was just:
The late checksum operation made the fragmenter believe that the IPv4 header was
60 bytes
long. That means it treated the next 40 bytes after the original 20-byte header as IPv4 options. Eight of those bytes were genuinely inside the linear head, though they had been payload. The
next 32 bytes were not part of the packet's logical linear data
.
Figure 4.
skb_headlen(skb) = 28
while the later copy length is 60. The discrepancy is 32 bytes. This is a logical skb-data out-of-bounds read; it need not cross the boundary of the physical allocation or an individual slab object.
That final distinction is important. “Out of bounds” here refers to the
sk_buff
's
valid logical linear packet data
, not necessarily to an access beyond the entire allocator object. The host may have physically mapped allocation tailroom past
skb_headlen()
. Reading those bytes and incorporating them into an outgoing network header still crosses a confidentiality boundary. They are host memory, not bytes the sender provided as part of the logical packet.
The IPv4 fragmenter can then generate outgoing fragments using the mutated header shape. The resulting transmitted packet exposes those bytes as apparent IP options. The problem has moved from an internal host state into an externally observable artifact.
That is the difference between the statements
“this might read past a buffer”
and
“the host emitted data outside the sender's logical packet.”
Why the proof needed controls
We did not want to confuse an interesting hex dump with a host leak. The evidence design separated an identity case, where the packet's original header length remained unchanged, from the active case, where a later operation changed its interpretation. It checked whether the final transmitted packet was structurally valid, whether nonzero bytes appeared past the known logical data, and whether those bytes differed from the sender's controlled guard data.
The tests also used an independent application-level receipt alongside raw packet observation. Those two signals helped distinguish a genuine host-side rewrite and transmission from a packet-construction or packet-capture artifact.
The first bounded disclosure reproduced
32 bytes per active case
. We treated the contents as sensitive and did not need to preserve unrelated raw host memory to demonstrate the boundary crossing.
We separately confirmed a host-availability failure on
disposable, researcher-owned Linux 6.12 and 7.x. hosts
.
05 / Why this was an escape primitive, not just a leak
A repeatable, attacker-controlled host-memory disclosure is already serious in a multi-tenant environment. It exposes information from a trust domain the guest is supposed to be unable to observe. It also changes the exploit-research problem: a working read primitive can help resolve uncertainty about host memory state and make additional memory-manipulation hypotheses testable.
In our
owned KVM fixture
, the research advanced beyond read-only disclosure. Using host-memory observations and carefully controlled allocation behavior, we demonstrated
selected 64-byte host-kernel writes
. We used the resulting capability in a bounded lab chain to execute a host-root helper and return a host-generated marker to the guest. Four separate true-cold boots completed that chain.
That is why we use the phrase
guest-to-host escape
for the isolated proof. It is not an inference from an out-of-bounds read, and it is not a claim of root command execution in any vendor's production environment.
Figure 5. Each rung is a different evidence claim. Source review alone does not prove a leak; a leak alone does not prove a write; a lab execution result does not become a production-execution claim.
The allocator-sensitive write chain, object-lifetime controls, and other hypervisor-specific adaptation are large enough to require a separate article. Although we suspect the security industry will use this post to figure out the other affected hypervisors and we expect exploits in weaker configurations to arrive in weeks, and exploits working in default hypervisor configurations to arrive in under a month.
Part 2 of pwnescape will deal with what it took to move from the primitive to host control
, rather than pretending that a 32-byte disclosure trivially becomes code execution, if the security community doesn't beat us to it.
06 / The broader failure mode: deferred-metadata trust inversion
What makes this research interesting beyond the particular kernel patch is the combination of
three different trust transitions
:
Origin trust:
a less-trusted guest or process describes an operation the host will later perform.
Interpretation trust:
the packet changes representation as link-layer headers are processed, and the kernel parses fields under a particular layout.
Temporal trust:
a deferred operation changes that already-parsed state before another kernel consumer uses it.
For our own research discussions, we call this pattern
deferred-metadata trust inversion
. That is a descriptive name for the mechanism. Its building blocks are known, and lots of the fundamentals the exploit abuses are publicly documented; the new and consequential result here is a concrete host-boundary exploit chain through these Linux networking interactions.
The recurring anti-pattern looks like this:
The corresponding audit question is not merely
“did we validate the checksum offsets?”
It is:
“after every transformation, can a deferred writer still target bytes whose semantic meaning has already been trusted?”
The distinction matters for defenses too. A narrow check that prevents IPv4-header overwrites can stop the memory-safety path demonstrated here without proving that every protocol-specific checksum destination is correct. During upstream review, researchers also raised distinct concerns about later mutation of transport fields after policy checks. Those are related consistency risks, but
they should not be folded into the proven 32-byte disclosure or claimed as fully addressed by the IPv4 fix
.
The lesson generalizes as an audit technique for deferred work and mutable metadata. It is
not evidence by itself that unrelated protocols, operating systems, or products are vulnerable
.
07 / What Linux actually changed
The story of the fix(es) is worth telling because the shape of the remediation changed during review.
Our initial candidate series addressed two different points in the path: admission of virtio checksum metadata and the IPv4 fragmentation consumer. The public
September patch series
explains that rationale and includes the reviewer discussion. Subsequent review identified more checksum-completion consumers and debated the risk of a broad check in a central helper versus targeted checks at multiple sinks.
Michael S. Tsirkin's accepted upstream patch took the latter approach: a small IPv4-specific guard placed
before
checksum completion in each of five affected consumers. The helper was added in
include/net/ip.h
:
The core invariant is simple:
For a normal nonnegative
csum_offset
, that ensures the eventual checksum output location cannot fall inside the IPv4 header. The check does not try to certify that the target is a valid TCP or UDP checksum field; it makes the narrower claim needed to protect the already-trusted
IPv4 network header
.
The accepted commit,
6785011f8b16
, adds the guard to these consumer paths:
Figure 6. One shared
ip_check_csum_start()
helper, five protected checksum-completion sites. The shared helper is in the sixth modified file. The patch is expressly described as defense in depth.
The critical new ordering at each relevant site is
validate the checksum start first, then complete the checksum
. In
ip_do_fragment()
, the simplified post-fix sequence is:
One detail is especially important if you are backporting or reviewing related work: this commit is
not a complete redesign of the virtio checksum API
. The accepted commit message explicitly calls it a defense-in-depth measure and says broader ingress validation requires further work. The original discussion also considered TUN/AF_PACKET scenarios without a VM.
Michael reproduced the original issue during private review. Willem de Bruijn and other networking reviewers evaluated the accepted approach, including the cost of changing widely used checksum paths.
The patch was applied to
net.git
on October 8, 2026, and subsequently merged into the mainline Linus's tree Oct 14th, 2026. Stable backports and official CVE publication should be checked against the live kernel records at publication time;
08 / Research notes: three days to the primitive, weeks to the fix
Date, 2026
Research milestone
Aug 18
Vercel publishes the $1 million Sandbox research challenge.
Aug 20
We submit the initial bounded host-memory disclosure report.
Sep 4
We report the host-kernel root cause privately to the kernel security contact and networking maintainers, with candidate patches.
Sep 7
Michael S. Tsirkin replies that he reproduced the issue and acknowledges the candidate patches.
Sep 19–22
Public netdev submissions and revisions expand review of the network-header invariant and related paths.
Oct 7–8
The revised upstream guard is posted and accepted into
net.git
.
Oct 13–14
Stable review and CVE coordination continue.
We made deliberate evidence distinctions throughout: a suspected bug versus a demonstrated disclosure, a disclosure versus a host write, an owned-host root marker versus a provider-production result, and a code review versus an accepted upstream patch. Those are not bureaucratic labels. They are how you keep ambitious vulnerability research falsifiable.
That is also the point of the AI systems around the models. The research loop is much closer to is
model or researcher proposes an invariant violation → build a bounded test → check controls and falsification cases → preserve evidence → iterate with expert researcher → ask independent reviewers to attack the conclusion → implement and retest an exploit
. We use that loop to search a larger space without lowering the proof standard for under 700$ of API tokens.
We are keeping Part 1 focused on the public kernel fix and our owned-host evidence. We are also keeping the provider-specific coordination and private production telemetry separate until their disclosure status is explicitly cleared.
09 / Why this matters to people building sandboxes
The popular mental model is that VM isolation lives in the virtual-machine monitor. Much of it does. But an attacker-controlled workload does not interact only with
arch/x86/kvm/
. It interacts with a host OS full of optimized, highly composable interfaces. Some of those interfaces are performance contracts.
If the metadata crosses a trust boundary, every deferred consumer has to inherit the right invariants. And if the packet can be transformed after those invariants are checked, the invariants have to remain true in the new representation.
That is why a bug that looks, at first, like a malformed checksum hint can become a memory disclosure and a guest-to-host escape primitive.
The problem was not how difficult IPv4 is to parse. It was that different parts of Linux were allowed to trust different versions of the same packet.
Special Thanks
A huge thank you to Michael S. Tsirkin of Red Hat, Willem de Bruijn and Eric Dumazet of Google, David Ahern of NVIDIA, Jakub Kicinski of Meta, Chris Arges of Cloudflare, Greg Kroah-Hartman of Linux Foundation, and the wider Linux kernel community for their technical guidance, collaboration, and efforts to get this vulnerability fixed upstream.
We're equally grateful to Guillermo Rauch, Malte Ubl, Andy Riancho, Andrey Sibirev and the entire Vercel team for their exceptional collaboration and commitment to protecting the wider industry. Special thanks also to Eric Daniels (Modal) and everyone else who contributed, reviewed, reproduced, or helped along the way. This research wouldn't have been the same without you.
There’s a real “*Why do we need this?*” question here and I don’t think Apple’s video answers it, at all. You need to think you want it if you’re going to buy it. And even if you already had a HomeView set up, I’m not sure how often you’d use it instead of your phone, or instead of just talking to i...
I’ll start with a nomenclatural sidenote: Apple seems to be going with “Apple HomeView” as the product’s name. E.g., the URL slug for it on Apple.com is
apple-homeview/
, not just
homeview/
. Few people notice and no one who doesn’t work in Apple product marketing cares, but they actually do the same thing with Vision Pro — in Cupertino, it’s “Apple Vision Pro” (once again including
the URL slug
). Yet this week’s new HomePod Mini is just “
HomePod mini 2
” and the existing 2nd-generation HomePod is just “
HomePod (2nd generation)
” — not “HomePod 2” or “Apple HomePod”. I certainly intend to just call it “HomeView”.
Apple introduced HomeView with a three-minute introductory film simulating a suburban family’s hectic before-school/work kitchen rush hour, with versions hosted
on Apple’s site
and
YouTube
. The most ridiculous aspect of it is that anyone would possibly make their kid French toast in that scenario. I’d have told my son to make his own goddamn French toast with that attitude. Or I’d have made a single serving and eaten it myself right in front of him. Bro.
I do think the basic concept is an intriguing idea. But as an implementation of that concept, my initial impressions are threefold. First, I am unconvinced that anyone in a family would use this for anything other than playing music or podcasts, rather than just using their phones. And if that’s the case, why not just have a HomePod? Apple’s video shows family members taking turns to use the HomeView, rotating it on the kitchen island to face themselves. Why? Why does the mom check her calendar on this, rather than on her iPhone, while the dad is using it to follow a French toast recipe? There’s a real “
Why do we need this?
” question here and I don’t think Apple’s video answers it, at all. You need to think you want it if you’re going to buy it. And even if you already had a HomeView set up, I’m not sure how often you’d use it instead of your phone, or instead of just talking to it like a screenless HomePod.
Second, all the touching and rotating — in Apple’s own demonstration — makes it seem awkward that HomeView must be tethered to a USB power cable. If you look closely in the video, they do show the USB power cable in some shots, but not many. And if you look really closely, this hypothetical family has drilled a hole in the center of their kitchen island to snake the cable through.
The hero shot introducing the product, of course, does not show the power cable at all:
We see a wee bit of the cable when the dad reaches to touch the screen to start the French toast recipe:
And then a few seconds later, after the mom rotates the HomeView to the side, so she can check her calendar (despite the fact that she knows the dad was using it to follow a recipe), we get our most honest shot of the cabling situation:
The above shot is at 0:49. It’s followed by two quick cuts to the dad and then the younger daughter, then at 0:52 we cut back to the mom (curious about her daughter’s new boyfriend situation), and, lo, the shot is now framed in such a way that we no longer see where the cable goes:
If you think that slight reframing is happenstance, you should stay away from poker tables. Most kitchen islands I’m familiar with — including my own — have power outlets on the sides of the island. I’m sure some people have power outlets on the top surface of the counter, but I can’t recall seeing one. These are kitchen counters, not office desks. But either way, there’d be a long USB-C cable cluttering the countertop. And if you do happen to have a power outlet on the top surface of your counter, there’d be an adapter sticking out of it, all the time, to duplicate this HomeView setup.
This family’s convenient hole in the center of their island countertop is a fantasy. Where does the cable go underneath? How exactly do they have a power adapter plugged in down there? What happens when something spills on the counter? When we custom ordered our kitchen, we weren’t asked if we wanted any holes drilled in our island countertop, and I’d have found it to be a very curious question if I had. It would have made me wonder if the guy asking the question had a hole or two drilled in his head.
I know, it’s a marketing video. Marketing videos present products in ideal settings. But the power cable is an essential aspect of the standalone HomeView. I’m not suggesting that it should be battery powered. You’d still need to plug it in every few days, which would mean most people would just leave it plugged in, which gets us back to needing to live with an always-visible cable and power adapter in one of our living spaces. The countertop hole this cable disappears into in this video is less
ideal
and more
dishonest
.
The wall-mounted option seems more appealing to me, but now you’re talking about a home improvement project and (for most of us) calling an electrician. And that raises the question of why the wall-mounted version costs the same $300 as the one with the connected base, even though the base provides the subwoofer. And it requires a mount, and the mounts cost $60 (USB-C), $80 (AC wired), or $130 (PoE — and this one is not available yet). So the wall-mounted version, when you include a mount, costs more but sounds worse? This doesn’t make sense.
Those points make me skeptical that there’s a place for HomeView in my home. We have a stereo pair of HomePods in our kitchen. Neither is on the center island, because that would be dumb. They’re on the counters along the outside of the kitchen, each near an outlet on the wall. In the four days since HomeView was announced, I’ve tried to imagine when I’d want to look at something on a screen on either of them. My count remains at zero.
My third early impression is that the display is surprisingly small. I saw HomeView in person in New York on Tuesday, and I think Apple’s video conveys its size very accurately. It’s small and cute. It’s much more like a HomePod Mini with a screen than a full-size HomePod with a screen. For some reason I was expecting the latter. This size observation is not a complaint, simply an observation. I actually think that making it small and cute makes it about as unobtrusive as an ever-present screen could possibly be. That’s good. But because it’s small you need to be close to it to read anything more detailed than large glanceable widgets.
The major difference between a device with a screen and one without is that you can watch video on a device with a screen. But HomeView clearly isn’t intended for that. It
can
play video but isn’t primarily
meant
to play video. If it were it would have a widescreen aspect ratio. But instead it has a square aspect ratio,
1
which is decidedly unsuited to video, unless, I suppose, you want a screen that is equally unsuited for both widescreen and tallscreen video.
So my skepticism boils down to the question of why anyone would want to add one (or more!) additional ever-present screens to our homes and lives. Phones can stay in our pockets until we need them. Watches remain on our wrists. HomePods can be tucked away unobtrusively in corners, and remain fully useful. HomeView needs to be in a prominent location for its display to serve any practical purpose. Apple’s initial pitch for it doesn’t earn that prominence for me.
I have often seen one engineer get much faster with AI coding agents; then adding a second engineer or a third on the same team doesn’t necessarily speed up development. Sometimes the “fast team” is just one person operating in a silo. What I wanted to understand was why teams didn’t seem able to move faster, even when they were trying.
What I found is that teams keep holding on to what they know while also trying to adapt to AI. The teams place agent-speed implementation within processes built for humans and thus slow it back down. The bottleneck is maintaining shared understanding, coordination, and a coherent direction while moving fast. Every person added needs more of all three, and the way we manage that traditionally doesn’t scale with agent speed.
Rethinking How We Build
The bottleneck limiting teams is not too much human judgement; it’s where and how we apply it.
Building the right thing and ensuring quality hinge on human judgement. It comes in the form of product definition, requirements, understanding how to apply architectural principles to solve problems in software engineering, as well as validating that our product can be released to customers.
Keeping up with agent speed requires setting aside the existing methods, processes, and points of friction we’ve put in place to manage and gate our own work. I’m not saying throw everything out the window, but if we want to build successfully and go faster, we have to work differently.
To come up with a solution, though, I did start by throwing a lot of things out the window, then added elements back. As an industry, we have rich expertise in software development, in honing judgement and knowing how to apply technology to real-world problems. But the mechanisms and tools we’ve applied to develop software need a clean slate rather than a simple tune-up. We need to be able to trust and verify that what we deliver matches what we designed.
My Method: Anchor Engineering
Anchor Engineering
is the method that connects design and judgement with instantiating your system through AI agents.
I’ve been developing this method as the answer to all the callouts above: moving fast, high quality, enabling teams. I’ve been deep in a cave for the last few months building with a bunch of teams like this, with thousands of my own commits across those teams. I even ended up building an application that uses AI to narrate the scope of changes that go in each day - because reading that is a better use of time than reviewing 100 commits every day.
In this method, our human judgement is baked into the guiding context with an agent-specific focus on design: anchors.
The
anchors
tell the AI what must be true about your system when it writes the code and builds the software.
AI does not care if the design you prescribe is high level or low level, it just needs to know what to build. This also means you don’t have to prescribe everything else for it to build the right thing; the anchors define what the right thing is, and you can let the agent fill in the rest.
All this lives in the
Anchor Book
, an artifact that co-exists with your code in the repository and provides a living home for human judgement and context of the system.
It also serves as your team’s shared mental model and build plan. Both of these grew out of some of my
earlier work
on how AI context can be directed and kept in a specific “space” by storing text that served as anchors for specific behavior.
The shared context and mental model in the Anchor Book enable the team to work together closer to agent speed. For this, I recommend a small development team that stays in active conversation, whether working together in person or virtually. They all work off of the plan within the Book, and also update it as they navigate design and development progress. Engineers push and pull the Book as part of development which keeps them working in sync.
Here’s a first set of principles that guide this method. This post lays the groundwork; I’ll cover the details, examples, and mechanics of the method in follow-up posts.
Principles of Anchor Engineering
1. AI amplifies the judgement of the people leading it
The result of engineering with AI is a reflection of the judgement applied at each step in the process. Anchor Engineering puts that judgement into the Book and its anchors so it becomes durable direction for every AI building loop. Engineers and AI sessions then continue from the same decision instead of reconstructing it through repeated handoffs.
AI has made software development more accessible, but using it effectively still requires engineering expertise, judgement, and domain knowledge. You can install a coding assistant, set it up quickly, and it will build
something
. What it builds entirely depends on your tool selection and configuration - and the context and instruction. The quality and depth of your instruction depend on the quality and depth of your expertise in software engineering - think of system design, scaling, knowing what works well and what does not given circumstances. AI does not replace the need for an expert; it amplifies the impact of an expert in the system it builds.
Consider the analogy of an AI-written document; we’ve all seen documents that on the surface look like they contain reasonable prose, but end up lacking where it counts. If you know the subject matter, you’ll probably recognize it very quickly. Writing software with AI coding agents can follow the same pattern. The result might be fine for some uses, but its quality depends on the expertise you bring to guiding its creation.
Judgement is part of the input to the software building process, guides the building itself, and verifies that the resulting software is correct and is ready to be deployed.
2. We own the process and the outcome; AI writes the code
The code should look like AI wrote it, because AI is what will maintain it.
This principle is a mental shift, and can be really freeing for us as engineers if we let it be; we stop editing and managing the code by hand. We own the goal, direction, and judgement in the process. AI writes, organizes, and iterates on the code.
We can appreciate beautiful code. Think of all the time we spent on this: the debates on your team about the best place to put brackets. We can mostly let this go. Correctness is critical; personal style is fleeting.
AI doesn’t care if code is organized around human aesthetic preferences; it does benefit from coherent patterns, clear and recognizable structures, well-defined constraints and use of standards it can recognize. Maintaining that helps AI maintain the code. Ultimately we humans care that the system is structurally sound, is correct, and satisfies the requirements.
We own the result, not the editing.
3. All software building artifacts are part of the codebase
This principle might sound familiar and dredge up memories of trying to keep documentation and code in sync. This is different, particularly when the artifact you use to build your system is your primary tool for updating it, coupled with the previous principle of not editing code outside of the AI build loop.
The Anchor Book I mentioned above is the home for all of your building artifacts - it represents the design and definition of your system: the anchors for each part of that design, the criteria by which your agent verifies those anchors are satisfied, and the planned chunks of work you can assign to your agents. It is not simply documentation in the traditional sense.
Another way to think about it: the Book defines your system, and you deploy your agents to instantiate it in whatever language you want. You can use the same Anchor Book to build a system in Rust, then Python, then Java (as long as the language fits the intended application). I have used the same Anchor Book to flip the language mid-development. Initially it applied Python. Then I decided Rust might be more appropriate, so I used the Book to change direction without changing the actual design. The implementation language changed; the system definition did not.
This artifact is living documentation and system definition and should be version controlled along with your code.
4. Antifriction: Remove friction and unnecessary stopping points
When you assess your processes, ask yourself: what function does this stopping point serve, and what faster mechanism can carry that function? I call the answer antifriction.
Antifriction
is an Anchor Engineering term for the faster replacement of a friction point that preserves the necessary function but removes the bottleneck.
This means we’re replacing something in our process that creates a human bottleneck with something else that lets the process go faster, without sacrificing quality.
This is where I find people start getting nervous and return to known methods. It’s important to look forward, not backward in this paradigm. Here are two examples from my experience.
Friction: Task Planning
Consider task planning for a small, focused team working with AI agents. The Anchor Book holds the context for the work that needs to get done to implement a system. If we additionally go to the manual effort of breaking the design down into tasks for team members, planning them into sprints, and assigning them - we are just where we started, with no wins and duplicated planning. If each engineer on the team using the Anchor Book and AI agents can knock out the amount of work in a day that would normally be planned across 4 weeks, the effort does not pay off.
The antifriction is milestone tracking instead of task tracking, so that the team can continue to move forward while still enabling program management to track the project, manage dependencies, and identify risks.
Friction: Team-Gated Code Review
Consider a team where the engineers guide their agents in developing code quickly, then depend on the team members to review their agent-written code. Teams review code to ensure issues are caught before they ship, verify code quality, maintain best practices and standards, etc. However, this is where speed goes to die. A team review is an asynchronous human gate, and putting it in a system with agent-produced code cancels out agent speed. As it is, on many teams a code review takes at least a day to get completed and teams still struggle to solve this with only human coders.
Instead, we enable our AI agents to apply automated testing and bug fixing loops and ensure that when the agent presents the resulting code to review, it has been through the testing gauntlet already. Having sound unit and integration tests, end-to-end tests, validation, etc. must take a front and center role in development (not that it shouldn’t have already). We make sure the AI agents eliminate as many errors as possible before completing the task, using not only AI adversarial and judge reviews but also deterministic testing. If you’re not mutation testing to test the output of your AI coding agent, you’re missing a great opportunity for a deterministic layer in your process; this step will test whether the tests the AI wrote catch deliberately introduced errors.
This is an appropriate point for a judgement check-in: the engineer who guided the agent should take a look at the resulting code and analyze it for structure and correctness, and validate that what came out of the AI building loop is what they expected.
The antifriction is removing the human team-gated reviews, and building out a comprehensive test plan for code changes. We keep a judgement step in the loop so that the engineer leading the AI building loop validates what was produced.
Code review also spreads knowledge and design context across a team; in this method, the Anchor Book carries that shared context and stays current as the team builds.
5. We don’t build with less understanding; we get to understanding faster
The method does not replace understanding with speed. It preserves the domain, design, operational, and implementation context required to build the system while reducing the time needed to assemble, share, absorb, apply, and update it.
I have talked with engineers off and on in the last year about what will happen to our mental model of the software we build if we are not “hands on” writing it, but instead defining it in terms of plain language text in markdown. Usually we build our mental models through writing the code, also through investing time in problem solving and designing, as well as explaining our approach and discussing with others. So how does this translate to a bunch of natural language directives to AI?
I designed the Anchor Book to be a structured artifact to ensure we can define a system with clear rules and outcomes with an implementation plan for AI agents. It tracks decisions, how they align with requirements and how those are realized in anchors, and then verified through tests in the code base. It also encodes human judgement within these mechanisms. Building the design into the Book means working with AI to ensure that what you are adding adheres to existing rules, or recognizing when it violates them and you need to solve the problem differently. This hands-on work creates a strong mental model in much less time than it would normally take to develop over the course of the project. We’re essentially compressing the time it takes to build and understand a full system, and creating the artifact that lives and grows as the system does. This means each person on the development team ends up with a crash course in the entire context for the system they are building - and a very rich mental model beyond the scope of what they’d normally need for task work.
What Comes Next
Building at agent speed takes shared understanding, coordination, and a coherent direction. The Anchor Book is how I bring these together. In the posts that follow, I’ll show what goes into the Book and how a team uses it to design, build, and verify a system.
Anchor what matters. Let AI reason through the rest.
I purchased a Matrix CoolRunner Rev D back in 2017. This little chip is called a glitcher and it’s a type of modchip. Its sole purpose, the reason it was designed, is to deliver a short pulse of energy (~ 100 nanoseconds) to an Xbox 360 Console.
You might ask yourself, “What’s the point in that?”. The answer is quite interesting.
Microsoft are good at security
It boils down to the simple fact that Microsoft learned from the mistakes of their previous console (the original Xbox) and designed security well on their successor.
So well in fact, that it was deemed essentially unhackable by conventional approaches:
tmbinc said it himself, software based approaches of running unsigned code on the 360 mostly don’t work, it was designed to be secure from a software point of view.
1
The entry point for the system, dubbed 1BL, is physically baked into the silicon of the Xbox 360’s CPU
2
. The job of 1BL is to load the next phase of the bootloader, called CB from flash storage, and verify that it was signed by Microsoft.
So without Microsoft’s signing keys, there was no real way to hijack control of the system during the boot process. And it only becomes harder as the console boots up through its different phases. Additional security features are turned on as it cascades up the boot chain. And they would all need individually circumvented to get any code running on the console that Microsoft haven’t been over with a fine toothed comb.
So if the door to the castle is locked, and the guards, who are wise to equine ploys, are checking ID at the door, how does one get in? Well you don’t use a key. You inform the guard that his shoelaces are untied and hit him over the head with a club.
Finding the weak link
The point is that if the lock itself is secure, and the procedures surrounding entry are sound, sometimes the weakest link becomes something more fundamental. In our metaphor this is a person, but in the case of the Xbox 360, it is the fact that computation relies on stable energy conditions to behave in a predictable manner.
And this is the idea that fault injection subverts. In the case of the Xbox 360, researchers found that by very quickly toggling a reset signal on the CPU (
CPU_RESET
), a signal that is usually supposed to reinitialise the CPU, something far more interesting happened. Instead of resetting, the CPU executed the current instruction incorrectly.
Graph demonstrating glitching as voltage over time
3
.
This gave the researchers a very useful primitive. They found that an instruction integral to the signature verification process, the
mr
(move register) instruction, could be glitched into ignoring a value it was about to move and instead move a 0 into its destination register
4
.
So by simply knowing when, and toggling the lights on and off, they gained arbitrary code execution.
The future is glitching
It is astounding to me that this kind of esoteric side channel exists at all. But I think the larger point is that it’s becoming more common.
The sort of trust chains that made the Xbox 360 hard to hack 10 years ago have now become commonplace in the world of computing hardware. Microsoft themselves began enforcing hardware backed secure boot for their Operating Systems back in 2021
5
.
More recently in 2024, the security features of an ESP32 v3 (secure boot and flash encryption) were bypassed using a fault injection attack
6
.
And there are recent examples specifically leveraging the Raspberry Pi Pico Microcontroller to perform similar fault injection attacks
Apple AirTag’s firmware was dumped in 2021 by stacksmashing using a Raspberry Pi Pico and fault injection
7
.
The PicoFly modchip, released in 2023 for the Nintendo Switch, uses fault injection to defeat secure boot on the console
8
.
To me, this suggests that fault injection has become a more attractive attack vector in recent years due to a security ecosystem that has hardened over time. But I think it has in turn also become more accessible than ever, with the advent of cheap and accurate microcontrollers such as the Pi Pico.
A love letter to the Pico
The Raspberry Pi Pico microcontroller, released in 2021 for £5 by the Raspberry Pi Foundation
9
.
The Pico itself is versatile because it allows for very precise timing via its PIO blocks. These specialised blocks come with enough primitives to implement many standard protocols and have an effective timing resolution of ~7.5 nanoseconds due to the 133 MHz clock
10
:
I have seen this versatility myself first hand when I finally dusted off the Matrix CoolRunner in 2026 and decided to take another crack at modchipping my Xbox 360.
Back in 2017, when I bought the thing, it was quite expensive to modchip an Xbox 360. You needed a number of tools and skills to successfully mod one:
A glitching chip
Solder and an iron
A NAND programmer
A JTAG programmer
I tried to save some money by building my own NAND / JTAG programmer using the printer port (LPT port) on a very old PC that I had in reserve for the specific purpose. If I had ever got this working it would have taken over 30 minutes to dump the NAND. I do not recall the reason but I did not manage to pull this off in 2017 and the project was shelved.
Reattempting this same procedure in 2026 was a breeze by comparison. I was able to flash
PicoFlasher
onto a Pi Pico and solder it to the correct pads on my Xbox 360. The dump operation then only took a handful of seconds to run.
Raspberry Pi Pico wired to the NAND interface header on the Xbox 360.
Raspberry Pi Pico wired to Matrix CoolRunner JTAG interface.
Summary
So, even the most carefully crafted tower can collapse under the weight of its own fundamental assumptions. Like many aspects of computer security, fault injection has become a game of cat and mouse, with increasingly sophisticated defences being met by new tools and methods of circumventing them.
But I think we have now reached a point where DIY tooling has really begun to shine, making light work of challenges that, just a decade ago, required expensive, specialised equipment.
And I have seen this first hand, a project that defeated me in 2017 was made trivial in 2026 by a £5 microcontroller.
Funnily enough, a software-only exploit for the Xbox 360 dropped just
last week
, rendering my years of effort somewhat moot. Nevertheless, it was a fascinating deep dive into the inner workings of the console and the security mechanisms designed to protect it.
References
Hackers breach Microsoft 365 tenants via ConnectWise supply-chain attack
Bleeping Computer
www.bleepingcomputer.com
2026-10-17 11:18:51
ConnectWise has shut down customer access to its Cloud Backup service (formerly SkyKick Cloud Backup) after hackers accessed application identities and compromised Microsoft 365 tenants. [...]...
ConnectWise has shut down customer access to its Cloud Backup service (formerly SkyKick Cloud Backup) after hackers accessed application identities and compromised Microsoft 365 tenants.
Reports of the malicious activity began emerging on Friday, with administrators observing unauthorized access to client data in Microsoft 365 tenants due to a potential “SkyKick/CW breach.”
Later on the same day, managed cybersecurity and threat detection platform Huntress confirmed the worries, saying that it had identified at least 162 compromised tenants in its environment.
In a post today, Microsoft also confirmed malicious activity involving ConnectWise’s Cloud Backup service, saying it identified unauthorized authentication attempts from an IP address on October 15.
ConnectWise’s cloud backup solutions provide backup and recovery services that help managed service providers (MSPs) and IT teams protect and restore customer data, such as emails and files, in cloud environments including Microsoft 365 and Google Workspace.
For Microsoft 365 backups, the service relies on permissions granted through Microsoft Entra ID. An application identity known as a “service principal” represents the software in a customer’s tenant and enables it to access resources according to the permissions granted.
Microsoft 365 tenant breaches
In a
security advisory
, ConnectWise said that it “recently identified unauthorized access to application identities within the ConnectWise Cloud Backup environment” and shut down application access for its partners and clients.
“We have no indicators to date that Cloud Backup partner backup data has been compromised. The existing cloud backup archive is not impacted by this service interruption and will be accessible once services are restored,”
ConnectWise says
.
However, the company has launched an investigation and is engaged in remediation efforts.
Based on reports from Microsoft, Huntress, and administrators, the malicious activity started at least on October 15 from a single IP address:
144.172.64[.]128
.
One
user on Reddit said
that they received a notification from the Microsoft Privileged Identity Management (PIM) service on October 15 alerting of a SkyKick service principal assigning itself the role of Exchange Administrator, despite not using the app in years.
Nevertheless, some of the reported IDs for the offensive SkyKick match those provided by Huntress, Microsoft, and Todyl - a cybersecurity platform primarily for MSPs and IT professionals.
According to Todyl researchers, the attacker authenticated directly to Microsoft 365 as the backup application using its secret, gaining the permissions customers had already granted it.
The sign-in requests were performed by an automated script, and since they did not involve a user login, protections such as multi-factor authentication (MFA) were ineffective.
“Because the application already held broad, previously granted permissions in each tenant, those sign-ins gave the attacker the technical ability to read and write mail and attachments, OneDrive and SharePoint files, and Teams chats,”
Todyl said
.
In the analyzed intrusions on nine tenants, Todyl researchers identified only sign-in activity and did not find evidence that the threat actor “created accounts, added permissions, changed passwords, or established persistence in any tenant through the backup app.”
Reconnaissance and persistence attempts
However,
Huntress saw
on nearly 50 tenants it monitors that service principals for “ConnectWise’s Cloud Management apps (Exchange Online, Microsoft Teams, and Microsoft Graph) assigned themselves directory roles, mostly Exchange Administrator.”
In one tenant, Huntress researchers also observed that the attacker established persistence, the operation taking around five minutes.
During the activity, Cloud Management - MS Teams (
24205314-2b89-4e07-a2a4-579e898a5640
) granted itself a Global Administrator role and added credentials to an MSP management tool and to Huntress’s own application.
Microsoft also
observed persistence activity
via a backdoor after successful service principal authentication, followed by “Microsoft Graph API reconnaissance and attempts to add additional credentials.”
It should be noted that all three cybersecurity companies tracked the malicious company to the same
144.172.64[.]128
IP address.
Microsoft Threat Intelligence characterized the incident as an active supply-chain attack, assessing that the attacker likely abused existing permissions, including Directory.ReadWrite.All.
Indicators and tenant checks
Huntress identified the legitimate Cloud Backup application ID
506e08f9-6e9a-4da4-942b-a099a03644ae
used in the attacks. Its investigation also linked the attacker IP address to scripted sign-in attempts on October 13 and 14, with the user agent
curl/7.88.1
.
Based on current evidence, there are at least three user agents linked to the malicious Cloud Backup service activity:
python-urllib/3.12
,
python-requests/2.31
,
python-requests/2.34.2
.
ConnectWise recommends that administrators check the service principal sign-ins in Entra, filter by the Cloud Backup application ID, and examine unexpected source addresses.
Microsoft also recommends reviewing application credential changes, OAuth grants, and related Graph activity.
Huntress advises administrators to disable the implicated ConnectWise applications, as well as check application credentials for unauthorized additions and review other Cloud Management integrations.
The company notes that older tenants may list Cloud Management apps under ‘SkyKick Cloud Manager’.
The company provides an extended list of application IDs for administrators to look for:
The vendor’s shutdown does not remove credentials already planted in customer tenants. Huntress says that admins should review secrets and certificates across all applications for unauthorized additions since October 13 and removing those entries.
Todyl warns that disabling an application stops new tokens from being issued, but existing tokens remain valid until they expire, and revoking user sessions does not end application-based access.
ConnectWise announced the backup service interruption at 05:01 UTC on October 17 but did not provide a timeline for restoring the connection.
The company did not report any evidence that stored backups were compromised and said existing archives would be accessible when reservices are restored.
At the time of publishing the victim count and the extent of data theft remains unclear, as well as the method the attacker used to obtain vendor credentials.
Automated Software Verification in the Age of AI Coding Agents
We are living in peak AI, with more and more developers shipping code without actually writing (or sometimes reviewing) it themselves. According to
a 2026 study by Faros
, which analyzed two years of telemetry from 22,000 developers across 4,000 teams, engineering throughput is increasing, while bugs, rework, review load, and production incidents are rising even faster in organizations with high AI adoption.
The numbers are striking: Faros reported 54% more bugs per developer, a roughly fivefold increase in median PR review time, and more than three times as many incidents per PR when comparing periods of lower and higher AI adoption. These are
correlations
, not proof that AI caused every one of those outcomes. A
subsequent Q3 report
also found that some of the earlier effects were easing, while verification, remediation, and operational costs continued to pile up downstream.
We need to slow down enough to understand, and improve, what we are doing here. One cannot expect a small team to meaningfully review enormous AI-generated diffs. At the speed at which AI can now push out code, even ordinary review practices are struggling to keep up.
So how do we preserve the speed of AI-assisted development without sacrificing software quality, reliability, and maintainability?
Simple:
automated software verification
. With the same clever tools, skills, and harnesses we use as AI engineers to push code at breakneck speed, we can build elaborate testing and verification automations.
Automated software verification that builds
justified
trust and confidence is the way forward. Not because any system can guarantee bug-free software, but because we need more ways to catch problems before they reach users.
What’s available right now?
There are a few concepts circling around at the moment.
Superpowers
One concept that has caught on is
Superpowers
, an agentic development methodology and collection of skills that works with coding agents and supported harnesses. It encourages your agent to behave more like a disciplined software engineer instead of immediately jumping into code.
For example, it can help refine what is actually being built instead of just assuming things. It emphasizes planning, test-driven development, debugging, and reviews, including having separate agents review the work.
This is a great start. However, depending on the task, following the whole methodology can slow down development, and it still doesn’t replace the broader checks needed to gain confidence in our code’s correctness and security. No plugin alone makes software bug-free or vulnerability-free.
RoboRev
Another interesting framework,
RoboRev
, comes from Wes McKinney, the developer behind the widely used pandas library. RoboRev brings continuous AI code review into the local development loop.
The idea is compelling: just like in-person peer reviews, we can have another LLM review code that our first LLM wrote. Having a separate reviewer, potentially using a different model, may catch mistakes or architectural problems that the authoring agent missed. It is another perspective, though not a guarantee of an unbiased or correct review.
In a typical RoboRev setup, you commit your code and a local daemon automatically reviews the commit using a configured coding agent. It surfaces findings that you can feed back into your current LLM and coding harness, fixing issues while the context is still fresh.
RoboRev also supports follow-up review workflows and targeted review tasks. The appeal is that verification becomes part of the coding loop, not something you remember to do at the very end.
Its documentation
covers the available commands and integrations.
But the concept of code review is not new. In 2026, providers such as Claude, Codex, GitHub Copilot, Cursor, Greptile, CodeRabbit, and Qodo offer AI-assisted code reviews.
Explaining all of them would put even the most terminally online engineer to sleep, so instead let us focus on the main ones.
Claude Code Review
Anthropic’s
hosted Code Review
is a heavy-duty PR reviewer. When triggered on a GitHub pull request, it sends multiple specialized agents to investigate changes in parallel and look for logic errors, security vulnerabilities, regressions, and missed edge cases, among other things.
The goal is a deeper review that may take more time and cost more than a quick local pass. As of October 2026, Anthropic lists this hosted service as a research preview for Team and Enterprise plans, with
separate usage-based billing
.
There is also an Anthropic-maintained
/code-review
plugin
for Claude Code. It runs a review from your coding workflow and can post findings to a PR. It is a different workflow from the hosted review service, so I wouldn’t treat them as identical in depth, setup, or pricing. Check your plan and usage terms before assuming the review is included.
OpenAI Codex Review
Codex code review
takes a similar approach to reviewing pull requests against the repository’s context and instructions. You can request a review with
@codex review
on a connected GitHub PR or configure automatic reviews. Codex also supports reviewing local changes before a PR exists.
You can be more descriptive about what you want checked: a diff, a PR, security concerns, or compliance with the specification. If the review finds a problem, you can ask Codex to prepare a fix, inspect the resulting change, and repeat the review. That gives you a useful review-and-repair loop, although review and implementation still need independent verification.
GitHub Copilot Code Review
GitHub has one of the simplest, most hands-free approaches. You can configure
Copilot Code Review
to automatically review PRs, follow repository instructions, and suggest fixes that can be applied or passed to the Copilot coding agent.
As seamless as it is, it introduces problems if you start blindly accepting its feedback. Copilot normally leaves comments rather than an approving review, though GitHub supports configuring approvals in some setups. Either way,
automated review is not the same as a safe merge decision
.
A tradeoff is that the review experience is more managed than a DIY agent workflow: you can customize its instructions, but you don’t have the same direct, per-run model configuration you get when invoking your own coding agent.
Cursor Bugbot
Cursor Bugbot
automatically reviews GitHub PRs, looking for logic bugs and other problems, and lets you act on the findings in Cursor. Its
Autofix feature
can also propose fixes through cloud agents.
Its biggest advantage is convenience for teams already using Cursor. The tradeoff is that much of the model selection and review orchestration is handled by Cursor rather than exposed as a fully customizable workflow. Cursor says it uses a combination of frontier and in-house models.
One reviewer isn’t enough
I like having a strong coding model write the code and a
separate
strong model review it. Different models can bring different perspectives, but model diversity isn’t magic: two agents can agree on the same wrong answer, overlook the same requirement, or confidently flag a bug that doesn’t exist.
The practical takeaway is to combine AI review with checks that don’t rely on an LLM’s judgment. And ideally, keep a human accountable for the final decision, especially on high-risk changes.
Okay, so we can review code. But there is much more we can do to increase our confidence that the code meets spec, doesn’t introduce bugs or vulnerabilities, and doesn’t accidentally expose secrets.
That’s what we talk about next.
The CI/CD pipeline in the age of AI and automated software development
Here is a comprehensive verification pipeline, built as a
superset
of what is possible. Each step can add confidence that the code works as intended, though not all teams will need every check, and no set of checks can prove software is perfect. The broader philosophy is well established in software engineering and aligns with frameworks such as
NIST’s Secure Software Development Framework
.
Not a fan of walls of text? There’s a diagram of the whole pipeline at the end of this section.
Code quality & build checks
Linter checks:
Check code for style violations and common mistakes.
Formatter checks:
Make sure formatting, such as indentation or spacing, follows our rules.
Type checking:
If using a typed language such as TypeScript, verify that types are used correctly.
Compilation/build checks:
Make sure the application compiles or builds successfully.
Automated tests
Unit tests:
Test whether individual units of functionality work as intended.
Integration tests:
Test whether multiple components work together, such as a payment flow that touches an API, database, and payment provider.
End-to-end (E2E) tests:
Verify important user workflows across the application from start to finish.
Security & dependency checks
Static application security testing (SAST):
Scan source code for patterns associated with potential security vulnerabilities.
Secret scanning:
Look for passwords, keys, or sensitive credentials accidentally included in the repository.
Dependency vulnerability scanning:
Find known vulnerabilities in package dependencies.
Dependency freshness and support status:
Identify outdated or unsupported packages that may need attention.
Agentic code review
General bug scanning:
Use AI agents to find and flag likely bugs.
Security-focused review:
Use AI agents to investigate potential security risks beyond what a rules-based scanner might catch.
Review against spec:
Check whether the latest PR or feature branch implements the requested behavior, including important edge cases.
Infrastructure & database checks
Container and infrastructure configuration scanning:
Look for insecure settings or misconfigurations in containers and cloud infrastructure.
Database migration validation:
Assess whether schema changes are safe to deploy, might cause data loss or downtime, or make rollback difficult.
Architecture & maintainability review
Bloat, complexity, and architecture simplification checks:
Use AI agents to identify unnecessary code, overengineering, excessive complexity, and opportunities to simplify the implementation.
Other checks worth remembering
Depending on the application, add
performance and load testing
,
accessibility checks
,
privacy and compliance checks
, and
software license / supply-chain checks
. A secure deployment can still be slow, inaccessible, or mishandle data. These checks don’t have to run on every commit, but they should have a place in the overall process.
Putting it all together, how can we configure these checks?
Most of the verification patterns we’ve discussed have been established practices for decades, and major platforms already provide tools to automate them. GitHub Actions, GitLab CI/CD, and Jenkins are common ways to orchestrate them.
Take
GitHub Actions
, for example. Developers define automated workflows in YAML files stored within their repositories. These workflows can be triggered by pushing code, opening a pull request, or merging changes. GitHub then starts an execution environment (a
runner
) and executes the workflow steps.
These steps often involve installing dependencies and running deterministic checks such as linters, tests, and security scanners. Increasingly, they can also invoke AI agents for more sophisticated, nondeterministic reviews. See
GitHub’s Actions documentation
and the official
Codex GitHub Action
.
A simplified workflow might look like this, in
.github/workflows/verification.yml
:
name: Code Verificationon: pull_request:permissions: contents: readjobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - run: ./ci/quality.sh tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - run: ./ci/tests.sh security: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - run: ./ci/security.sh infrastructure: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - run: ./ci/infrastructure.sh agent-review: # This example skips external forks and Dependabot-triggered runs; # bot reviews need separate setup. if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 with: fetch-depth: 0 persist-credentials: false - uses: openai/codex-action@v1 with: openai-api-key: ${{ secrets.OPENAI_API_KEY }} permission-profile: ':read-only' prompt: | Review the changes in this PR relative to base commit ${{ github.event.pull_request.base.sha }}. Use git diff to inspect the changes. Check for: 1. Logic bugs and missed edge cases 2. Security vulnerabilities 3. Compliance with the project specification 4. Unnecessary complexity or overengineering Report actionable findings with file paths and line numbers. Do not modify files.
This is an illustrative workflow, not a drop-in CI configuration.
The
./ci/*.sh
scripts are placeholders for scripts you would write in your repository. The agent job runs a review but does
not
automatically post the findings back to the PR; that requires an additional reporting step. In a real project, also pin third-party actions to trusted commit SHAs, restrict permissions, and carefully separate code from untrusted contributors and workflows that can access API keys. GitHub and OpenAI both publish
guidance on secure PR workflows
and
Codex Action security
.
Note that with an agentic review, you can configure your own LLM provider and credentials in GitHub Actions. The official Codex Action uses an OpenAI API key; using another provider would require that provider’s corresponding integration.
However, running this
whole
pipeline for every PR can get expensive, especially for teams practicing continuous integration with many PRs throughout the day. Some checks and agentic reviews take minutes rather than seconds, and the cost of the AI calls can add up.
It is much faster and more convenient to run cheap checks early and save the heavier ones for later stages or higher-risk changes.
This is where the pre-commit, post-commit/push, pull request, pre-production, and production stages come in.
Ideally, in a mature testing workflow, we categorize the checks by stage and by the risk of the change.
Still text-avoidant? Another diagram is waiting for you at the end of this section.
Pre-commit
This is the stage before code is committed locally.
What should happen here:
Formatting, linting, type checking, focused unit tests, build checks when fast enough, and secret scanning. Some of these can run through Git hooks; others can run directly in your editor or coding-agent harness.
Post-commit / push
This is the stage after code is committed and pushed to a remote repository.
What should happen here:
Broader unit and integration tests, SAST, and dependency vulnerability scanning. Local post-commit review tools can also give fast feedback after each commit.
Pull request (PR)
This is where proposed changes are reviewed and verified before merging into the main branch.
What should happen here:
Relevant automated tests, agentic bug scanning, agentic security reviews, specification compliance reviews, and architecture/complexity assessments. More comprehensive checks should be reserved for higher-risk changes. Require key checks to pass before merge using
repository rulesets
.
Pre-production / deployment
This is where code is verified before being released into the production environment.
What should happen here:
Full integration and E2E tests where appropriate, infrastructure configuration scanning, database migration validation, deployment smoke tests, and final security checks. For risky releases, consider staging or canary deployments and a tested rollback plan.
Production / post-deployment
This is the stage after code has been deployed and is running in production.
What should happen here:
Application health checks, error monitoring, performance monitoring, security monitoring, smoke tests, anomaly detection, and automated rollback when it is safe to do so.
How big tech runs AI software factories
Some large enterprises have been tinkering with this topic for years now, as they have the talent to pull it off and the deep pockets to tokenmax. As Adam Faik lays out in
How to build an AI-native software factory
, Uber, Shopify, DoorDash, Spotify, and Stripe all offer a glimpse into where the state of the art lives right now in this constantly evolving software factory lifecycle.
In short, teams generally get a gateway or front door that routes their requests, those requests are qualified through proper permissions and governance, then pushed through a largely automated pipeline. This pipeline has access to the code, company context, and internal tools it needs to research the request, land on a spec, propose a plan, build the thing, test the thing, and have proof to show for it. Diffs, screenshots, tests, automated reviews, and a whole slew of analytics, which are then reviewed by developers before code is actually merged or pushed to production.
In other words, developers increasingly focus on coming up with the problem to be solved, providing some input on how that might happen, and letting the agentic workflow handle much of the implementation and verification. Once done, developers serve as glorified reviewers and final gatekeepers before the PR merge or production push. Of course, the degree of autonomy varies between companies, and humans are still involved in important decisions along the way.
There is a lot more to this process, particularly around security, isolated environments, verification, and costs, and many details I’ve left out, but I think
Adam’s article
is a fascinating read for anyone curious about the different ways these AI software factories are configured and run at scale.
The practical agentic software development workflow I use
So, for those of you who have gotten this far, allow me to walk through one PR to bring the case home.
A diagram summarizing my full pipeline follows at the end of this section.
Say I have a new request to create a profile page for my app so users can see and update their profiles.
Using a strong coding model (often Claude in my setup) I explain in as much detail as I can muster what the profile page should do and look like.
My agentic workflow returns a spec. We go back and forth a couple of times, I review it carefully, and we update it until I’m satisfied. I then ask the agent to create an implementation plan broken into strategic, practical, sequential steps that can logically be divided into commits.
I also ask it to run the plan by a second top-tier model, such as Codex, to see if anything was missed or could be improved. The final plan includes the unit, integration, and end-to-end tests we intend to build.
I review the plan, iterate on it if needed, and approve it.
At that point, my main coding agent starts working on the plan, step by step or commit by commit. After each step, it asks another strong model to review the changes.
If the change is high-stakes, for example if it touches payments or sensitive production flows, I also review each commit in the meantime. Otherwise, I may wait until the whole feature is finished before doing my deep human review.
Once the coding agent gets suggestions for improvement, either from the second LLM or from me, it incorporates those changes and moves on to the next step.
This continues commit by commit, with changes to the frontend, backend, or any other code necessary. Along the way, the agent runs unit tests, integration tests, and E2E tests as appropriate. For the software I build and maintain, many of these tests are relatively cheap and fast to run. If anything fails, it gets flagged, and we correct it.
Finally, when we get to the last commit, I ask another model to review
the entire change
—all commits and all diffs—against the original spec and flag anything that was missed. If something is flagged, we investigate and fix it. Otherwise, we move on.
Now we are at the PR stage. We’ve implemented, reviewed, and re-reviewed the code against the spec and run tests along the way to ensure everything still works.
I then review the full diff myself, giving it attention commensurate with the gravity of the change. The more important the change, the more careful the review. I also run the other automated checks: SAST, dependency scanning, agentic bug review, and agentic security review. Some of these use AI agents; others use deterministic tools.
Finally, I ask the agent that built the feature to come up with short and simple manual tests I can do to confirm that the change works.
I launch the code locally or in a test environment, run those checks, and deploy to production if everything passes.
If the change is very complex or touches sensitive data, I may also run a limited, safe set of smoke tests in production, without exposing real user data or making destructive changes.
This flow allows me and my team to ship code quickly while building confidence that what we ship meets spec and has gone through meaningful testing and security checks. Not perfect confidence (software is never guaranteed bug-free or impossible to hack), but far more confidence than blindly merging whatever an agent generates.
And this is really the point:
if AI makes writing code cheap, verification has to become a first-class part of how we build software.
If you’re curious about how I run this lightweight workflow harness, let me know and I’d be happy to share it with you.
Until next time, may your tests pass and your context windows never run out.
~Mihai
Sources and references
The sources below support the research findings, product capabilities, and CI/CD/security guidance mentioned above. Product features, plan availability, and pricing can change.
Faros —
The Acceleration Whiplash
(Q2 2026):
2026 AI engineering report
. Study scope, throughput, review load, bugs, and incidents.
Faros —
The Speed Trap
(Q3 2026):
Latest report takeaways
. Nuance on later AI-adoption patterns and downstream costs.
Superpowers (Jesse Vincent / obra):
GitHub repository
. Skills-based development workflow, planning, TDD, debugging, reviews.
Adam Faik, The AI Thinker:
How to build an AI-native software factory
(October 2026). How Uber, Shopify, DoorDash, Spotify, Stripe and others run coding agents at scale, from intake to merge.
Qwen3.8-27B on the iPhone 18 Neural Engine at 15–70 tok/s (1.5 bpw)
Qwen 3.8- 27B on iPhone 18 Apple Neural Engine.
Added draft model , dflash-2 at ~ 2.8 bpw ( mixed 2-4 vector quantization with small drop in acceptance rate)
Base is
@
PrismML
Bonsai-2, 1.585 bpw requantized to 1.5 bpw ( VQ 6 bits per 4 weights)
Decoding speed is 15-60 tps.
We had a security breach last night related to a large scale distillation attack that impacted 1.4% of OpenCode Console users
We have notified them all this morning via email
The incident is ongoing so we cannot share more details at this point but we are working with Anthropic, OpenAI, and Google to remediate
Let me share about it. Some is my anecdotal experience, some my opinion, and some facts. Parsing which of these is what in each sentence is not going to happen.
EDIT: I have seen some online reaction to this, and appreciate your kind comments. If you are thinking about applying to naturalize, I encourage you to go ahead and consult at your local Legal Affairs Bureau. Act according to what they tell you there, not stuff you hear or read on the internet in places such as this random gringo’s blog. The list of required documents below is intimidating, but your case won’t be the same as anyone else’s. They treat every application individually, so the horse’s mouth is that of the Ministry of Justice, not me.
In 2012, I was at the Legal Affairs Bureau for something else and decided I wanted to start naturalizing. I had been thinking about it for a long time. I stepped into the department that handles naturalization.
Intentionally, the Government of Japan has designed the process of obtaining Japanese citizenship to be opaque, demand extensive documentation, take at least a year, and have an outcome based partly on subjective judgment.
At the first 2012 visit, an old Ministry of Justice bureaucrat kindly listened to my initial consultation. A first consultation usually requires an appointment, but he accommodated me. This would not happen today. Far more people are now applying for citizenship. The Legal Affairs Bureau for Hachioji was then located in Minami Osawa, within city limits but far away on the south edge of town. It takes about 40 minutes to drive or take a train there. Happily, the bureau is now back in the main part of town near the courthouse.
In a small i̶n̶t̶e̶r̶r̶o̶g̶a̶t̶i̶o̶n̶ consultation room, the bureaucrat asked routine questions about my nationality, number of years in Japan, marital and family status, and so on. I was proud of my Japanese fluency, community activity, and experience working in Japanese politics. Subconsciously, I think I expected to be recognized for surpassing specialness.
The bureaucrat had seen plenty of people like me. He knew how to dampen expectations: Describe the process.
The preliminary documentation I would need to gather (in order of hazy memory, and later aided by referring just now to the spreadsheets I was constrained to create): An original birth certificate for each of my parents and each my six siblings. Original copy of proof of my parents’ marriage. An affidavit signed and dated by my mother attesting that she gave birth to me. List of members of my wife’s family, including their names, dates of birth, nationalities, and current status of interaction with me. A statement regarding whether each above individual wanted to also naturalize, and whether they were in agreement or opposition to my naturalization. Original copy of my birth certificate. Proof of my marriage. List of every address of every place I ever lived and the dates beginning and ending my living there. Complete academic history starting with preschool. Any diplomas or degrees obtained in the course of that academic history. Complete work history with company name, position(s) held, and dates of starting and leaving. All information originating in English had to be submitted in both original form and also translated into Japanese, with a certificate of the accuracy of the translation. Japanese translations could not include alphabet letters—only kanji, hiragana, katakana, or Arabic numerals (I suppose we should give thanks that kanji numerals were not required). But every proper noun in the awkwardest katakana. All documents originating in Japanese submitted with one original and one copy. My certificate of residence. My Zairyu (residence) card. My driver license. All tax returns of me and my wife from some number of years I can’t recall. Statements of withholdings from all employers or income sources for me and my wife. Proof that I and my wife were subject to and had paid applicable taxes to the National Tax Agency, Tokyo, and Hachioji, respectively. Proof of paying health insurance premiums. Proof, issued by the Pension Office, that I had paid my employment insurance. All of the above were going to be evaluated to see that I had not only paid, but paid
on time
, for said number of years. An official driving record issued by the National Police Agency, listing any and all traffic violations during the maximum 10 or whatever years that such data are retained. I had a company, did I? Then also provide for the same number of years all of its financial statements, proof of paying national corporate taxes, proof of paying consumption taxes, proof of paying prefectural taxes, proof of paying city taxes, proof of paying withheld employee taxes, proof of paying employment insurance. The company registration, Articles of Incorporation, a list of clients, and a description of the business and its prospects. My wife’s family register. A statement from my wife that we were indeed married and had indeed had those kids together. A statement from my wife indicating whether she agreed with or was opposed to my naturalization. Three photographs of our family together on separate occasions (proving that we always pose in the same position as I take a selfie, causing the set of three photographs to look utterly suspicious). A listing of all household income sources and monthly expenditures categorized severally and exhaustively. Certification of Child Allowance disbursements received from the city. List of all loans, the institution making the loan, the amount of principal, monthly payment, and purpose of loan. List of bank accounts, with copy of all pages of each bank book. Proof of current citizenship issued by the US embassy. Original copy and Japanese translation of every page of all my passports expired and current, along with list organizing into a timeline the dates of my travel into and out of every country I had ever visited. Map showing my current place of residence. Map showing my current place of employment. A free-form, handwritten statement of my motivation for seeking citizenship. Certificate of enrollment of each of my children at their respective schools. Certificate of employment issued by my company about me. Certificate of the amount of my salary, issued by my company. The title and registration to each plot of land and building I owned. My certificate of passing the Japanese Language Proficiency Test (JLPT) Level 1. A photo of my face, two copies. A form listing what my name would be following naturalization.
In 2012, I was already certain that I would be spending the rest of my life in Japan as part of society here. But my brain had not developed to the point of being able to direct my physical body to take the actions necessary to create or gather the above items.
Also, I wanted to run for city assembly after obtaining citizenship. My wife knew this. In her wisdom, she did not want me to run for city assembly. I was going to have to do all of the actions on my own, and then also somehow prevail upon her to express her assent to my naturalization application. There was going to be an interview where the bureaucracy asked her opinion, and it was going to carry weight.
I knew that one could hire an attorney to aid one’s naturalization application. I also knew deep down that the attorney was essentially going to say “put together [all of the above items] and I will submit the application for you.” Interviews were still going to be in person. A translation agency, no better than the one that was my own company, was going to be paid to translate everything. It would have the single advantage that I would have to answer to someone to get everything done. But I was not flush with cash for an attorney, or motivation. I did at least schedule a second consultation—the appointment is in my 2013 calendar. I may have actually not gone. I’m not sure. The old bureaucrat is surely now retired.
The first attempt thus died on the vine after a mildly heroic effort.
The most heroic naturalization efforts made in 2012 were not made by me, but by my parents and siblings. Having been told at that first consultation that they were required, I asked each of them to go get original copies of their birth certificates re-issued. They are so very good to me, and they dutifully did so. It was undoubtedly a massive pain. My siblings were born in a variety of US states that are not where they live now, because my dad was in the US Navy. I don’t know what they had to do to get the originals, but each was given to me.
I made another run at the process in 2018. Again it did not take.
I spent a hell of a long time living in Japan without ever applying for permanent residency. PR never felt like the way for me, because I always assumed I would be applying for naturalization at any moment. Every time I renewed my spouse visa, the people processing the documentation would remark on how unusual it was.
Then around September 2024, I was again at the Legal Affairs Bureau. It had been moved back into the main part of town, as noted above. My purpose that day was not to apply for naturalization, but to get a company registration issued, or maybe pull a property title. Again I saw the sign pointing to the department that handles naturalization. Again I impulsively went to the window and asked to apply for naturalization. This time I was afforded no consultation. I remember getting a glance at the appointment book as they opened it to see when I could get an appointment for a consultation, and it was chock full of names. They scheduled me the next available two-hour slot, in October.
At the October appointment, a new grizzled old veteran met me. He first confirmed my Japanese ability through conversation, then by having me read and write some things. The passage I had to read was from a children’s book, all written in hiragana. The funny thing that will surely resonate with a lot of people is that it is harder to read pure hiragana passages. It’s an unnatural form that doesn’t exist except in children’s books or messaging meant to be understood by people who can’t read anything else (which purpose I do not disparage, mind you). It would have been far more natural to read normal Japanese that includes kanji and katakana. Anyway, I read the thing. Maybe choppily, because grizzled veteran had me nervous. Then I wrote as directed. He panned my handwriting. Haha. “Get off my back, bro. I am an objectively accomplished linguist.” Well, that ain’t the test.
He gave me pretty much the same list as above. Except now I had started
another
company. Of course every document was still needed for it, along with all the others. I think they had removed the requirement for a translation certification, though. Credit where due.
Since 2012, I had also bought property and built a house on it. I had gotten new passports and filled their pages by traveling to many more countries. I had 13 more years of life under my belt, and it all required that much more documentation. Happily, I had also gotten better at handling administrative tasks like tax filings and pension payments. Not through personal growth, but by hiring people to do them on my behalf. My driving record was now spotless, with youthful speeding and parking indiscretions dissolved by the limitations of nation-state record retention. I was making more money. My company was more successful. My marriage was better. I had articulated internally why I wanted to naturalize. I had made more social contributions, like volunteer firefighting in Shobodan, chairing the Ichou Festa, and neighborhood association work.
At the October 2024 appointment, we set an appointment at the next available date, in February 2025, for the official submission of my application.
Getting the package of all the above documents and other items together was absolutely daunting. A fresh hell. As February 3 approached, I still hadn’t gotten everything together. February 2 was an all-nighter. Translations were cranked out, items were organized, copies were made, everything was stacked together. The stack was easily over two feet high. I packed it all into a couple of big department store shopping bags.
At the submission, grizzled veteran and I went through each item. He affixed a “RECEIVED” stamp to each. We found that two or three items were missing, or I had misunderstood what was needed. I promised to send them by Letter Pack immediately. At the end I was assigned an entry-level bureaucrat who would be my case worker. I was told to enter the Legal Affairs Bureau phone number into my phone and be ready for calls asking for extra information or appointments. I was told the procedure for calling the specific extension and stating my case number before asking for my case worker.
I was apprised that my application would only proceed while I was in Japan: Prior to any business or other trip outside Japan, I had to call and notify when I was leaving and returning. My application would stop for precisely that number of days. When returning, I was to call and check back in with my case worker. Happily for business and sadly for naturalization, I made many international trips from February 2025 to June 2026. The Ministry of Justice assiduously delayed my application accordingly. I understand this policy, though. If you want to naturalize, be in the country. At the same time, it required patience to know that being gainfully employed in international business was delaying the application.
My first case worker was transferred away after only a few contacts by phone. A new one was assigned. Their primary characteristic was mumbling inaudibly on the phone. They were young, maybe early 30s. There were occasions where I could tell that my phone call had caused them to remember something they were supposed to have done, and without my calling it wouldn’t have gotten done.
During Covid, the US FDA and other regulatory bodies stopped coming to Japan to inspect medical device and pharmaceutical facilities for about three years. My primary business is to assist life science firms by helping them to understand and comply with the regulations, and then to prepare, host, and interpret regulator inspections of their facilities. So obviously, the company’s revenue and profits suffered severely during that time . Surveying my Covid-era company financials, my case worker decided they were not good. He called me one day: “This sure is some bad company performance.” Me: “Yeah, Covid hit us hard. We could have taken government assistance and put our employees on leave at reduced salaries, but I decided to use savings and then take out loans that I have paid back to the last yen faithfully, to keep paying full salaries. We stayed open and handled what work we were still getting to support our clients.” Him: “Well, it’s still not very good.” That was a frustrating conversation. I don’t doubt that he passed a hard test or two to become a national civil servant, but he also clearly had no experience running a business.
He asked me to write down the above explanation of why the company had done poorly during that time. I did. I addressed it to the Minister of Justice (as all these submissions are) and worded the extensive explanation to pointedly refute the case worker’s view. I emphasized that I kept people employed during a crisis and thought this criticism of our results was horseshit, and to please kindly continue considering my application.
The same case worker failed to call to notify me of the application result, until four days after the
官報 Official Gazette
carried notice of my naturalization being approved. That was inconvenient in many ways, especially because that is the number of days sooner that I could have applied for and obtained a Japanese passport, allowing me to resume business travel. Until the passport is issued, I am stuck in the country and unable to leave for business or any other purpose. Japanese citizens are prohibited from leaving the country without a passport. I am certain that the case worker just let the notification sit on his desk for four days. Bad job by him.
In light of that final insult and all the above and more details I have forgotten or omit, it may seem strange to say that overall, I am okay with the process.
I don’t think citizenship is a light thing. It is not rational to make it friction-free or fast. I was not ready to naturalize in 2012. The system is arcane and arbitrary, and also worked correctly to weed me out of the process. It impressed upon me the importance of following the rules and making a contribution, which honestly impacted how I behaved and thought thereafter. When I was absolutely committed, I was able to get through the process.
My name after naturalization is the same as it was before: Derek Lynn Wessman. Except now in official records it is written in katakana, since alphabet letters cannot be listed on a 戸籍 family register, which is the foundational document on which a Japanese citizen’s identity rests.
A lot of people believe that one must adopt a kanji name when naturalizing, but this has never been the case. However, it seems that in the past, pressure was placed on applicants to adopt Japanese-sounding and -appearing names. The entire naturalization process, especially scrutiny of siblings and parents, has many vestiges of its Cold War-era focus on the Zainichi Korean residents of Japan who were then the most frequent applicants. The government was anxious to find out if an applicant had ties with North Korea.
Why not change my name, though? I could certainly imagine adopting kanji whose pronunciation approximates my name, or adopting my wife’s former family name, or taking the appellation of some historical figure I like, such as
Yamamoto Kansuke
. I kept my name because I love it. I am proud of the name Wessman, which I hear was adopted so an ancestor could join the Swedish army when the quota of people with his previous name Bengtsson was already filled (or something like that). I like the name Derek. My middle name is from my uncle, who, if you search or ask AI, is an exceptional person of great accomplishment. Most importantly, my whole household is already this family name and would be greatly inconvenienced by a name change this far into their lives.
I do need to notify banks, change some documents and listings, and go through procedures on a number of fronts. All in all, it’s not a huge burden.
A fun fact: Upon having my family register created, I had to re-propose to my wife. Being added to one’s spouse’s family register is the administrative act of marriage in Japan. Until now, my wife was the head of her own family register and my kids were listed with her on it, along with some foreign bozo tacked on who she was married to (me). I wouldn’t be surprised if this latest 2026 proposal gave her pause. She did kindly came along, and so did the kids. Reunited and it feels so good. Not unrelated: I do not plan to run for office in the near future.
The moment of receiving citizenship was this: The above case worker called me four days late. He asked when I could come in to receive the government-issued document that attests to my naturalization. I said I was on my way. He said okay. I arrived. He invited me into a small i̶n̶t̶e̶r̶r̶o̶g̶a̶t̶i̶o̶n̶ consultation room. We both sat down, separated across a desk by a Covid-era plastic divider. He handed me the Certification of Identity of Naturalized Person. He told me to take it to city hall and apply to have a family register created for me. He pronounced a benediction on the whole process: Good old “
o-tsukaresama deshita
.”
That was it. No pledge of allegiance. No huddled masses pronouncing oaths together. No pomp and circumstance. Just walking down the sparse stairway of the plain public building feeling happy that I had finally joined my fate with this country that I love. I liked it.
Linux bugs fixed per release over time: >2× rise since 2026-04
Linus Torvalds
released
the 7.2 kernel
on August 17, after noting that the number of fixes
coming in was still "
bigger than I would have wished for
". In fact,
7.2 was one of the busiest development cycles in the kernel's history,
adding nearly 600,000 lines of code. It's time to look at some statistics
to get a handle on how the kernel's development community is changing.
There were 16,418 non-merge commits brought into the mainline for
the 7.2 release, exceeding the (already busy) 7.1 release; it is, in fact,
the second-busiest release in the kernel's history. Only the
6.7 release
brought in more commits but, while
6.7 was dominated by the merging of the bcachefs development history, the
volume for 7.2 is more broad-based.
$ sudo subscribe today
Subscribe today and elevate your LWN privileges. You’ll have
access to all of LWN’s high-quality articles as soon as they’re
published, and help support LWN in the process.
Act now
and you can start with a free trial subscription.
These commits were contributed by 2,652 developers, a big increase
over the previous record (2,479 in 7.1). If one looks at the history of
developer involvement since the beginning of the Git era, the result is:
(This plot, like much of the information here, comes from the subscriber-only
LWN Kernel Source Database
). There has been a clear
trend over that entire history: the number of developers contributing to
each release increases over time. But the slope of that line has clearly
changed.
The most active developers working on 7.2 were:
Most active 7.2 developers
By changesets
Uwe Kleine-König
151
0.9%
Rosen Penev
146
0.9%
Ian Rogers
138
0.8%
Johan Hovold
133
0.8%
Arnaldo Carvalho de Melo
131
0.8%
Chuck Lever
129
0.8%
Eric Dumazet
121
0.7%
Ville Syrjälä
115
0.7%
Johannes Berg
112
0.7%
Krzysztof Kozlowski
110
0.7%
Thorsten Blum
108
0.7%
Namjae Jeon
106
0.6%
Christoph Hellwig
104
0.6%
Sean Christopherson
100
0.6%
Jakub Kicinski
96
0.6%
SJ Park
94
0.6%
Mike Rapoport
91
0.6%
Dmitry Baryshkov
87
0.5%
Eric Biggers
86
0.5%
Rafael J. Wysocki
78
0.5%
By changed lines
Matthew Stewart
83587
8.4%
Hawking Zhang
62893
6.3%
Miguel Ojeda
38979
3.9%
Ian Rogers
31949
3.2%
Darren Ye
20843
2.1%
Ethan Nelson-Moore
16893
1.7%
Harry Wentland
15233
1.5%
Uwe Kleine-König
13803
1.4%
Ingo Molnar
13649
1.4%
Chuck Lever
10172
1.0%
Eric Biggers
10067
1.0%
Jakub Kicinski
9449
0.9%
Rodrigo Siqueira
7749
0.8%
Johannes Berg
7110
0.7%
Arnd Bergmann
7085
0.7%
Emil Tsalapatis
6810
0.7%
Vivek Aknurwar
6544
0.7%
Rob Clark
6490
0.6%
Sabrina Dubroca
6401
0.6%
Svyatoslav Ryhel
6072
0.6%
Uwe Kleine-König [
KSDB
]
was the biggest contributor of commits to the 7.2 release with cleanups
through the driver subsystem. Rosen Penev [
KSDB
] contributed a long
list of LLM-authored bug fixes throughout the architecture-specific,
driver, networking, and crypto subsystems, among others. Ian Rogers [
KSDB
] worked extensively on
the user-space
perf
tool, as did Arnaldo Carvalho de Melo [
KSDB
]. Johan Hovold [
KSDB
] made numerous
improvements, mostly in the SPI and USB subsystems.
Matthew Stewart [
KSDB
]
reached the top of the lines-changed column by following the time-honored
tradition of adding more massive, machine-generated amdgpu header files;
Hawking Zhang [
KSDB
] did
likewise. Miguel Ojeda [
KSDB
] brought
the Rust zerocopy
crate
into the kernel source. Darren Ye [
KSDB
] added the MediaTek mt8196
sound driver.
Just over 8% of the commits in 7.2 carried Tested-by tags, while 48%
included Reviewed-by tags. The review tags, in particular, are showing a
mild downward trend in recent releases:
Whether that decline reflects an actual decrease in the amount of review
taking place is unclear at best. In any case the most active testers and
reviews for this cycle were:
Test and review credits in 7.2
Tested-by
Dan Wheeler
117
7.0%
Luiz Capitulino
54
3.2%
James Clark
44
2.6%
Sarthak Sharma
44
2.6%
Venkat Rao Bagalkote
32
1.9%
Tommaso Merciai
27
1.6%
David Riley
27
1.6%
Jie Gan
27
1.6%
Geert Uytterhoeven
25
1.5%
Arthur Kiyanovski
25
1.5%
Marek Szyprowski
25
1.5%
Randy Dunlap
24
1.4%
Shivaprasad G Bhat
24
1.4%
Rinitha S
21
1.3%
Vitaly Prosyak
20
1.2%
Reviewed-by
Konrad Dybcio
231
2.2%
Dmitry Baryshkov
225
2.1%
Andy Shevchenko
175
1.7%
Geert Uytterhoeven
171
1.6%
Krzysztof Kozlowski
152
1.5%
Frank Li
147
1.4%
Ilpo Järvinen
145
1.4%
Christoph Hellwig
143
1.4%
Jan Kara
121
1.2%
Christian König
120
1.1%
Linus Walleij
116
1.1%
Alex Deucher
105
1.0%
Simon Horman
102
1.0%
Jeff Layton
101
1.0%
Ido Schimmel
94
0.9%
Dan Wheeler [
KSDB
] is, as
always, the top tester by virtue of his work with AMD graphics-driver
patches. On
the review side, Konrad Dybcio [
KSDB
] added
his tag to 231 changes while Dmitry Baryshkov [
KSDB
] tagged
225; the same two, who both tend to focus on drivers and devicetree files
for Qualcomm devices, were at the top of that list for the 7.1 cycle as well.
Work on the 7.2 kernel was supported by 249 employers that we were able to
identify; the most active of those were:
Most active 7.2 employers
By changesets
(Unknown)
2743
16.7%
Intel
1512
9.2%
Google
1191
7.3%
Red Hat
873
5.3%
AMD
813
5.0%
Qualcomm
767
4.7%
(None)
743
4.5%
NVIDIA
535
3.3%
Meta
441
2.7%
(Consultant)
429
2.6%
SUSE
358
2.2%
Renesas Electronics
328
2.0%
IBM
307
1.9%
Kylin
278
1.7%
NXP Semiconductors
264
1.6%
Oracle
245
1.5%
Arm
222
1.4%
BayLibre
203
1.2%
Microsoft
201
1.2%
Bootlin
194
1.2%
By lines changed
AMD
224121
22.4%
(Unknown)
103861
10.4%
Google
102565
10.3%
Qualcomm
59021
5.9%
Intel
53661
5.4%
Red Hat
51559
5.2%
Meta
38635
3.9%
(None)
28218
2.8%
NVIDIA
27417
2.7%
MediaTek
22025
2.2%
NXP Semiconductors
17692
1.8%
BayLibre
15972
1.6%
Oracle
12233
1.2%
Microsoft
11786
1.2%
Renesas Electronics
11103
1.1%
Linaro
10209
1.0%
(Consultant)
9362
0.9%
IBM
9205
0.9%
Texas Instruments
8398
0.8%
SUSE
8350
0.8%
The most significant change this time around, arguably, is the significant
increase in developers with unknown affiliation. This is partially, at
least, a reflection of the ongoing flood of new developers entering the
kernel community.
New developers and their tools
Each of the previous two kernel releases had set a record for the number of
first-time developers contributing changes; 7.2 has broken that record
again, with 613 contributors [
KSDB
] who had not been seen
here before. Here, once again, the trend is clear:
The most active new developer was Bryam Vargas [
KSDB
], who contributed
43 commits fixing problems in the input, NVMe, F2FS, AppArmor,
Landlock, SELinux, NTFS, WiFi, ATA, SCSI, networking, Ceph, and Thunderbolt
subsystems, among others. As has been observed here before, it would be
difficult for a seasoned kernel developer to reach deeply into that many
subsystems over the course of a single development cycle — at least, if
they wanted to understand what they are doing. For a previously unknown
developer to do this is surprising at best. Vargas's patches do not carry
Assisted-by tags, though, so we are left to believe that this work was done
without LLM assistance.
Overall, 1,111 changes in 7.2 (under 7% of the total) carried
Assisted-by tags — a significant increase over the 301 seen in 7.1. The
real count of LLM-assisted patches in 7.2 must surely be far higher than
that, though. Many developers do not supply those tags (often — but not
always — out of ignorance of the rules), maintainers rarely ask about LLM
use, and at least one maintainer
actively strips those
tags
when applying patches. Accurately tracking commits developed with
LLM assistance may turn out not to be possible, but it sometimes feels like
the kernel community does not care enough to really try.
The other way in which LLM usage is making itself felt in kernel
development is in the area of patch review. There are 252 patches
in 7.2 with Reported-by tags crediting the
Sashiko review system
[
KSDB
];
568 commits mention Sashiko in their changelogs. Other LLMs are
also clearly being used to find kernel bugs, though, with real effects.
The 7.2 release contains 4,830 commits with Fixes tags, indicating
that they fix a bug introduced by a previous commit. To see just how
significant an increase is, consider this plot, an updated version of one
that has been seen here before (most recently for the
6.17 development cycle)
:
The heavy green line plots how many commits in each release contained Fixes
tags, while the heavy brown line is the number of commits that were
identified by Fixes tags in subsequent commits. The crossover point is at
5.9, suggesting that, as of that release, the kernel community started
fixing more bugs than it introduced. That conclusion will not hold,
though; it will take years for all of the post-5.9 bugs to be identified
and fixed, and that line will shift as it happens.
The noteworthy part of the plot, though, is at the right-hand side, where
the number of commits carrying Fixes tags increases dramatically, after
having been roughly level for quite a few releases. That, it seems, is
what happens once large numbers of people start turning LLMs toward the
task of finding bugs in existing software. This is going to be an
interesting trend to watch. The number of bugs cannot be infinite — even
in the kernel — so the rate of bug detection and fixing must eventually
fall off. The existing bugs will have been fixed, and LLM review will have
reduced the number of new bugs introduced. At least, that is the hope.
If that drop-off does
not
happen, there will be some interesting
questions to answer. It seems reasonably clear that the spread of LLMs has
enabled people to create kernel patches who would not have been capable of
doing so before. If that is true, it is not much of a stretch to conclude
that, in many cases, the submitters of these patches do not fully
understand what those patches do. Perhaps the LLMs are good enough that
this understanding is no longer necessary, but it could also be that we are
creating a pile of code that nobody has ever really understood, but which
will need to be maintained in the coming years.
The Linux kernel is aimed at production use, not research or
experimentation. But there is currently a massive experiment being run on
the kernel's development processes and community. This community has
absorbed new processes and tools many times over its 35-year history, and
will almost certainly find a way to do that this time as well. But that
absorption has not always been without turbulence along the way.
Meanwhile, there are nearly 14,000 non-merge changesets sitting in
the linux-next repository and poised to be pulled for the 7.3 release; over
1,100 of them contain Assisted-by tags. It would seem that the high level
of activity that has characterized recent releases will not be ending
anytime soon. As always, keep an eye on LWN as we follow the next
development cycle (and those that come after).
An experimental TypeScript port of the TypeScript 7.0.2 compiler (
TypeScript-Go
, or tsgo), compiled to native code with
scriptc
.
Installation
Install the compiler from npm:
npm install -D tsc-ts
npx tsc-ts -p tsconfig.json
The
tsc-ts
package runs a native executable from a per-platform optional dependency (
@tsc-ts/darwin-arm64
,
@tsc-ts/linux-x64-gnu
, …). See
packages/tsc-ts
.
A scriptc host: macOS, Linux, or Windows, with
clang
available for linking
Build
npm ci
npm run fetch:upstream # clone tsgo at the pinned commit
npm run build # the Node build of tsc-ts (packages/tsc-ts/dist) and the documentation site
npm run build:oracle # tsgo reference builds in packages/tsgo/dist
package.json
pins scriptc
0.3.5
, with its
@scriptc/threads
package. The build fails with any other version.
Compiler
packages/tsc-ts/src/compiler
is the compiler, ported from tsgo 7.0.2 as idiomatic TypeScript. Each part is compared with tsgo on TypeScript's test corpus (about 12,500 files, 17,000 units after splitting multi-file cases):
Part
Compared with tsgo
Status
Scanner
tokens, values, errors, rescans, JSDoc
all files match
Parser and AST
tree, diagnostics, API source file encoding
all units match
Binder
symbols, tables, flow graph, name resolution
all units match
Module resolution
results, package IDs,
--traceResolution
all requests match
tsconfig.json
and programs
--showConfig
,
--listFilesOnly
,
--explainFiles
all cases match
Command line and options
output, errors, exit codes,
--locale
all cases match
Diagnostics catalog
messages, 13 translations, output formats
all match
JavaScript emit
emitted files, 39 option sets
all compared units match
Declaration emit
.d.ts
and
.d.ts.map
output, declaration errors
all units match
--build
,
--incremental
output,
.tsbuildinfo
, emitted files,
--watch
all scenarios match
Type checker
diagnostics per file
all files match
The corpus scripts are in
packages/tsc-ts/scripts
(
*-corpus.mjs
).
API server
tsc-ts --api
serves the same API as TypeScript 7.0.2's
tsc --api
, over stdin and stdout, so tools that drive
tsc --api
(such as scriptc) can run
tsc-ts
instead.
npm run build -w tsc-ts
node packages/tsc-ts/dist/tsc-ts/src/main.js --api --cwd path/to/project
Native builds read lib files from the executable's directory, or from
TSC_TS_LIB_DIR
:
npm run build:native -w tsc-ts # packages/tsc-ts/dist/tsc
npm run build:native:dev -w tsc-ts # unoptimized, faster to build
TSC_TS_LIB_DIR=upstream/typescript-go/internal/bundled/libs packages/tsc-ts/dist/tsc -p path/to/project
TSC_TS_BIN=packages/tsc-ts/dist/tsc
runs the tsc-ts tests that take a native build against it.
The server is checked against
tsc --api
7.0.2 response by response, and scriptc builds the same programs with either. It runs on the tsc-ts compiler, natively or under Node.
Language service methods are supported:
getCompletionsAtPosition
,
getJsDocTags
,
getDocumentationComment
,
getReferencesToSymbolInFile
,
getReferencedSymbolsForNode
and
getSignatureUsages
. Like
tsc --api
, completions that need auto imports (global identifiers, import statements, exhaustive
switch
cases) report
completion list needs auto imports
. The profiling methods (
startCPUProfile
,
stopCPUProfile
,
saveHeapProfile
) are not supported.
Testing
npm test# compare tsc-ts with tsgo
npm run bench -w tsc-ts # time tsc-ts against tsgo and TypeScript's JavaScript compiler
npm run lint # oxlint
npm run format # oxfmt
Normally, America’s highest value exports are either oil, pharmaceuticals, or aircraft and their parts. Not now. Starting in October 2025, the value of gold exports has topped all other categories almost every month. For information on U.S. nonmonetary gold exports through December 2025, go to
https://fred.stlouisfed.org/series/IEAXGG
That’s not just because the price of gold reached record high prices. In February 2026, the tons of gold exported may have set an all-time record.
The majority of gold exports are going to Switzerland, almost certainly to the refiners there. The second greatest quantity is going to Hong Kong, which is the global destination for gold going to China. The third greatest quantity of exported gold is going to the United Kingdom, where the
London Bullion Market Association
is the world’s largest gold trading exchange.
The U.S. government is still reporting that its gold reserves are unchanged, so these exports look to be coming from current mine output and recycling operations.
Why is this happening?
There is no official explanation of why U.S. gold exports have soared in recent months. But here is my speculation.
There are multiple foreign governments growing leery of the future loss of purchasing power of the U.S. dollar, where they would prefer a different reserve asset with a better track record. Among all foreign central banks combined, the value of their gold reserves now exceeds their holdings of U.S. Treasury debt.
Most foreign nations do not have the economic and financial power when negotiating with the U.S. government or businesses to demand payments for goods and services other than in dollars.
China does have the economic and financial clout to press for payment in gold instead of dollars. The Chinese Central Bank has a track record the past few years of reducing its holdings of U.S. Treasury debt, from $1.096.1 trillion in April 2021 to $784.3 billion in February 2025, and the latest reported at just $693.3 billion in February 2026. Much of the decrease in Bank of China U.S. Treasuries has been replaced with gold.
The Chinese government is also working to decrease the use of the dollar in international commerce, through the creation of alternative payment systems and the promotion of the “unit” for transactions among the member nations of the BRICS consortium.
When you add up the gold held by the Chinese central bank (which has a decades-long track record of underreporting gold reserves, Chinese sovereign investment funds, the Chinese military, the inventories held by companies owned directly by the Chinese government or the Chinese military, and private citizenry, there are multiple analysts who consider that nation effectively controls the greatest amount of gold of any government.
When you put these factors together, my suspicion is that a high percentage of U.S. gold exports are going to China, though some must first detour through Swiss refineries to convert the gold into kilogram bars of acceptable purity. It is possible that the U.S. government may have acquiesced in this form of payment in return for other political concessions having to do with a number of global uncertainties.
Can I prove this? No. But it does make sense, much more than any other explanation.
Last column’s numismatic trivia question.
Last time I asked—
Why did the Coinage Act of 1834 reduce the gold content in U.S. coins?
From the late 1700s to the 1830s, the relative value of gold to silver had increased. As a result, pre-1834 U.S. gold coins contained a higher value of gold than their face value. Many were being melted down. In 1834, the U.S. government reduced the gold content in coins to match
the face value to the international value of the gold they contained.
This week’s trivia question
Here is this week’s question.
Which denominations has the U.S government issued in both coin and currency?
Come back next week for the answer.
Patrick A. Heller was honored as a 2019 FUN Numismatic Ambassador. He is also the recipient of the American Numismatic Association 2018 Glenn Smedley Memorial Service Award, the 2017 Exemplary Service Award, the 2012 Harry Forman National Dealer of the Year Award, and the 2008 Presidential Award. Over the years, he has also been honored by the Numismatic Literary Guild, Professional Numismatists Guild, National Coin & Bullion Association, and the Michigan State Numismatic Society. He is the communications officer of Liberty Coin Service in Lansing, Michigan, and writes “
Liberty’s Outlook
,” a quarterly newsletter on rare coins and precious metals subjects. He now volunteers with the National Coin & Bullion Association as its Industry Issues Advisor. Past newsletter issues can be viewed at
www.libertycoinservice.com
. Some of his radio commentaries, "Things You ‘Know’ That Just Aren’t So,” and “Important News You Need To Know,” can be heard at 8:45 a.m. Wednesday and Friday mornings on 1320-AM WILS in Lansing (which streams live and becomes part of the audio archives posted at
www.1320wils.com
).
You may also like:
Artie (YC S23) Is Hiring Enterprise AES and Senior Engineers
OpenAI has added four more cases of misbehaving AI agents to a disclosures page it stood up following the Hugging Face hack in July, in an effort to be more transparent.
The incidents OpenAI disclosed this week all occurred in June, but OpenAI was not aware of three of them until months later in August or September.
Of the 19 total incidents OpenAI details on the disclosure page, most occurred in May or June, but OpenAI did not discover or disclose them until months later. The earliest incident is from January, and the most recent is from Oct. 6.
All of the incidents are examples of what AI researchers call “misalignment,” which is when an AI model fails to follow instructions or takes actions that the person developing the model did not authorize and would not have wanted the model to take. There is no known, silver-bullet solution to preventing this behavior, and it is an active area of research.
Downloading 24 years of unauthorized hospital bed data
Of the four cases OpenAI uploaded this week, it marked two as “critical.” In
one of the critical cases
, an internal model that was “highly persistent” downloaded 24 years of hospital bed data from an unnamed government website without permission. OpenAI did not immediately respond to
Fortune’
s request for comment on which government website it was.
The website initially blocked the agent’s request, but the AI ultimately found a way to bypass the access controls. Multiple times along the way, the agent’s “chain of thought,” in which an agent writes down its reasoning steps, indicated that the model itself was questioning if its actions were “ethical,” but it ultimately proceeded.
On OpenAI’s side, another AI model that acted as an automated grader of the research task the other AI model was trying to fulfill did not consistently flag this behavior as problematic. It “marked some responses incorrect and others correct,” the report said. The way graders assess AI behavior can shape whether it occurs again. In a Sept. 11
essay
on misalignment by Turing Award–winner Yoshua Bengio, he said the Hugging Face incident may have occurred because automated graders rewarded cheating and hacking in previous training runs.
“With the OpenAI agents, there is reason to believe successful cheating was actually rewarded: When the scoring program does not see the cheating, it pays out anyway, and such cheats become more likely next time,” Bengio said.
OpenAI says it has since improved its security as well as its alignment grading. “In response to this and to other incidents, we’ve strengthened our security controls, blocked models from accessing the live internet during training or evaluation, improved our alignment grading, and extended our misalignment monitoring to all reinforcement learning and evaluation traffic,” the company noted.
The most recent incident OpenAI has disclosed, which occurred on Oct. 6, involved one of the AI models the company uses as an automated grader. In that case, the grader tried to upload fraudulent reports on what it had found in an evaluation. This is an example of why relying on AI models to grade the training runs of other AI models can be problematic.
Making an unauthorized purchase with someone else’s cryptocurrency
In
another disclosed case
, a model in the GPT-5.6 Sol family—the predecessor to OpenAI’s current flagship model, GPT-6 Astra—accessed a cryptocurrency wallet the human testers had not provided it, and made an unauthorized payment to complete a task during testing. This occurred on June 26. OpenAI discovered it in September.
“The model questioned whether it had permission” to make the purchase, OpenAI said, again referring to what the model had recorded about its own reasoning in its chain of thought. It then reasoned with itself that since it found the information publicly, it could use it. In the model’s chain-of-thought logs, it figured that since the wallet it found was public, that “funds could be stolen anytime.”
It then concluded, “We can deploy!” It later asked itself again if the act was done “ethically,” and reasoned that the funds were “effectively abandoned.”
Getting internet access, changing live systems
The other
incident
OpenAI flagged as critical involved a model looking up public data, which theoretically is acceptable, but in the process it accessed the organization’s internal system, made changes to it, and was still able to “retain access … even after reverting the changes,” OpenAI said. It also downloaded 147,451 rows from nonpublic data tables. Perhaps most concerningly, the model did not disclose any of its actions to the evaluators.
In the
final case
OpenAI disclosed, an AI agent was able to get internet access from a research environment that should have been isolated—potentially similar to what happened during the Hugging Face incident, in which hundreds of AI agents were able to get internet access, although OpenAI did not directly compare these two incidents.
In the newly disclosed case, the agent knew it was not allowed to access the web, so it asked “external services” to perform actions it was blocked from doing. It did this even after it had found another way to answer the question, and also continued to develop its crafty work-around even after completing the task.
Semaglutide, a widely used weight loss drug sometimes sold as Ozempic or Wegovy, slowed biological aging across multiple epigenetic clocks in a randomized, double-blind, placebo-controlled clinical trial.
Credit: iStock/Eduardo Monroy Husillos
Beyond the widespread attention GLP-1 drugs are receiving for treating obesity, lowering blood sugar and decreasing the risk of cardiovascular disease, emerging research is investigating their other potential impacts — including their effects on aging.
Now, a new study provides the first randomized, placebo-controlled clinical evidence that semaglutide, a widely used GLP-1 drug, slows down the accumulation of biological aging markers in the DNA of adults with HIV. The study is published in
Nature Communications
.
Researchers at the University of California, San Diego and several partner institutions analyzed data from a previously published
clinical trial
of 108 adults with HIV‑associated lipohypertrophy, a condition in which excess fat builds up around the abdomen. About half of the participants received weekly injections of semaglutide, with the rest receiving placebo injections.
The team used a set of biological “epigenetic clocks” to track cellular aging over the 32-week treatment period. These clocks detect DNA methylation, chemical marks on DNA that help regulate how genes are turned on or off without changing the genetic sequence itself. By measuring changes in these marks, the team could assess whether the treatment was associated with a slower or faster biological aging pattern.
People with HIV often experience accelerated aging, even if it is well-controlled with antiretroviral therapy, according to first author Michael Corley, Ph.D., associate professor at UC San Diego School of Medicine and the
Stein Institute for Research on Aging
. However, the study found compared to the placebo group:
Participants treated with semaglutide exhibited a broad pattern of slower biological aging across epigenetic clocks linked to inflammation and blood, brain, heart, kidney, liver and metabolic health.
The drug slowed the pace of biological aging by 9 %, as measured by the
DunedinPACE
epigenetic clock.
The drug significantly slowed biological processes associated with the risk of all‑cause mortality and age-related disease, as measured by the
PCGrimAge
epigenetic clock.
Research suggests there are several mechanisms by which semaglutide may influence biological aging. By reducing inflammation and metabolic stress, GLP-1 drugs decreased chronic immune activation, a primary driver of accelerated aging in people with HIV. They also reduce visceral and ectopic fat that accumulates around the abdomen and organs, which may help curb the inflammatory and metabolic signals that promote aging.
“Emerging data also suggest that GLP-1 drugs may reprogram certain cells in different organs, which could help explain why we see effects across multiple aging clocks,” said Corley.
While the study focused on people with HIV‑associated lipohypertrophy, Corley says it may also offer lessons for the wider population.
“Many of the biological processes we study in HIV are also central to aging in the general population,” he said. “Because these processes can emerge earlier or be more pronounced in people with HIV, this community can help us identify interventions that may improve healthspan more broadly.”
We are not saying that semaglutide reverses aging or makes people younger. What we are seeing is a signal that it may slow some of the biological processes associated with aging.
Michael Corley, Ph.D.
In a related pilot study published in
npj Aging
last month, Corley and another team of researchers found that taking semaglutide for 24 weeks:
Reduced the rate of biological aging for 42% of participants with HIV and metabolic dysfunction-associated steatotic liver disease (MASLD) — also known as fatty liver disease — as measured by the
DunedinPACE
epigenetic clock. Those participants also had a greater reduction in liver fat compared with participants whose pace of aging sped up.
Slowed aging associated with the risk of all‑cause mortality in 34% of participants as measured by the
PCGrimAge
epigenetic clock.
Increased the length of telomeres — repetitive DNA sequences at the ends of chromosomes that protect genetic material — in nearly 49 % of participants as measured by the
PCDNAmTL
epigenetic clock. Those participants also tended to walk faster after treatment, suggesting better physical function.
Together, these studies add to growing evidence that GLP-1 drugs may influence pathways involved in biological aging.
“We are not saying that semaglutide reverses aging or makes people younger,” said Corley. “What we are seeing is a signal that it may slow some of the biological processes associated with aging. With newer GLP-1–based therapies now emerging, the field has an opportunity to test whether different drugs in this class have distinct effects on aging biology and to identify which patients may benefit most.”
Larger clinical trials are needed to confirm the findings, determine how long treatment effects last, and establish optimal dosing and treatment duration for both people with HIV and the broader population. Future studies will also be needed to test whether the effects of GLP-1 effects on aging biology are enhanced when combined with lifestyle interventions such as diet, exercise and sleep optimization.
The
Stein Institute for Research on Aging
plans to translate these results into individualized “aging dashboards” to track biological aging with epigenetic clocks, enabling clinicians to design personalized therapies that target the underlying mechanisms of aging and help prevent age‑related diseases.
Additional co-authors on the Nature Communications study include: Alina P. S. Pang at UC San Diego; Varun Dwaraka and Ryan Smith at TruDiagnostic; Danielle Labbato and Grace A. McComsey at University Hospitals Cleveland Medical Center; Allison Ross Eckard at the Medical University of South Carolina; and Grace A. McComsey at Case Western Reserve University. The study was funded, in part, by the National Institutes of Health (grants P30 AI036214, R01DK121619 and UM1TR004528) and the James B. Pendleton Charitable Trust.
Additional co-authors on the npj Aging study include: Alina P. S. Pang at UC San Diego; Douglas W. Kitch and Amy Kantor at Harvard T.H. Chan School of Public Health; Fred Sattler at University of Southern California Keck School of Medicine; Pablo F. Belaunzaran‑Zamudio at the National Institute of Allergy and Infectious Diseases. Todd T. Brown at Johns Hopkins University School of Medicine; Alan Landay at the University of Texas Medical Branch; Jordan E. Lake at UTHealth Houston; and Kristine M. Erlandson at University of Colorado Anschutz Medical Campus. The study was funded, in part, by the National Institutes of Health (grants P30 AI036214, UM1 AI068634, UM1 AI068636, UM1 AI106701) and the James B. Pendleton Charitable Trust.
Corley serves as a scientific advisor for TruDiagnostic.
Amazon uses union-busting AI surveillance to monitor union risk in UK warehouses
Garfield Hylton has long known that Amazon monitors and logs every minute of his working day. Every product he scans, every second he takes between scans, every time his scanner is briefly inactive – all of it is tracked, recorded, and used to set productivity targets and predictions.
But what 62-year-old Hylton didn’t know is that Amazon seemingly also monitors potential “dissent” in the Coventry warehouse where he works, using AI to surveil posts on social media and the company’s internal staff bulletin board.
Internal documents
made public as part of a court battle between Amazon and a Canadian union suggest the tech giant uses Atlas, an in-house AI forecasting tool, to predict how likely its warehouse staff in the US, Canada and the UK are to attempt to form a union, stage a sit-in, or conduct other “disruptive labour events”.
The documents, which appear to be training resources for Amazon managers in Canada, contain an appendix stating Atlas amasses “hundreds of data points” – including posts on Reddit forums and employees’ responses to internal feedback surveys, as well as wider information on the workplace and any previous industrial action – to award warehouses a risk score of between 100 and 900 for union activity.
The lower the score, the more likely Atlas believes workers – whom Amazon calls ‘associates’ – in that warehouse are to unionise or take other actions that could impact Amazon’s productivity or profitability. The document states that for the company’s leadership, higher scores are “better”.
This “makes it clear that they think the union is bad”, Michael Newman, a partner at London-based law firm Leigh Day, told openDemocracy. Newman said it tells “a very different story” from Amazon’s previous assertions that it does not seek to prevent workers from joining a union.
Warehouses appear to be categorised into five tiers based on their Atlas score, where Tier 5 is “no immediate perceived risk” and Tier 1 is “future activity is imminent”. The document suggests this scale can be used to “inform staffing decisions, resource planning, standard actions, and ownership to mitigate risks to Amazon labour structure”.
An Amazon spokesperson refuted the characterisation of Atlas as “individual employee monitoring or surveillance”, stating: “This is site/building level activity only.”
They added that the company does “not track individual employees’ opinions, affiliations or union membership”, or any “personal data”, and said Atlas is not used to monitor dissent, but to “help us understand where associates need more support and to ensure we’re addressing issues that they raise”.
In total, 16 Amazon warehouses across the US, Canada and the UK are “Tier 1”, according to the document. Two are in the UK: a £500m robotic-fulfilment centre in Sutton Coldfield, north-east Birmingham (referred to by Amazon as EMA4), and the warehouse where Hylton works near Coventry (BHX4).
An Amazon US employee is surveyed on their feelings "about the future of AI at Amazon". Source: Facebook
Hylton, whose role involves receiving goods into the warehouse and dispatching them on to other warehouses, is a member of the GMB union. He believes the extent of the data Amazon has collected on his colleagues creates a huge power imbalance, with workers having only their own experiences to defend themselves.
“It’s not right in a democracy… the employer should not be interfering,” he said, speaking to openDemocracy soon after learning about the Atlas tool from GMB. “Workers should be allowed to decide if they wish to choose to unionise,” he continued, adding: “If you're then monitoring, you're undermining a process deliberately and willfully.”
Rachel Fagan, an organiser for GMB, told openDemocracy: “It’s quite clear from these documents that these sites are being monitored for union activity. Everyone knows that Amazon is heavy on surveillance, but this becomes more personal.
“Amazon is using this technology to essentially outwit or manoeuvre workers that want to organise [a union]. Nothing in this fight against Amazon is an even playing field; they have all the wealth, all the technology, everything to their disposal and they use it,” she added.
GMB has long tried to unionise Amazon workers in the UK, coming closest to winning formal recognition in Coventry in July 2024. Employees at the warehouse became the first in the country to take
strike action
against Amazon in January 2023, and around 2,600 took part in an official ballot for union recognition at the site six months later, which GMB
lost by just 28 votes
.
The union and Foxglove, a tech justice non-profit, have accused Amazon of using “dirty tricks” to swing the vote in its favour. These include the mass
hiring of non-unionised workers
and allegedly plastering QR codes that employees could scan to cancel their GMB membership over screens, cafeteria tables, and toilet doors in the warehouse in the run-up to the vote.
Foxglove and Leigh Day are representing two workers in a legal challenge against Amazon’s use of ‘click-to-quit’ QR codes. They argue that the tool was an attempt to “bully” workers into ending their union membership.
The documents revealing Amazon’s Atlas AI tool were disclosed as part of a legal challenge by Canadian union Unifor and shared with US non-profit publication
Truthout
. The British Columbia Labour Board ultimately ruled that Amazon had
violated multiple local labour laws
, following an earlier ruling that found the company had unlawfully
imposed a wage freeze
on unionised workers at a warehouse outside Vancouver.
Rosa Curling, co-executive director of Foxglove, described the level of surveillance detailed in the document as “highly intrusive”, showing that Amazon has a “very intentional policy to try and bust organising, bust unionising efforts, and they are using all sorts of tools to do that”.
Curling continued: “We are actively reviewing these documents to see what additional arguments, if any, we should be adding to our existing claim to unlawful inducement, or indeed on like this ongoing breach of workers' rights to organise, which is a well-respected right in UK-made laws.”
Amazon told openDemocracy that a framework called Atlas is not currently used in the UK. The company had not responded to our question about whether it uses a similar system with a different name at the time of publishing.
Commenting on the AI system, Leigh Day’s Newman added: “Now we know Atlas is used by Amazon, we’ll be asking more questions about what data points are used, how these scores were reached.”
Amazon has previously been found guilty of
“excessive” surveillance
of its workers. In 2022, French data watchdog CNIL fined the company €32m (£27m) for breaching General Data Protection Regulation (GDPR) rules by tracking worker activity so precisely that an alert was triggered if workers were inactive for between one and 10 minutes.
Asked whether Amazon’s Atlas tool is an appropriate level of worker surveillance, a government spokesperson said: “Employers and workers have a shared interest in workplace monitoring technologies being used transparently and in ways that are fair, accountable and reliable, so that they can support productivity and good management while maintaining trust in the workplace.
“We expect all employers to respect workers’ rights to take part in lawful trade union activity.”
An Amazon spokesperson said: “The GMB's characterisation is wrong. This isn’t surveillance. Like any responsible employer, we have numerous ways for our team to provide us with feedback, and we use that feedback to identify where we can improve the day-to-day experience of our employees.
“Our employees always have the choice of whether or not to join a union. What matters most to us is the direct relationship between our teams and their managers – it means every person’s voice is heard, not just a few, and that when someone spots a way to improve their job, we can act on it quickly. We’ve made real progress in recent years on the things that matter, like pay and safety, and we know there’s always more to do. That’s our focus: getting better every day.”
Pass Mermaid syntax to
render()
and insert the returned SVG into your page.
import{render}from'pele';const{svg}=render(`flowchart LR A[Mermaid text] --> B[SVG]`);document.querySelector('#diagram').innerHTML=svg;
Explore
Pele in use
Pele is
open source
, developed for
Obsidian
to render diagrams quickly and match your theme. It is named after
Pele
, the goddess of volcanoes and fire.
Object permanence
: Big Mouth Billy Bass x Linux; No-Fly lists v common sense; Lemony Snicket advises the 1%; "Aloha From Hell"; KSR v Elon Musk; "Everything Belongs to the Future"; Trump's mail-servers run Win2003; Copyfraud v covid.
Israeli ad-tech company was a delivery system for "mercenary spyware" (
permalink
)
More than half of all internet users have installed an ad-blocker; Doc Searls calls it the largest consumer boycott in history. As large as that boycott is, everyone – yes,
everyone
– should block
every
"programmatic" ad, because the entire system is so insecure that failing to do so could result in the total compromise of any or all of your digital devices.
That's the inescapable conclusion of Citizen Lab's latest blockbuster investigative report, "Exposing AdFection," which reveals how the largest ad-tech companies in the world, including Google and Facebook, allowed themselves to be hijacked by a "mercenary spyware" company that used the ad system to locate targeted individuals and serve "zero-click malware" that took over their computers and phones without them having to take
any
action:
These tech giants amassed detailed surveillance dossiers on virtually every internet user, and they've assigned each of us unique, persistent identifiers, like a Social Security Number for spying. These companies
also
allow advertisers – or anyone pretending to be an advertiser – to serve blobs of code (which is all an ad is) to anyone based on those identifiers.
This allowed an Israeli spyware company called Discover-Tech (which masquerades as an ad-tech company) to sell totalitarian governments and sleazy corporate mercenaries the ability to pluck individual internet users out of the billions who log in every day and then serve "malicious ads" (that is, blobs of arbitrary code) to those targeted users. These malicious ads contained "no-click, zero-day" attacks, which meant that they exploited previously unknown vulnerabilities to take over devices without
any
user interaction. The mere act of loading a web-page or opening an app that relied on one of these gigantic ad-tech companies to serve ads was enough to compromise your device. No clicks needed, and no warning.
Among the targets of this attack campaign were the computers of workers at Al Jazeera. They were attacked with malware from the mercenary spyware company Candiru (which now calls itself "Integrity Labs" because irony is not dead). Beyond Candiru, Discover-Tech also facilitates attacks by numerous criminal mercenary spyware companies, serving ads on hundreds of thousands of sites and apps.
Discover-Tech was "certified" as a safe supplier by Google, Yandex, Microsoft, Beeswax (a division of Comcast) and IAB, the ad-tech industry's leading professional association. Ironically, Discover-Tech even attacked users by serving them malicious GDPR notices that appeared to let users opt out of commercial surveillance.
Because Discover-Tech was certified by all these industry bodies and firms, it had access to more than
four billion
ad-auctions, meaning that on
billions
of occasions, it was able to collect the identities of users loading apps and visiting websites, check them against the list of targets, and attack any victims it discovered through this dragnet.
Discover-Tech is an Israeli company with ties to other Israeli spyware and hacking companies, including through its board, whose members included Eric Banoun ("One of the pioneers of offensive cyber in Israel" –
Haaretz
). They have overlaps, relationships and affiliations with a rogue's gallery of Israeli companies, including the notorious NSO Group, who routinely sell cyber-weapons to the world's worst governments and whose products have been used to attack journalists, embassy workers, and activists.
The whole incident highlights the monumental insecurity of the ad-tech industry, whose indiscriminate and voracious surveillance and manifestly insufficient vetting and security auditing now exposes every internet user in the world to terrifying targeted attacks. These companies – including Google, a thrice-convicted monopolist whose surveillance tendrils are wrapped around the whole world – claim that they operate their networks with prudence and oversight. But the proof is in the pudding: for years, they've played host to a murderer's row of cyber-mercenaries who used their infrastructure to attack journalists and others.
The only way to avoid this is to block ads. This is easy enough to do in a browser (which is why the majority of internet users have installed an ad-blocker in their browsers), but it's
illegal
to reverse-engineer and modify an app so you can block the ads in it:
Many websites run anti-ad-block scripts that push out nagging, guilt-tripping notices that call you a thief and a cheapskate for blocking ads. Ignore those notices: if a website is running "programmatic" ads that allow arbitrary third parties to spy on billions of people and target individuals for malicious device takeovers, they are charging too high a price to see their content.
Some sites go further: their notices demand that you either turn off your ad-blocker or pay for a subscription. This "pay or okay" scheme is illegal in Europe, California and other territories with strong privacy laws, and they are morally bankrupt besides. Privacy shouldn't be a luxury item and
everyone
deserves to be secure from cyber-attacks:
This report also provides the most comprehensive rebuttal to a dangerous idea that refuses to die: that we should improve competition in the ad-tech sector by assigning every internet user a mandatory, government-issued advertising ID to "democratize" ad-targeting and followup (which the sector calls "attribution"):
Despite all this, none of it is an indictment of ads
per se
. The problem here isn't
advertising
, it's
surveillance
. The ad-tech sector has convinced advertisers that targeting ads to
users
rather than
content
will massively improve ad performance. The evidence for this is
very
poor: targeted ads improve clickthrough rates by less than 5% (relative to content-based ads that relate to the substance of the page you're looking at), and they're incredibly expensive (and
very
dangerous!) to serve.
On top of all that, surveillance-based ads shift power away from publishers (who know more about the materials they publish than any ad-tech company ever will) to spying ad-tech companies (who can spy on users in ways that no publisher could ever match). Whatever minor additional revenues surveillance advertising can wring out of the market are totally swamped by the cost of the ad-tech sector's own operations, which the ad-tech sector makes up for by grossly underinvesting in security and by colluding to cheat publishers
and
advertisers, charging more for ads and paying less to the websites that run them:
If we want to improve competition in advertising services, the answer isn't to facilitate spying (which also allows the world's scummiest cyber-mercenaries to stage and serve targeted attacks). We should ban surveillance advertising altogether, restoring context-based ads to their role as the way that publishers make an honest living without selling out their audiences:
"Red Team Blues": "A grabby, compulsive thriller that will leave you knowing more about how the world works than you did before." Tor Books
http://redteamblues.com
.
"Chokepoint Capitalism: How to Beat Big Tech, Tame Big Content, and Get Artists Paid, with Rebecca Giblin", on how to unrig the markets for creative labor, Beacon Press/Scribe 2022
https://chokepointcapitalism.com
“Once Is Enemy Action,” a science fiction novel about the origins of modern technofascism. Today's words: 563 (26602 total).
"The Post-American Internet," a sequel to "Enshittification," about the better world the rest of us get to have now that Trump has torched America. Fourth draft completed. Submitted to editor.
A Little Brother short story about DIY insulin PLANNING
This work – excluding any serialized fiction – is licensed under a Creative Commons Attribution 4.0 license. That means you can use it any way you like, including commercially, provided that you attribute it to me, Cory Doctorow, and include a link to pluralistic.net.
Quotations and images are not included in this license; they are included either under a limitation or exception to copyright, or on the basis of a separate license. Please exercise caution.
"
When life gives you SARS, you make sarsaparilla
" -Joey "Accordion Guy" DeVilla
READ CAREFULLY: By reading this, you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies ("BOGUS AGREEMENTS") that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.
ISSN: 3066-764X
DPI and the Homeless Workers Movement in Brazil
Internet Exchange
internet.exchangepoint.tech
2026-10-15 11:03:50
Concrete possibilities for broader governance and popular participation....
In recent years, alongside India, Brazil has consolidated itself as a global protagonist in the field of Digital Public Infrastructures (DPI). Pix, launched in 2020 by the Brazilian Central Bank (BCB), reached around 170 million users, becoming the main payment system in the country. A similar number of people use
GOV.br
, the digital government and identification scheme that integrates over 4,600 digital services. Unlike the Indian governance arrangement, which can accord varying roles to the state (e.g., Aadhaar is backed by the government as a provider, while the Unified Payments Interface (UPI) is owned by commercial banks, hence the government is just an enabler), the Brazilian context is often cited in international fora as an example of how governments may provide scalable, free of charge, and inclusive DPI.
Nonetheless, a structural contradiction lies behind that recognition. Although Brazil leads the development and adoption of DPI, these systems are still primarily governed through technocratic instances. Individuals and organized social movements do not have a seat in decisions on the design, development, and maintenance of major DPI. Pix is regulated by the BCB with indirect participation of private financial companies and consumer protection non-profit organizations in the Pix Forum, but those spaces are quite opaque, with very limited visibility to broader society. Similarly,
GOV.br
is controlled by the Ministry of Management and Innovation in Public Services, partnered with state IT company Serpro, without binding instances of popular participation.
This gap is not a minor issue. On the contrary, as
Governance, Openness and Security of Digital Public Infrastructure in India
by the internet Research Lab (hereafter, the “GOSDPI paper”) demonstrates through the Indian model (Aadhaar, UPI, FASTag, etc.), the lack of sufficient public governance is not an accident but a structural feature that enables private appropriation and data misuse. As the GOSDPI paper documents, this was exemplified by how the National Payments Corporation of India, the entity in charge of 80 percent of digital payments in India, argues that it does not function as a state institution, hence avoiding transparency and access to information. Brazil has not reached that situation yet, precisely because only systems operated by the state are considered DPI. The risk, however, lies in rigid vertical structures and in the privatization legacy, if there is no structured social control over these systems. There is an urgent need to reflect upon how to build broader democratic governance in DPI already massively adopted.
MTST as a bottom-up laboratory
It is within this context that the Homeless Workers Movement (MTST) gains relevance. Founded on the accumulated experience of the Landless Rural Workers Movement (MST), but focused on urban contexts, the MTST has been fighting for and organizing workers whose labor relations are not covered by traditional unionism. Their main form of struggle is the occupation of land that does not fulfill a social function in urban centers, especially in the peripheries of large metropolises. The MTST is a popular, urban movement fighting for housing, but it is also more than that.
Since 2020, differently from a purely claim-making approach, the
MTST started to build its own digital infrastructures
. There are several examples, among them the Victory App, which allows the organization of the movement and communication among members, and Hire Those Who Struggle (Contrate Quem Luta), a WhatsApp-based tool that connects workers from the movement with supporters who want to hire services such as cleaning and construction. All initiatives were built through the movement’s own resources, governed through assemblies, and oriented towards a common social goal rather than profit.
The movement has also been articulating a coalition for
popular digital sovereignty
with other social organizations, such as the MST, the World Women’s March, and the Brazilian Network for Digital Sovereignty, thus having the power to bring solid representation to broader debates. It is worth mentioning that the MTST already works as an external auditor for Brazil’s electronic voting machines and has developed digital participation tools for electoral campaigns with inclusive and accessible interfaces.
Brasil Participativo as digital public infrastructure for participation
Beyond Pix and
GOV.br
, there are other digital public infrastructures taking shape in Brazil. One of them is Brasil Participativo (Participatory Brazil), which allows citizens to contribute to making public policies. Originally launched for the elaboration of the
Participatory Multi-Year Plan (PPA) 2024-2027
, Brasil Participativo reached about 1.4 million users, proving to be technically viable and socially appealing. However, its first version was for a one-time consultation, without binding power and subject to being discontinued by a future government.
Brasil Participativo (BP) was developed using a
digital public good, the free software Decidim
, allowing anyone to access the code and propose eventual changes. Yet in practice, no one beyond the laboratory responsible for development has contributed to the system. Moreover, like other mainstream DPI in the Global South, BP runs on cloud infrastructure from major Big Tech companies (the Achilles heel of DPI). Beyond a direct channel with society, Brasil Participativo can also be thought of transversally across other DPIs. That is, using Brasil Participativo as a cross-cutting governance axis, connecting civil society to different sectoral forums. The same citizen, authenticated through the digital ID
GOV.br
, could contribute proposals to the Pix Forum (the participatory instance of the instant payment system), and participate in consultations regarding digital policies and governance more broadly, such as the National Strategy for Digital Government.
That means making BP a structural and permanent layer of the Brazilian state. Moreover, in late 2025, one of the major leaders of the MTST became the Secretary-General of the Presidency of the Republic, the ministry in charge of the digital participation agenda. This institutional bridge opens unprecedented possibilities for convergence.
The state-society convergence and political risks
The federal government took an important step in April 2026 when it released the results of the public consultation for the
elaboration of the Brazilian Digital Transformation Strategy
. The government expected to gather diffuse contributions, precisely through BP. The result, however, was surprisingly convergent. Among multiple stakeholders (academia, the private sector, civil society organizations, and ordinary citizens), the points of greatest consensus were the demand for digital sovereignty based on Digital Public Infrastructures and the need to guarantee popular participation in governance processes, thus democratic alternatives to digital sovereignty. In other words, when the government opens listening channels, society responds clearly. The public consultation thus creates a legitimate mandate for the construction of participatory mechanisms. And it is exactly at this point that Brasil Participativo can become a key DPI that enables democratic control and avoids capture by large foreign providers.
However, there is a clear political risk. The elections of 2026 could bring a change in government that decides to discontinue or weaken Brasil Participativo, as has happened with other participatory tools in the past. To ensure its survival beyond electoral cycles, it is essential to structure effective participation from multiple actors that create distributed ownership and shared responsibility. That means involving municipalities that can adopt and adapt the platform for local participatory budgets, implementing companies that provide sustainable technical support, the developer and civic tech community that contributes to coding and auditing, and academia that produces evidence-based improvements and monitors outcomes. Without this multi-layered ecosystem, Brasil Participativo remains dependent on the political will of a single federal administration, which is a fragile foundation for any digital public infrastructure.
Concrete mechanisms can still be pursued. DPIs can be designed or altered to guarantee binding seats on governance councils for representatives of popular movements and union federations. Ideally, though not very probable in the short term, these organizations would have veto power over changes that undermine fundamental rights. The introduction of new features in major and sectoral DPIs could be qualified through Brasil Participativo, making it an obligation for the institutions in charge to hold participatory processes, even on highly technical subjects. Furthermore, social movements could be formally recognized as auditing bodies, receiving public funding to conduct independent inclusion, security, and privacy audits.
Finally, to broaden the "public" aspect of DPI, they could be developed with community modules that are not controlled entirely by the state. Pix and
GOV.br
could consider adopting open modules that would enable faster adoption and bottom-up development of solutions, hence increasing capillarity and efficiency for those acting in the territories, such as the MTST.
The central question is not whether popular movements like the MTST can participate in DPI governance, but under what conditions that participation becomes possible and sustainable. The MTST has already shown representativeness, organizational capacity, and hands-on experience with digital technology, from internal apps to external audits of electoral systems. What is missing is an institutional architecture that articulates state and society without subordinating one to the other. Brasil Participativo, if anchored in a distributed ecosystem of municipalities, civic tech communities, implementers, and academia, can become that permanent bridge.
Therefore, a genuine digital public infrastructure for social participation would not treat popular movements as mere consultants or beneficiaries. It would recognize them as legitimate co-governors, precisely because they bring territorial roots, democratic practice, and a proven ability to build technology from below. The risk of political discontinuity after 2026 is real, but so is the opportunity to lock in a participatory model that no future government can easily dismantle. That is the concrete horizon for DPI and the MTST: one that promotes public-popular partnerships instead of public-private ones; and does not deny the material dimension of infrastructure in general.
Alexandre is currently a coordinator of digital participation at the General Secretariat of the Presidency of Brazil, PhD candidate in design of DPI at UdK Berlin-Weizenbaum and member of the Homeless Workers Movement Tech Sector.
Mallory Knodel Named Chicago Council Fellow
IX’s Mallory Knodel
has joined the Chicago Council on Global Affairs
as a senior nonresident fellow on technology and governance. She is one of four new fellows appointed by the Council, a nonpartisan nonprofit that publishes research and hosts discussions on global affairs. In the role, Knodel will contribute to the Council’s research, programming and analysis on how technology affects power, security and human rights around the world.
If you find our emails useful, consider becoming a paid subscriber! You'll get access to our members-only Signal community where we share ideas, discuss upcoming topics, and exchange links. Paid subscribers can also leave comments on posts and enjoy a warm, fuzzy feeling.
Not ready for a long-term commitment? You can always
leave us a tip
.
Why Britain should reject the lure of cheap – and scary – Chinese AI
Guardian
www.theguardian.com
2026-10-17 11:00:33
In the west the technology comes with at least some effort to provide security and a benign intent – not so from China There is much to fear from artificial intelligence developed in China and handed to businesses and governments in the west almost free of charge. Every month Chinese AI developers s...
There is much to fear from artificial intelligence developed in
China
and handed to businesses and governments in the west almost free of charge.
Every month Chinese AI developers such as DeepSeek and Xiaomi dispatch the latest versions of their “open-weight” models that allow users to take the core software and use it without paying an expensive ongoing licence.
In Britain, we love cheap Chinese kit, usually setting aside any concerns about how it was made and who by.
The row over whether to allow Chinese electric cars unfettered access to British retail forecourts is a case in point. They are
cheaper than other EVs sold in the UK
and, consumers ask: What is not to like? These same consumers might consider how Chinese EVs are subsidised by Beijing deliberately to boost exports and, in so doing, undermine foreign domestic car industries.
Cheap AI takes this export threat to a higher level.
It’s scary because Beijing is entering a new phase in the long march of economic development, taking the world’s second largest economy closer to making China great again.
Go back 10 years and Xi Jinping’s close supporters were alert to the internal contradictions of a totalitarian, command and control state apparatus and how it could trigger social unrest, much as it did in the last century
in Tiananmen Square
.
A property crash that still acts as a drag on the economy, rising unemployment, poor health services in many regions, a mismatch of men and women, an ageing population – they could all be the spark that threatens Communist party rule.
Then came AI and the state discovered complete control.
Now Beijing has huge surveillance capabilities, using AI to capture images of its citizens and monitor their activities if they need to.
Don’t think it means Chinese people are under virtual house arrest. They can go about their daily lives, gathering in the street for an impromptu dance or to discuss how their local region might be better run. But serious dissidents? They are rooted out and sidelined, re-educated or punished.
For the central committee, AI is a blessing. While the financial constraints from having to please a domestic audience have not entirely disappeared, Beijing’s leaders can concentrate on the threats they face from the rest of the world.
Not that it wants to invade countries in the same manner as Russia. China’s reinvigorated
belt and road initiative
creates permanent channels for trade less obviously than the previous iteration, allowing Beijing to turn states into clients who depend for the basics of life on Chinese technology.
Where Russia is using AI to enhance cyber-attacks on European government agencies and businesses to create chaos, China wants merely to widen the circle of friends that consume its goods without asking awkward questions.
Military force is also being contemplated. Now that Beijing can redirect precious resources previously needed to subsidise Chinese consumers, it is building a fleet of warships to challenge the US in the Pacific, much as Japan did in the 1930s. Taiwan, the engine of semiconductor development, is in its sights.
Meanwhile, Chinese developers are launching AI models by the dozen each month at a fraction of the cost of US equivalents.
There are tech analysts who say Chinese models add to the rich tapestry of AI, supplementing the closed, proprietary models of OpenAI and Anthropic. And they say there are European and Indian versions in development. Adding to that tapestry, Meta is fast developing open AI models, but like the other challengers, lags in the race to win over customers.
In practice, an AI user has the choice between a cheap Chinese open system they can tweak for their own ends or expensive US software that comes with bells and whistles they probably don’t need.
Both types have the potential to destroy humanity, as
many AI experts have documented
. But on a more mundane level, in day-to-day use, only one comes with at least some effort to provide security and a benign intent, and it’s not the Chinese option.
As Ross Burley says, Chinese AI comes with extra baggage. Burley is director of the
Centre for Information Resilience
(CIR), an independent, non-profit group dedicated to, among other things, exposing human rights abuses and countering disinformation.
He says DeepSeek cannot access the properly isolated use of its software, “but that addresses just part of the risk. Running a model on your own servers doesn’t automatically remove any political censorship. Or indeed repair weaknesses in any security defences.”
An
evaluation report
by the US National Institute of Standards and Technology (Nist) found political censorship in downloaded DeepSeek models running on its own infrastructure, which means that hosting those models in the UK wouldn’t, by itself, remove censorship.
“We should be deeply concerned about embedding Beijing’s political restrictions into systems that businesses and public services rely on for information and decisions,” he says.
The policy governing DeepSeek’s online chatbot says it collects prompts and uploaded material, processes and stores personal data in China, and permits disclosure to Chinese authorities.
The consequences for policymaking are profound. The UK should reject the lure of cheap Chinese AI and seek to better tame US AI while supporting domestic and EU suppliers.
Relying on Chinese tech, from cars to AI, is going to hollow out industry and undermine the security of our data.
Drupal patches critical RCE flaws, warns exploits may emerge soon
Bleeping Computer
www.bleepingcomputer.com
2026-10-17 10:32:48
Drupal has patched two critical vulnerabilities that could allow attackers to execute code remotely on websites running any supported version of the content management system. [...]...
Drupal has patched two critical vulnerabilities that could allow attackers to execute code remotely on websites running any supported version of the content management system.
The security issues impact the software core's Field UI module and the contributed Entity List module. Drupal issued an advance warning at the beginning of the week, urging administrators to apply updates promptly because attackers could develop exploits shortly after the vulnerabilities’ disclosure.
“The Drupal Security Team urges you to reserve time for core updates at that time because exploits might be developed within hours or days,” the project's
security team warned
.
“We recommend updating to the latest supported patch (bugfix) release for your site's version of Drupal before October 14, so that you can address any other upgrade issues before the security window.”
Drupal is a free, open-source content management system used to build and manage websites, particularly popular among government agencies, universities, and non-profit organizations.
Earlier this week, the open-source project disclosed the two details, noting that "all currently supported versions of Drupal core are affected."
CVE-2026-108097
: A remote code execution vulnerability in Drupal core’s Field UI module that could allow attackers to execute arbitrary code on affected servers.
CVE-2026-108099
: A flaw in Entity List, a contributed module for creating entity lists without Views, that could enable remote code execution.
The security advisory for CVE-2026-108097 notes that the flaw cannot be exploited using Drupal core alone, but contributed modules can provide multiple exploitation paths, including at least one that requires no authentication.
Additionally, custom code may also expose the vulnerable functionality.
Successful exploitation of CVE-2026-108099 requires a similar interaction with contributed modules or custom code and includes at least one known exploitation path that does not require authentication.
Administrators are urged to update Drupal core to version 10.6.19, 11.3.19, or 11.4.10, depending on their release branch, and update Entity List to 3.0.10.
"All versions of Drupal prior to 10.6.x, as well as all versions of Drupal 11 prior to 11.3.x, are end-of-life and no longer supported," the developer said
The flaws also impact Drupal 12 pre-releases before beta2, but these are not meant to be used in production environments. The final stable 12.0 version will include fixes for both flaws.
Administrators who cannot upgrade to a secure version are advised to uninstall Drupal’s core Field UI module (field_ui) as an effective mitigation measure.
Also, Drupal Steward protects against some known attack vectors but does not cover every possible exploit.
The US federal budget deficit for 2026 officially came in Friday at $1.992 trillion, a final tabulation to close out the government's fiscal year and another reminder of Washington's spiraling reliance on red ink.
This deficit number represents about 6% of the
US gross domestic product
and was a result of $5.403 trillion in total revenues for the fiscal year against total spending of $7.396 trillion.
The 2026 reading is a 12% jump from 2025's $1.775 trillion deficit.
The red ink has led to dire warnings from economists that the US now routinely runs annual deficits that were previously seen only during recessions and wars. The gross US national debt
passed $40 trillion in August
and now sits above $40.3 trillion.
The latest
"Debt to the Penny"
reading from the Treasury Department came this past Wednesday, putting the gross US national debt at $40,329,229,827,541.02.
A bus shelter in Washington display the US National debt in August. (Jemal Countess/Getty Images for the Peter G. Peterson Foundation)
·
Jemal Countess via Getty Images
The independent budget hawks at the Committee for a Responsible Budget
noted in a recent analysis that
"the country's future fiscal outlook is even more dismal," noting that annual deficits could reach $3.1 trillion by 2036 without a change in the fiscal trajectory.
The group noted that annual interest costs on the debt are now $1.1 trillion, a record 3.4% of GDP, making it the second-largest line item in the government's budget. Interest on the debt still costs less than
Social Security
, but it is now more expensive than either Medicare or the defense budget.
Members of President Trump's team have tried to downplay this year's tabulation — the highest annual deficit reading other than 2020 and 2021, when budgets were inflated by COVID-era spending — as a blip and insist that the US fiscal situation is getting under control.
Indeed, the impact of tariff refunds has been significant: $144.6 billion in tariff refunds were given out over the past year — but analyses of the deficit also show a variety of factors that have driven up deficits.
Treasury Secretary Scott Bessent and President Trump are seen during an event in the Oval Office of the White House on Oct. 7. (Anna Moneymaker/Getty Images)
·
Anna Moneymaker via Getty Images
A
Hamilton Project tracker of government expenditures
shows how government spending has increased at a steady pace in 2026. The tracker looks at spending by calendar year and shows that as of Oct. 14, government spending has jumped each of the last three years.
We had LLMs write precise mathematical rules, or a formal semantics, for how a small programming language should behave. We then used Lean, a tool for checking mathematical proofs, to prove that the interpreter—the program that runs code written in that language—follows those rules even after being compiled into low-level instructions understood by a RISC-V computer chip.
LLMs are growing alarmingly capable at finding and exploiting bugs in
production software, with increasing reports of AI-assisted hacks
in the wild.
Fortunately, LLMs are advancing quickly in their ability to write
verified software
: programs that come with mathematical proofs,
checked by a computer, that rule out entire classes of bugs.
In April, our agents
built a JavaScript-to-WebAssembly
compiler
but could not prove that it preserved
program behaviour. Months later, our agents
verified Linux’s nftables
compiler
, which translates firewall rules
into instructions the kernel executes. In September, MIT researchers
Frans Kaashoek and Nickolai Zeldovich used AI agents to
verify the xv6
operating-system kernel
down to its
machine code.
Our goal at Basis is to develop verification methods that could plausibly scale to all software, so that the systems powering critical infrastructure are secure by design and keep pace with attackers’ growing capabilities.
As LLMs advance in capability, the bottleneck is shifting away from theorem proving and towards the problem of specification: how can we be sure that the statements we prove capture the behaviour we actually care about?
To prove anything about a program, we first need a mathematical description of what it does.
This starts with describing the programming language it is written in: what every statement, loop, and function call means when it runs.
These descriptions are called a
formal semantics
, and can be written with pen and paper, but are increasingly expressed in a proof assistant such as Lean.
A handful of languages have one (Standard ML, WebAssembly, and C via CompCert), as does the RISC-V instruction set that a growing number of processors execute.
Developing each of these semantics took years of expert effort.
Most programs, however, are written in languages that do not have a formal semantics, presenting a major bottleneck for deploying verified software at scale: without a semantics, there is nothing precise to prove against.
A natural solution is to use LLMs to write semantics, but LLMs make mistakes, and a broken semantics undermines every proof built on it.
Testing helps, but as we show below, a semantics can pass every test and still be wrong. What is needed is a means to verify the semantics itself.
Languages without a formal semantics still have interpreters or compilers, which in practice define what their programs mean.
Here we consider a radical idea: make the LLM prove that its semantics agrees with the real interpreter on every program, treating the interpreter as ground truth. To do this, we compile the interpreter to RISC-V, whose meaning is already formally defined. That gives an exact, if unreadable, description of what the interpreter does with any program. The LLM then writes readable rules for the language and proves in Lean that, for every possible program, those rules predict exactly what the compiled interpreter prints. If a rule is wrong, the proof gets stuck.
We report on an experiment where we had LLMs develop a semantics and
its proof together for a small language. We used Lean to prove that the interpreter, the
program that runs code written in that language, follows those rules
even after being compiled into low-level machine instructions. The
whole development, semantics and proof, is
on GitHub
.
The rest of this post walks through this
experiment, explaining first why semantics are the bottleneck for
larger verification efforts and why tests aren’t sufficient to build
trust in them. We then show how the proof process refined the semantics,
how we handled the memory reasoning, and what tools we built on the result.
Every verified program starts from a semantics
Before you can prove a program does anything, you have to define how
each operation transforms its state, that is, define its
semantics
.
Most languages describe their semantics informally in prose, in a
reference manual, and leave the concrete details to the compiler or
interpreter implementation. A
formal
semantics writes the rules down in mathematics, precisely enough for a
proof checker like Lean 4 to use them. Notable examples include
CompCert’s semantics for C, CakeML’s for ML, and JSCert’s for JavaScript.
Each one took years of expert effort, and often covers only a restricted
subset of its language.
For this experiment we used an extended version of WHILE, the small
imperative language used in textbooks such as Nielson and Nielson’s
Semantics with Applications
.
Our version has integers, strings, first-class functions with closures,
if
,
while
and
for
loops, and runtime errors. Its interpreter is 1,855 lines of
C, and a WHILE program looks like this (it prints 55):
var i = 0;
var sum = 0;
while (i < 10) {
i = i + 1;
sum = sum + i;
}
println(sum);
The semantics an LLM wrote for WHILE is a set of rules, one for each
kind of expression and statement. These rules describe how to evaluate
an expression in terms of its subexpressions. For integer addition,
the rule is:
st, env ⊢ l ⇓ a, st' st', env ⊢ r ⇓ b, st'' a + b = c
──────────────────────────────────────────────────────────
st, env ⊢ l + r ⇓ c, st''
A rule reads from the bottom up. The line at the bottom is its
conclusion. Starting from state
st
in environment
env
, the
expression
l + r
evaluates (
⇓
) to
c
and leaves state
st''
.
The state holds variable values, closures and everything printed so
far; the environment says which variables are in scope. The premises
above the line explain how the result follows from the subexpressions.
First
l
evaluates to
a
, leaving state
st'
. Then
r
evaluates to
b
in that state, leaving
st''
. The final premise,
a + b = c
,
adds the two integer values using WHILE’s 64-bit wrapping arithmetic.
Take
(1 + 1) + x
, with state
[x ↦ 5]
and environment
{x}
:
x
holds 5 and is in scope. Applying the rule gives:
That is, to evaluate
(1 + 1) + x
, we first evaluate
(1 + 1)
to get
2, then look up
x
to get 5, and add the two values to get 7. Neither
subexpression changes the state, so
[x ↦ 5]
remains unchanged.
To justify the first premise, we apply the addition rule again:
These rule applications form a tree that derives the value of the
whole expression from the values of its parts.
The LLM wrote about 400 lines of rules like these, in Lean (
the full
semantics
).
Each rule looks reasonable on its own, but an end user has no rigorous
way to tell whether they faithfully describe how WHILE programs behave
when they are actually run.
A semantics can pass every test and still be wrong
The usual way to check a semantics is to run it. Take a test suite,
run each program under the semantics and under the real interpreter,
and compare what they print. Unfortunately, in practice, this process
is insufficient to build trust in the generated semantics.
For example, an early version of our semantics passed the test suite
generated for the WHILE interpreter, but disagreed with the binary
when a function’s name reached 59 characters:
fn aaa…aaa() {} // a name of 59 a's
println("" + aaa…aaa);
semantics: <fn aaa…aaa>
binary: <fn aaa…aaa
The semantics said that concatenating a function with a string would
include its full name between
<fn
and
>
. The binary dropped the
closing
>
, and for longer names it dropped part of the name too.
No test in the suite tried functions with names this long.
The reason is in the
C
interpreter
that turns a value into a string when you concatenate it with
+
:
stringify
returns a string value as it is. Any other value is first
printed into a 64-byte buffer on the stack and then copied into a
freshly allocated string. A named closure is printed with
snprintf
as
<fn name>
, an anonymous one as
<fn>
, and the built-ins fall through
to the default case,
<native fn>
.
snprintf
writes at most 63 characters into the 64-byte buffer. The
initial semantics used the same rendering rule for concatenation and
printing, and missed this limit. To prove agreement with the binary,
the LLM had to give concatenation its own renderer. The
corrected
semantics
cuts a closure’s rendering to its first 63 bytes:
"" + f ⇓ take 63 ("<fn " ++ f ++ ">")
This is the kind of detail an
implementation accumulates internally but nobody writes down
explicitly, which is precisely why a semantics transcribed by hand, or
written by an LLM, can miss it. Nor is it a detail no program would
notice: code in dynamic languages routinely relies on the string form
of a function, for logging, for dispatch keyed on a name, or for
comparing serialised values. Even simple violations like
this undermine any verification effort built
on top of the semantics, and can leave holes that hide security
vulnerabilities. To build secure and scalable semantics, we need to go
beyond tests, since a test suite only checks the programs someone (or
an agent) thought to write.
Ship your interpreter
Shipping your interpreter means checking the semantics against the
implementation people actually run. Compile the interpreter the
language already has, and make the LLM prove that the binary
refines
the semantics, that is, that the two agree on what every
program prints.
theorem endToEnd_refinement :
∀ p c, Loaded interpRunLayout p (fillZero c) →
(∀ out, BigStep p out ↔ Halts c out 0) ∧
(Diverges c → ¬ ∃ out, BigStep p out)
The theorem says for any WHILE program
p
, and
any
machine
configuration
c
, if the machine configuration satisfies a property
Loaded
, then the semantics match what the compiled binary will
do.
Loaded interpRunLayout p (fillZero c)
here says that
c
is a
machine about to run
p
through the interpreter binary. The first
conclusion,
(∀ out, BigStep p out ↔ Halts c out 0)
, says that the
semantics derives output
out
if and only if the machine halts with
exit code
0
having printed
out
, i.e. for successfully terminating
programs the predicted outputs are equivalent. The second says that any program
p
on which the machine runs forever (
Diverges c
), is a program the
semantics derives no terminating output for.
We can visualise this theorem as a
commuting square
, showing how the
semantics and the binary agree on a program’s output. In the diagram
below, the top arrow relates a program
p
to the output
out
predicted by the semantics. The bottom arrow relates a machine
state
c
to the output printed when the binary halts successfully.
The dashed line on the left is the
Loaded
condition connecting the
program to that machine state. Under this condition, the theorem says
the two outputs agree, shown by the double line on the right. The
orange arrow shows how a failed attempt to prove that agreement sends
the LLM back to revise a rule of the semantics.
For a program loaded into the machine, the semantics and successful execution agree on the output.
The theorem catches a wrong semantics in both directions. If the
semantics is too permissive, it derives an output the binary never
prints, and the left-to-right half fails. If it is too strict, it has
no rule for something the binary does, and the right-to-left half
fails. Either way the LLM gets a proof obligation it cannot discharge.
In our experience, that obligation usually points at the rule that is
wrong.
RISC-V is an open processor design. We use its formal model, written
in
Sail
and translated into Lean,
to define how each machine instruction executes. The binary is the
actual ELF executable: 1,855
lines of interpreter C compiled by gcc, linked against dlmalloc and
newlib, 25,336 instructions in all. For comparison, the xv6 kernel
verified with MachCSL is 8,697 RISC-V instructions, built from 6,593
lines of C and assembly, although its proof also covers concurrency,
which ours does not need. The C compiler’s output, the C library and
the memory allocator are all inside our theorem. A person
who wants to trust the result reads the statement above, the hypothesis
Loaded
, and the two short definitions of
Halts
and
Diverges
. They
do not need to trust
BigStep
, because the proof checks it against the
binary.
Developing the semantics and proof together
Developing the proof forced the LLMs to account for four details in
the semantics:
integer arithmetic had to wrap at 64 bits, because negating the
smallest integer was unsatisfiable against the machine;
a
for
loop’s initialiser had to ignore an abrupt status, because
the C does;
built-ins had to render differently in
print
and in concatenation;
long closure names had to be cut at 63 bytes.
Each correction started either as an obligation that would not close
or as a run of the binary that disagreed with the semantics.
The 63-byte cut is a representative example. The proof of the
concatenation case needed the semantics’ rendering to equal the
binary’s, and for long names it didn’t, so the obligation could not be
discharged until the rule changed.
The proof also caught mistakes in the LLM-generated lemmas about the C
library. The LLMs stated what each function does and then proved
that statement against the machine code. An allocator reserve that no
heap satisfied after a single
malloc(24)
, a
realloc
lemma that was
false for sizes that wrap, and an
exit
routine that writes
errno
without its lemma saying so all showed up the same way, as obligations
that would not close.
Separation logic makes the binary proof tractable
LLMs wrote all of the proof. Most of the difficulty lay in reasoning
about memory. We needed a specification for
malloc
, the function
that allocates memory, which would let us prove that allocating a new
block preserves the data already held by the interpreter. Even
println("n = " + x)
allocates three strings and frees two of them.
Throughout those calls, the program’s variables and the half-built
result must remain intact.
The textbook way to do this is to give each function a Hoare triple
together with a
footprint
, a set of bytes the function may write.
Facts about memory outside the footprint carry across a call
unchanged. A triple
{ P } code { Q }
reads as “if
P
holds before
code
runs, then
Q
holds after it”. For
malloc
, such a
specification reads roughly as follows, where
F
is a fixed set of
addresses:
{ heap H }
p := malloc(n)
{ heap ((p, n) :: H) and p is fresh }
modifies F
Unfortunately, no such
F
exists. From the same heap,
malloc(32)
writes the header of the new top chunk at address
0x82000238
, so
F
must contain that address.
malloc(64)
instead returns the block
[0x82000210, 0x82000250)
, which contains it. Once the caller owns
that block, facts about its bytes have to survive later calls, so
F
must also exclude
0x82000238
. The LLMs
proved in
Lean
that no fixed set of addresses can satisfy both requirements, after a
first attempt that worked around the problem one fact at a
time had stalled for three weeks.
From the same heap,
malloc(32)
writes a byte that
malloc(64)
would hand to the caller. The allocator's write footprint must change as ownership of memory changes.
Separation logic solves this by making the footprint depend on the
heap. We ported
MachCSL
, the logic
behind the xv6 proof, to the newly released
iris-lean
.
1
In separation
logic the allocator
owns
the free bytes of its arena, and
malloc
’s
specification
hands part of them to the caller:
{ isHeap H }
p := malloc(n)
{ (p = 0 ∗ isHeap H)
∨ (isHeap ((p, n) :: H) ∗ blockOwn p n) }
Here
∗
is the
separating conjunction
, which says that its two
halves hold of disjoint parts of memory, and the result
p
is either
null or a fresh block.
isHeap H
owns every byte of the arena outside
the live blocks
H
. Initially, the allocator owns
0x82000238
, so
malloc(32)
may write it. If the caller instead requests
malloc(64)
,
that byte passes to the caller through
blockOwn
, and later calls
cannot touch it. Anything else the caller owns is not
mentioned in the specification, and the frame rule carries it across
the call in one step. After the port, the rest of the proof closed in a
few days.
LLMs write the semantics and the proof linking it to the existing interpreter binary; Lean checks that proof against the machine model.
At its peak the proof was about a million lines of Lean, two thirds of
it generated by 35 scripts the LLMs wrote, which read the binary and
emit a proof rule for each of about 11,800 instructions. A later pass
replaced the generated proof families with abstractions proved once,
such as a symbolic executor for machine code, and brought the proof
under 200,000 lines. It uses no axioms beyond Lean’s standard
ones (
propext
,
Classical.choice
and
Quot.sound
).
The theorem applies to real programs
A theorem with a hypothesis is only useful if that hypothesis can be
satisfied. If
Loaded
described a machine state that never occurs,
our theorem would hold vacuously and tell us nothing about the binary.
We had the LLMs
prove in Lean that
Loaded
holds for ten
programs
.
For each one, they constructed a machine state at the interpreter’s
entry, with the program in memory alongside the binary, the runtime
and the allocator. Lean checked that each state met the theorem’s
precondition.
2
Loaded
specifies the memory and registers needed to run the program through the interpreter binary. The program enters as a syntax tree (orange); the surrounding code and runtime state come from the interpreter.
We also replayed 85,483 machine steps from the executable and checked
that the resulting memory matched the constructed state byte for
byte. The link from the executable file and its boot trace to that
state was checked by scripts; Lean checked the precondition and the
execution from that state onwards. For the full
loop test
program
,
which extends the earlier example with two more sums, the binary
provably halts after printing
55
,
2500
and
36
on separate lines.
The precondition includes enough heap and stack space for the program.
A
later
theorem
replaces these two assumptions with checkers that run on the program.
A validated semantics also works as an interface. Anything you prove
sound against
BigStep
is sound for the binary, by composing it with
the refinement theorem, and that composition is a few lines of
Lean. So we had LLMs build four tools on top of it.
The type system, program logic and analyser reuse the interpreter's refinement proof. The compiler is proved to implement the same semantics directly on RISC-V.
The refinement proof took about a month and is about 140,000 lines of
Lean. The four tools below were opened as pull requests over three
days, and come to about 33,000 lines between them, most of it the
compiler.
The first tool is a
type
checker
.
It catches invalid operations before a program runs. For example,
these two programs are rejected:
"a" - 1; // subtracting an integer from a string
var x = 1;
x = "s"; // assigning a string to an integer variable
The
proofs for these
examples
show that neither program can pass the checker. Its soundness theorem
rules out type errors in accepted programs, including when they run
through the interpreter binary. Division by zero, a failed
assert
and the interpreter’s call-depth limit remain possible; those require
reasoning about values as well as types.
The second tool is a
program
logic
,
which lets us prove what a particular program computes. The loop near
the start of this post adds the integers from 1 to 10. The full
test
program
also adds the odd integers from 1 to 100, using
break
and
continue
,
and computes a third sum with nested loops. The LLMs used the logic
to prove that running this program through the interpreter binary
terminates and prints exactly:
The third tool is an
abstract
interpreter
,
an analysis that tracks possible values through a program and raises
alarms for potential runtime errors. It analyses that same test
program with
no
alarms
,
proving it free of runtime errors. It also establishes that the final
values of
sum
,
total
and
acc
are 55, 2500 and 36. The analysis
computes these results automatically, and its soundness proof connects
them to execution of the binary.
The fourth tool does without the interpreter entirely. In April, our
agents built a compiler but could not prove it correct. Here the
semantics came first, and the LLMs built a
verified
compiler
from all of WHILE (strings, closures, calls,
for
,
return
and
assert
) straight to RISC-V. Compile the sum program above, and the
resulting machine code prints the same three numbers. The correctness
theorem establishes agreement for every program meeting its
preconditions. A
checked
version
analyses allocation cost, so its theorem needs no assumption about
available heap space.
Dropping the interpreter also makes WHILE programs faster. We ran
every program in the interpreter’s test suite both ways on the
spike
RISC-V
simulator. Counting the interpreter from the moment it starts evaluating, so that
parsing is not charged against it, compiled code retires between 2.7
and 8.2 times fewer instructions, and both routes print the same
output. These are instruction counts on a simulator rather than timings
on hardware.
Compiling these WHILE programs reduces instruction counts by a factor of 2.7–8.2 while preserving their output. Counts come from the spike RISC-V simulator and exclude parsing by the interpreter.
Once the semantics is trusted, it
is
the language, and the binary we
started from is no longer needed to run WHILE programs.
What’s next: Lua, OCaml and, one day, CPython
Our experiment with WHILE targeted a toy language. LLMs developed its
formal semantics, proved that the compiled interpreter follows it,
and built verified tools on top. We are now scaling this approach up
to real languages.
Ship your Lua
targets Lua 5.4.7 compiled to bare-metal RISC-V. The binary already
runs on the Sail model and agrees with native Lua, and the plan cuts
the proof at the VM: first the bytecode interpreter against a bytecode
semantics, fragment by fragment over opcodes, then the source language
against the bytecode.
Ship your OCaml
takes advantage of the way OCaml bootstraps itself. OCaml’s bootstrap compiler is checked
into its repository as bytecode,
boot/ocamlc
, and runs on
ocamlrun
.
We have
ocamlrun
running on the Sail model, compiling programs with the
real
boot/ocamlc
. The plan there ends in a fixpoint: if the source
semantics says the compiler compiles its own sources to exactly the bytes
of
boot/ocamlc
, and the compiler’s back end is proved correct, then
those bytes get a meaning without verifying their 412,000 bytecode
instructions one at a time.
For both projects, we have already stated the headline theorems in
Lean. What remains is to close their proofs.
The north star is CPython. We believe that current agents make an
LLM-written, machine-validated semantics for Python feasible, given
enough compute. Tools like the ones in the previous section could then
be built on it, with guarantees that reach the CPython binary.
Apple TV Price History, Charted
Daring Fireball
glog.glennf.com
2026-10-17 10:06:18
Glenn Fleishman:
I wondered what the entry-level, initial price of each Apple TV
box at introduction was, from the March 2007 original to the Apple
TV 4K (4th generation) announced October 13, 2026, adjusted for
inflation. So I charted it.
I suppose this doesn’t mean Apple has given up on maki...
I wondered what the entry-level, initial price of each Apple TV box at introduction was, from the March 2007 original to the Apple TV 4K (4th generation) announced October 13, 2026, adjusted for inflation. So I charted it.
—
11 min read
Solid lines are what Apple charged; dashed lines follow each launch price forward through inflation to today.
Original (2007–2016)
Apple TV HD
Apple TV 4K
List price while on sale
Launch price carried forward in inflation-adjusted dollars
Click or tap the chart for a larger, scrollable view.
Entry-level models and prices
Model
Configuration
Price period
US$ then
Sept 2026 US$
Inflation adjustment uses the BLS Consumer Price Index for All Urban Consumers (CPI-U, U.S. city average, all items, 1982–84 = 100), rebased to September 2026 (336.940, the latest release). Prices are Apple's U.S. list prices at launch and at announced changes; the 4th-generation Apple TV 4K ships November 13, 2026. Each dashed line takes a model's launch price and multiplies it by the CPI ratio at every month since, ending at the September 2026 equivalent on the right edge.
Solar surpasses nuclear power globally for first time – pv magazine Global
Solar and wind are increasingly outpacing nuclear power globally, with solar generation surpassing nuclear for the first time in 2025, according to WNISR 2026. The report highlights nuclear’s slow growth, lengthy construction timelines and limited small modular reactor deployment, contrasting them with rapid renewables and battery expansion.
The
World Nuclear Industry Status Report (WNISR) 2026
, overseen by French nuclear energy consultant
Mycle Schneider
, shows that wind power alone surpassed nuclear generation on a monthly basis in March 2025, followed by solar in April – the first time global monthly solar generation exceeded nuclear output.
From March 2025 through June 2026, either solar or wind individually generated more electricity than nuclear every month. In March, April and May 2026, both technologies independently surpassed nuclear generation.
Increasing gap
According to the report, the gap between renewables and nuclear widened substantially in 2025. Global solar capacity increased by 510 GW to 2,383 GW, up 27% year on year, while wind added a record 159 GW to reach 1,291 GW, an increase of 14%. By comparison, installed nuclear capacity rose by just 1.5 GW to 399.5 GW, while operating nuclear capacity declined by 0.5 GW to 368.6 GW. The report notes that nuclear capacity has remained essentially flat for more than 25 years, while wind and, particularly, solar have expanded rapidly.
The report’s PV figures, however, are based on relatively conservative estimates. More recent data from IEA PVPS indicate that global PV additions reached around
690 GW in 2025
, about 180 GW more than the figure used by WNISR. This suggests the gap between solar and nuclear capacity – and their respective growth rates – was even wider than indicated in the report.
“The reality of the nuclear industry on the ground is quite sobering for those who expected to find a booming sector,” Schneider told
pv magazine
. “Recently, U.S. nuclear company Holtec put an initial public offering (IPO) on hold just days before its planned stock market listing, through which it had hoped to raise almost $1 billion. Its peer, Fermi, has lost about 80% of its stock value since it was first listed in October 2025.”
“The main reason? These companies have little or nothing to show on the ground to convince investors to continue providing cash,” he added. “Meanwhile, the world’s operating nuclear fleet increased output by 1.1% – with output declining outside China – while global solar power generation jumped by a stunning 30%, surpassing nuclear’s annual electricity production for the first time. One is tempted to say: It’s the growth rates, stupid!”
The report identifies falling battery costs as a potential enabler of continued PV expansion, particularly as grids contend with growing volumes of variable renewable generation and periods of low or negative electricity prices. Grid-scale battery deployment accelerated sharply in 2025, with 104 GW and 257 GWh connected during the year. More than 78% of cumulative battery energy storage system (BESS) capacity was installed between 2023 and 2025.
Slow expansion
The report shows that the global nuclear sector is expanding slowly, with most new activity concentrated in China and Russia. As of July 1, 2026, 411 reactors were operating in 31 countries, excluding 30 units in long-term outage, with operating capacity at 374.7 GW. In 2025, nuclear plants generated 2,703 TWh, up 1.1% year on year, largely driven by a 7.6% increase in China. Outside China, nuclear generation declined by 0.2% and remained well below its 2006 level. Nuclear’s share of global electricity generation slipped to 8.8%, its lowest level in four and a half decades and roughly half its 1996 peak of 17.5%.
Four reactors started supplying electricity in 2025, while seven closed, resulting in the first negative annual reactor balance since 2021. Between 2006 and 2025, 104 reactors started up and 106 closed. China accounted for 53 of those startups and no closures, meaning the rest of the world recorded a net decline of 55 reactors. Although global nuclear capacity increased by a net 21.5 GW over the two decades, China alone added 52.3 GW, while capacity outside the country fell by almost 30.7 GW.
The construction pipeline has nevertheless expanded. Seventy-three reactors were under construction as of July 1, the highest number since 1987, with China accounting for 37. Russia remains the dominant international supplier, with Russian technology involved in 29 reactors under construction worldwide, including 22 outside Russia. Nine out of 10 reactors being built are in Asia or Eastern Europe.
Long construction times and delays remain a feature of new nuclear projects, according to the report. None of the 16 reactors connected to the grid between 2023 and 2025 was completed on schedule, with an average construction period of 10.9 years. Of 13 reactors scheduled to start generating electricity in 2025, only four did so. Some projects have experienced exceptionally long timelines, including Slovakia’s Mochovce-4, where construction began more than 40 years ago, and Iran’s Bushehr-2, where construction originally started in 1976.
Construction starts accelerated in 2025, however, reaching 12 units, the highest annual total since 2010. Nine were in China, two in Russia and one in South Korea. Of the 52 reactor construction starts recorded worldwide between 2020 and 2025, all but one involved the Chinese or Russian nuclear industries, either domestically or abroad.
Limited progress on small modular reactors
The report questions whether small modular reactors (SMRs) can deliver on their long-standing commercial promises, noting that progress remains limited despite growing government support and public funding.
“For decades, small modular reactors have been held out as holding great promise for expanding nuclear power into various new markets. Remarkably similar claims have been made by the nuclear industry in multiple countries. Nowhere have these claims come true,” the authors said.
The authors challenge several claimed advantages of SMRs, including lower costs, modular construction, improved safety, reduced waste and easier siting. Many commercially proposed designs are 300 MW or larger, while an analysis cited in the report suggests some SMR designs could generate between two and 30 times more nuclear waste than larger reactors.
The report also questions whether modular manufacturing can achieve economies of scale without a large and predictable market. Still, SMR projects are advancing in several countries. Canada began construction of GE-Hitachi’s BWRX-300 in 2026, while China continued testing its Linglong One demonstration reactor. Russia is developing floating and land-based SMRs, while the Czech Republic and Sweden are pursuing Rolls-Royce projects. The report questions whether the EU can meet its goal of deploying its first SMRs by the early 2030s.
The United Kingdom has committed £2.6 billion ($3.5 billion) to advance three Rolls-Royce reactors at Wylfa, with a final investment decision expected in 2029. At 470 MW, the design exceeds the commonly used 300 MW threshold for SMRs.
In the United States, federal funding supports projects involving GE Vernova, TerraPower, X-energy and Kairos Power. While some have reached permitting or construction stages, many remain years from commercial operation. Overall, the report says SMR development remains heavily dependent on public funding, while commercial deployment, construction timelines and the claimed benefits of modular construction remain uncertain.
Global overview
The report also provides detailed country-level assessments covering developments in major nuclear markets and potential newcomer countries, as well as nuclear decommissioning, the Fukushima disaster and Russia’s nuclear interdependencies.
These sections examine reactor operations, newbuild plans, closures, policy developments and the challenges associated with aging fleets. The report also tracks the dismantling of closed reactors, developments in Japan 15 years after the Fukushima accident, and the nuclear industry’s continuing technology, fuel and supply-chain links with Russia.
This content is protected by copyright and may not be reused. If you want to cooperate with us and would like to reuse some of our content, please contact:
[email protected]
.
Thank you
Adaobi
for such a wonderful suggestion. All credit to her for the idea, we are still workin’ on it!
My genius friend Adaobi Adibe sent me a paper on making biological tissues transparent. In
“Achieving optical transparency in live animals with absorbing molecules”
, the authors make biological tissues, like chicken breast, transparent by soaking them in a solution of tartrazine. Tartrazine is the very bright yellowish-orange food dye that is found on Doritos.
We aim to do a more ambitious replication imminently. But as a warm up, I tried to replicate parts of this protocol by soaking chicken breast in tartrazine solution. I got partial transparency but not to the degree of the paper. The sample below is an approximately 2mm thick raw chicken breast cut from a 5mm slice that was soaked in ~0.19 M tartrazine solution for 6 hours at room temperature. I took an image of this with a desk light. You can see the grid lines showing through from underneath. The chicken, even though the texture to the touch is the same, has a visual quality like that of gummy bears.
The original paper used 0.62 M, 40 °C and a machine shaker, but I couldn't find a way to do this safely, nor did I have the equipment to do so. Hence the altered protocol.
The image below is a different angle of my sample. The sample on the left is the same 2mm thick chicken breast slice as above. And the sample on the right is a control where I soaked it in water (it is slightly yellow since this process is super messy and I got dust on it).
In the top part of the sample we do see some transparency, with the 5mm x 5mm grid showing through. The visual quality of the chicken breast takes on a gummy-bear like quality. Kinda makes me wanna chew it if it wouldn't give me Salmonella.
I don't wanna get copyrighted by Doritos so here is a cartoon of where you can find tartrazine in the wild.
How does this work?
The current model we have is that the absorbance properties of the tartrazine also shift the refractive index of water. By pushing the refractive index of water to that of protein and lipid solution, we make the object more transparent. I’ll explain this in great detail later.
Tartrazine was from APC Pure. It was >80% dye content, which means some uncertainty over what the true molar concentration will be. I then prepared three concentrations of tartrazine at these molar concentrations, one of which was just a 0 concentration as a control.
Tartrazine: 2 g, Tap water: 18 g, w/w: 10%, Molality (mol/kg water): 0.21, Tartrazine (mmol): 3.7, Molarity (approx.): ~0.19 M
Tartrazine: 6 g, Tap water: 14 g, w/w: 30%, Molality (mol/kg water): 0.80, Tartrazine (mmol): 11.2, Molarity (approx.): ~0.56 M
Tartrazine has M = 534.4 g/mol. Moles use the nominal mass (the powder is >80% dye, so true values are up to ~15% lower). Molarity assumes a final solution volume of ~20 mL.
This is what the tartrazine looked like. It doesn't have an odour, and it seems to be considered food safe by the FDA, so I didn't bother wearing gloves for this bit. Here is a picture of the tartrazine and the specs.
Product
: Tartrazine E102 FG, C.I. 19140
Dye content
: >80%
Molecular formula
: C16H9N4Na3O9S2
Molecular weight
: 534.37 g/mol
λmax (in water)
: 425 nm
Water-insoluble matter
: <0.20%
Subsidiary dyes
: <1.00%
Heavy metals (as Pb)
: <40 mg/kg
To prepare the solutions I used a jeweller's scale to weigh out the right amounts and then added tap water to the weights listed in the table.
To dissolve the tartrazine, I mixed it with a glass stirrer at room temperature until there were no visible lumps.¹
Here are the different solutions at different concentrations, the most concentrated one on the left, the middle concentration in the middle, and then a water control on the right.
Next, I got chicken breast fillets from Tesco. I cut a 5mm thick slab and then cut three pieces out to around 15mm in length.
I then soaked 5mm thick slices of chicken breast in each of the three solutions.
After 6 hours of soaking, these were the results.
First, the chicken in the highest concentration solution failed, because the tartrazine seemed to crystallise. This is what it looked like - it got all crusty.
For the middle concentration (~0.19 M), the chicken appeared gelatinous. But it wasn't transparent. The control chicken remained completely opaque.
I threw these pieces out and then tried again with the method below.
And then I tried again with the same procedure, with the aim of soaking it for 12 hours at room temperature. Given the issues with the highest concentration (~0.56 M), I only tried the water control and the middle concentration (~0.19 M). But this time I put the chicken in test tubes and covered it, given that I was gonna leave it out for 12 hours at room temperature. I wanted to mitigate the food safety risk.
This was the 12-hour-soaked piece. Whilst it's hard to see with the camera, there was some slight visible translucency compared to the control.
To examine it I put it under some light above.
I then cut approximately 2mm slices of chicken. This was quite fiddly to do with a small slimy piece. Here is what it looked like compared to the control.
This technique has been used to make fluorescence imaging much easier in live animals.
On my end, doing this well could add to the set of things that independent scientists could image at home. We might be able to probe internal structures of things more casually. Making things transparent would give better images and would allow independent scientists to look at tissue structure more closely.
Effective observation at low cost is one of the themes of my research. I wrote about writing tracing software for Brownian particles using my microscope in my last post. I am also thinking about trying to match the performance of CO2 gas sensing using pressure, which would make that type of sensing cheaper. In line with this theme, I’m super excited about attempting weird and cool techniques to make structures more easier to probe!
Here’s is more than you ever wanted to know about optical transparency.
A material can be opaque for two reasons. First, a material can absorb light and block it. Second, it can scramble light due to different refractive indices.
First, light rays from the other side could be absorbed when they pass through. If light is absorbed, the light can't hit your eyes and you can't see the other side. Light can have multiple wavelengths, and the wavelengths absorbed by the material are determined by the material's
spectra
. To calculate the spectra, we can approximate the physical behaviour of molecules to that of an electron around a potential. The Schrödinger equation tells us that this system can only occupy a discrete set of energies, and it tells us which ones these are. The differences between these energies set the wavelengths that are ultimately absorbed by the material.
In reality, materials are composed of lots of different things and so we expect them to also absorb different wavelengths.
Another reason for opacity is less obvious, but more interesting. The refractive index of a material tells us how quickly light travels within the medium. When light travels between materials with different refractive indices, it deflects slightly. When a material is packed with sub-materials that have different refractive indices, the refraction within causes light rays to get scattered since light rays ping around.
Biological materials contain a mix of different sub-materials inside - fibres, cells, proteins, and more. Each of these materials contains a different refractive index. When you have a material with one refractive index embedded in a material with a different refractive index, you get scattering. This scattering causes the light from the other side to get scrambled. The diagram below shows this.
We can model biological materials as a 'base material' of water, with chunks of lipids and proteins embedded inside, all of which have different refractive indices.
To make something transparent, we need to exploit the two causes of opacity. One approach is to try to change the absorbance spectra of a material so that it absorbs fewer wavelengths of light.
Alternatively (and this is the approach we'll cover in this post), we could try to change the refractive index of the water inside to match the embedded media. The image below shows this principle with biological tissues. If you can change the refractive index of water with a dye, you can then match it to the refractive index of proteins and lipids, which is slightly higher.
If you manage to do this without modifying the absorbance of a material, you should be able to make it more transparent.
Ok, so the game is to change the refractive index. Here is a map of the calculations we need to do to figure out how to modify the refractive index of a material.
To understand where the refractive index plays a part in a quantitative model, let's model how light travels according to Maxwell. Light is an electromagnetic wave, comprised of oscillating electric and magnetic waves. For this essay, let's focus on the electric field part to get the key intuitions.
Using complex representation, if light travels down the z axis, in a vacuum, we can write down the equation of light as the following. Because it's a wave, we can write
\(E(z, t) = \mathrm{Re}\left\{ E_0\, e^{\,i\omega z / c \;-\; i\omega t} \right\}\)
Where E₀ is the amplitude (how strong the field is), ω is the angular frequency (at a fixed point the field goes round once every T = 2π/ω),
c
is the speed of light,
z
is distance along the beam and
t
is time. Crest to crest, the wavelength is λ = 2πc/ω.
In media though, we expect both the speed of light to change in the medium, as well as some absorption. We can rewrite the equation as follows
\(E(z, t) = \mathrm{Re}\left\{ E_0\, e^{\,i(n' + i\kappa)\,\omega z / c \;-\; i\omega t} \right\} = \mathrm{Re}\left\{ E_0\, e^{-\kappa \omega z / c}\, e^{\,i(n' \omega z / c \;-\; \omega t)} \right\}\)
The coefficient in the exponential n′ is a multiplier behind the spatial term, and represents the real refractive index. κ represents how much the wave attenuates, and is meant to denote absorption.
In practice we can group n′ + iκ as one number, and then refer to this as the complex refractive index.
First we need to try to change the real refractive index. If we can increase the refractive index of water to match the tissue refractive index, we would have a more transparent material. Water has a refractive index of 1.33. And although this number is variable, protein and lipid rich structures have a refractive index of around 1.45. So the game is to adjust the refractive index of the water around it towards 1.45, which would make it more transparent.
Whatever we do to the water, we also need to make sure that we don't make the absorbance property too high. If κ gets too high, then we'd end up absorbing all the light and it won't go transparent.
So how do we shift the refractive index? To understand refractive indices, we first need to understand polarisation. To first order, a material consists of electrons bound to nuclei. When an electric field is applied to a material, the relative positions of the electrons to their nuclei change.
For a positively charged particle and a negatively charged particle, polarisation is the magnitude of that charge multiplied by the displacement of one from the other. To calculate the polarisation, we need to model how far electrons displace from the nucleus under the electric field.
Electric fields provide a force on charges that are free. To model the effect of an electric field on a material, we treat the positive nucleus as fixed, and the electrons as free. To calculate the effect of the system, we'll use the Lorentz oscillator model.
In this model, the electrons are modelled to be bound to the nucleus like a damped spring, with the electric field applying a forcing. We can solve it exactly how we would solve a damped spring problem:
Newton's second law for the electron, with the light's field oscillating at ω:
\(m\ddot{x} = -m\omega_0^2\, x \;-\; m\gamma\,\dot{x} \;-\; e\,E_0\, e^{-i\omega t}\)
If we try an Ansatz for the position of the electron x(t) = x₀ e^(−iωt) (the electron oscillates at the driving frequency), we get that the position of the electron relative to the nucleus is given by the following expression.
The dipole moment is p = −ex, and with
N
electrons per unit volume the polarisation per unit volume is
\(\mathbf{P} = N p = \frac{N e^2/m}{\omega_0^2 - \omega^2 - i\gamma\omega}\; \mathbf{E}\)
In this setup, ω₀ represents the natural frequency of the bound electron, which is the frequency the molecule absorbs at (for tartrazine, the 425 nm peak), γ represents the damping rate, which sets how broad that absorption peak is, and ω is the frequency of the electric field. Now we've found polarisation, we want to relate it to the refractive index itself. To do that, we need to do some gymnastics with two identities.
By convention, the polarisation can be written as proportional to the electric field
\(\mathbf{P} = \varepsilon_0\,\chi\,\mathbf{E}\)
where ε₀ is the permittivity of free space, χ is the electric susceptibility (a dimensionless number that says how easily the material polarises), and
E
is the electric field. Comparing with the Lorentz oscillator result above,
To relate our polarisation, and electric susceptibility to the refractive index, we use the following trick.
The below is an AI-assisted proof with manual checking.
This degree of polarisation and the electric field is encoded in something called the
electric displacement field D
. And the relationship between D and the electric field is linear, with the coefficient called the relative permittivity, εᵣ.
P
here represents the polarisation per unit volume, and is the average induced dipole moment across all of the material.
It turns out that the relative permittivity is related to the complex refractive index as follows:
\(n_c^2 = (n' + i\kappa)^2 = \varepsilon_r\)
The proof of the relationship between refractive index and permittivity for a standard electric wave is standard, and is in the footnote below.² And so, to change the complex refractive index, we need to change the relative permittivity of the material.
To proceed, we use an approximation. The electric displacement field is a function of the polarisation of a material. But when we mix two materials together, we can add their polarisation densities.
Before adding tartrazine, we have that water obeys
But we know that each polarisation is proportional to the field, with its own susceptibility:
P
(water) = ε₀ χ(water)
E
and
P
(tartrazine) = ε₀ χ(dye)
E
, where χ(dye). Substituting that in, we get
For a dilute dye, χ(dye) is small compared to n(water)², so we can expand the square root and use a Taylor expansion to get the modified refractive index of the water with the dye.
n_c is complex. If we write it out as n_c = n′ + iκ and split the electric susceptibility of χ(dye) that we got into real and imaginary parts, the dye shifts the real refractive index and introduces absorption by
\(\Delta n' = n' - n_w = \frac{\mathrm{Re}\,\chi_d}{2 n_w}, \qquad \kappa = \frac{\mathrm{Im}\,\chi_d}{2 n_w}\)
And putting in the Lorentz form of χ(dye) that we got earlier
For tartrazine and red light, ω is below the resonance ω₀, so ω₀² − ω² > 0 and Δn′ is positive. This means the dye raises the refractive index of the water. Meanwhile κ carries a factor of γω in the numerator and is only large near ω ≈ ω₀,, which means that we don't get absorbance.
References
Ou Z, Duh YS, Rommelfanger NJ, Keck CHC, Jiang S, Brinson K Jr, Zhao S, Schmidt EL, Wu X, Yang F, Cai B, Cui H, Qi W, Wu S, Tantry A, Roth R, Ding J, Chen X, Kaltschmidt JA, Brongersma ML, Hong G. Achieving optical transparency in live animals with absorbing molecules. Science. 2024 Sep 6;385(6713):eadm6869. doi: 10.1126/science.adm6869. Epub 2024 Sep 6. PMID: 39236186; PMCID: PMC11931656.
²
Here are Maxwell's equations for electric and magnetic fields in a material. This is generated by Claude.
The question is then - how do any of these relate to the refractive index?
No free charges or currents (ρ = 0,
J
= 0), non-magnetic. Faraday's law says that the curl of an electric field is the negative of the magnetic field's time derivative. Take the curl of Faraday's law, and then substitute in
This is where εᵣ enters: the polarisation current ∂
P
/∂t adds to the vacuum displacement current. Then (taking εᵣ constant in time, i.e. working at a single frequency)
esp32sim — an ESP32 emulator in Rust:
Xtensa (ESP32, S3) and RISC-V (C3, C6)
Instruction-level emulation of four ESP32 SoCs, across
both of Espressif's CPU architectures
.
Each boots the
real mask ROM
, the real 2nd-stage bootloader and an unmodified application
image — no patched firmware, no stubs in the way — with enough of the SoC modelled to run real
projects end to end. No cloud, no accounts. MIT.
The
classic ESP32
also boots its ECO3 ROM on dual LX6 cores, with GPIO, UART and timers;
--board ttgo-tdisplay
adds the LilyGO TTGO T-Display's ST7789 and buttons.
These full-listing and hardware counts describe earlier manual runs. CI runs the checked-in
sampled decoder corpora and emulator golden outputs; it excludes the external full-listing
tests. The Xtensa objdump test excludes PIE operand comparisons. Hardware trace comparison
normalizes window exceptions and resynchronizes delay loops, so it is not uninterrupted
cycle-by-cycle agreement. See the
test scope
,
CI workflow
,
Xtensa decoder test
and
hardware comparator
.
Most of the SoC is shared: the C3 reuses the S3's UART, USB-Serial/JTAG, systimer, timer groups,
GPIO, SPI flash controller, GDMA and SHA/AES/RSA models unchanged, and adds its own memory map,
cache controller and interrupt matrix; the C6 reuses the same models again, with its own memory
map, PLIC front-end, L1 cache, PCR and always-on LP blocks. Only the CPU crates are genuinely
separate.
Try it in a browser, no install:
https://mikroverk.github.io/esp32sim/
— Linux on the
S3, the Touch-LCD-4B panel with its SID player, the pocket-tank LLM aquarium, and the C3 and C6 demos.
esp32sim/
emu-core/ the Bus and Core traits, Trap, ClockTree, AArch64 encoder — shared by both cores
esp-soc/ Machine<S: Soc>: scheduler, device time, console, scripts, web UI, loaders, boards —
one machine for every chip; a chip plugs in its cores, bus and interrupt routing;
the virtual WiFi access point, the network behind it and the NAT, for every chip
esp-periph/ the peripheral IP the chips share (UART, systimer, TIMG, GPIO, SPI_MEM, GDMA, crypto,
I2S, RMT, I2C, …), the Device trait, and the device_set! table that mounts them
── ESP32-S3 (Xtensa LX7, dual core) ──
xtensa-lx7/ decoder (sampled objdump checks plus optional full listings), interpreter
(windowed regs, loops, XEA2 exceptions/interrupts, FPU, MAC16, booleans,
PIE SIMD), basic-block interpreter, AArch64 JIT, objdump-compatible disassembler
esp32s3/ SoC + boards: memory map, cache MMU, SPI flash/PSRAM, SHA/AES/RSA, RNG,
systimer, timer groups, interrupt matrix (per core), GPIO, USB-CDC,
UARTs, I2C, GDMA + I2S/LCD_CAM, RMT TX, regi2c, RTC WDT, WiFi MAC;
board/: atech14 / waveshare-cam / waveshare-lcd4b / waveshare-amoled18-v2 / none
cli/ the `esp32sim` command line, every chip (`--chip`); `esp32sim-c3` / `esp32sim-c6` are alias binaries
── ESP32-C3 and ESP32-C6 (RISC-V, single core) ──
riscv-rv32/ RV32IMAC decoder (sampled objdump checks), interpreter, disassembler
esp32c3/ the C3 SoC: memory map, interrupt matrix, cache controller, RNG;
peripheral models shared with esp32s3 where the IP is identical
esp32c6/ the C6 SoC: unified memory map and MMU, interrupt matrix + PLIC/INTPRI, L1 cache,
PCR, the LP blocks (reset cause, software reset, RTC timer), ASSIST_DEBUG,
the 802.15.4 and WiFi MACs
tests/ golden-output regression tests and their fixtures (tests/README.md)
── shared ──
wasm/ C-ABI crate wrapping all three Machines for the browser in one module
web/ browser UI (board drawing, console, audio, camera) + emu.js/worker.js for wasm
hw/ JTAG differential-test scripts against a real board, captured C3 and C6 consoles
examples/ hello_world (IDF, S3, C3 and C6), waveshare-cam (autopling run script + photo),
wifi-station (S3), c6-wifi-station (builds for the S3, C3 and C6; the WiFi goldens'
firmware), c6-radio-dashboard (WiFi + 802.15.4 on the C6 board)
tools/ PIE table generator (TRM-derived); bench.py (interleaved A/B benchmark);
wasm-build.sh (the WebAssembly module)
Boards (ESP32-S3)
The SoC model emits pin-level events (GPIO edges, RMT symbol streams, I2S samples); a
BoardModel
(
esp-soc/src/board.rs
) interprets them.
--board atech14
(default) is the Atech
14‑port board with its ST7735, WS2812 ring, encoder and buttons;
--board none
is a bare
module — any ESP32‑S3 firmware, console only;
--board waveshare-lcd4b
is the Waveshare
ESP32‑S3‑Touch‑LCD‑4B (ST7701S 480×480 over the LCD_CAM RGB bus, GT911 touch, TCA9554, codecs)
running the esp32-screen LVGL panel with touch;
--board waveshare-amoled18-v2
is the Waveshare
ESP32-S3-Touch-AMOLED-1.8 V2 (CO5300 368x448 over QSPI, CST820 touch);
--board waveshare-cam
is the Waveshare
ESP32‑S3‑CAM‑OV5640 (CH32V003 IO expander, OV5640 over SCCB, ES8311/ES7210 codecs on I2C0,
speaker on I2S1, OV5640 on the LCD_CAM DVP port) — runs the
waveshare-autopling
firmware
(IDF 5.5, 16 MB flash, 8 MB octal PSRAM:
--flash-mb 16 --psram-mb 8
) end to end: camera frames
from
--cam-image
or the browser (picture upload / webcam) → esp‑dl pedestrian detector on the
emulated PIE SIMD unit → pling on the ES8311. See
examples/waveshare-cam/
. Adding a board =
implementing the trait (
gpio_changes
,
rmt_frame
,
i2c_devices
,
camera_frame
, …).
The Pocket Synth firmware the
atech14
demos run is its own project:
atech-firmware
— a PlatformIO build of the SID synth and a cRSID
player for real
.sid
tunes. This repo carries the built images it produces, in
web/wasm/fw/public/
.
cargo build --release
FW=web/wasm/fw/public # the demo images the goldens and the web page run
./target/release/esp32sim --boot rom \
--bootloader $FW/atech-bootloader.bin --ptable $FW/atech-ptable.bin --app $FW/atech-firmware.bin \
--script $FW/atech-script1.txt --wav out.wav --tft-png tft.png --max-seconds 5
The mask ROM ELF is picked up from
~/.espressif/tools/esp-rom-elfs/*/esp32s3_rev0_rom.elf
(shipped with ESP‑IDF). Without ESP-IDF,
tools/fetch-demo-assets.sh --no-linux
puts the S3, C3 and
C6 ROMs in
web/wasm/fw/
: pass
--rom web/wasm/fw/esp32s3_rev0_rom.elf
, or set
ESP32SIM_ROM_DIR=web/wasm/fw
for the tests.
--boot app
skips ROM+bootloader and loads the app
image directly.
A plain ESP‑IDF project, e.g.
examples/hello_world
(the IDF 5.5 get-started example built with
idf.py set-target esp32s3 && idf.py build
):
prints the ROM banner, the bootloader and app logs on UART0,
Hello world!
, the countdown, and
then reboots through the RTC watchdog exactly as silicon does (
rst:0xc (RTC_SW_CPU_RST)
),
~30× faster than real time. Chip resets (software, RTC watchdog) restart the machine from the
ROM with the right reset cause;
--no-reboot
stops at the first reset instead.
Run — ESP32-C3
esp32sim-c3
runs unmodified ESP-IDF firmware on the emulated RISC-V core, from the real mask
ROM through the real bootloader into FreeRTOS. Same flags as
esp32sim
(
--trace
,
--break
,
--watch
,
--peek
,
--disasm
,
--log-periph
), printing RISC-V mnemonics with symbols.
prints the ROM banner, the bootloader log,
Hello world!
and the reboot, three times over.
Checked line-for-line against a physical C3 module:
205 of 208 console lines identical
over
three boot cycles — the difference is the ROM's
Saved PC:
line.
--mac
,
--reset-cause
and
--strap
let a run adopt a board's identity so the comparison is meaningful. WiFi station mode
supports open and WPA2 virtual APs with DHCP and NAT. No boards;
--boot app
unsupported. See
docs/esp32c3.md
for what works,
what does not, and the five emulator bugs the hardware found.
Run — ESP32-C6
esp32sim-c6
is the same front end on the ESP32-C6: RV32IMAC, the PLIC, a unified memory map.
Checked against a Waveshare ESP32-C6-LCD-1.47:
203 of 204 console lines identical
over three
boot cycles, including the ROM's
Saved PC:
after
esp_restart()
; the one difference is that
line on the first boot.
--board waveshare-c6-lcd147
adds that board — the ST7789 over SPI2 and
the GDMA, the WS2812, the BOOT button — and the C6's 802.15.4 MAC answers energy scans, so the
board's LVGL spectrum-scanner firmware runs end to end (
examples/waveshare-c6-lcd147/
). The MAC
also sends and receives frames with the timing of the air, and
--cooja
makes the C6 an external
mote of Cooja-NG, driven in exact lock-step over NDJSON (an unmodified Contiki-NG-on-IDF image
exchanging broadcasts with emulated MSP430 nodes). WiFi works too:
--wifi
attaches the same
virtual access point as on the S3 (see
WiFi
below). See
docs/esp32c6.md
.
Scripts (host actions at emulated time)
1.5 press btn1 150 # GPIO17 low for 150 ms
2.2 knob cw 2 # two quadrature detents on CLK5/DT4
3.4 press btn2 120
4.0 serial {"action":"set_note","value":"9"} # into USB-CDC RX
5.0 stop
WiFi (ESP32-S3, C3, C6 and the classic ESP32)
--wifi ssid=NAME[,psk=PASS,chan=N,bssid=..]
attaches a virtual access point that the
unmodified
Espressif WiFi blob associates with — scan, authentication, association and, with a passphrase, the
WPA2-PSK four-way handshake — and a virtual network behind it (DHCP, ARP, ICMP, DNS, SNTP off the
host clock).
--net nat
(the default) relays the guest's TCP and UDP over ordinary host sockets, so
firmware reaches the real network;
--net none
refuses it. No firmware changes, no root, no tun
device.
runs the esp32-screen energy panel: it joins, takes a lease, syncs its clock, fetches two days of
electricity prices over
HTTPS
and polls a real Home Assistant on the LAN.
docs/networking-howto.md
is the how-to (flags, debugging, limits);
docs/wifi-plan.md
and
docs/networking-plan.md
describe how the MAC model and the packet path work, and the Networking section of
docs/architecture.md
the layers every chip shares.
The ESP32-C6 joins the same access point and the same network, through its own MAC model
(
docs/wifi-c6-plan.md
): one station, legacy rates, no power save.
examples/c6-wifi-station
is the specimen — scan, join, lease, five pings, and the state on the
board's screen — and every C6 radio run needs
--stub bb_init=0
(the PHY's baseband calibration
wants analog hardware):
The ESP32-C3 joins the same access point too, through a MAC model derived from the S3's. The
same station example, built for each chip without the display, is committed under
web/wasm/fw/public/
as the input of the WiFi goldens (
wifi_station_{s3,c3,c6}
in
cli/tests/goldens.rs
), so it runs without a local build:
P=web/wasm/fw/public
./target/release/esp32sim-c3 --boot rom --flash-mb 4 --console usb \
--bootloader $P/c3-wifi-bootloader.bin --ptable $P/c3-wifi-ptable.bin --app $P/c3-wifi_station.bin \
--wifi ssid=esp32sim,psk=esp32sim-pass --max-seconds 14
examples/c6-radio-dashboard
runs WiFi and 802.15.4 energy scans in one firmware, a page each.
In the browser (WebAssembly)
tools/wasm-build.sh # the module -> web/wasm/esp32sim.wasm
tools/fetch-demo-assets.sh # mask ROMs, xterm.js and the Linux image (--no-linux skips its 16 MB)
python3 -m http.server -d web 8790 # then open http://127.0.0.1:8790/?wasm&fw=hello
The demo firmware is committed; the mask ROMs, xterm.js and the Linux image are not, and every demo
boots from the ROM, so run the fetch once. It gets the same files the Pages site serves.
The same emulator compiled to WebAssembly, running inside the page in a Web Worker: pick a board,
load the ROM ELF and firmware from disk (or
?wasm&fw=<name>
for a hosted manifest), press Boot.
hello_world, the Touch-LCD-4B panel with its SID player, the Atech board, the ESP32-C3 and the
ESP32-C6 all run at real time in Chrome; there is no NAT (the browser has no sockets). The S3 has
a WebAssembly JIT of its own (hot blocks and regions, PIE on WASM SIMD). See
docs/wasm.md
.
Live:
https://mikroverk.github.io/esp32sim/
— Linux 6.11 on the ESP32-S3
(
svermigo/Linux-on-esp32-S3
, log in and type on the
console), the Touch-LCD-4B panel with its SID player, the Atech board,
pocket-tank
(a 4-bit transformer steering the fish on
the Touch-AMOLED-1.8), and the ESP32-C3 and C6
booting hello_world; or load your own firmware for any chip from disk (pick the board, or
esp32c3
/
esp32c6
).
Debugging
--trace [--trace-from N]
,
--break ADDR
,
--watch ADDR
(stop when a word changes),
--peek ADDR[,N]
,
--profile
(pc histogram),
--log-periph
(first touch of every
unknown register),
--stop-after-exceptions N
,
--gram-png
(raw ST7735 GRAM),
--no-jit
(interpret instead of running native code — must give identical results).
Env:
ESP_EMU_DEBUG
,
ESP_EMU_DEBUG_SPI
,
ESP_EMU_DEBUG_USB
,
ESP_EMU_DEBUG_WIFI[_FRAMES]
,
ESP_EMU_DEBUG_NET
,
ESP_EMU_DEBUG_AES
,
ESP_EMU_DEBUG_SHA
,
ESP_EMU_DEBUG_RSA
.
Documentation
docs/adding.md
— adding a peripheral, a board with devices, a CPU/chip, an observer
Written from the ESP‑IDF register headers, the Xtensa core config shipped with ESP‑IDF, the
RISC-V specification and the C3 and C6 technical reference manuals, and observed firmware behaviour. QEMU was consulted only to confirm instruction semantics
(no code copied). MIT.
Differential testing against real silicon (
hw/
)
Every chip is checked against hardware, by different methods: the S3 in
JTAG lock-step
(below), the C3 and C6 by
diffing a captured console
against the emulator running the same
binaries (
hw/c3-hello-world-real.txt
, 205/208 lines identical — see
docs/esp32c3.md
;
hw/c6-hello-world-real.txt
, 203/204 — see
docs/esp32c6.md
). Those comparisons found five emulator bugs each, including
a device-command race and a cycle counter that did not restart at reset — neither of which a
board-free test would have caught.
ESP32-S3, JTAG lock-step
DIFF_DIR=hw/<board> FLASH_MB=8 hw/difftest.sh 3000
— the scripts read efuses/strap from the
attached chip over JTAG, then step it and the emulator in lock-step on the same flash dump
(
flash-8M.bin
if present). Atech board, 2026-08-25: 3000 steps from reset, 0 divergences.
Any ESP32‑S3 board on USB works (its built‑in USB‑Serial/JTAG carries both the console
and JTAG). The flow, all scripted:
# one-time: dump the board's bootloader/partition table/app start (esptool) into hw/flash-0-1M.bin
hw/difftest.sh 8000 # reset → single-step 8000 instructions on the chip and in the emulator, diff
hw/difftest-at.sh 403c8948 6000 # run both to a PC (here the 2nd-stage bootloader entry), then step 6000 and diff
difftest*.sh
read the chip's efuses (
hw/efuse.txt
), strapping pins and the peripheral
reset state (
hw/reset-regs.txt
, dumped over JTAG at
reset halt
) and start the emulator
from the same image and state.
hw/compare.py
diffs
pc a0..a15 ps windowbase
per
instruction, masks
PS.INTLEVEL
(forced during single‑step), hides window‑exception
handlers (the debugger steps over them atomically) and resynchronises across CCOUNT‑timed
delay loops, which iterate a different number of times when each step takes milliseconds.
Result so far: the ROM reset path (8000 steps) and 3000+ steps of the IDF 5.5 bootloader
run with zero PC divergence; remaining register differences are RTC‑domain values that
depend on the previous boot.
Live board UI (ESP32-S3)
./target/release/esp32sim --boot rom --bootloader … --ptable … --app … --web 8766
# open http://127.0.0.1:8766/
--web PORT
runs the emulator in real time and serves
web/run.html
: the 14‑port board
(knob + LED ring, buttons, speaker VU, the ST7735 in its physical orientation plus a readable
copy), USB‑CDC and UART0 consoles, an action box for the SDK JSON protocol, and audio through
WebAudio. Inputs: click the buttons, wheel/drag/←→ on the knob, click the cap to push it.
Performance / real time (ESP32-S3)
Blocks of instructions are decoded once and executed from a cache, then compiled to native
AArch64 code (
--no-jit
falls back to the interpreter and must give identical results); idle
cores (
waiti
) are skipped, device time is delivered lazily against computed timer deadlines,
and interrupt lines are recomputed only when a source changes. See
docs/speed-plan.md
for the measurements behind each step.
The Pocket Synth firmware runs at real time with margin while idle or playing notes; the one
place it cannot keep up is a full display redraw, where core 1 runs 100 % busy bit‑banging SPI
(4.8 M instructions per 20 ms — 240 Minsn/s needed, ~70 Minsn/s achieved on an M‑series
MacBook). Each redraw therefore costs ~0.3 s of lag, which the UI's adaptive audio buffer
absorbs (it grows on underrun, up to 400 ms) and the pacer recovers afterwards; if the
emulator ever falls more than 0.5 s behind it resynchronises instead of bursting. The header
shows
real time
,
⚠ N s behind
and the resync count.
ESP_EMU_RT_LOG=1
prints every 20 ms window that took > 40 ms wall with both cores'
instruction counts and PCs.
hw/wsdrive.py [port] [seconds]
drives the UI protocol without a
browser (button presses + knob turns) and reports push gaps, lag and audio delivered — use it
to measure changes to the scheduler.
Contributing
Contributions are welcome.
CONTRIBUTING.md
lists the checks a pull request needs
(the same ones CI runs) and the conventions for tests, experiments and evidence.
Third-party code, data and demo files keep their own licenses:
pocket-tank
(
mediacutlet/pocket-tank
, MIT). Its
bootloader, partition table and app are committed under
web/wasm/fw/public/
with
pocket-tank-LICENSE.txt
; its model is fetched.
MicroPython
(
micropython.org
, MIT): the
official ESP32_GENERIC v1.29.0 image of the T-Display demo, fetched by
tools/fetch-micropython.sh
,
not committed; the demo's app and filesystem are in
examples/ttgo-tdisplay
with Russ Hughes's
st7789py driver and fonts (MIT), notice in
web/wasm/fw/public/tdisplay-NOTICE.txt
.
ESP-IDF ADC calibration data
(Espressif, Apache-2.0): the curve-fitting coefficients
and S3 ADC1 calibration from #165, now together in
esp-periph/src/sar_adc.rs
;
see
esp-periph/LICENSE-ADC
.
This Might Be the Earliest Known Spear Murder In Earth’s History
403 Media
www.404media.co
2026-10-17 09:36:29
Archaeologists have discovered a puncture wound from a spear in the shoulder blade of a Neanderthal that lived 75,000 years ago, offering a possible glimpse of early interpersonal violence....
Welcome back to the Abstract! Here are the studies this week that lived and died by the spear, drew unequal lots, paged Fox Mulder, and peered at an alien moon.
First, scientists discover a mortal spear wound in a Neanderthal who lived 75,000 years ago, possibly opening a window into the origins of hominid violence. Then: disparities from beyond the grave, an unexplained population of near-Earth objects, and the word from Jupiter’s moon Ganymede.
Some 75,000 years ago, an adult Neanderthal died from a brutal strike to the chest by a sharpened wooden spear, and was subsequently laid to rest by their kin.
Eons later, in 2020, the remains of this individual were unearthed from deep in the floor of Shanidar Cave, an ancient Neanderthal hangout in what is now Iraqi Kurdistan. The bones of the deceased, named Shanidar A, preserve the spear puncture in the shoulder blade, suggesting that they were impaled with the weapon through the heart to their back.
Shanidar A—whose sex is unknown—also sustained a brutal face injury that had partially healed at their time of death, suggesting that this individual had been cared for while they recovered from this non-fatal wound. The body appears to have been carefully interred in a small area of the cave that contained other Neanderthal remains, implying it was an intentional burial ground.
The entrance to Shanidar Cave. Image: Osama Shukir Muhammed Amin FRCP(Glasg)
“Shanidar A’s shoulder injury appears to have been fatal, but the apparent placement of the body in a location that subsequently became part of a tight cluster of Neanderthal individuals, who were likely intentionally deposited within living memory of each other, strongly suggests a level of care during and immediately after death,” said researchers led by Emma Pomeroy of the University of Cambridge.
Taken together, the discovery of Shanidar A adds to the evidence that Neanderthals nurtured each other in life and performed symbolic funerary rituals after death. These bones may also represent one of the earliest direct examples of interpersonal violence in any hominin, the term for humans and their close relatives, assuming that the Shanidar A was intentionally slain.
However, it’s hard to distinguish whether the death blow was an attack from another Neanderthal—or perhaps a member of our own species
Homo sapiens
—or if it was an accidental injury sustained while hunting.
Shanidar Cave was occupied by Neanderthals for at least 50,000 years leading up to their mysterious extinction. While we will never know the complexity of their stories, our human cousins were clearly capable of compassion, care, and respect for the dead.
For the past several years, researchers led by astronomer Beatriz Villarroel have discovered strange “transients”—unexplained objects or phenomena in space—in historical photographic plates from before the launch of the first spacecraft, Sputnik, in 1957. The nature of these transients has become hotly debated among astronomers, with theories ranging from instrumentation defects to lurking alien spaceships.
In a recent study, the team re-analyzed the transients with machine learning, an effort reinforced previous findings that “transient numbers diminish significantly in Earth’s shadow”—hinting they are real objects that reflect less sunlight in our planet’s shade—and that they are more likely within one day of atmospheric nuclear tests during the mid-20th century.
The left image presents examples of three transients (green circles) identified on the POSS-I red plate taken on August 11, 1953. The image at right is the same region in a POSS-II red image taken on September 3, 1989. The yellow circle indicates a plate defect on the left image.
Bruehl, Stephen et al.
“If one accepts that both key findings in this study represent real phenomena…we are left with a very small set of provocative hypotheses that would be considered highly implausible by most,” said researchers led by Stephen Bruehl of Vanderbilt University and co-authored by Villarroel.
“For example, is it possible that unknown to the public there were multiple launches of artificial satellites long before Sputnik with some launches timed to coincide with U.S. nuclear tests? Or rather, do the current findings represent detection of a non-human technosignature? Finally, might our results represent detection of an entirely new yet unknown physical phenomenon?”
“Additional research on this topic is clearly warranted,” the team concluded.
Hard agree. When a mystery’s leading explanations include 1) secret satellites that upend spaceflight history, 2) ALIENS (!!!), and 3) exotic novel phenomena, it’s fair to keep digging for answers. My own preference is that it turns out to be some unholy combination of all three, but for now, we will have to just keep literally watching this space.
Let’s keep playing in haunted graveyards—it's spooky season, after all. This time, we’ll take a long walk through about 2,300 ancient burials in the Central Plain of China. In a new study, scientists probed the emergence of wealth inequalities in these ancient communities by studying this huge sample dating from 9,000 to 3,500 years ago.
The team assessed the relative wealth of the deceased individuals with a number of proxies, including the value of grave goods buried with them, their physical health, and chemical clues about the quality of their diets, which can be preserved in bones.
The results suggest that inequality was present in many of these communities long before the rise of an official state hierarchy, and that “no single pathway led to persistent inequality across early centers of social complexity,” according to the study. However, one clear correlation that emerged in the analysis was the association between violence and inequality, with the former exacerbating the latter.
Geographic setting and archaeological sites in the Central Plain. Archaeological site locations were compiled and mapped by the authors based on published excavation reports. Image:
Li, Dongdong et al
“In the Central Plain…the emergence of violence signals a structural transformation” that suggests that “violence contributes to the amplification and structuring of inequality, although reverse or reciprocal dynamics cannot be excluded,” said researchers led by Dongdong Li of the Chinese Academy of Social Sciences.
While the rise of organized states and kingdoms can accelerate wealth stratification, this study proves that humans are capable of pioneering local homegrown inequalities in myriad ways.
We’ll close with an update from Ganymede, the largest moon in the solar system, which orbits Jupiter. As the only moon with its own magnetic field and a candidate in the search for alien life due to its subsurface ocean, Ganymede has long fascinated scientists.
Now, a team has compiled comprehensive observations of Ganymede’s surface terrain using observations from a range of advanced telescopes, including the Very Large Telescope in Chile and the James Webb Space Telescope. The aim of the study, in part, is to prepare for two spacecraft currently en route to Jupiter—the European JUICE mission, and NASA’s Europa Clipper—which will arrive in the early 2030s.
Ganymede being Ganymede. Image: Juno Mission – NASA/JPL-Caltech/SwRI/MSSS/
Kevin M. Gill
Ganymede “remains a cornerstone object of planetary science due to its geological complexity, internal magnetic field, and potential astrobiological interest based on the presence of a subsurface conducting ocean,” said researchers led by Clement Royer of Paris-Saclay University. “Its surface morphology…argues for a history of significant endogenic activity, possibly including plate-like tectonics and cryovolcanism.”
Indeed, one of Ganymede’s most interesting surface features is a mysterious “darkening agent" that extends over much of the moon’s equatorial regions. The composition of the darkening agent “remains unresolved,” according to the study, though likely guesses include carbon-rich graphite or iron-rich magnetite.
The team anticipates that the Jupiter-bound spacecraft “will provide an unprecedented view of the surfaces of the Jovian moons” that will reveal many of their secrets. At least that’s one thing we can look forward to from the 2030s.
A small flock of mallards going about their day: three hens, two
drakes and two broods of ducklings. No recordings. Every quack is
synthesized as it happens and heard from where you stand on the bank.
Build
predictable
,
concurrent
,
time-sensitive
, and
distributed
systems.
Lingua Franca is a coordination language for efficient, deterministic, multi-threaded, time-sensitive, embedded, and distributed programs. The result of decades of research, it offers more repeatable behavior than other concurrent programming frameworks, including threads, pub-sub, actors, and service-oriented architectures.
Deterministic Concurrency
Lingua Franca offers a straightforward way to write deterministic multi-threaded and distributed applications, eliminating concerns about thread management, synchronization, and race conditions.
Built-in Timing Semantics
Timing is embedded within Lingua Franca's core, empowering developers to handle time-sensitive tasks with precision and without the complex timing logic typically required in concurrent programming.
Simplified Distribution
Lingua Franca enables seamless transition from single to distributed system architectures with minimal modifications, abstracting away the complexities of distributed systems programming.
Architect your application in LF
import Player from "../Player.lf"
main reactor RockPaperScissors { // Instantiate two Player reactors here player1 = new Player(id=1) player2 = new Player(id=2)
// Make connections between them player2.reveal -> player1.observe player1.reveal -> player2.observe }
A New Programming Paradigm
Lingua Franca is the first reactor-oriented coordination language. It allows you to specify reactive components and compose them. Lingua Franca eliminates race conditions by construction, makes it easy to specify timed behavior, and removes the need to perform manual synchronization.
Consider a game of "rock paper scissors" where two players need to reveal their choice simultaneously. In Lingua Franca, "at the same time" has a clear and precise meaning. This makes the implementation simple and intuitive, and guarantees it to be fair. If the Player class were to observe the other's choice before revealing its own, Lingua Franca's causality analysis would find a causality loop and tell you that the program is invalid.
Not a New Programming Language
With Lingua Franca, you forget about thread libraries or message passing middlewares, but you continue using the languages you like. The bodies of reactive code that make up the functionality of reactors are written in the programming language of your choice. We currently support C, C++, Python, TypeScript, and Rust.
Open-source and Supported by Research
Lingua Franca was first developed at UC Berkeley where it was influenced by decades worth of research in models of computation.
Shortly after its inception, researchers from Kiel University and TU Dresden joined the team, contributing diagram synthesis and layout technology, highly-efficient runtime implementations, and various compiler improvements. Since then, we have worked with real-time systems experts from UT Dallas, embedded systems specialists from NTNU, and networking and security researchers from Hanyang University and ASU.
The power of AI is worrying senior Labour figures – as is the fear of ‘falling behind the public’
Guardian
www.theguardian.com
2026-10-17 07:33:20
Westminster appears to be waking up to warnings over AI safety, with concerns over its use by extremist groups and bad actors “I have this sense that, within a few months, AI is going to be all anyone is talking about,” said one cabinet minister, with an ominous stare. It was Labour conference, with...
“I have this sense that, within a few months, AI is going to be all anyone is talking about,” said one cabinet minister, with an ominous stare.
It was
Labour
conference, with everyone from ministers to activists jubilant at Andy Burnham’s takeover and a bounce in the polls after the change of leader.
But a number of senior Labour figures were privately starting to name the power of AI as the thing worrying them most, alongside the immediate pressures on the cost of living and fragile economy.
One cabinet minister – with a brief unrelated to technology – told the Guardian that dangerous, out-of-control AI was the issue keeping them up at night, fretting about the threat to humanity. It was “not killer robots” causing the worry, they explained, but the idea of a huge amount of concentrated, super-intelligent power potentially ending up in the hands of bad actors.
Another expressed concern that the government was “falling behind the public” in terms of dealing with worries about AI safety – and that it needed to catch up fast.
Ed Miliband was strident about the dangers of AI at the Labour party conference.
Photograph: Wiktor Szymanowicz/Future Publishing/Getty Images
In his conference speech,
Ed Miliband
was the most strident about the “daunting” dangers of AI, making the case that politicians could not and would not allow the profits of tech companies “to come at the expense of our children or indeed humanity”.
And it has not taken long for these alarm bells to ring even louder, with the last seven days looking like the week Westminster fully woke up to the warnings.
A flurry of activity started on Monday with Kanishka Narayan, the AI minister, stating it was
“likely, if not inevitable”
that rogue agents would hack the British state, and saying the UK was looking to strengthen its forthcoming cybersecurity legislation.
Kanishka Narayan said it was ‘likely, if not inevitable’ that rogue agents would hack the British state.
Photograph: Carlos Jasso/AFP/Getty Images
It was the main topic of discussion at cabinet on Tuesday, and that was followed by the MI5 chief Ken McCallum warning AI was “supercharging the cybersecurity contest between attackers and defenders”. He said
the biggest threat was extremist groups
using the technology to unleash bioweapons – toxins used to cause death and disease.
Liam Byrne, the chair of the business, innovation, science and trade committee, said the change of government from Keir Starmer to Burnham was partly behind the increased focus on protecting the UK from AI threats but more still had to be done. “The reality is that the Starmer administration was much too close to the big tech companies,” Byrne said. “And Burnham is not, frankly, so there has been a change of posture. Those things, plus the security services issuing their warning, that is what has changed the weather on this.”
One senior Labour government figure agreed that Burnham’s government was taking AI safety warnings more seriously. “I do feel there has been a shift. Under the last lot, too many of them had drunk the tech-bro Kool-Aid,” he said.
Ken McCallum, the director general of MI5, warned of extremist groups using AI to unleash bioweapons.
Photograph: Jonathan Brady/WPA/Getty Images
Byrne’s committee held an evidence session this week with civil service leaders in charge of AI security and executives from the key companies –
Anthropic
, OpenAI, DeepMind and Meta – with a split between them about whether government testing of new models should be mandatory.
He said his committee was “lighting up” the issue, particularly in terms of working with the US to regulate and monitor new models. It had been reported that Donald Trump’s administration had asked AI companies not to share their latest models with the UK’s cutting-edge AI Security Institute for testing, though Narayan confirmed this week that they had managed to retain cooperation.
But Byrne said the government now needed to seize the moment and take the lead on new regulation, particularly if Trump’s Republicans lost control of Congress in the midterm elections to the Democrats.
“I think the government is still caught in a dilemma between how to keep model access, given a capricious US president, and the safeguards that the industry itself now says are essential. It’s make-your-mind-up time, I would say,” Byrne said.
“The companies want to cooperate … It’s not in their commercial interest to issue models which are lethal. Now they too have got to navigate the White House. So I just think this is a moment when the government has actually got to do what is right for the country because Congress is about to change the dynamics on this in the US.”
Liam Byrne said the government now needed to seize the moment and take the lead on new regulation.
Photograph: House of Commons
The UK’s upcoming G20 presidency will be the key moment to push for international action to rein in AI. Geoffrey Irving, the former chief scientist at AISI who
spoke at this week’s parliamentary hearing
, believes Whitehall concerns are justified. OpenAI and Anthropic’s technology has already shown its hacking capabilities but their models are released with safety guardrails in place that at least mitigate against the threat of malicious behaviour.
However, so-called open source AI models are freely available and can be adapted. Typically, they caught up with the paid-for models such as OpenAI’s within less than a year, said Irving, although they could cause disruption already.
“It’s very likely that open source models are already
powerful enough to do serious damage,” Irving told the Guardian, adding that he expected open source technology to reach the capabilities of OpenAI and Anthropic products “soon”. Safety guardrails “either don’t exist or can be trivially removed” from open source models, he added.
The business committee heard this week that
AI-enabled bioweapons
could become the next serious threat to manifest itself, in the wake of cybersecurity, as models become more powerful and therefore capable of designing novel bio-harms – although experts suggest there is a gap between designing dangerous pathogens and weaponising them.
Concerns over cybersecurity and bioweapons can escalate rapidly to fears about AI wiping out humanity in a variety of scenarios – a concern that is widespread within the AI community, and is shared by Irving.
However, some experts argue that the government should focus on immediate risks from AI. Prof Elena Simperl, a co-director of the Institute for Artificial Intelligence at King’s College London, said the existential risk argument had “no evidence” and was a “theory” rather than a credible threat.
“There are bigger, more immediate risks that AI technology is posing now and are actually evidenced, like hacking and signs that AI can be as addictive as social media,” Simperl said.
There is said to be concern over the cancellation last year of the AI programme at Porton Down.
Photograph: Jack Taylor/Getty Images
In the absence of international AI regulation, there are some in Whitehall worried about whether the UK is doing enough preparation to defend against AI warfare and attacks.
Defence sources said there was concern about the cancellation last year of the AI programme at the government’s Defence Science and Technology Laboratory (Dstl), based at Porton Down, with worries that this was shortsighted given the need for cutting-edge research on advancing the nation’s capabilities and defending against its risks.
This was countered by an MoD spokesperson who said AI was “transforming defence from industry to the battlefield and will play a decisive role in how we fight and defend” and that it must be “integrated across all workstreams, rather than a standalone programme”. They pointed to a £400m investment in AI-focused capabilities over the next four years to “prepare the UK for the future of warfare”.
Others in Whitehall have the opposite concern: that worries about safety could become too dominant – and end up holding back the government’s adoption of tools that could be transformative for productivity and solving longstanding problems in public services, from medical care to reducing waiting lists.
The former cabinet secretary Gus O’Donnell told the Guardian that ministers needed to be as aware of “the risk of being left behind” when it came to AI as being aware of the need for guardrails.
Launching a Global Government Forum report on AI with the tech firm Cognizant, O’Donnell told the Guardian: “There is a big need to get it better and to really push on. I’m really optimistic, but the challenge for us, obviously, is managing the risks along the way, making sure that we don’t make mistakes, which reduce people’s trust, which means that that sets us back.”
The future of programming – A.I. Wasserman and S. Gutz (1982)
Fake Linda and me: the Agatha Christie-worthy mystery of the fraudster who stole my byline
Guardian
www.theguardian.com
2026-10-17 07:00:30
How a string of bizarre events led writer Linda Geddes to don her sleuthing cap and dig into a world of shadowy impersonators It started with an entirely ordinary interaction on LinkedIn. Someone had tagged me in a post, saying how much they’d enjoyed contributing to a New York Post article I’d writ...
I
t started with an entirely ordinary interaction on LinkedIn. Someone had tagged me in a post, saying how much they’d enjoyed contributing to a New York Post article I’d written about “chronoworking”. As the author of a book about circadian rhythms, it was exactly the sort of subject I might write about. Except I’d never heard of this person, let alone interviewed them.
I clicked on the link and my stomach dropped. There, above an article about people who organise their working lives around their biological clocks, was my name: Linda Geddes.
It was the latest in a string of increasingly bizarre events that had begun three weeks earlier, when a friend who works as an editor at the scientific journal Nature texted to ask whether I’d been pitching stories to one of her colleagues. I hadn’t.
It turned out that someone had been approaching Nature editors using my name and an email address that wasn’t mine, referencing articles I’d previously written to make their pitches more convincing. Worse, the journal had recently encountered another impersonator posing as
Caroline Williams
, a former colleague of mine. That person had convinced an editor at Science to commission and publish an article under Caroline’s name, receiving about $1,000 for it.
Further digging revealed that Fake Linda had also pitched a story to Science, unsuccessfully. Then, last week, an editor at Nature Medicine
contacted me to ask whether
I’d been pitching to them and Nature Health as well.
I donned my sleuthing cap and discovered a potential link between Fake Linda and Fake Caroline. Entering my impersonator’s email address into Outlook.com’s account recovery system revealed a partially obscured Gmail recovery address. An editor at Science had independently discovered the same address pattern associated with Fake Caroline’s email.
Linda Geddes: ‘As someone whose livelihood depends on the reputation I’ve spent decades building, I find this deeply unsettling.’
Photograph: Haybooks-May/Alamy
As someone whose livelihood depends on the reputation I’ve spent decades building, I find this deeply unsettling. Someone is potentially making money by passing themselves off as me, while putting my professional credibility at risk. Apart from one interview conducted by email, the quotes in the New York Post article were lifted from previously published features, without attribution. Many of Fake Linda’s pitches also bear the hallmarks of AI-assisted writing. Even unsuccessful pitches could damage relationships with editors.
The New York Post has since removed the article, conducted an internal review and referred the matter to the appropriate authorities, a spokesperson said.
What I find particularly baffling is the motive. Freelance science journalism is hardly a lucrative profession, and is quite niche. My best guess is that a struggling freelancer is impersonating more established peers to boost their earnings, perhaps using AI to make the process more efficient. But how would they receive payment without revealing their identity?
Other possibilities have crossed my mind. Could it be a PR professional trying to secure coverage for a client, or someone testing how easily publishers can be fooled? Perhaps it is someone with a personal grudge. But as Caroline put it: “Why us? We’re nice!”
Dr Simon Miller, the director of policy, strategy and communications at the UK fraud prevention service Cifas, is equally bemused. “Ordinarily, if you’re seeking to defraud, you’re seeking to do it at scale, in a relatively light-touch way, using mechanised, industrialised processes,” he said. “This is tantalisingly unusual. It’s almost the stuff of Agatha Christie, but with 21st-century technology.”
Journalists are far from the only people finding their names attached to work they didn’t produce. In April, Prof Eric Topol, of the Scripps Institute in California, discovered his name on a scientific paper he knew nothing about
.
Four of his five supposed co-authors were similarly unaware of the paper, while the fifth could not be identified. Within hours of Topol flagging the incident on X, the journal’s website had disappeared.
In April, Prof Eric Topol discovered his name on a scientific paper he knew nothing about.
Photograph: Bloomberg/Getty Images
Topol, who is a bestselling author, said he has discovered at least 12 books on Amazon with his name on that he didn’t write, including several cookbooks. “I don’t even know how to cook,” he said. Particularly upsetting was when a patient told him he’d read his supposed memoir. “They said: ‘I was reading it, and a lot of those things don’t seem to be accurate.’ That’s how I found out about it.”
Leslie McIntosh, a vice-president of research integrity and security at Digital Science, said someone might add a respected name to a scientific paper without permission to make the work appear more credible. Fraudsters also sometimes added respected researchers as editors to make bogus journals appear legitimate and attract publication fees. Even more nightmarish would be someone deliberately publishing misleading information under someone else’s name to damage their reputation. “If their name ended up on a retracted paper, they would then have to explain that retraction,” she said.
Employers are encountering yet another form of impersonation. Jamie Collier, a researcher at Google Threat Intelligence, said criminals had used stolen personal information to secure remote jobs under other people’s names, sometimes without the victim’s knowledge.
Generative AI is making such deception easier, “mainly by stripping away the usual tell-tale red flags that hiring managers relied on to spot fraud,” Collier said. Large language models can generate convincing CVs, tailored cover letters and fabricated evidence of professional experience.
“Real-time video filters and voice-cloning tools are the next step. While live deepfakes are still relatively nascent … threat actors are already testing them to bypass quick video screenings and mask regional accents,” Collier said.
The
Society of Authors and the Writers’ Guild of Great Britain
have warned of increasingly sophisticated scams involving people impersonating literary agents and publishers, in an attempt to get writers to part with money or sign away their rights.
The Society of Authors’ chief executive, Anna Ganley, said she personally received between five and 10 scam emails a day, supposedly from book festivals, literary agents, publishers and others. Some writers had lost thousands of pounds after responding to genuine-sounding offers. “It’s incredibly difficult for writers, because you are often looking for opportunities to market your books,” she said.
Unlike those scams, Fake Linda’s activities seem like a lot of work for relatively small financial gain. But the latest technology could make such impersonations easier. Miller said: “AI is allowing criminals to create sophisticated impersonations at unprecedented speed and scale.”
Or multiple impersonations. I’ve since identified a third science journalist,
Sara Novak
, with a potential link to Fake Linda and Fake Caroline. Fake Sara apparently pitched a story to Chemical and Engineering News in August, which was declined. When Real Sara shared her impersonator’s email address with me, I discovered it links to the same masked recovery address.
The real Sara Novak.
The consequences extend beyond those being impersonated. “The risk for journals and publishers is huge,” said Dr Ben Johnson, the chief editor at Nature Health
,
who turned down a pitch by Fake Linda. “People trust the Nature brand as a source of evidence-based quality information. If an AI-generated story from a fake journalist is submitted then I will likely spend hours editing it from AI slop into Nature prose, including all the fake quotes from people never interviewed.”
All of this raises uncomfortable questions about how you can be sure you know who you’re dealing with when communicating online. When I emailed the New York Post about my impersonator, it agreed to help rectify the situation, then asked: “I see that you’re emailing me from a Guardian email address. Is there any other info you can provide to verify who you are?”
After discovering that Science had inadvertently published a news story by Fake Caroline, its managing news editor, John Travis, said his team had started running all pitches and drafts through AI detectors, “though they are not perfect”. “We also require Zoom calls for any new writers,” he said.
The experience has also put editors at Nature on higher alert. “Sadly, for early career freelancers, this makes me less likely to commission news stories from journalists that I haven’t worked with before,” Johnson said. “I will also have to try to find the time to have a call with new freelancers before they write, to check they are who they say they are.”
Even video calls are no guarantee of identity. Google Threat Intelligence recently documented
North Korea-linked hackers
using real-time deepfakes to lure executives into Zoom calls with trusted peers. “They faked video and audio glitches to get the target to download a ‘troubleshooting tool’ that wiped out their credentials and wallets,” Collier said.
Miller advises independently checking unexpected approaches through an established email address or telephone number. McIntosh advocates several layers of verification, like the multiple identity checks at airports. “You have to have multiple ways to ensure and triangulate that you’re speaking to the person you think you’re speaking to,” she said.
For people whose identities have been hijacked, Miller advises warning professional networks and monitoring for further impersonation attempts.
There may also be legal remedies. Rupert Earle, senior counsel at the London law firm Bates Wells, said that under UK law, impersonating someone to secure paid work could constitute fraud. Victims could also have civil claims for “passing off” – misleading people into believing that work or services come from an established person or business – or false attribution, if work they didn’t create was published under their name.
However, identifying the perpetrator and taking legal action can be difficult, particularly when the publications are overseas and the impersonator’s location is unknown. Despite uncovering several clues linking Fake Linda and Fake Caroline, we still don’t know who is behind the accounts.
But the hunt for Fake Linda continues. I’ll be reporting the incident to the UK’s
Report Fraud
service. I’ve also sent a cease-and-desist email to my impersonator, demanding they stop.
For such a prolific writer, they’ve gone surprisingly quiet.
MapQuest will now show you where Flock cameras are in your neighborhood
You can see the locations of known outdoor surveillance cameras in the app.
Matthew G Eddy/Shutterstock
MapQuest has been on quite the unexpected tear over the last couple of months. The mapping service's app surged in popularity after it refused to refer to Lake Ontario as Lake America (unlike
Google Maps
and
Apple Maps
). MapQuest also added useful, long-overdue features like
Android Auto support
and
public transit directions
.
The layer will show you where
Flock cameras
are. It also displays the locations of cameras from the likes of Motorola Solutions (Vigilant), Genetec, Axis Communications, Axon, Leonardo (ELSAG), Neology, Rekor, PlateSmart, Ubicquia and Verkada. The layer sits alongside options to view traffic and incidents, so it should be easy to find in the app.
MapQuest announced the update with a short video that's set to Rockwell's "Somebody's Watching Me." Chef's kiss, no notes.
You might not be able to easily avoid these cameras on your commute or other usual routes, but the layer may be helpful in illustrating how pervasive these things are in your area. It's useful information to have for those who are trying to rid their neighborhoods of surveillance cams.
Ministers must be honest about Russian threat to UK, says former Foreign Office head
Guardian
www.theguardian.com
2026-10-17 06:19:32
Peter Ricketts calls for more resilience in protecting banking, energy and water systems from cyber-assaults Ministers need to be honest with the British public about the immediate threat posed by Russia, which could soon lead to lives being lost, a former national security adviser has said. Peter R...
Ministers need to be honest with the British public about the immediate threat posed by
Russia
, which could soon lead to lives being lost, a former national security adviser has said.
Peter Ricketts, who advised David Cameron when he was prime minister, became the latest figure to warn about the scale of the threat posed by “hybrid attacks” from Vladimir Putin’s forces.
The peer, who is the former top civil servant in the Foreign Office, said banking systems, energy or water supplies could be targeted by Kremlin cyber-assaults. He called for further investment in resilience for key sectors.
It comes in a week where the heads of
MI5
and the British army have warned about the danger posed by Moscow.
Lord Ricketts also dismissed Andy Burnham’s claim he wanted to be a “bridge” between the US and Ukraine.
Speaking to BBC Radio 4’s Today programme, Ricketts said: “I think they’ve really got to start a conversation with the British people about what may be coming, because not only is Putin trying to break morale in Ukraine, he’s also trying to undermine morale in European countries.”
In response to a question over the impact of disruption by Russia, he added: “I’m not saying there’s going to be industrial war with tanks rolling across the north German plain.
“But these hybrid attacks are getting more reckless, more dangerous. One day, people are going to land up being killed somewhere, and so we are going to have to look at responding in that sense and finding the money to do it.”
Speaking about Burnham’s comments at prime minister’s questions this week saying he wanted to be a bridge between Washington and Kyiv, Ricketts said: “I don’t really go on this bridge business. I mean, I don’t think in Trump’s current mood there’s any influence that Britain can have in the short term.”
Ricketts’s comments join those by the director general of MI5, Sir Ken McCallum, and the chief of the general staff, Gen Sir Roly Walker, in the last few days about Russia.
On Tuesday, McCallum said MI5 was devoting more resources to combating threats from hostile states than it did during the cold war and described Russia as the “number one aggressor”.
And on Friday, Walker told 700 troops at Catterick garrison in North Yorkshire that politicians would soon need to have a “frank conversation” about the “sacrifices” that would be needed to prioritise defence and security.
Walker, a former special forces commander, said soldiers would
probably need to fight in a war
, given the “extreme jeopardy in the world at the moment”.
The warnings come after a difficult week for Kyiv, with the US appearing to withdraw support.
Trump said the decision to pause sanctions was in the US “national interest”, despite previously signing them into law in September.
Last week, he lifted restrictions on Russian diesel amid spiralling fuel prices in the US ahead of the midterm elections.
He also suggested Ukraine needed a new president. Volodymyr Zelenskyy hit back this week during an EU summit, saying it was nice to be among “real leaders”.
There are also concerns that the US has withdrawn intelligence sharing with Ukraine, leaving towns and cities across the country vulnerable to attack.
Ricketts said the government should spend more money on protections for key infrastructure in Britain, including energy, transport, air traffic control and defence.
He said: “They all need better protection, and that’s an argument that needs to be had with the British people because we need to find the money to do it.”
Dems Have an Opportunity to Force an End to the Iran War. Will They Take It?
Intercept
theintercept.com
2026-10-17 05:57:00
With Democrats campaigning on ending the war, advocates want them to put their money where their mouth is and risk a lame-duck shutdown.
The post Dems Have an Opportunity to Force an End to the Iran War. Will They Take It? appeared first on The Intercept....
For months, Democrats
have forced Republicans to take vote after vote on President Donald Trump’s unpopular war on Iran. Now those votes could help Democrats retake Congress — and they will immediately have opportunities to follow through on their anti-war rhetoric.
Democratic leaders like House Minority Leader Hakeem Jeffries of New York have been cagey about their strategy on Iran for the lame-duck period before the next Congress is sworn in on January 3. So far, months of Capitol Hill maneuvering have produced few concrete results. And one path to potential progress for ending the war is laden with risk: threatening a government shutdown.
Opponents of the war say that, with Democrats pushing for support based on their efforts to end to the war, they owe it to voters to put government spending on the line.
“It will certainly demonstrate whether Democrats are willing to stretch themselves and put up a fight and get uncomfortable,” said Hannah Morris, the vice president of government affairs for the liberal, pro-Israel group J Street, which opposes the conflict. “So much of the rhetoric has been about the Iran war.”
In the months since the conflict began on February 28, Democrats and the handful of Republicans opposed to the war have poured most of their energy into votes based on the
1973 War Powers Resolution
, which limits the president’s power to wage war without congressional approval. In June, they succeeded in securing House and Senate passage of a war powers resolution, but the Trump administration has ignored the vote, arguing the law is unconstitutional.
Advocates still believe the Trump administration
should be bound
by the June resolution, but they concede that other paths may have more teeth.
If they really want to stop the war, Democrats will have to confront questions of timing,
divisions
within their own caucus, and the risk of a government shutdown.
One prime opportunity could be the December 11 expiration of a spending bill called the continuing resolution that has been funding the government since the last shutdown. Democrats could attempt to attach a rider to the bill prohibiting the use of any of its funds for the Iran war. If that bill does not pass both chambers, the government shuts down.
The process will provide Democrats with rare leverage before the next Congress is sworn in.
Congressional Democratic leaders have not said whether they are willing to risk a shutdown, however. Jeffries did not tip his hand when he was asked during a recent interview with CNN.
“Listen, we’ll deal with the appropriations process when we deal with the appropriations process,”
he said
. “Right now, the mechanism that is in front of us will be to aggressively move war powers resolutions until we end this war in the best interest of the American people.”
Some Democratic candidates in hotly contested races have gone much further than Jeffries, zeroing in on the appropriations issue. Rep. Tom Barrett, of Michigan’s 7th Congressional District, was one of the few Republicans to vote for an Iran war powers resolution. But environmental activist
Will Lawrence
still attacked him at a recent debate on the issue of war funding.
Morris, who is part of a coalition of groups that have called on Congress to cut off funding for the war, said she is not sure how aggressively Democrats will be willing to pursue the issue during the lame-duck period.
“Will they be willing to shut down the government over this? I don’t have real answers. I think there are a lot of variables here,” she said.
Another option supported by many advocates is the pending debate over the National Defense Authorization Act, the annual Pentagon budget and policy bill. Critics of the war argue that Congress could attempt to insert a provision into the law cutting off authorization for the conflict.
Democrats should be willing to block the bill if it does not include “meaningful restrictions” on the administration’s ability to wage the war, said Hassan El-Tayyab, legislative director for Middle East Policy at the Friends Committee on National Legislation.
“That’s the mandate we’re seeing from the American people,” he said. “They shouldn’t pass a massive defense bill while leaving the administration free to pursue yet another open-ended war in the Middle East.”
The defense bill is generally
considered
“must-pass” legislation on Capitol Hill, providing leverage for Senate Democrats who could block it with a filibuster. The office of Sen. Jack Reed, D-R.I., who plays a key role in the process as the top Democrat on the Senate Armed Services Committee, did not respond to a request for comment.
Falling short of either of those paths, Democrats could continue to try to pass more war powers resolutions. With their party poised for a dramatic shift in its favor in the
midterm elections
, Democrats could even try to exert pressure on Republican legislators to vote in favor of the resolutions, some opponents of the war believe.
Democrats could also wait until January, when they are widely predicted to retake control of one or both chambers of Congress. Holding the gavel in the House or Senate will give them vastly expanded powers to set military spending and launch investigations into the conduct of the war.
One key Democrat, Rep. Adam Smith of Washington, told The Intercept in a statement he was willing to pursue multiple paths to stopping the war, but all of them face obstacles until the next Congress.
“I am open to exploring options for using the NDAA or appropriations bills as a way to end the war,” said Smith, the ranking member of the House Armed Services Committee. “That effort would most likely require bipartisan support. Unfortunately, I am not confident that there is sufficient Republican will or support for such legislative efforts or to override an inevitable veto.”
Whether in this Congress or the next, cutting off spending for the war appears to be the best way for Democrats to force the Trump administration to negotiate with Iran, according to Brian Finucane, a former State Department official who serves as a senior adviser at the nonprofit International Crisis Group.
“If they are serious,” he said, “they should be willing to play hardball, and that would require using the power of the purse.”
"Tame" boar and deer are instinctively adapting to the wolf in the Netherlands
Prooidieren op de Veluwe zoals wilde zwijnen en herten hebben hun gedrag aangepast op de wolf. Dat zeggen boswachters en faunabeheerders. Het blijkt ook uit unieke beelden van Natuurmonumenten.
Contexte Tech
MCP · search · AI · decentralisation · open source
Tony, creator of Contexte Tech · October 17, 2026
We search less and less with a list of links, and more and more by asking an AI assistant a question. But where does the answer come from? Often from the model’s memory, frozen at its training date, with no source and no licence. The
Model Context Protocol (MCP)
changes this: the assistant fetches the information directly from those who publish it.
MCP in two sentences
MCP is an open protocol that lets an AI assistant call tools provided by a server: search, read a resource, fill in a text template. The same server works with Claude, ChatGPT, Cursor, VS Code and any assistant that speaks MCP: you write the tool once and it works everywhere.
Launched by Anthropic in November 2024, the protocol was adopted within months by the main assistants and developer tools, then handed over in December 2025 to the Agentic AI Foundation, a foundation of the Linux Foundation. It evolves through dated versions (2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25, 2026-07-28), and a public registry lists the servers.
From one central index to thousands of sources
A classic search engine copies the web into its own index, then ranks what it copied. With MCP, it is the other way round:
each publisher keeps its data
at home and exposes it through its own server;
the assistant queries several servers on demand
, at the moment of the question;
the answer comes with what goes with it
: the source, the licence, the author, the date of the last update.
Nobody needs to copy everything: search becomes
decentralised
. A statistics office, a public administration, a laboratory or a small specialised website can answer assistants directly, with up-to-date figures, without going through an intermediate index.
What it changes for users
Up-to-date answers
: the assistant reads the data as the server publishes it at the moment of the question, not a training memory.
Verifiable sources
: every answer can link back to the original page.
Clear rights
: when the server states the licence, it travels with the data and you know what you may do with it.
Less invention
: when the server does not have the information, it can say so; the assistant then has fewer reasons to fill the gap, even if nothing fully prevents it.
What is still missing
Decentralised search is only worth something if it stays honest. Three things still have to be built, server by server:
citation
: the assistant must show where the information comes from, with the author, the original source and the publisher;
trust
: the content returned by a server is data, never an instruction for the assistant;
measurement
: a publisher must be able to know how many people reach it through assistants, without tracking them.
Our server as an example
The Contexte Tech catalogue (datasets, prompts, contexts and tools for AI, largely built on European public sources) is open to every assistant at:
https://contextetech.com/mcp
No account, no key. In practice:
Search
: the assistant finds the resources that match the question, in 9 languages, with their title, licence, author and link.
Reading
: it loads a resource by its short code (the rows of a dataset, the template of a prompt, the instructions of a context).
Required citation
: every loaded resource ends with a Source line that the server’s instructions require the assistant to repeat: the resource, its author, the original data source, the publisher and the licence, each with its link.
Measurement without tracking
: the links tell which assistant the visit comes from, with no personal data.
Protected content
: what members write is flagged to the assistant as data, and resources are checked when they are published.
Try it
Add
https://contextetech.com/mcp
as a connector in your assistant, then ask:
load n8qhje
The assistant loads a dataset for finding the NAF (APE) code of a business activity, built on the official INSEE classification published on data.gouv.fr, and cites its source. The full guide is on the
MCP server
page.
A common foundation
What if the MCP protocol became the common foundation of smart, decentralised search? MCP does not replace the web: it gives assistants a way in. The more open, sourced and honest servers there are, the more AI search will look like what we expect from it: answers that say where they come from. If you publish data or reference content, now is the right time to open your own server.
DeepSeek-V4.1-Flash-1017
is a minor update to
DeepSeek-V4.1-Flash
, delivering substantial improvements across reasoning, coding, agentic tasks, and visual benchmarks. Alongside these gains, the model reduces task execution time and output length, enabling users to complete tasks faster and at lower cost and advancing the performance–cost Pareto frontier across multiple agent harnesses.
Benchmark
DS-V4.1-Flash-1017
DS-V4.1-Flash
K3
GLM-5.3
GPT-5.6 Sol
Opus 5
HLE w/o tools
42.6 (44.0†)
36.8 (39.1†)
43.5
42.0†
44.5
56.3
Terminal-Bench 4.0
42.3
31.2
12.6
37.9
39.9
51.8
DeepSWE v1.1
77.0
74.2
67.5
66.9
73.0
74.0
ProgramBench
29.1
20.3
17.5
19.0
23.0
37.0
NL2Repo-Bench
68.2
65.4
58.0
58.0
56.8
75.3
Automation-Bench v1.0.6
60.5
54.8
46.7
48.8
45.8
50.3
Agents’ Last Exam
35.4
31.8
27.6
28.5
26.7
28.6
Apex Bench v1.1
72.1
64.6
47.8
56.6
54.3
65.8
Chartography (w/tools)
83.0
78.9
68.1
—
79.9
84.0
BabyVision (w/tools)
92.5
89.6
85.7
—
88.9
94.1
ZeroBench-main (w/tools)
51.0
49.0
41.0
—
53.0
52.0
† denotes the text-only subset of HLE. We use the Claude Code harness for Terminal-Bench 4.0 and the Mini-SWE-V2 harness for DeepSWE v1.1.
Prompt Encoding
This release does not include a Jinja-format chat template. The
encoding
folder contains a self-contained Python reference implementation (
encoding.py
) with test cases for multi-turn conversations, tool calling, thinking mode, numeric reasoning effort, mid-conversation system messages, and interleaved image content.
For production use, we additionally release
deepseek-recipe
, a set of Rust libraries with Python bindings that provides the same prompt format as a maintained, protocol-aware toolkit. It converts Messages, Chat Completions, and Responses API requests into the Conversation format, encodes them into DeepSeek V4 and V4.1 prompts or token IDs, and parses model output back into complete or streamed responses — covering thinking, tool calls, images, and generation settings. Model inference, tool execution, and HTTP transport are left to the caller.
Minimal Inference
Please refer to the
inference
folder for instructions on weight conversion and running inference locally.
Recommended sampling parameters:
Parameter
Value
temperature
1.0
top_p
1.0
context_window
1M tokens
max_tokens
≥ 256K
License
This repository and the model weights are licensed under the
MIT License
.
Citation
@misc{deepseekai2026deepseekv41flash,
title={DeepSeek-V4.1-Flash: Pushing the Limits of KV Cache Compression},
author={DeepSeek-AI},
year={2026},
}
Contact
If you have any questions, please raise an issue or contact us at
service@deepseek.com
.
The Oxide control plane operates two different DNS services: external DNS, exposed to our customers, provides names for locating the system’s externally-facing API and web console; internal DNS only operates on the system’s internal network and provides service discovery for components of the control plane. These use separate deployments of the same stack. Here are the basics:
The authoritative source of truth of DNS data (i.e., the names and records that the DNS servers should report) is the control plane database. This is a strongly consistent distributed database (CockroachDB).
The core of the control plane is a component called Nexus. When something happens that should trigger a DNS change (e.g., a component is added or removed that provides service either internally or externally):
Nexus first updates the DNS configuration in the database.
A series of background tasks in Nexus propagate the updated configuration to all in-service DNS servers. These tasks run in response to events that change DNS and periodically (to deal with transient failures, missed wakeups, etc.)
This whole flow is asynchronous with respect to the event that triggered the change, but it generally completes in a few seconds in a working system.
But everyone knows that when infrastructure goes offline,
it’s always DNS
that’s at fault. So in working on this system, we spent some time thinking about: what can go wrong in this process? When it breaks, how will we know why?
To be specific: suppose a customer reports that a DNS name they expect to be there is missing. They get no records when they query the external DNS server. What could be wrong? Well:
The DNS data in the database could be wrong.
The propagation process could be broken:
Maybe Nexus hasn’t noticed that the DNS data has changed.
Maybe Nexus has the wrong list of DNS servers. (e.g., maybe one was added to the system but not added to the propagation list)
Maybe the propagation of the DNS data to the DNS servers is broken.
Maybe the propagation process is stuck.
The DNS server may be serving the wrong data for its configuration.
If we got a report that DNS was doing the wrong thing, it seems obvious that what you’d want is a tool that could report all of these things:
What’s in the database?
What names are part of the DNS configuration?
When was it last updated? By which Nexus? Why?
For each Nexus instance, for the last propagation attempt:
When did it start? Is it still running?
What version of the DNS configuration is it trying to propagate?
What DNS servers did it find that it should propagate to? When did it determine that?
What was the result of the last completed attempt to propagate DNS configuration to each server?
For each DNS server, what version of dns data is it operating from?
This example was the catalyst for building
omdb
, the Omicron debugger.
Omicron
is the internal name for the control plane on Oxide systems. It’s the Omicron debugger, not the DNS debugger, because we figured that this wouldn’t be the only subsystem that we needed runtime observability for.
[
1
]
Now, we built DNS propagation in terms of a new abstraction called
background tasks
. Background tasks have basic observability built in. They’re basically just asynchronous Rust functions with a few properties: they can be called (
activated
) in response to certain events; they’re always activated on some period as well; the complete set of them is statically defined; and they can return an arbitrary status payload (currently, a schemaless JSON object). With these pieces,
omdb
is able to generate a useful summary report about DNS propagation without
omdb
itself knowing too much about it. First, it can report basic documentation that comes from the server:
# omdb nexus background-tasks doc | grep -A1 "dns.*internal"
note: Nexus URL not specified. Will pick one from DNS.
note: using DNS server for subnet fd00:1122:3344::/48
note: (if this is not right, use --dns-server to specify an alternate DNS server)
note: using Nexus URL http://[fd00:1122:3344:102::3]:12221
task: "dns_config_internal"
watches internal DNS data stored in CockroachDB
--
task: "dns_propagation_internal"
propagates latest internal DNS configuration (from "dns_config_internal"
background task) to the latest list of DNS servers (from
"dns_servers_internal" background task)
--
task: "dns_servers_internal"
watches list of internal DNS servers stored in internal DNS
and here’s the status:
# omdb nexus background-tasks show dns_internal
note: Nexus URL not specified. Will pick one from DNS.
note: using DNS server for subnet fd00:1122:3344::/48
note: (if this is not right, use --dns-server to specify an alternate DNS server)
note: using Nexus URL http://[fd00:1122:3344:104::3]:12221
task: "dns_config_internal"
configured period: every 1m
currently executing: no
last completed activation: iter 4500, triggered by a periodic timer firing
started at 2025-06-10T03:31:47.775Z (23s ago) and ran for 1303ms
last generation found: 18
task: "dns_servers_internal"
configured period: every 1m
currently executing: no
last completed activation: iter 4500, triggered by a periodic timer firing
started at 2025-06-10T03:31:47.775Z (23s ago) and ran for 1ms
servers found: 3
DNS_SERVER_ADDR
[fd00:1122:3344:1::1]:5353
[fd00:1122:3344:2::1]:5353
[fd00:1122:3344:3::1]:5353
task: "dns_propagation_internal"
configured period: every 1m
currently executing: no
last completed activation: iter 4502, triggered by a periodic timer firing
started at 2025-06-10T03:31:47.775Z (23s ago) and ran for 876ms
attempt to propagate generation: 18
DNS_SERVER_ADDR LAST_RESULT
[fd00:1122:3344:1::1]:5353 success
[fd00:1122:3344:2::1]:5353 success
[fd00:1122:3344:3::1]:5353 success
This is a tidy example of what I call
developing for debugging:
in building the system, we assume that any part of it can be unexpectedly broken in production. We think up front about what information we’ll want to debug it and then make sure we’re able to collect it from production systems.
Note that once we invested in some basic abstractions like background tasks, it was very little work to factor the pieces of DNS propagation so that we get these little status reports. Yet with this, in just a few seconds, we can determine exactly where the propagation pipeline broke down. The result is a system that’s not just functional, but debuggable.
Software should be able to exonerate itself
It’s great when software can tell you what’s wrong with it. It’s even better when it can convincingly tell you that it’s
working
.
It’s one thing for a system like this to report:
or:
DNS propagation is up to date.
Okay. But is that really true? "0 problems" means "0 problems that this program knows about". "up to date" is vague at best and potentially wrong as soon as the words arrive at your screen.
The system above reports much stronger, affirmative evidence when it’s working
correctly
: it says "I propagated DNS version 18, which I discovered at 2025-06-10T03:31:47.775Z, to these three DNS servers (which I discovered at 2025-06-10T03:31:47.775Z) and that all had finished by 2025-06-10T03:31:48.651000Z.
This is
so much more
information. Very often, this can tell you that DNS
isn’t
the problem.
[
2
]
And even when it’s something else, this information can help you make timeline of events for figuring out what did happen. Maybe the user queried DNS before propagation completed?
Other benefits
There are so many other benefits of developing software like this:
You can use
omdb
while building the system to play with it and test it out before writing automated tests. We didn’t do that here, but you can imagine building the database part before the rest of the propagation pipeline and using
omdb
to see Nexus noticing when it gets updated. Debugger-driven development is the subject of a whole
Oxide and Friends
podcast episode.
You can use
omdb
while working on an existing system to understand how it behaves. In this case, you could imagine seeing what happens when some DNS servers are offline.
You can use
omdb
to teach people how the software works. Onboarding docs for the DNS subsystem (which don’t exist, but should!) can walk through an example change to DNS and the subsequent propagation. Mentors can show it to new team members. A demo (at this level of detail) is worth a thousand diagrams.
You can use
omdb
as a tool for communicating about software changes. Instead of telling people about the new DNS system, you can give a deep systems demo of the DNS subsystem in 10 minutes, showing not just
that
a DNS change got propagated as expected, but
how
, and even showing what happens when things aren’t working.
From past experience, I can say that when a team manages to do this across the system, the easy availability of debugging information can really change the emotional tenor of handling support calls. A lot of people naturally view debugging as a painful distraction from something else they’d rather be doing. It’s extra stressful when you’re under the gun because a customer’s waiting for a fix. A lot of the stress comes from the fear and uncertainty. When you’ve built out these tools, you can solve more problems quickly (and more confidently). It still sucks to know a customer’s in pain, but it’s a lot less scary when you know how to figure it out.
I also have this gut feeling that, ironically, software built this way is less likely to
have
runtime problems because this process often prompts you to think about them in development. I can’t say I’ve got any data to back that up.
Show HN: I got tired of btop not seeing my Mac's chip, so I built siltop
A calm, honest system monitor for Apple Silicon, in the terminal you already live in.
Real watts, real clocks and real temperatures from every M1–M5 chip. No sudo, no telemetry, about 1.3% of one core.
Screenshots come from
siltop --demo
, a canned 60-second session (build burst, GPU inference, battery drain, rising heat), so they look the same on every Mac.
Why another monitor?
btop
is beautiful, but on a Mac it can't see the chip: no watts, no GPU, no cluster clocks.
asitop
and
powermetrics
see the chip but need
sudo
.
macmon
is lean but stops at the SoC. siltop sits in between:
as clean as you want by default, as deep as you need when something is wrong.
siltop
btop
macmon
asitop
CPU / GPU / ANE / DRAM watts
✓
—
✓
✓
Per-cluster clocks (E / P / Super cores)
✓
—
✓
✓
Temperatures and fans
✓
CPU temp
temps
—
Per-process energy and GPU
✓
—
—
—
Full process manager (tree, signals, filter)
✓
✓
—
—
Runs without
sudo
✓
✓
✓
—
Machine-readable output
JSON / NDJSON / Prometheus / CSV
—
JSON
—
Self-cost was measured back to back with btop and macmon on the same machine; the method and raw numbers are in
docs/research/12-self-cost.md
.
Highlights
Truth
Numbers come straight from macOS: the SMC for fans, temperatures and system power,
IOReport
for CPU and GPU clocks and energy, Mach and
sysctl
for CPU, memory and processes. No
ps
, no
powermetrics
, no scraping.
A reading the Mac doesn't give is shown as absent, never as a made-up
0
. Fanless Airs show no fans, desktops show no battery, a process the kernel won't describe shows
—
.
A one-line verdict (
All normal
,
Busy: rustc using 9.1 cores
,
Hot: fans at 80%
) with the evidence behind it.
Speed
About 1.3% of one core at a 1 s interval, half of what btop costs at the same rate (2.5%) and on par with macmon (1.4%), measured back to back on an M5 Pro. It only redraws when something changed, and pausing (
p
) stops sampling entirely.
One native binary of about 3 MB, written in Rust. Starts instantly.
Beauty
Braille graphs on one shared, time-linear clock, so every panel lines up;
z
zooms time.
Themes built from your terminal's own palette, readable on translucent and blurred windows. Ten built-in themes plus a theme pack, btop theme import, and 256-colour, 16-colour and
NO_COLOR
fallbacks.
Two surfaces:
Work
for digging in,
Glance
for a small always-on window. The layout adapts from 80×24 up. Five presets on
1
–
5
and a zen mode (
Z
) that leaves only the graphs.
Control
A process table with live filter, sort by any column, tree, app grouping and a details card (threads, open files, ports) with a signal picker, renice and background QoS. A kill is refused if the pid was reused since you chose it.
Full mouse support, htop and btop key profiles, a searchable settings page, and a config file that keeps your comments.
Beyond the dashboard
--json
/
--json-stream
for scripts and status bars,
siltop line
for tmux and SketchyBar, alerts with shell hooks, a timeline with reports, session record/replay, a Prometheus endpoint, a sustained-performance bench and a multi-Mac fleet view.
Install
Requires macOS on Apple Silicon.
Homebrew
brew install cloaky233/tap/siltop
Prebuilt binary
(curl downloads are not quarantined, so it runs straight away)
Make sure
~/.local/bin
is on your
PATH
.
siltop update --yes
keeps this copy current. Every
release
also has a
.zip
and SHA-256 files. A copy downloaded with a browser is quarantined by macOS and blocked on first run, because it is not notarized. Clear that before running it:
xattr -d com.apple.quarantine siltop
.
Then run
siltop
. Try
siltop --demo
first if you just want to look around.
Usage
siltop # the dashboard
siltop --demo # a canned 60 s session, no hardware needed
siltop -i 1s --theme paper # sample every second, Paper theme
siltop --surface glance --no-mouse # the compact surface
siltop --json | jq .cpu.clusters # one JSON sample (schema 1)
siltop --json-stream --count 3 -i 500 # NDJSON, one line per interval
siltop --diagnose # "All normal" / "Busy: Safari using 3.1 cores" + evidence
siltop doctor # chip ids, SMC keys, HID sensors, readability, self-cost
siltop line --style tmux # one status line: "cpu 12% gpu 3% 8.4W 51°C"
siltop report week --json # energy by app, peak temps, time spent hot
siltop agent install # alerts in the background, at login
siltop record --duration 10m # a crash-tolerant session trace; `siltop replay` plays it
siltop serve # Prometheus metrics on 127.0.0.1:9101
siltop bench --duration 5m # sustained CPU test: clocks, heat, throttling
siltop fleet studio mini.local # this Mac beside two others, over your own ssh
siltop completions zsh # also bash and fish; `siltop man` prints the manual
The
user guide
walks through every panel, what the numbers mean, keys, settings, presets, themes, alerts, scripting and troubleshooting.
?
inside the app shows every key;
m
opens the menu;
s
opens settings.
Configuration
Everything is optional. Settings live in
~/.config/siltop/config.toml
(or under
$XDG_CONFIG_HOME
), are written only when you change something, and keep your comments. The guide lists
every key
. Useful environment variables:
Variable
Effect
SILTOP_THEME=<name>
Use that theme.
auto
(the default) reads the terminal.
SILTOP_KEYS=htop|btop
htop or btop key layout
SILTOP_COLORS=truecolor|256|16|none
Override the colour-depth guess
SILTOP_ICONS=nerd
Nerd Font icons in panel titles
SILTOP_NO_UPDATE_CHECK=1
Never run the opt-in daily update check
NO_COLOR=1
Attributes only (bold, dim, reverse)
Privacy
No network of its own.
siltop does not link an HTTP stack. If you opt in to update checks, it runs
/usr/bin/curl
against the GitHub releases API at most once a day and sends only its version in the
User-Agent
.
siltop serve
listens on 127.0.0.1 unless told otherwise;
siltop fleet
runs your own
ssh
.
No telemetry.
Nothing about you or your Mac is collected or sent. Crash files stay on your Mac.
No sudo.
Every reading comes from APIs a normal user may call. What the kernel withholds (other users' processes) is shown as
—
, not guessed.
FAQ
Why do some processes show
—
?
macOS only lets you read CPU, memory and energy for your own processes. Rows owned by other users keep their name and pid, but the kernel refuses the rest, so siltop shows
—
rather than a made-up
0
. Their CPU is still counted in the machine total.
Why does a watt figure sometimes show
≈
and an age?
Some power rails publish in batches, not every sample. Between publications siltop holds the last measured value and marks it
≈
with its age instead of inventing a number or dropping to zero.
Why does my CPU read lower than Activity Monitor's?
The graph is frequency-weighted: a core busy at half its top clock counts as half busy, so it shows how much of the chip's real capacity is in use. Cluster rows show both the busy share and the clock.
Intel Macs, Linux?
No. siltop is built around Apple Silicon APIs. Other platforms compile (the collectors are stubbed out) but sample nothing.
How it works
Four crates with a strict dependency direction (core ← {metrics, ui} ← bin):
The binary: event loop, input, CLI, the demo session
Each interval,
Sampler::tick()
on a worker thread builds one immutable
Snapshot
; the UI renders it read-only. See
crates/ARCHITECTURE.md
.
docs/research/
is a knowledge base on how macOS exposes this data: SMC keys per chip generation, the
IOReport
energy recipe without sudo, process data sources, graph rendering and colour on translucent terminals. If you're writing your own macOS monitor, start there.
Contributing
Bug reports with
siltop doctor
output are the most useful thing you can send, especially from a chip or Mac model not covered yet. See
CONTRIBUTING.md
for building, tests and golden screens.
I'll be radically honest here - I never really got the idea of "Test Driven Development". I'm much more of a "telnet into production and damn the consequences" kind of guy. Look, it's much more fun and my cardiologist recommends severe shocks every now and again.
The essence of unit testing is pretty simple:
Feed a function some data
See how it responds
Send it good data and if it returns "true" the test passes. Send it bad data and make sure it returns false. Easy peasy lemon squeezy.
As part of my
NLnet funded work on ActivityBot
, I'm writing some proper tests for my bot framework. I am hopeful that some of them will be useful to other projects doing similar things.
There are four major classes of tests - here are the problems I've found while writing them.
A basic test might be how to validate that an ActivityPub username is valid. Typically it would be something like
@edent@mastodon.social
- what assumptions do we make with that? It starts with an
@
and has another
@
somewhere in it, dividing into two parts, the user and the server. The server has to be a valid domain name - but that can include non-ASCII Internationalised Domain Names and Emoji domains.
What about the user part? Is it just A-Z and 0-9? Can it have dots? What about apostrophes like an email address?
Basically, how easy is it find the specifications for all the various component parts of ActivityPub? Not very!
As I've written about before,
HTTP Signatures are difficult
. There are two main problems. The first is verifying signatures.
In order to do that, you need to gather a bunch of signatures and then find a way to replay them into the test. So I'm in the process of saving signatures which I can then share with others.
The second problem is
generating
signatures. Sure, you can run tests on the signatures - but there's only one
real
way to test whether they're acceptable…
Passing tests means nothing if you can't communicate with others and they can't communicate with you.
Some tests are easier than others. Sending a signed request should be easy and repeatable. But receiving messages isn't easily automated. It requires being able to control an external server and asking that to send messages.
With the
Mastodon API
it is possible to make requests which will interact with your server - but only if it is a
public
server.
Which coffee chain was founded in London in 1971? The Saturday quiz
Guardian
www.theguardian.com
2026-10-17 02:00:24
From Divine, Frank Fiegel and Helen Kane to the West Sussex estate pioneering rewilding, test your knowledge with the Saturday quiz 1 Which classic of political theory was dedicated to Lorenzo de Medici?
2 What is the only jazz act to win the Mercury Music prize?
3 Spanish is an official langu...
1
Which classic of political theory was dedicated to Lorenzo de Medici?
2
What is the only jazz act to win the Mercury Music prize?
3
Spanish is an official language of which African country?
4
What 2026 release is said to be the most expensive entertainment product ever created?
5
Which West Sussex estate is a pioneer of rewilding?
6
Which gas is named from the Greek for “lazy”?
7
US doctor Sara Cohen writes bestsellers under what pseudonym?
8
Which coffee chain was founded in London in 1971?
What links:
9
c 6000BC; 79; 512; 1631; 1906; 1944?
10
Divine (witch); Frank Fiegel (sailor); Helen Kane (flapper); The Beatles (vultures)?
11
Mark Brown; Mo Johnston; Kenny Miller; Steven Pressley?
12
Bag; dismiss; plunder; sherry for Falstaff?
13
Caring; Elvis; Famous Five; Revenge; Travolta?
14
Grease; A Chorus Line; Cats; The Phantom of the Opera (currently)?
15
Martin Gilbert; Roy Jenkins; William Manchester; Andrew Roberts?
All shook up by the Elvis clue?
Photograph: Michael Ochs Archives/Getty Images
The answers
1
The Prince by Niccolò Machiavelli.
2
Ezra Collective.
3
Equatorial Guinea.
4
Grand Theft Auto VI.
5
Knepp.
6
Argon.
7
Freida McFadden (The Housemaid etc).
8
Costa.
9
Major eruptions of Mount Vesuvius.
10
Inspired cartoon characters: Ursula in The Little Mermaid; Popeye; Betty Boop; in The Jungle Book.
11
Played football for both Rangers and Celtic.
12
Various definitions of sack.
13
Nicknames of dresses worn by Diana, Princess of Wales.
14
Musicals that have been the longest-running show in Broadway history.
15
Wrote major biographies of Churchill.
Palantir patient data tech rejected by many NHS trusts in England
Guardian
www.theguardian.com
2026-10-17 02:00:24
Exclusive: health bodies across country say controversial US firm’s data platform no better than systems already in use NHS organisations that care for millions of people in England are rejecting Palantir’s patient data technology, according to freedom of information responses that reveal health bos...
NHS organisations that care for millions of people in England are rejecting Palantir’s patient data technology, according to freedom of information responses that reveal health bosses believe they can find better or equal alternatives in many cases.
Some health bodies said the £330m federated data platform (FDP) operated by the controversial US company had made it easier to manage waiting lists and has improved surgery scheduling. But, from Gateshead to Truro, others said they were declining to use it or had carried out trials and reverted to old systems. A Suffolk trust said other systems “supercede” the FDP’s functionality, while Greater Manchester’s care board called the Palantir system “duplicative” and “retrograde”.
The responses come as Andy Burnham’s government faces a crunch decision about whether to exercise a break clause in the seven-year NHS-Palantir deal, which was intended to better integrate the health system’s data to improve clinical accuracy and efficiency. Protests against the US firm’s role have also focused on its other contracts with the Israeli military and Donald Trump’s homeland security forces. There is also dispute over evidence for the system’s effectiveness and public concern about the involvement in the
NHS
of a company cofounded by the tech billionaire Peter Thiel, who said in 2023: “The NHS makes people sick.”
According to more than two dozen FOI responses reviewed by the Guardian, 16 trusts and health boards declared they do not use it, following its introduction in March 2024. They include the University hospitals of North Midlands NHS trust, which said it will not use it primarily because “it does not appear to provide functionality over and above what we have already” and Dorset HealthCare university trust said it “will not be adopting or going live with the FDP”. Humber Teaching NHS foundation trust said: “We have no plans to use it.”
Cambridgeshire and Peterborough NHS foundation trust said it has used the system but it has “not offered significant improvements on local systems”. Avon and Wiltshire mental health partnership NHS trust said it had yet to find an FDP tool that offered significantly more than its existing capabilities and University hospitals Birmingham NHS foundation trust, which cares for more than 2 million people, said it had no plans to use it, citing “limited expected benefit over existing solutions”. The FOIs were gathered by Medact, a health campaign that opposes Palantir’s role in the NHS, and posted to a public transparency website, WhatDoTheyKnow.
Palantir has previously challenged claims that other software could be just as effective, with its senior vice-president, the former Labour MP Tom Watson,
saying last week
: “If there are companies that can do it, they would have taken part in free and open competition” to run the FDP.
Watson, a Labour peer and former minister alongside Burnham, was appointed as Palantir’s chief lobbyist last month amid a wave of opposition to the Palantir deal. He warned his former colleagues in Labour not to let “mob rule … lead procurement practices”.
But two parliamentary select committees have
urged
the government to end Palantir’s contract, including the Commons’ science and technology committee. Martin Wrigley, a Liberal Democrat member of the committee, said the NHS boards’ responses “justify what I have been saying for the last year, which is that Palantir’s system is just not that good”.
“Once again we have proven that centrally dictating a solution to the NHS can’t work,” he said. “We have to get back to developing interoperability so each trust has its own software but with a set of standards for how they interact. Palantir are great sales people but they over-promise and under-deliver.”
Dr Rhiannon Mihranian Osborne, a spokesperson for Medact, said the FOIs showed alternatives existed, a safe transition away from Palantir was possible and “the government has no excuse to extend the contract”.
“Instead of outsourcing key NHS functions to big tech companies, the government must back NHS innovation and the highly skilled NHS data professionals who work alongside doctors and nurses to deliver care in the public interest,” she said.
A protest against Palantir’s role in the National Health Service at St Thomas’ hospital in London.
Photograph: Toby Shepheard/Reuters
Palantir accused Medact of “slanted analysis” and of “misleading the public”.
“The FDP is, objectively, a successful programme,” a spokesperson said, adding that its purpose was to provide trusts with tools to draw on depending on their existing capabilities and needs. “It is one of just 20% of major government programmes with a green delivery rating, with ministers
stating
that it ‘is significantly exceeding its benefits forecast and has exceeded every target’.”
It said NHS trusts, including Chelsea and Westminster, Leicester, Northampton, Bath, North Cumbria, Croydon, Great Western, Dorset, Chesterfield, Ashford and St Peters and Norfolk have publicly praised the FDP.
Palantir also points to NHS data that shows trusts using the FDP have carried out 117,000 additional operations and a 14.3% reduction in discharge delays for long-stay patients. NHS
England
has, however, had to add a caveat to its statistics, making clear it cannot draw conclusions about cause and effect as other variables have not been controlled for.
The government’s national data guardian for health and social care, Dr Nicola Byrne, this week
urged
ministers to give substantial weight to the “trust factor” when deciding on Palantir’s fate. More than 44,000 people have filed legal objections to their health data being shared with, stored in or used by the FDP. Byrne, a government-appointed watchdog, said there was evidence “a significant number of local organisations” were reluctant to adopt the FDP including due to concerns about Palantir and “a preference for other solutions”.
Sophie Don, the chief executive of Voror, a patient data company that bid unsuccessfully against Palantir, said: “Of course Palantir isn’t the only company that can do this. It doesn’t surprise me that it is making things harder … If NHS staff are choosing not to use it, it’s a clear sign it’s not creating value. There are many home-grown systems that would release much more value to the NHS than the [Palantir] platform.”
A spokesperson for NHS England said: “137 NHS trusts have now reported benefits from the wide range of tools available on the platform – helping staff join-up and improve care for patients, and work more efficiently.”
Israeli settlers attack olive framers & Washington Post journalist in West Bank
Israeli settlers have attacked Palestinians across the occupied West Bank in a coordinated movement to disrupt the annual olive harvest, burning cars and trees and injuring Palestinians and a
Washington Post
photographer.
Masked settlers wielding clubs and other weapons attacked people attempting to harvest their olives in
West Bank
towns on Friday. Palestinian authorities said they recorded attacks in eight villages, and injuries among at least 20 people.
American photojournalist recounts Israeli settler attack in the occupied West Bank – video
It was the latest series of attacks in a deadly campaign of Israeli settler violence against Palestinians in recent months, violence which has drawn accusations of “ethnic cleansing”, including from the British government.
In the town of Abu Falah, near Ramallah,
at least 80 settlers, some of whom were carrying firearms or clubs, gathered to stop Palestinians from harvesting their olives, using slingshots to hurl rocks at the farmers in view of Israeli military vehicles. When some of the Palestinians then picked up rocks to defend themselves, the Israeli military fired teargas in their direction.
Teargas fired by Israeli forces.
Photograph: Léo Corrêa/AP
The Israeli Foreign Press Association said in a statement: “This is the latest in a long line of violent attacks by Israeli settlers against journalists and other civilians in the occupied West Bank. Yet our repeated calls for action to confront this lawlessness have been ignored by Israeli authorities.”
Among those injured was the Washington Post photographer Heidi Levine, who was beaten by settlers in an attack that lasted more than 10 minutes, according to witnesses. Settlers stole her passport, phone, wallet and equipment.
“I was attacked, pushed to the ground. Luckily, I had my flak jacket and helmet, otherwise I probably wouldn’t even be here, because they just kept kicking and kicking me,” Levine said from a hospital bed in Ramallah. She said the attack ended when her Palestinian colleagues intervened to save her.
In a statement, the Washington Post said Levine had been wearing visible markings clearly identifying her as a journalist.
The office of Israel’s prime minister, Benjamin Netanyahu, said that the facts surrounding the attack on Levine were “unclear”, suggesting the attack was the fault of “200 Arabs and far-left activists” who confronted Israeli youths. The office added that it condemned “violence against anyone”.
Levine speaking to journalists in hospital after the attack.
Photograph: Ali Sawafta/Reuters
There has been a
surge of settler violence
against Palestinians over the past month. Settlers have carried out at least 170 attacks since 27 September, around the start of the annual olive harvest, according to Yesh Din, an Israeli rights group.
Every year, settlers attack Palestinians trying to harvest their olives, but there has been a rise in violence this year as Israel’s elections approach at the end of October.
At least four Palestinians had been killed and more than 100 others injured over the past month, Palestinian authorities said. Thousands of trees have been damaged.
Israel imposed new rules on the olive harvest this year, barring Palestinians from harvesting their trees located in Area C, an area under the Israeli military’s control, which comprises most of the West Bank’s agricultural land.
Palestinians and activists collecting olives after the attack on Friday.
Photograph: Léo Corrêa/AP
The new orders prohibit Palestinians from entering about 8,800 hectares (21,800 acres) of agricultural land – a 30% increase from the year prior – without the approval of the Israeli military. By contrast, the military gave Israeli citizens access to more land this year.
The rights group Peace Now says the military decreased the amount of land Israeli citizens were prohibited, for the purpose of preventing settler violence, from entering from about 1,070 hectares in 2025 to 680 hectares in 2026.
The olive harvest is an economic lifeline for Palestinians and has grown in importance since Israel revoked work permits for many Palestinians in the West Bank after the Hamas-led attack on 7 October 2023.
Photos and videos showed large swathes of agricultural land with uprooted olive trees in Kufur Malek, outside Ramallah, where Israeli bulldozers razed trees.
Settlers rarely face accountability for their violence, even when well-documented. Rights groups say settlers enjoy the protection of the Israeli military, which intervenes only if Palestinians try to defend themselves.
Netanyahu, has on occasion condemned the violence, which he says is due to just about 100 settlers, but he has taken few steps to stop it.
Settlements have rapidly expanded across the West Bank under his rightwing government, leading to international condemnation. The UN and most countries judge settlements to be in violation of international law.
Friday’s attack in Abu Falah followed a similar attack hours earlier near the West Bank village of Turmus Ayya, where settlers burned three cars after attacking Palestinians harvesting olives.
Videos shared by the Israeli rights group B’tselem showed hundreds of bags of olives “violently” stolen by Israeli settlers from Palestinians and taken to Israeli olive presses.
Sarit Michaeli, an independent activist, said settlers were stealing Palestinians’ olive crop on a scale “never seen before in my 22-year history of working on this issue”.
A spokesperson for the US embassy in Jerusalem said it was aware of reports of the attack and declined to comment further due to privacy laws.
STAC-M3 Benchmark: L tick database 1.0 on Oxide OxVM w/ 128 vCPUs & 1.25 TiB of RAM
STAC recently performed STAC-M3™ benchmark audits on a stack featuring the L tick database 1.0 from L Labs PBC running on a single Oxide OxVM cloud virtual machine with 128 vCPUs and 1.25 TiB of RAM, with 5 x 3.44 TB Oxide Local NVMe disks.
STAC-M3 is the industry standard enterprise tick-analytics benchmark for database and hardware stacks that manage large time series of market data. It provides a vendor-neutral framework for evaluating the performance, efficiency, and scalability of time-series databases used in financial analytics and backtesting.
This report covers the baseline suite (Antuco), for performance under fixed conditions. Results for the Shasta suite are available
here
.
In these latest tests, the combination of the L tick database and the Oxide OxVM cloud virtual machine achieved the following:
This solution achieved the highest storage efficiency (STAC-M3.v1.1.STORAGE.EFF) of any published STAC-M3 Antuco result, 364%
1.86x the efficiency of the previous best result (SHK211203)
This solution outperformed all publicly disclosed results for STAC-M3.β1.1T.YRHIBID-2.TIME
1.81x faster than the previous best result (KDB211210)
Compared to SUTs using the q language, this solution achieved the fastest mean-response STAC-M3.β1.1T.NBBO.TIME
1.58x faster than the previous best result (KDB230707)
Was faster in 11 of 17 mean-response time benchmarks than all other publicly disclosed results using a cloud-based deployment architecture
Outperformed a similar SUT using the q language, NAND flash storage / NVMe SSD, and the same file system (KDB250929) in 9 of 17 mean-response time benchmarks, including:
8.4x speed for STAC-M3.β1.10T.THEOPL.TIME
Over 1.7x speedup in STAC-M3.β1.1T.STATS-UI.TIME
The Stack Under Test included:
Database
L tick database 1.0 from L Labs PBC
Database node
1 x Oxide OxVM cloud virtual machine, with:
1 x 128 vCPU Oxide Virtual Turin-like Processor
1,280 GiB VM memory (1,259 GiB visible to the OS)
5 x 3.44 TB (3,200 GiB) Oxide virtual NVMe disks
Operating system
Ubuntu 24.04.4 LTS
The report provides detailed performance metrics, methodology, and visualizations for the Antuco suite.
The full benchmark report is available for download below. Insights Subscribers can also access detailed system configurations and the code used in this project to reproduce the results in their own environments. To learn more about subscription options, please
contact us
.
User login
Show HN: Llmspeed – feel how fast a local LLM runs before you buy the hardware
Estimates for a short prompt on a single device. Measured numbers come from community benchmarks (r/LocalLLaMA, localscore.ai and more); others are derived from similar setups or projected from specs.
Open source on GitHub
.
orib: Bringing back the old Reddit interface, with a few new enhancements
Bringing back the old Reddit interface, with a few new enhancements.
ORIB is a Manifest V3 browser extension. On
www.reddit.com
it replaces the current page with a classic layout: subreddit bar, blue header, ranked posts, sidebar, and threaded comments. It reads Reddit's public JSON listings and posts votes, saves, hides, comments, and submissions through Reddit's existing session.
The extension itself lives in
extension/
. Docs and the store listing stay outside that folder so they are not part of the upload.
Install
Open
chrome://extensions
(or the equivalent page in another Chromium browser).
Turn on Developer mode.
Choose
Load unpacked
and select the
extension
directory.
Visit
reddit.com
. The page should show the classic layout after a short "loading classic reddit" state.
The content script matches
*://www.reddit.com/*
and runs at
document_start
.
What it covers
Frontpage and subreddit listings, including hot, best, new, rising, controversial, and top
Comment threads, with collapse and inline reply
User profiles and
/saved
A classic submit form at
/submit
Subreddit sidebar (subscriber count, users online, public description, and the subreddit's own stylesheet)
Expando previews for self text, images, galleries, and Reddit-hosted video
Upvote, downvote, save, and hide while you are logged in
Keyboard navigation in the style of Reddit Enhancement Suite
These paths stay on Reddit's own UI:
/chat
,
/settings
,
/poll
,
/mod
, and
/message
.
Keyboard shortcuts
Shortcuts are ignored while focus is in an input, textarea, or content-editable element. Press
Shift+?
on a classic page for the in-page list.
Key
Action
j
/
k
Next / previous post or comment
Enter
Open the selected title in a new tab
x
Toggle the selected post's expando
Shift+X
Toggle every expando
c
Open the selected post's comments
a
/
z
Upvote / downvote the selection
s
Save the selected post
h
Hide the selected post
Store package
Version 0.1.0 is what gets submitted. From the repository root:
powershell -File scripts/pack.ps1
That writes
dist/orib-0.1.0.zip
. The zip contains only
manifest.json
,
renderer.js
,
classic.css
, and
icons/
, with the manifest at the root of the archive. Upload that zip. Do not upload the git repository.
I spent most daylight hours yesterday driving in torrential rains in pretty bad visibility, and I was astonished how many cars didn’t have their lights on.
It looked something like this. The cars with tail lights on were somewhat visible, but the cars without them didn’t stand a chance:
I read up about it, and it turns out that the issue wasn’t as much forgetfulness or carelessness. Rather, it all might have to do with iconography.
Cars have two main settings for lights:
“regular driving,” meant to be used at night and during limited visibility – like in heavy rains,
“parking,” which activates only front lights, at half brightness, and (for some reason) leaves the tail lights off.
The UI for lights seems to typically look like this:
Without knowing, can you figure out which setting is which?
The left icon with two lights facing away from each other means the parking lights. The far-right icon with one light pointing slightly down (“low beams”) is regular driving lights. The latter is the right thing to do in the rain, but the assignment feels kind of arbitrary to me, and I could totally see the icons going the other way.
Also, the above is a somewhat gentle situation. In my rental car, the lights were on a stalk, and the setup looked more like this:
Here:
the lightbulb on the left is a meta indicator for “this is the main light setting” (you can see it above too, on the dial),
the middle part with the wavy line is fog lights,
the arrow-heavy thing on the right informs of two things: pull on the stalk for high beams (another mode), or rotate the stalk left or right for turn signals.
That’s a lot of stuff going on, and many similar icons that do not appear immediately understandable. The whole interface seems optimized for motor memory, but harder to approach at first.
In both modes, the feedback
from inside the car
is exactly the same – you see the interior dashboards illuminate, and the front lights go up. At night, you might spot the difference in the front light intensity. But in the daytime rain, it’s less likely – especially if it’s a rare intense rain you don’t encounter often. Most importantly given the beginning of the story, you simply can’t see what your tail lights are up to.
From reading up on it, I believe what happened was the confusion between the two modes – people were driving with the best of intentions, actually turning on the lights… except the wrong kind of lights.
(Many cars have an AUTO option now, but would you trust it to choose the right thing? I didn’t, being unsure if it properly accounted for daylight rain driving.)
Lost perhaps amidst the recent conversations about
icons in menus
and
app icons
was another subtle change: Apple started embracing more iconography on buttons, too.
You can see it on keyboards, where the U.S. models followed in the footsteps of international ones, now showing symbols instead of legends for Tab, Caps Lock, Shift, Fn, Enter, Return, and Delete. Here’s the previous generation and the 2026 one:
The shift also happened on screens. Below are examples from the last three versions of iOS (18, 26, and 27), side by side.
When starting a new note, it’s not just the keyboard’s ↵ that replaced Return. The back icon also lost its legend, and Done became a checkmark:
Here might be the best case scenario, with Cancel and Done swapped with icons:
In this AirDrop screen, Done became a close box:
Elsewhere, Cancel morphed into ×, in an unfortunate position next to a different ×. Plus, Search on the keyboard became a loupe:
When screenshotting, Done was splintered into a checkmark and an ×:
And here, Done transformed into a checkmark, while Edit became a new kind of a paint icon:
Sometimes, what appears on the surface to be simple is actually far from it. For example, there’s a trend in Twitter clients to use icons instead of text labels for buttons. Just icons, no text at all. These icons don’t take much space, look elegant and maintain that simple feel of Twitter, except…they’re actually just confusing.
Fadeyev also quoted Jef Raskin’s take on icons:
In every study that considered the question, icons were demonstrated to be more difficult to understand than were labels, especially at first viewing, which contradicts one of the most frequently cited reasons for using icons, namely, comprehensibility for beginners. […] Although it is true that tiny icons can take less screen space than labels, you have to ask: At what cost? The smaller a button, the longer it takes to operate it, and the more difficult it is to find; also, it is difficult to make a small icon distinctive.
I like that take.
Here’s my personal go-to cheat sheet when it comes to iconography:
icons are compact, allowing you to squeeze in “more UI,”
people probably understand only a few icons (close box, checkmark, plus, some chevrons), and can learn others – but the learning process will be harder than you think,
icons can break the monotony of an all-text interface,
well-made icons make the interface look more attractive in a way type can’t.
I don’t believe Apple is doing it all just for aesthetical reasons. My guess is that it’s more about the first bullet point above: liquid glass added so much chrome and padding that Apple simply ran out of room for text labels encased in glass.
At the first glance, Apple is avoiding the car light problem by using popular icons. However, there’s a new challenge: most of these icons are
too
popular, and overloaded with meaning:
checkmark: “commit” or “to do item/checkbox”?
×: “close” or “clear”?
loupe: “search” or “zoom”?
The only outlier is the edit icon, relatively new and likely unknown. With the extra challenge that on-hover tooltips don’t exist on touch devices, the way forward would be to use the paint icon consistently to teach it to people, but it seems Apple isn’t yet doing a great job at that. The below screenshots are all iOS 27, where you can see the leftover Cancel and Done labels in place, and a missed opportunity to put the new edit icon next to Customize to help people connect the concepts:
I wish I could peek inside Apple to see how these efforts are faring, and what’s in store.
To go back to keyboards, I am curious why Apple didn’t consistently apply text
and
icons for all the affected keys, like they did for the bottom row a while back. Here there was enough room:
And how could we solve the car problem, if iconography is indeed the culprit? I could imagine a similar idea here as well:
But the funny thing is that most modern cars have a digital dashboard, so for the first time, tooltips
are
an option. You could imagine turning the stalk and seeing this kind of a message appear for a few seconds, the description and the icon side by side to help the user connect one to the other:
Perhaps seeing the word “parking” would help some people realize their mistake.
Of course, introducing a tooltip means “
now you have two problems
,” but let’s save that for a different post.
Not cool: who hacked France’s supermarket fridges?
Guardian
www.theguardian.com
2026-10-17 00:00:20
Whether it was youngsters proving their skills or state sabotage, Europe’s most hacked country was left with a mountain of waste after food began cooking in freezers Shortly before midnight last Sunday, the digital thermostats controlling hundreds of supermarket cold aisles across France began to fl...
Shortly before midnight last Sunday, the digital thermostats controlling hundreds of supermarket cold aisles across
France
began to flicker and rise.
In a
“bizarre and unprecedented” cyber-attack,
hackers had remotely overridden the temperature settings on thousands of freezers, fridges and chiller cabinets pushing them from as low as -27C (-16.6F) to well over 50C (122F).
Over the next four to six hours, the food inside first defrosted, then slowly began to cook.
Shop staff arriving early to restock shelves reported catching a blast of hot air, like opening an oven, when they went to fill freezers. One Normandy supermarket reported a number of its freezers had been pushed to 80C (176F). In certain stores, the extreme temperature rise had sparked fires triggering sprinklers and water damage.
“It was a catastrophe,” said one worker at the large Intermarché supermarket in the south-west suburb of Issy-les-Moulineaux in
Paris
. “They pushed the freezers here up to 62C. Everything had to be thrown away. It was such a waste.”
Supermarket staff had to remove tons of spoiled food and work late to reorder and restock shelves.
Photograph: Lucien Libert/Reuters
After removing tons of spoiled food, staff at the store worked until almost midnight on Monday to reorder and restock shelves. “Thankfully, we were able to get things almost back to normal the same day,” another shop worker added. “But we had to clear out everything in the freezers.”
If shop managers first assumed it was an isolated failure, it soon became clear up to 700 stores – including those from the Intermarché, Coopérative U, Carrefour, Leclerc and Monoprix chains along with a number of smaller independent shops – had been victims of a cyber-attack.
Dominique Schelcher, the president of Coopérative U, said 80 of its 2,000 supermarkets had been targeted. “This is a completely unprecedented, unexpected, and extremely serious attack. In my entire professional career, I’ve never seen anything like it,” the shocked executive told French radio.
The Paris public prosecutor’s office immediately opened an investigation into the latest in a series of cyber-attacks that have made France the most hacked country in
Europe
.
Gérôme Billois
, a partner in the cybersecurity and technology company Wavestone, said the hack had the hallmarks of political sabotage.
“The two most feasible scenarios are either it was a group of youngsters or activists who wanted to blow up a few freezers to prove what they could do, or it was a destabilising attack, what we call sabotage, by internal or external state actors,” he said.
A woman walks past empty refrigerators at an Intermarché supermarket in Névez, western France.
Photograph: Fred Tanneau/AFP/Getty
“As for the attack’s signature, the most likely scenario is still a destabilisation attack – one designed to convey the message to populations that they are not safe, to convey the impression that the government is falling apart, and ultimately to instil fear.
“Currently there are two international actors known for doing this sort of thing: Iran and Russia.”
The hackers had pirated the controllers supplied by the Danish company Danfoss that controls the freezers and fridges. Most supermarket cold aisles are connected to the internet to allow remote maintenance and alerts for system failures. Initial investigations suggest the hackers disabled alarm systems before tampering with the thermostats, or extended the defrost programme by several hours to avoid triggering alarms.
Danfoss said it had identified security flaws last year and had “long recommended” that customers install updates or replace obsolete unsupported systems. The affected refrigeration units were “running outdated firmware”, it said. In the days following the first wave of attacks, France’s cyber-attack alert centre
ANSSI confirmed
supermarkets using controllers from two other companies were also targeted.
Marta Rybczyńska, a cybersecurity specialist and researcher, said she had found previous security warnings about old supermarket freezers running out-of-date software and newer models not having firmware updated.
French supermarket director apologises after cyber-attack spoils fresh and frozen food - video
“Some of these freezers hadn’t been supported by the manufacturers for several years and there were notices saying they should be replaced. Other freezers were newer but the software hadn’t been updated,” Rybczyńska said.
“The hackers found these weaknesses and used them.”
She added: “Many of the freezers appear to have been running with a default password. The hackers were able to modify or turn off the alerts so the shops only realised when the first person arrived in the morning and saw the damage that had been done.”
The most recent French cyber-attack mirrors a similar incident in the US in August when connected fridges and freezers at a dozen military commissaries – on-base food stores – went into
unscheduled defrost cycles overnight
causing massive food loss.
France is the most heavily pirated country in Europe by the volume of records exposed by hackers, according to the cybersecurity and risk management company
Upguard.
In the last three years, hackers have breached France’s health system, France Travail, the government-run jobseekers agency, the National Agency for Identity Documents (ANTS) and most of the big mobile phone companies. This summer, the economy and finance ministry lost the personal and fiscal records of 678,000 taxpayers to a series of cyber-attacks.
Supermarket employees restock goods in Nancy, north-east France.
Photograph: Muhammed Said Tako/Anadolu/Getty
Billois says France has fallen behind in addressing cybersecurity and has still not adopted the EU’s Cyber Resilience Act (2024) that introduced mandatory security for internet-connected devices.
“It’s a text that’s not political and that everyone agrees on but is delayed because there’s always more urgent legislation or there are quibbles about amendments, and this has been a disaster,” he said.
In the UK, the cyber security and resilience (network and information systems) bill to tackle cyber threats, is wending a similarly tortuous way through parliament. However, it fails to directly cover the food industry.
Supermarket boss Schelcher was quick to shift the blame for the attack on to unnamed refrigeration contractors who maintain the cold aisle equipment. “Our supermarkets are not customers of Danfoss,” he told RTL radio.
As yet, no individual or group has claimed responsibility for the supermarket cyber-attack; Paris prosecutors have instructed detectives from its anti-cybercrime unit but Billois says finding the hackers will take time.
“It’s possible they’ll be identified eventually, but it could take weeks if not months to be certain because hackers know how to hide their tracks,” Billois said.
Rybczyńska added: “Whether it’s possible to trace the hackers depends on their level of capability; if it’s a handful of youngsters, it’s easier because they probably won’t have thought to remove traces. If they are professionals it’s more complicated and will take longer. If they’re in a foreign country, it’ll be extremely difficult.”
The total cost of the cyber-attack has yet to be calculated but Thierry Cotillard, the CEO of Intermarché, said losses could run to “tens of millions of euros”, which store companies say is unlikely to be covered by their insurance.
“It’s a bizarre story,” Billois added. “There’s a shared responsibility between the supermarkets, the refrigeration companies who are sub-contractors and who maintain the material, and the software company. We cannot say who is to blame except, of course, the hackers.
“But in the end it comes down to freezers connected to the internet without being adequately secured. And that must be a wake-up call to everyone.”
A simple Jev-like decision maker. Without the hype.
Hand it one whole message — an email, a ticket, a review, a doc, whatever you
pasted out of the support queue — and tell it what you want done with it. It
hands back
one
decision, as JSON:
{
"actionable": "Reply to Sam and cc finance about the overdue March invoice.",
"take_action": true,
"confidence": 95,
"generated_response": "Hi Sam, ... (the reply, written out)"
}
That's the whole thing. No agents. No orchestration. No prompt engineering. No
five-hundred-token preamble to memorise. One message in, one decision out, in a
file you can just read.
Whole message, judged once.
It doesn't chop the thing into paragraphs and
it doesn't go line by line. One message, one decision.
You say what you want.
It asks before it answers, and what you want done
is what drives the reply it writes.
The answer has a shape.
actionable
(a string),
take_action
(a
boolean),
confidence
(an integer, always in
[34, 100]
). No tuple you have
to guess at.
Runs on your Mac if you want.
DeepSeek over the network, or a small
ternary MLX model sitting right there on the machine. Switch whenever.
It writes it all down.
Decisions pile up in
responses.json
as
response1
,
response2
, … and other models can read them over MCP.
Then type
shev
. The installer uses a user bin directory already on PATH
where possible. Otherwise it adds a small, removable PATH block to your shell
profile; open a new terminal and type
shev
—no manual shell edits needed.
Prefer npm?
npm install -g @noorslvt/shev
shev
This installs the package
@noorslvt/shev
, with the terminal commands
shev
and
shev-cli
. The unscoped npm registry name
shev
belongs to an
unrelated project;
do not use
npm install -g shev
for this tool. You can
also install straight from the repo without the registry:
Both installers prefer a matching prebuilt release and otherwise build with
Rust (installing the minimal Rust toolchain if necessary). npm runs a
postinstall
step that fetches the right binary or builds it; macOS/Linux are
supported by the npm launcher, and Windows users can use WSL.
Recent npm releases gate install scripts. If your install is skipped,
shev
tells you what to run; you can also fix it up front:
# if npm blocked the install scripts:
npm approve-scripts @noorslvt/shev # or:
npm rebuild -g @noorslvt/shev --foreground-scripts
This removes registered shev binaries, its saved keys/config, local model data,
tracked chat records, unchanged tracked shev MCP registrations, and the exact PATH
blocks added by its installer. A full npm-backed uninstall also runs npm's
package removal. Modified binaries/profile blocks, externally managed weights,
host recovery backups, unrelated host settings,
non-chat metadata in export files, source checkouts, and shared tools/caches
(Rust, Node, uv, Codex, OpenCode) are not deleted.
You can also remove the npm package directly:
npm uninstall -g @noorslvt/shev
This removes the npm package and its binaries.
Modern npm does not execute
uninstall hooks
, so it cannot also remove persistent settings/models/history
or external MCP registrations. Use
shev --uninstall
for full cleanup;
it handles the npm package removal too. Persistent npm data deliberately lives
outside the package so a normal npm upgrade does not erase private keys,
history, or model downloads. No background uninstall watchers or npm overrides
are installed.
What you need
Best for local use:
Apple Silicon —
M1 or newer, 16 GB of RAM and up
.
8 GB
will fit the local model too, but it's tight.
Everything else:
runs anywhere with a DeepSeek API key. No Mac required.
Only the local model cares about the Mac. It runs on MLX, and MLX is Apple
Silicon only, so "run it on your machine" means "run it on a Mac". Point shev at
a DeepSeek key instead and the work goes over the network — then it builds and
runs on any platform Rust does.
Quick start
Bonsai is the default. Install it through
/model
if needed; no API key is
required. DeepSeek is optional through
/model
; its key is stored at
~/.config/shev/config.json
as
0600
.
Type or paste the whole message.
enter
sends it,
ctrl+j
drops a new
line in the middle of a multi-line one.
Say what you want done with it — "draft a short reply", "does this need me
today", "where's the risk here".
Read the decision.
enter
starts the next one, or click
▸ open responses.json in Finder
and go look at the file.
After the first run it's just: run
shev
, type, done.
The TUI
The home/start screen has a white ASCII wordmark directly over the wallpaper,
without a background box or JSON pane. Once a chat starts, two windows appear:
Left, the model output.
Every decision as a clean field list. The prompt box sits flush at the
foot, with its mode line ("Build · bonsai (local) · …") on the last row.
Right, this turn's JSON only.
The raw record for the decision you are on,
so you can read the file without leaving the screen. Drag across JSON text to
select it; releasing the mouse copies exactly the selection and shows
✓ copied to clipboard
at the top center. The mouse wheel scrolls the JSON
independently.
/copy json
copies the complete record, including off-screen text.
Text panels use
#0F0E08
over the dimmed photo wallpaper. Type
/
for commands:
Panels are inset from the terminal edges. Skills/tools menus show names only;
long menus scroll around the selected row instead of clipping it off-screen.
Command
What it does
/file <path>
Load a message from a file (drag-and-drop works too)
/copy [json]
Copy selected JSON or the last response;
json
copies the complete record
/key
Enter or replace the DeepSeek API key
/cancel
Abort the request in flight
/clear
Clear the visible chat and input; keep saved history
/reset
Confirm clearing the chat, all saved history, loaded context and counters; keep keys/models
/help
Show the keybindings
/model
Pick the model and manage it (keys, install, uninstall)
/home
Back to the home screen (the transcript is kept)
/history
Jump through the decisions so far
/mcp
Install, remove, or report the local MCP bridge
/skills
Load existing skill guidance;
/skills off
clears supporting context
/tools [server]
Connect to a registered MCP server and inspect read-only tools
/tool server/tool <JSON>
Call a read-only tool and attach its result to the next decision
/plugins
Show host-plugin compatibility limits
/quit
Leave
Handy keys:
Key
What it does
enter
Send the message, then the intent
ctrl+j
Newline inside the box
ctrl+t
Switch the model (DeepSeek ↔ Bonsai)
ctrl+h
Open the history (same as
/history
)
ctrl+d
in history
Confirm deletion of only the selected saved entry
ctrl+y
Copy selected JSON, or the last generated response
ctrl+c
Quit
/clear
starts a fresh chat view;
/history
can reopen retained records.
/reset
and history deletion default to
cancel
in their confirmation menus.
Confirmed changes update the responses file, so MCP clients see them too.
Models
/model
switches between two backends and manages each one.
DeepSeek
— the secondary, explicitly selected remote option; needs an API key. Options: enter a new
key, remove the stored key, or cancel.
Bonsai (default)
—
prism-ml/Ternary-Bonsai-2-2B-mlx-2bit
, a small ternary model that
runs on Apple Silicon through MLX. Options: install it from the internet
(about 1.2 GB, into
~/.local/share/shev/models
) or uninstall it.
The Bonsai pack ships its own loader, because its weights can't be loaded by
stock
mlx-lm
/
mlx-vlm
(they report
Unsupported model type: prism_hadamard_qwen35
). So shev runs the pack's bundled runtime in a resident
worker, using
uv
with the pack's pinned requirements. Repeated requests in the
same session reuse the loaded model; a one-shot loader remains as fallback.
Nothing listens on a port. The first local request
installs the MLX stack into a
uv
environment, which can take a few minutes.
Output-head experiments
This pack ties its output to
language_model.model.embed_tokens.as_linear
;
there is no separate
language_model.lm_head
. Its native 2-bit operation
requires the pack's Hadamard transform. Changing a
bits
parameter alone is
not a valid conversion.
tools/bench-bonsai-head.py
compares native 2-bit with a correctly repacked
4-bit output head
in memory
, leaving input embeddings and installed files
untouched. Run with the pack's
runtime/requirements.txt
, after a local shev
request has created
~/.local/share/shev/models/shev_bonsai_worker.py
:
uv run --python 3.12 --with-requirements \
~/.local/share/shev/models/Ternary-Bonsai-2-2B-mlx-2bit/runtime/requirements.txt \
python tools/bench-bonsai-head.py
With the current deterministic prompt, one local run measured 1.55 ms/head and
669 ms/decision for native 2-bit, versus 2.29 ms/head and 734 ms/decision for
repacked 4-bit. Both scored 6/6 action labels on a tiny smoke test; an earlier
prompt/sampled baseline scored 3/6. This is not evidence of general accuracy,
and the improvement is from the prompt/sampling changes, not from repacking.
Repacking cannot recover precision already lost in the 2-bit checkpoint.
Native 2-bit therefore remains the default. Hardware, prompts and output length
affect these timings; existing explicit provider selections are preserved.
MCP
Shev's MCP server lets
another assistant read your saved decisions
. It does
not run Bonsai/DeepSeek or edit your files. No API key, OAuth login, terminal,
network port, or separately started TUI is required: the MCP host starts shev
as a subprocess and talks JSON-RPC over stdin/stdout.
1. Choose the history file
Save at least one decision using an explicit file path, for example:
shev --file "$HOME/shev-responses.json"
Inside that TUI run
/mcp install
(or
/mcp
→ install). This writes a
descriptor under
~/.config/shev/mcp/
and registers the executable and absolute
history path in an existing global OpenCode config, with a private backup.
/mcp status
reports the registration;
/mcp uninstall
removes shev's own
unchanged registration. It does not delete your decisions.
2. Connect OpenCode or Codex
For OpenCode, reconnect
shev
from
/mcps
or restart the client after
installation. Alternatively, register it explicitly from a shell (replace
the executable path if you built from source):
Both
shev --mcp
and
shev-cli --mcp
work. For a source build, use
/absolute/path/to/repository/target/release/shev
after
cargo build --release
.
Do not put shell expressions such as
$(pwd)
inside a JSON/TOML command array.
3. Ask the host assistant to use shev
Example prompts in OpenCode/Codex:
“Use shev's
latest_decision
tool and summarize my most recent decision.”
“Use shev's
search_decisions
with query
invoice
and limit
10
.”
“Read
response2
using shev's
get_decision
tool.”
Tool
Example arguments
Result
list_decisions
{"limit": 20}
Most recent records, oldest first
latest_decision
{}
Latest saved record
get_decision
{"key": "response2"}
or
{"index": 2}
One saved record
search_decisions
{"query": "invoice", "limit": 10}
Matching saved decisions
Resources are
shev://decisions
(all records) and
shev://decisions/latest
(latest record). Reads use the file afresh, so decisions
saved by an open TUI become available without restarting the MCP process.
Troubleshooting:
unknown option --mcp
means the host is launching an old
TUI binary. Update/rebuild the
exact executable in the MCP command
and
reconnect shev. Current releases dispatch
--mcp
before terminal setup. If
connection succeeds but no decisions appear, check that the host and TUI use
the same absolute history path. Starting
shev --mcp
manually will wait quietly
for protocol input; this is normal, not a frozen chat window.
Reuse existing skills and tools
/skills
reads existing
SKILL.md
files from Codex, Claude, shared
~/.agents/skills
,
~/skills
, OpenCode's XDG config directory, and ancestor
project
.opencode
,
.agents
, and
.codex
skill folders, plus local skill
directories configured in OpenCode. It loads guidance
into memory; it does not install, edit, or execute skill scripts.
/tools
reads MCP registrations from Codex's
config.toml
and OpenCode's
global/project JSON or JSONC, including V2
mcp.servers
.
CODEX_HOME
and
XDG_CONFIG_HOME
are respected. Selecting a server connects and lists tools;
selecting a tool shows its argument schema and prepares
/tool server/tool {}
.
Edit the arguments, then enter to call it. Successful results become reference
context for the next decision;
/skills off
unloads them. Supporting context
does not replace the user's original intent in history.
Only tools with
readOnlyHint: true
and without
destructiveHint: true
can
be called. Unknown/mutating tools are blocked, not silently approved.
MCP
annotations are declarations from your trusted server, not a security sandbox
;
only use servers you trust. Starting a configured server can run its startup
code. Calls have time/output limits and cannot request sampling or approvals.
Stdio and streamable HTTP (JSON/SSE) are supported. Configured headers and
environment-based tokens are reused without logging them; host-managed OAuth
credentials are not copied. An OAuth-only server reports an authentication
requirement rather than claiming success.
The top of the right pane names the loaded skill or successfully called tool
and its source. Integration identity is also stored with its decision. Merely
discovering/selecting a server is not reported as a successful tool call.
OpenCode's configured JavaScript plugins are listed with compatibility notices.
Host-specific plugins cannot run natively in shev
; they require their host
runtime. Their MCP interfaces, where registered, can be used through
/tools
.
shev never rewrites host configuration during discovery or tool use. Explicit
/mcp install
is separate and backs up configuration before registration.
CLI
The TUI is the friendly front door. The line CLI is
shev-cli
and it's meant
for pipes:
echo"Your invoice is 30 days overdue."| shev-cli -i "draft a polite reminder"
shev-cli "Should I ship this today?" -i "answer yes or no and why"
shev-cli --mcp # serve decisions over MCP on stdio
Option
Meaning
-c
,
--once <message>
Judge one message and exit
-i
,
--intent <text>
What you want to do with it
-f
,
--file <path>
Where decisions are appended (default
responses.json
)
--mcp
Serve the recorded decisions over MCP (stdio)
Useful environment variables:
Variable
Meaning
DEEPSEEK_API_KEY
Use this key instead of the stored one
SHEV_RESPONSES_FILE
Where decisions are appended
SHEV_INTENT
Default intent for a non-interactive run
SHEV_MODELS_DIR
Where local models live
SHEV_HOME
Managed npm state root (set automatically by the npm launcher)
SHEV_BONSAI_MAX_TOKENS
Local worker token cap (default
256
; cold fallback
2048
)
SHEV_BONSAI_STREAM
1
enables worker token-delta protocol messages
SHEV_BONSAI_TEMPERATURE
Local sampling temperature (default
0
, deterministic)
The footer shows token usage and the last decision's elapsed milliseconds.
The resident worker reports real local token counts; the cold fallback has no
usage metadata and reports zero rather than guessing. The concise summary and
generated response remain alongside the JSON. A measured warm run took about
750 ms versus 2500 ms including initial model loading—not a claim of Jev's
sub-100-ms latency.
Malformed local decisions receive at most two format-correction retries; usage
includes those attempts. Retries can add latency and still fail rather than
silently recording invalid JSON.
Where things live
Path
What it is
~/.config/shev/config.json
API key and the selected model (
0600
)
responses.json
The decisions, appended as
response1
,
response2
, …
~/.local/share/shev/models/
Downloaded local models
~/.config/shev/install.json
Installer-owned binaries/PATH blocks and history paths for scoped cleanup
The npm launcher isolates its config, default history, and models under
~/.local/share/shev-npm/state/
(or
$XDG_DATA_HOME/shev-npm/state/
) instead
of the paths above. This data survives npm upgrades. Shell
and MCP integrations still read your existing host configuration without
copying credentials. Explicit
--file
/
SHEV_RESPONSES_FILE
paths stay where you
chose them and are tracked for explicit
shev --uninstall
cleanup.
The intention behind this repository is to make source code of the Estonian
online voting system available for public review.
The repository is not used for active development, but will be kept up to date,
so the code that can be found here is the code that is used for election. As the
voting system used for legally binding elections must strictly follow the
legislation, the actual development of Estonian I-voting system and I-vote
verification application is supervised by State Electoral Office of Estonia.
Please refer to
www.valimised.ee
for further information.
I've been working on systems administration / engineering / infrastructure development for many years and
somehow I've managed to avoid any interaction with Kubernetes. This avoidance wasn't accidental; my work required very tight control of workload placement in physical locations.
Over time, I developed a skeptical view of Kubernetes without really having a solid basis for it, other than a vague notion of it being "a new way of doing things" and "unnecessary complexity".
I decided it was time to base my opinions on facts rather than perception, so here I am, writing what I learned.
While there are a lot of tutorials covering the usage and operation of a Kubernetes cluster, along with basic descriptions of its components, they did not quite work for me. Many of these resources lightly cover
what
the components do, but often miss the underlying reason or the tradeoffs.
This post aims to cover these concepts from a perspective I would've found useful, and it does not aim to be exhaustive.
Namespace
: a logical subdivision of the
Cluster
. provides scope for names (like DNS search domain)
It's easier to observe the relationship between these concepts in diagram form:
While this may be an OK
-ish
explanation, it wasn't really something that would've been useful for me – a lot of infrastructure platforms look
something
like this diagram; there's nothing special here
A control loop will continuously perform
actions
(via a control element), if necessary, to achieve a
desired state
, and it will do this by observing specific variables (via a sensor).
An interesting detail is that the control element does not necessarily
directly
affect what the sensor observes.
This description is very generic, so here are some examples:
A workload that needs to process events from a queue
Desired state: empty queue
Sensor: depth of the queue
Control Element: number of event processing servers
A workload that needs to horizontally scale to handle user load
Desired state: Maintain P90 latency below X ms
Sensor: Latency metrics from backend
Control Element: Spin up new Pods to handle the demand
A
Service
is a networking-level concept which provides stable access to a set of backing Pods, it offers:
A
stable identity
: unchanging (virtual) IP address & a DNS record
Load balancing: distributes incoming traffic across the Pods
Service discovery: allows other components to find and communicate with the Service
Compared to "classic" clusters, a Service provides a similar abstraction to the combination of:
N nodes running
Keepalived
+ NGINX (with a dynamic set of backends)
CNAME records for the virtual (Keepalived) IP
Whenever a new Service is created:
A Virtual IP will be assigned to it
Every Node will update its networking configuration (
netfilter
) to forward any packet destined to each Service's Virtual IP instead to the backing Pods.
The networking configuration is updated by a Controller that runs on every Node:
kube-proxy
, whose primary responsibility is to watch the state of all
Service
objects and update the
netfilter
rules on every change.
This design means that all Nodes act as load balancers for Service traffic, so there is no single point of failure in Service traffic forwarding, and that traffic forwarding capacity scales with Cluster size.
For me, an interesting property of this design is that every Node receives the rules for
every
Service, which has some implications:
Very simple implementation for
kube-proxy
The number of rules may be large, which may be problematic for certain traffic forwarding implementations (
iptables
linearly evaluates every rule)
Traffic is forwarded multiple times in some scenarios, providing higher availability at the cost of extra load on the cluster
When a Pod is moved to another node, the traffic will be forwarded twice until the old DNS entry expires
No need to deal with cache invalidation for DNS entries at the
kube-proxy
level
Misbehaving clients (eg: ones that do not re-resolve DNS before reconnecting) will continue to work
We can look at the life of a packet that travels from "Pod 1" to "Service 1":
but by doing that, you are
manually
scheduling the execution of this pod
once
; which is easy, but has some nasty limitations:
If the Node that host the Pod dies, the Pod will not get re-scheduled
If the Pod is terminated due to resource pressure on the Node (via
eviction
) it also won't get re-scheduled
You can't go "now I want to have 2 of these"
Instead of creating a Pod directly, you can create a
ReplicaSet
which is a Controller, and as part of it's control loop it will ensure that the right number of Pod replicas are running at all times, which solves the problem of Node failure/eviction deleting your Pod.
ReplicaSets allow you to update the desired number of replicas,
and nothing else
(eg: updating
nginx
version, or exposing another port) – you would need to delete the resource and re-create it.
To address these limitations, you can use a
Deployment
, which is a Controller that will ensure the right number of Pods
with the right image
are running
eventually
.
The
eventual
part is very important, as Deployments allow you to update which image (or version) the Pod is running and to select the rate of change, covering the standard workflow of a "version upgrade".
Said differently, when you update a Deployment, it creates a new ReplicaSet and gradually scales it up while scaling down the old one, enabling rolling updates.
By default, containers within a Pod do not share storage/filesystem.
If you want to share storage between containers in a Pod, you can use an
Ephemeral Volume
, whose lifecycle is tied to the Pod - when the Pod shuts down, the data is deleted.
Ephemeral Volumes seemed useless
1
, but they do have some use-cases:
Log shipping from a sidecar
A sidecar populating caches for the main application
If you want to have
actually persistent
storage, you could use a
Persistent Volume
, which has a lifecycle that is decoupled
2
from the Pod's.
You'd define such a Volume with a
Claim
, like this:
Multiple users (Pods) of the same Claim will share storage, as always this is fairly risky if there are multiple writers
A PersistentVolume is backed by different drivers (NFS, SMB, iSCSI, ..) but which one is being used is not clear to the Pod, so the Pod cannot rely on features (like atomic renames)
If you want to haver per-instance persistent storage, you can use a
StatefulSet
which defines in a single resource: a workload (Pod), replica count, mount configuration and volume claim
template
.
Some interesting things with
StatefulSet
s:
Pods have stable hostnames (
nginx-0
,
nginx-1
, ..)
Deployments are executed in order:
Creation of Pods in ascending order (0, 1, ..)
Deletion of Pods in descending order (3, 2, ..)
Updates Pods in descending order (3, 2, ..)
This seemed
weird
, and the explanations that I found online say that apparently lower numbered instances are "core" or "more stable" – I don't get it, as a crashy Pod will not get renumbered. Maybe it'd be better to update in descending "uptime" order? Maybe this "seniority"/"stability" got retconned for Pods, and Kubernetes just needed
an
order?
Operationally, at this point it's still unclear to me how you'd manually investigate the contents of a Persistent Volume, other than attaching to the running container & executing commands there; what if my container does not bring a shell?
We've covered the main parts of Kubernetes - Control loops, Services, Workloads and Storage. Learning about this concepts has allowed me to form the less-baseless opinion I was looking for (though, I still have not operated or used a cluster).
Overall, I think the
concepts
make a lot of sense, specifically I think Services (including the networking model, and kube-proxy) are fantastic, and that keeping the Controller pattern as an engine for resource management is the right way to operate.
I'm left with some open-ended questions/rants, which I'll leave here for your enjoyment
Your cluster could be changing at any point as work happens and control loops automatically fix failures. This means that, potentially, your cluster never reaches a stable state.
As long as the controllers for your cluster are running and able to make useful changes, it doesn't matter if the overall state is stable or not.
Why does it not matter if the state is unstable? If I'm operating a cluster that can't settle, I'd like to know immediately!
Given the Controller pattern, why isn't there support for "Cloud Native" architectures?
I would like to have a ReplicaSet which scales the
replicas
based on some simple calculation for queue depth (eg: queue depth / 16 = # replicas)
Defining interfaces for these types of events (queue depth, open connections, response latency) would be great
The Kubernetes "community" seem to have absolutely hell-bent on making their lives harder by basing tools on
text interpolation
of all things. It's like they saw
Ansible
and thought, "Hey, that looks terribly painful. Let's do that!".
Check out this
RabbitMQ scaler
(KEDA, maintained by Microsoft) as an example:
value: Message backlog or Publish/sec. rate to trigger on. (This value can be a float when mode: MessageRate)
What do you mean that the
type
for
value
depends on the
value
of
mode
?? And what do you mean
mode
is a string when it should be an enum??
How did
Helm
manage to become popular?? How is it possible for a tool like this to do
text templating
of all things that could be done?
Take this
arbitrary NGINX
chart and check how most values are handled with
manual string indentation
:
{{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 14 {{- end }}
Why are we generating a structured language (YAML), with a computer, by manually adding spaces to make the syntax valid? There should be no intermediate text-template representation like this one.
Re: my post today on the still-vaporware Tesla Roadster and Benedict Evans’s maxim that “Elon Musk is a bullshitter who delivers”, a reader sent me this YouTube short of Charlie Munger’s answer to a question at Berkshire Hathaway’s 2020 shareholder meeting regarding Tesla’s volatility and Musk’s sel...
Owning Tesla stock has been a bit of a roller coaster ride as of late: During the first week of February, for example, the stock had "one of its wildest weeks ever,"
CNBC reported
, with the share price "swinging hundreds of dollars in both directions." On Thursday, when Tesla announced it will sell
2.65 million new shares
of stock, the share price jumped
nearly 5%
. After it announced the new stock will sell at
$767 a share
on Friday, the stock fell
2%
in premarket trading.
"My thoughts are two," Munger, who serves as the Journal's chairman replied. "I would never buy [Tesla], and I would never sell it short," he said, referring to a technique investors use to bet that a stock will decline.
And "I have a third comment," the billionaire investor continued: "Never underestimate the man who overestimates himself. I think Elon Musk is peculiar and he may overestimate himself, but he may not be wrong all the time."
At the Daily Journal's 2019 shareholder meeting, Munger shared similar thoughts, but also said that he personally
would not hire
Musk.
"I want the guy who understands his limitations instead of the guy who doesn't," Munger said at the time. "On the other hand, I've learned something terribly important in life…. These weird guys who overestimate themselves occasionally knock it right out of the park.
"I don't want my personal life to be [around] a bunch of guys who are living in a state of delusion, who happen occasionally to win big. I want the prudent person," Munger explained.
Musk and Tesla did not immediately respond to CNBC Make It's request for comment.
Warren Buffett, Berkshire Hathaway chairman and Munger's longtime business partner, has also given his opinion on Musk.
"He's trying to do something to improve a product, and I salute him for that," Buffett said on
CNBC's "Squawk Box"
in May 2018. It's "not easy" to do that, Buffett said. "The American public will decide whether [Tesla's electric cars are] a success."
According to
Musk's compensation package
, if Tesla stock hits $3,665, the company's profit target hits $14 billion a year and other financial targets are met, Musk will get more than $55 billion. With the added value to Tesla and Musk's personal payday,
that would make his total net worth over $175 billion,
CNBC
reported
. Jeff Bezos, the richest person in the world, currently has a net worth of $131 billion, according to
Bloomberg's Billionaires Index
.
Right now, Musk is the 24th richest person in the world, according to the index, with a net worth of $41.1 billion. Buffett is worth $89 billion, the index shows, and Munger is worth $2 billion, according to
Forbes
.
With Friday's Tesla announcement, Musk pledged to buy $10 million in shares Tesla's secondary stock offering. Board member Larry Ellison will buy $1 million in shares, the electric car company said.
When editing code in a modern IDE or editor, developers rely on its refactoring
features to automate common transformations. Today, we are excited to introduce
interactive refactoring
in
gopls
, powered by a new capability we are
proposing for the
Language Server Protocol (LSP)
that brings dynamic, multi-step dialogs directly into your favorite editor.
Crucially, we designed this capability (in collaboration with the Dart team)
not just for Go, but as an open standard for all programming languages and
editor ecosystems. Working support is already available in gopls
v0.24.0
and
the official Go extension for VS Code v0.56.0.
What is the Language Server Protocol (LSP)?
The LSP is an open standard that decouples language-specific
features from specific text editors. As you navigate and edit code, your
editor (such as VS Code, Neovim, or Emacs) and a language server (like gopls)
engage in a continuous JSON-RPC exchange to provide features like autocomplete,
hover documentation, diagnostics, and code actions.
Multi-step code transformation
Today, almost every code transformation in the LSP is like a function of no
parameters: you trigger the operation, and the server immediately computes the
edits. (Renaming a symbol is the sole exception: because it is a function of one
parameter, the desired new name, it required its own dedicated
PrepareRename
RPC in the protocol.)
"Add struct tags", without questions
The language server must deduce the user’s intent from context alone, namely
the cursor position and the enclosing syntax tree. When that context is not
enough, the server is forced into one of two choices: apply a one-size-fits-all
default, or refrain from offering the transformation altogether. The limitation
lies not in gopls’s ability to compute the necessary edits, but in the
LSP’s lack of a mechanism for language servers to ask the user for input.
For many transformations, this parameterless model works well. But many others
need additional input from the user: which struct tags to add and in what
naming convention, which interface to implement, which file to move a
declaration to. Without a way to ask, gopls could only guess—“Add struct
tags”, for example, always produced
json
tags in
camelCase
—or not offer the
refactoring at all. With interactive refactoring, language servers can now
easily provide new operations with one or more parameters.
"Add struct tags", with questions
While some language extensions have worked around this limitation by embedding
custom, language-specific dialog logic directly into individual editors, doing
so leaves behind other editors (such as Neovim and Emacs) that stick strictly
to the LSP with minimal custom client code. More importantly, editor-specific
workarounds go against the fundamental purpose of the LSP: to decouple
language-specific features from editors so that each server improvement benefits
every client.
Similarly,
“Remove struct tags”
now asks you for the specific tag keys
you wish to delete (for example, removing only
db
tags while preserving the
json
tag), rather than wiping out all struct tags indiscriminately.
Interactive "Remove struct tags" in VS Code
Implementing interfaces with dynamic symbol search
When creating a type to satisfy an interface, developers previously had to copy
the interface declaration and manually turn it into a set of methods on the
receiver type (or rely on external tools like
impl
by manually typing the
receiver and qualifying the name of the interface).
Since gopls v0.23.0, with interactive refactoring:
Place your cursor on any concrete type and select the
“Add methods to X to implement an interface…”
code action.
A text entry field appears, inviting you to choose the name of an interface
type. It makes dynamic queries to gopls to auto-complete names of types in
your workspace and the standard library (for example,
maphash.Hasher
).
If the selected interface has type parameters, gopls asks for a
concrete type argument for each type parameter (such as
Foo
).
Gopls generates complete method stubs with appropriate receiver names and
instantiated method signatures.
Interactive "Add methods to implement an interface..." in
VS Code
Moving declarations across files and packages (preview)
Moving declarations manually by cutting and pasting can easily break references
and requires tedious import cleanup across multiple files. While scheduled for
an upcoming gopls release, our working implementation already demonstrates how
interactive file selection streamlines cross-file and cross-package moves:
Place your cursor on any top-level declaration and select the
“Move declaration X”
code action.
A file picker dialog lets you choose an existing destination
.go
file or
specify a new file path.
Gopls moves the declaration along with its dependent declarations (such as
unexported helpers or methods) while leaving unrelated symbols in place,
updates references across your workspace, and cleans up imports in both the
source and destination files.
Interactive "Move declaration" in VS Code
In the example below, we move the type
Foo
from package
from
to package
to
. Its method
Print
and the unexported constant
bar
, which only
Foo
uses, move along with it, while the unrelated function
Baz
stays behind:
// from/from.go
package from
import (
"fmt"
"strings"
)
const bar = "bar"
// Doc comment for Foo
type Foo struct{}
func (f Foo) Print() {
fmt.Println(bar)
}
func Baz() string {
return strings.ToUpper("baz")
}
// from/from.go
package from
import "strings"
func Baz() string {
return strings.ToUpper("baz")
}
// to/to.go
package to
import "fmt"
const bar = "bar"
// Doc comment for Foo
type Foo struct{}
func (f Foo) Print() {
fmt.Println(bar)
}
Slaying the dragon (gopls v0.24.0)
As a demonstration of multi-step interactive dialogs and a self-contained test
case for client editor implementations, gopls v0.24.0 offers a
“Slay the
dragon”
code action when you place your cursor on a package-level variable
named
dragonSlayer
(for example,
var dragonSlayer string
). Happy hunting!
What’s on the Horizon
Interactive refactoring establishes a foundational capability in gopls,
opening up several exciting directions on our roadmap:
Change signature refactoring (
#38028
)
: Adding, removing,
or reordering function parameters across a workspace requires input that
cannot be deduced from syntax alone, such as the new parameter order or the
default argument expression to insert at existing call sites. Interactive
forms allow gopls to collect these details before rewriting the declaration
and all call sites.
Interactive conflict resolution
: When a code transformation encounters
naming collisions, identifier shadowing, or ambiguous references, gopls can
ask the user for guidance, such as asking for permission to proceed or
offering to rename conflicting symbols on the fly.
Interactive commands beyond code edits
: Because interactivity is modeled
at the LSP
command
layer, it naturally generalizes to non-edit server
operations that require user configuration, such as configuring test or
benchmark runs with profiling flags (CPU, memory, tracing).
Getting Started and Sharing Feedback
Interactive refactoring is available in gopls
v0.24.0
and
vscode-go
v0.56.0
(with proof-of-concept client integrations also explored for
Neovim
and
Emacs
).
We would love to hear your thoughts as we continue
refining interactive code actions in gopls:
For general feedback or feature requests, file an issue on the
Go issue tracker
.
(Special thanks to Alan Donovan, Alex Putman, Brian Wilkerson, Danny Tuppeny,
Hana Kim, Madeline Kalil, Peter Weinberger, and Robert Findley for their
insights, discussions, feedback, and collaboration on this work.)
Happy refactoring!
Flexport Is Hiring a Biz Ops Leader in Office of CEO
Global trade touches every industry, and most of it still runs on phone calls and spreadsheets. We're building the AI-powered, autonomous platform that runs the entire supply chain.
Our mission is to make global trade so easy there will be more of it. Come help us build.
The most interesting job in the world's biggest industry.
Containers get stuck. Ports back up. Customs rules change overnight. These are physical problems with real goods on the line, so AI here doesn't replace the people doing the work. AI gives them Iron Man suits, and we've already cut 80% of the emails our teams used to send.
Our team continues to grow while raising the bar for excellence, innovation, and technology.
Flexport runs 45+ offices worldwide and we're still opening more. Our teams speak over 70 languages. Between relocations, Marco Polo, and global summits, you'll have multiple opportunities to travel the world.
Flexport warehouse
Flexport office
Flexport coverage
Help customers solve their hardest problems with the best technology and experts in the industry.
Empower the Client
Customer obsession is the foundation of our culture. We are successful only when our customers are winning consistently.
Play the Long Game
There are no shortcuts. We operate with integrity, putting safety, compliance, and long-term customer trust ahead of short term gains.
Act Like an Entrepreneur
We are principled entrepreneurs who live in reality but are never satisfied with the status quo. We are endlessly curious and constantly seek to create meaningful change.
Simplify
We turn complexity into clarity. We challenge assumptions, eliminate unnecessary steps, and streamline processes to create reliable, scalable solutions. We communicate clearly and concisely and celebrate simplicity.
Win as a Team
We solve problems for our customers as one global team. We break down silos, collaborate across departments and time zones, and never let hierarchy or bureaucracy stand in the way of doing what’s right.
Use Tab or arrow keys to navigate slides.
I love working at Flexport because every day brings a new challenge in global trade, and I get to face those challenges alongside the sharpest people I’ve ever worked with. That shared energy and our relentless drive to innovate make every day genuinely fulfilling.
I've enjoyed working in a space where the problems feel non-abstract and relevant especially in a time of so much uncertainty in global trade. In my 7 years at Flexport I've grown from a SWEII to a Senior Software Engineer to an Engineering Manager, and then I was given the chance to move across the world from Chicago to Amsterdam. Flexport has afforded me opportunities that have made both my life and my career more interesting and exciting.
What makes Flexport a great place to work is the combination of a supportive team and an environment intentionally built for growth and ownership. I’m constantly empowered to tackle new challenges, learn from exceptionally smart colleagues, and push myself to level up every day.
The problem set is vast and ever-changing, yet tangible in the physical world. The commercial opportunity is immense, and the impact on customers is real. Our product offering is uniquely positioned. Our strategic vision is inspiring. Our culture is characterized by velocity, creativity, and ambition. I feel each of these elements on a daily basis, which makes Flexport an incredible place to build.
I've been at Flexport for almost 9 years, across account management, operations, and now leading our Control Tower product. What's kept me around: the people are sharp and hungry, the problems never run out, and you get autonomy to figure things out and build the solution. But the part that gets me out of bed each day is I've always felt like Flexport genuinely cares about its people and its customers.
There is never a boring day at Flexport. We've been on the front lines of COVID, tariff shocks, the Suez Canal closure, and now Hormuz. When global trade gets disrupted, our customers feel it, and we build the tools that help them respond and keep their supply chains humming along. Working on problems that matter this much, with people I actually enjoy seeing every day, is hard to find anywhere else.
Flexport.org uses logistics as a positive force for good - enabling organizations to deliver global aid and meet their sustainability goals with greater ease and lower costs.
I don't have any global logistics experience. Should I still apply?
Absolutely. One of the keys to our success is bringing hard-working, talented technologists into the world of global logistics and giving them the opportunity to impact this massive, antiquated industry. There's tremendous opportunity in showing people that something that appears boring like global shipping is actually incredibly interesting. And there are few industries with a starker contrast between the complexity of the problem at hand and the sophistication of the companies attempting to solve it. Where competitors see cardboard boxes that need to get moved, and opportunities to buy low and sell high, we see a world of fascinating network economics, supply and demand elasticity questions, complex coordination challenges, routing optimization, and a huge array of other problems that are best solved with technology than any amount of industry experience. Don't get us wrong, we value domain experience and are blessed to have hired so many of the smartest people from global logistics to work on our team. But we absolutely require new approaches and innovation that almost always comes from outside the sector.
I'm interested in applying. What should I do next?
It all begins with the first step: Find a role that looks right and
apply online
. You can filter your search by either location or team.
We recommend only applying for one role at a time, so pick the best fit and send in your application.
What happens after I apply?
Once you apply, our recruiters will be in touch if it’s a good fit and we'll begin the process of getting to know each other.
They may ask you for things like work samples, but more than anything they will be listening and sharing more about what makes Flexport such a great place to work.
What does the interview process look like?
Our straightforward hiring process is designed to give you all the information you need to make an informed choice about your next career.
First, apply. Then, one of our recruiters will be in touch. If it’s a good match, you’ll be invited to meet with a diverse interview panel, including the manager and members of the team, structured in such a way as to mitigate bias.
By the end of the process, you will have a very real feel for what life is like at Flexport. We look forward to meeting you.
Apple TV Started at $69 in 2015
Daring Fireball
www.macrumors.com
2026-10-16 20:37:01
Joe Rossignol, reporting for MacRumors back on 9 March 2015:
Apple CEO Tim Cook on Monday at the “Spring Forward” media event
in San Francisco announced that Apple TV will now cost $69,
discounted from its regular price of $99. The new price for the
set-top box arrives on the heels of the announ...
Apple CEO Tim Cook on Monday at the “Spring Forward” media event in San Francisco announced that Apple TV will now cost $69, discounted from its regular price of $99. The new price for the set-top box arrives on the heels of the announcement of
HBO Now for Apple TV
. The new price appears to apply to the third-generation Apple TV, as the company did not announce a new set-top box on stage at the Yerba Buena Center this afternoon.
A revamped Apple TV has been rumored to be in the works for quite some time, but the next-generation set-top box is not expected to be announced until later this year or beyond. The upcoming Apple TV is expected to have an improved, tactile remote control and a brand new operating system with a built-in App Store. New apps are also expected to have redesigned user interfaces.
MacRumors contributor Aaron Perris has uncovered an image file from Apple for an unreleased Apple TV 4K, suggesting that a new model will finally be released soon. The image is specifically for an "Apple TV 4K (4th generation)" model.
Apple TV 4K (4th generation) image (on a gradient)
The image reveals that the Apple TV will have the same external design as the current model, with all of its...
Just two days before Apple's "Welcome home" experience in New York, Bloomberg's Mark Gurman has leaked several details about the new products set to be unveiled, including an all-new smart home hub, a HomePod mini 2, and a new Apple TV 4K.
Here is an all-in-one summary of the details shared by Gurman:Apple's home hub with a touch-enabled display will be named HomeView, seemingly confirming a ...
The next iPad mini, HomePod mini, and Apple TV 4K models have all leaked, just a few weeks before the devices are expected to be announced. Specifically, MacRumors contributor Aaron Perris discovered a few of Apple's official images of the devices, confirming their existence and some new features that are planned.
The most notable iPad mini details revealed in today's leak include an A20 Pro ...
Friday Nite Videos | October 16, 2026
Portside
portside.org
2026-10-16 20:20:56
Friday Nite Videos | October 16, 2026
barry
Fri, 10/16/2026 - 20:20
...
Bernie Shocks with WSJ Poll on What Americans Really Want. Death by Firing Squad. Yuval Abraham and Rachel Szor on NAZA. One of the Reddest Counties Is Losing Faith in Trump. Dario Amodei Quit OpenAI To Make AI 'Safe.' And Now?
Do you let LLMs write both your tests and your code?
Lobsters
lobste.rs
2026-10-16 19:53:05
I'm curious what stance others have taken? Or what they've experienced with this? I'm toying with adding a rule to our values.md that the LLM can only significantly generate one or the other.
I'm reviewing a merge request at the moment where it's clear the LLM mostly did both, and they're highly tau...
I'm curious what stance others have taken? Or what they've experienced with this? I'm toying with adding a rule to our values.md that the LLM can only significantly generate one or the other.
I'm reviewing a merge request at the moment where it's clear the LLM mostly did both, and they're highly tautological. And I can see how it over engineered the code, just to be able to write more tests almost.
Show HN: Fakeipedia – Wikipedia for worlds that don't exist
Apple: ‘Strengthening App Review Guidelines Against Nonconsensual Intimate Imagery and Bait-And-Switch Apps’
Daring Fireball
developer.apple.com
2026-10-16 19:40:59
Apple Developer News:
As outlined in our App Review Guidelines, pornographic material
has long been prohibited on the App Store — this includes apps
that generate nudity or sexually explicit imagery, such as
“nudification” apps that create sexually explicit images of real
individuals without the...
The App Review Guidelines are a core part of the safe and trusted experience that the App Store strives to offer users around the world — and the foundation of that trust is clear standards that are consistently enforced.
As outlined in our App Review Guidelines, pornographic material has long been prohibited on the App Store — this includes apps that generate nudity or sexually explicit imagery, such as “nudification” apps that create sexually explicit images of real individuals without their consent. Apps that host user-generated content are required to filter objectionable material, give users a way to report offensive content, and let users block abusive accounts. Apps containing hidden or undocumented features are also prohibited on the App Store, including apps that misrepresent their purpose during review and only reveal harmful capabilities — such as “nudification” — after approval, a tactic commonly known as bait-and-switch.
We want great apps and the innovative developers behind them to succeed on the App Store, and as new risks and novel user experiences emerge, we evolve our App Review Guidelines to maintain the trust of users and developers alike. Today we’re publishing updates that strengthen and extend the existing App Store protections, continuing to build on our long-held standards for privacy, quality, and safety.
1.2:
Content moderation requirements now explicitly cover nonconsensual intimate imagery — including imagery generated using AI tools — as content that apps must proactively prevent and remove from their platforms. Developers who fail to implement adequate safeguards — or don’t remedy violations after notice — risk violating the Developer Code of Conduct and being removed from the App Store.
2.5.19:
This rule clarifies our longstanding prohibition on apps misrepresenting what they do during the App Review process and then changing after approval — for example, adding features or functionality that weren’t included in the version of the app that was submitted to App Review. Apps found engaging in this conduct are subject to removal from the App Store and removal from the Apple Developer Program.
Section 5:
The App Store has always prohibited apps that facilitate human trafficking or the exploitation of children (including child sexual abuse material). When we find instances of apps containing such content, we remove them from the App Store. We’ve updated Section 5 of the App Review guidelines to make clear that apps with such content will be removed from the App Store and blocked from alternative distribution.
We’re committed to keeping bad actors off the App Store, with established processes in place to review and act on apps that violate our guidelines. Last year, we prevented over 150K apps with safety issues from reaching customers and terminated over 193K developer accounts for engaging in fraud and abuse. These violations trace back to malicious actors — in some cases coordinated fraud operations — working to conceal harmful content that only becomes active once an app is approved, and as their tactics evolve, we continue to evolve our own tools and resources to prevent and catch this kind of behavior even faster. We do not hesitate to remove apps, and terminate the developers behind them, when they violate these guidelines.
Bleached corals thrive within days when touching healthy neighbour
This video shows a bleached coral fragment brought back to health within weeks through fusion with a vibrant fragment from the same individual.
Credit: Danny Collins
Scientists have rapidly restored bleached coral in a laboratory by placing it in contact with a healthy fragment, giving hope for reversing widespread coral decline.
Rising sea temperatures are stressing corals, causing the animals to expel the symbiotic algae that live in their tissues and give them their colour — a process known as bleaching. Because the photosynthetic algae (Symbiodiniaceae) provide corals with most of their nutrients, without them, the marine organisms are likely to starve and die.
A team of researchers has now shown that it is possible to fully reverse this bleaching process, in just days. It reported the findings in
Science Advances
on 14 October
1
.
“This incredible new result — that fast and full recovery is possible in bleached coral — can inspire solutions that eventually may be scalable,” says Fiorenza Micheli, a marine ecologist at Stanford University’s Center for Ocean Solutions in California and a co-author on the study.
The healing touch
In early 2025, marine scientist, and study co-author, Stephen Palumbi at Hopkins Marine Station in Pacific Grove, California, was working in the lab and noticed that two coral fragments in a tank were accidentally touching. Where the healthy and bleached fragment met, colour had begun to seep into the ghostly branch. “I’d never seen that before,” he remembers.
Symbionts spread from the healthy into the bleached coral.
Credit: Danny Collins
Danny Collins, who was studying how disease spreads through coral contact as part of his PhD at Stanford, set out to investigate whether algae can also spread and, if so, how.
He prepared ten pairs of coral fragments from the same animal (
Pocillopora damicornis
)., Each pair had a bleached and a healthy fragment. He set up five pairs so that their fragments touched each other, and five with their fragments separated by a few millimetres. In the touching pairs, the bleached coral recovered within eight weeks.
“We were blown away when we watched the colour of the algal symbionts transfer over to the bleached coral, reviving it in a very short period of time,” Collins says. By week two, the symbiont population was doubling every four days, which is much faster than the recovery times seen in studies of coral recovering naturally in the wild
2
,
3
.
After touching the healthy fragment for a week, a bleached branch could fully recover on its own, even if separated from the healthy branch.
In the slightly separated pairs, the bleached fragments died after 20 weeks.
Using high-powered microscopy, the team showed that two coral fragments fuse together by creating a tissue bridge — enabling symbiont transfer. This only occurred for coral fragments taken from an individual of the same genetic make-up, called a genet. Fragments from different species and even different animals of the same species did not fuse together, and so did not nurse the bleached piece back to health.
Strange Times Make for Strange Bedfellows
Daring Fireball
x.com
2026-10-16 19:34:03
Mark Zuckerberg, on X:
Muse Spark Open — weights releasing today — runs great on new
Mac Studios thanks to work with @johnternus and Apple.
John Ternus, replying:
Congrats to the team! Amazing to run a model of Muse Spark Open’s
caliber and scale this efficiently, right from your desk. Mac...
Axios-Ipsos Poll: “Medicare for All” Support Surges
Published
Medicare Is a Right | Illustration: Sarah Grillo/Axios
Supporters of "Medicare for All" now outnumber opponents by nearly 2-to-1, according to a new survey of U.S. adults from the
Axios-Ipsos American Health Index
.
The big picture:
Two-thirds of all survey respondents — and half of Republicans — said the federal government should be willing to spend more tax dollars to lower health care costs for Americans.
Why it matters:
With three weeks to go before the midterm elections, and private health insurance premiums and prescription prices crushing voters, these findings suggest a path for swing-state candidates who embrace socialized medicine.
But the public's openness is driven more by desperation than by confidence in government. Affordability is foremost on most Americans' minds, and health care brings almost daily reminders of economic pressure.
Between the lines:
Survey respondents say they want more government intervention — but they trust those leaders less than ever.
Trust in President Trump for health-related information fell to a survey low of 20%.
Trust in Health Secretary Robert F. Kennedy Jr. fell to a survey low of 25%.
Trust in congressional Republicans (20%) and Democrats (25%) also were at lows.
By the numbers:
43% of Americans said they support the idea of establishing a "Medicare for All" program to provide government-run health insurance to all, largely replacing private health insurance; 24% oppose the idea and 32% say they aren't sure.
Nearly half of independents (47%) support it, as do 62% of Democrats.
21% of Republicans support Medicare for All, and 27% are undecided, compared with 52% who oppose the idea.
The other side:
Opponents said their top reason is they fear Medicare for All would have a worse quality of care than private insurance.
Other reasons were feeling it would become too expensive for taxpayers; that government should not be providing health care; or that it would expand the size of government too much.
But resistance to the idea has changed markedly from recent campaign cycles, when centrist Democrats were likelier to embrace a public health insurance option or a version of Medicare for All with a role for private insurance.
What we're watching:
Respondents said they'd be more likely to support congressional candidates this year if those candidates favored expanding government subsidies of health care costs, reinstating enhanced Affordable Care Act tax credits that expired at the beginning of this year and expanding prescription drug discount platforms.
Republicans are less supportive than Democrats and independents. But the GOP is divided over expanding government subsidies for health care costs, with 31% more likely to back a candidate who supports the idea, 29% less likely and 31% saying it would make no difference.
Half of respondents said they'd be less likely to support a candidate backed by pharmaceutical and drug companies, compared with 7% saying they'd be more likely.
What they're saying:
"Health care is one of the significant ways that people experience economic pressure every day," said Mallory Newall, Ipsos senior vice president for U.S. public affairs.
"'Medicare for All' is still something that many Americans have questions on" and "the amount of Americans answering 'not sure' tells me people's sentiments aren't fully formed," Newall said. Still, the current level of support is "noteworthy — and it is not solely driven by members of the Democratic Party," she added.
Depending on the candidate's party affiliation or the makeup of their district, "Maybe they don't call it 'Medicare for All,'" Newall said. But expanding federal programs to cover more Americans' health costs "is a message that can connect with voters during this cycle."
Methodology: This Axios-Ipsos Poll was conducted Sept. 25
–
28, 2026, by Ipsos' KnowledgePanel®. This poll is based on a nationally representative probability sample of 1,122 general population adults age 18 or older.
The margin of sampling error is +/-3.0 percentage points at the 95% confidence level, for results based on the entire sample of adults.
We launched Axios in January 2017 with a belief that remains urgent today: The world needs smarter, more efficient coverage of the topics shaping our fast-changing world. We pledged to put our Audience First, always.
Sign up
for a free Axios newsletter.
A Perfect Economic Storm
Portside
portside.org
2026-10-16 19:18:34
A Perfect Economic Storm
barry
Fri, 10/16/2026 - 19:18
...
On Wednesday, the
Consumer Price Index for September
came in hotter than expected. Inflation was up at an annual rate of 3.7 percent. Gasoline prices rose 34 percent over the past year, and home heating oil is up a staggering 74 percent.
Combined with other factors, this news spooked the stock market. The tech-heavy Nasdaq fell by 2.7 percent.
Then on Thursday, the
Producer Price Index (PPI) report
clocked a wholesale price rise of 1.3 percent just in September, an increase of 6.3 percent over the past year, and the largest 12-month increase since December 2022.
The other factors signaling deep trouble include a bond market that keeps bidding up rates on long-term Treasury securities, now the highest since 2002, reflecting expectations of more inflation, and increasing interest costs throughout the economy. This in turn adds to consumer and small-business pain and increases borrowing costs for the heavily leveraged tech sector. Mortgages are now well above 7 percent.
President Trump’s deal with Vladimir Putin to buy 300,000 tons of Russian diesel infuriated legislators of both parties as foreign policy, but as Paul Krugman pointed out, Trump evidently failed to do the arithmetic. That quantity equals just half a day of U.S. diesel consumption.
As Krugman wrote, “I would strongly guess that they didn’t do the math, that 300,000 tons sounded like a lot to them and that they had no idea that it was trivial for an economy the size of America’s.”
If Trump didn’t check the math, the markets quickly did. The price of diesel dropped a few cents on the announcement of the deal, and then returned to trend.
In addition, the likely slowdown in the AI build-out adds to the risk of a crash. The seemingly strong economy has been heavily reliant on AI borrowing and spending. Likewise high-flying tech stocks, which are heavily invested in each other. Whether from the mass protests against data centers, or a sense in the industry that AI has overinvested in its future market, or from genuine worries about risk, a slowdown is coming.
Nearly all of the resurgent inflation is the result of direct and indirect effects of the Iran war, plus Trump’s chaotic tariffs.
All of this means that a highly leveraged economy is likely to unwind; and unwinding rarely proceeds in an orderly fashion.
How much of this is Trump’s doing? When Trump took office in January 2025, the COVID-driven inflation had been wrung out of the economy. Nearly all of the resurgent inflation, and in turn the higher interest rates, is the result of direct and indirect effects of the Iran war, plus Trump’s chaotic tariffs.
And for the sixth month in a row, real wage growth has lagged price increases, signaling stagflation. This jams the Fed. Where slow growth might signal the need for lower rates, the high and rising price levels could trigger additional rate hikes, further sandbagging growth.
The Fed has one more rate-setting meeting before the election, on October 27-28. A rate hike could spook financial markets further.
Fed Chair Kevin Warsh made upbeat comments
at an IMF meeting in Bangkok suggesting that the Fed might hold off on raising rates. That was enough to reassure the stock market—for now. At some point, this confidence game has to end.
Coda: When the Democrats come back into power, there will be a massive need for rebuilding, and extensive investment will also be needed as stimulus.
Earlier this week, I wrote a post asking
where the jobs will come from
as AI displaces more and more employment. Several readers wrote me to point out that in addition to the human service jobs that I proposed, there will be a need for millions of jobs in such areas as environmental remediation, new green infrastructure, as well as housing construction.
There is never a shortage of useful work to be done, though free-market capitalism fails to provide the payment mechanisms to create the needed jobs. We can resume that project once Trump, his war, and his stagflation are behind us.
Robert Kuttner is co-founder and co-editor of The American Prospect, and professor at Brandeis University’s Heller School. His latest book is Notes for Next Time: Surviving Tyranny, Redeeming America.
Trump Is Begging To Be Impeached
Portside
portside.org
2026-10-16 19:12:48
Trump Is Begging To Be Impeached
barry
Fri, 10/16/2026 - 19:12
...
The first time was in 2019, after he was caught trying to extort the Ukrainian government into manufacturing “evidence” to use against Joe Biden ahead of the 2020 presidential race.
The second time was after that race, in 2021, when he led an effort to overturn the election results on Jan. 6, culminating in a riot and assault on the U.S. Capitol.
Much of what Trump has done in his second term either meets or exceeds the threshold of his first impeachment. There is his corrupt profiteering off the presidency, his occupation of American cities with the National Guard, his use of Immigration and Customs Enforcement and Customs and Border Protection as a secret police, his attempts to seize the power of the purse, his abuse of the pardon power, his unlawful political retaliation against law firms and universities and his attacks on press freedom — all impeachable offenses.
No, he hasn’t done anything as singularly transgressive as Jan. 6. But in a real sense, the second Trump administration is no less than an authoritarian conspiracy against the constitutional order — a Jan. 6 by other means, including a whole-of-government effort to subvert the midterm elections and preclude any prospect for true democratic accountability.
In Federalist No. 65, Alexander Hamilton explained that impeachment covered those offenses that “are of a nature which may with peculiar propriety be denominated political, as they relate chiefly to injuries done immediately to the society itself.”
By that standard, the despotic and anti-republican character of Trump’s presidency is itself an impeachable offense, above and beyond any particular action.
But while there is fertile ground for a third impeachment, it is unclear whether Democrats are willing to make one happen. When asked, Hakeem Jeffries, the House minority leader, has been noncommittal, saying that Democrats have neither “ruled anything in” nor “ruled anything out” with regards to a possible impeachment.
The former Chicago mayor Rahm Emanuel, who has been soft-launching a campaign for president for the last year, says that Democrats should avoid impeachment altogether. Asked on NBC’s “Meet the Press” if Democrats should impeach Trump, he said, “No, because it’s not going anywhere, and it’s going to be a food fight, and it’s just going to be we return to the politics of fighting.” According to Axios, Senator Tammy Duckworth of Illinois has taken a similar stance: “Don’t be impeaching anybody,” she said. “Let’s just get back to work.”
Rather than devote time to an impeachment investigation and a subsequent trial, the idea is that Democrats would pass legislation and attempt to make good on the promise of a more affordable America. But while it is important that Congress get back into the habit of legislating, it seems naïve to the point of delusion to think that Democrats would have anything like a cooperative partner in the White House. If anything, the loss of a supine Republican majority and the prospect of
any
accountability is quite likely to push Trump to abuse power even further. Think of it as a game of chicken, in which he’s daring the Democratic majority to try to stop him.
Our site’s security protections triggered a block. If you
think this was in error, email us at
[email protected]
. Please include how you got to this webpage and the
Cloudflare Ray ID located at the bottom of the page.
If you would like to inquire about permission to access our
content, email us at
[email protected]
.
Quoting Addy Osmani, Morgan Westlee Lunt, and Qing Wang
Simon Willison
simonwillison.net
2026-10-16 18:06:37
We think "did a human read the code?" is an imprecise proxy for "what could go wrong with this change, and which check—automated or human—is the right one to catch it?"
Asking that question also changed when review happens. Before, review was a gate at the end of the road: write the code, open a PR,...
We think "did a human read the code?" is an imprecise proxy for "what could go wrong with this change, and which check—automated or human—is the right one to catch it?"
Asking that question also changed
when
review happens. Before, review was a gate at the end of the road: write the code, open a PR, wait for your colleague.
Now, review runs continuously, more like spellcheck while you write. Most changes have been reviewed and fixed by Claude at least once before a human is asked to look. This catches most routine mistakes, and saves team attention for higher-level questions and scrutiny.
Electron micrographs of brown fat cells reveal one of their hallmarks: an extraordinary number of mitochondria, which, as described below, are involved in heat generation | credit: Colorado State University
When people think of fat, they typically picture the jiggly tissue around the belly that stores extra calories. That’s
white fat
. But there’s another type, called
brown fat
, that does the opposite. Typically found around the neck, armpits and in the chest, brown fat burns calories to generate heat and has been linked to health benefits.
A study of more than 100,000 people — the largest of its kind — is now expanding that list of benefits. It revealed that people with ‘active’ brown fat are less affected by a number of health issues, including type 2 diabetes, depression and anxiety, than are those without it. Researchers used an artificial-intelligence model to quantify, from scans, the participants’ active brown fat, which is fat that is ‘turned on’ and burning calories. They concluded that the more active brown fat people have, the greater the protection they have from disorders and diseases.
“This is one of the most comprehensive and, probably, significant works in the field,” says Shingo Kajimura, a molecular biologist at Harvard Medical School in Boston, Massachusetts.
Because this is a retrospective study, more work is needed to prove that brown fat is indeed causing all these benefits, says Irfan Lodhi, a molecular biologist at Washington University in St. Louis, Missouri. “But it’s still a very interesting and surprising study,” he says.
Turning up the heat
Scientists have known for decades that brown fat burns calories to produce heat. The fat helps newborns to stay warm, and scientists thought it vanished after babies developed the ability to shiver. But in 2009, researchers reported the discovery of brown fat in human adults for the first time
2
,
3
,
4
.
To map active brown fat in people, scientists use imaging techniques that highlight metabolically active tissue. They inject people with a type of radioactive glucose, and use a combination of positron emission tomography (PET) and computed tomography (CT) scans to reveal which tissues are taking up the glucose — highlighting where brown fat is activated.
These techniques are typically also used to diagnose and monitor cancer. So, a team led by Paul Cohen, a physician-scientist at the Rockefeller University in New York City, partnered with Memorial Sloan Kettering Cancer Center, also in New York, to obtain data from more than 100,000 people who had these scans while going through treatment there.
The researchers first put people into two categories: those who had active brown fat at the time of their scans and those who didn’t. Then they looked at participants’ electronic health records and found an association between having active brown fat and having a lower risk of type 2 diabetes, high blood pressure and several other cardiovascular diseases. This confirmed the findings of a smaller study from Cohen and his colleagues in 2021
5
. The latest study, however, looked beyond metabolic conditions and found that brown fat might also protect against mental-health conditions such as depression, which came as a surprise to the authors.
Chilling out
The mechanisms through which brown fat could prevent psychiatric conditions are not clear. Some studies suggest that people with cardiovascular disease and metabolic dysfunction are at a higher risk of developing depression and anxiety, says co-author Nicolás Gómez-Banoy, a physician-scientist also at the Rockefeller University. “A potential explanation is that, because people with brown fat have a healthier metabolic profile, they will have less psychiatric issues,” he says.
Not much is known about how to boost brown-fat activity, either. Studies have shown that exposure to cold can activate brown fat
6
. “But most people don’t like to be cold,” Cohen says, so it isn’t a solution that would be practical for many beyond those who enjoy cold-water swimming. One drug, called mirabegron, that is used to treat urinary incontinence, has been shown to activate brown fat, but it comes with cardiovascular side effects.
The authors analysed drugs that study participants had been prescribed, and they looked for potential associations with brown-fat activity. They found a positive association with drugs used to lower blood pressure called angiotensin receptor blockers. The researchers tested one drug of this type, called losartan, in cells and in mice, and found that it boosts the activity of brown fat.
“The dream is that we can use these kinds of data as a platform for not only learning new biology, but maybe repurposing already-approved drugs to activate brown fat in humans and leverage the benefits that come from that,” Cohen says.
In "Wayfinding," a Washington Heights-Inwood immigrant community takes the stage of the People's Theatre to make myths and fairy tales all their own....
Last month the
People's Theatre
, the long-running community theater collective in Washington Heights and Inwood, opened the
Centro Cultural Inmigrante
, a gorgeous gathering space with a sprawling theater, a cafe, and studios. And its latest production,"
Wayfinding: Señas del Camino
," is exactly what the largest Latine-owned theater in New York state was built for: a play which casts local residents in a collaborative production drawn from their own stories. Led by the Colombian director
Catalina Beltrán
, the cast of eight consists of mostly immigrants to the U.S., and "Wayfinding" was created with each actor's personal journey in mind, combining their experiences and input into "three stories of escape, survival, and discovery."
In advance of the show's
opening this weekend
at the People's Theatre—before it moves on to engagements at the Whitney Museum of Art and Flushing Town Hall, all free—Hell Gate spoke with Beltrán about the process of creating the piece, how the community members came to be cast, and what showgoers can expect from the majority-immigrant production. "It's a very nice, cross-cultural experience of sharing," she said, "about our backgrounds and how we imagine ourselves becoming part of the society, helping to build a society that is equitable and based on care."
Hell Gate: How did you come to this project?
Catalina Beltrán:
So, the community productions have been at the core of the People's Theatre for years, because this is a theater that does theater
with
the community that it serves, not just
for
the community. This production has been happening for a few years, but it started taking like a very particular shape three years ago, when the actor
Reza Salazar
was invited to direct an iteration of it. I'm mentioning this because that's also when I came in and became familiar with what they do. I worked as an assistant for Reza, and the next year, I was invited to direct my first community production with the People's Theatre, which was called "The Space We Share."
What it means to me—both that production, and the one I'm doing now—is just giving an introduction to theater to some of the community members. We also get some aspiring actors participating in these programs, but it's not necessarily an introduction in terms of the technical tools of performing. We do a little bit of that, but it's mostly the exercise of collaborating and creating something from scratch.
In the case of "Wayfinding," as the director I came in with the theme, because wayfinding is a very interesting thing that us humans do. I also brought in a couple of stories—a myth and also a fairy tale— that talk about wayfinding. The rest all of it just happens in the room, which I think is just a very magical exercise in understanding how stories, even when they seem to not relate to us, eventually do relate to a shared human experience. It's also an exercise on how people who don't know each other end up creating a mini-society. I always see it as a wonderful experiment of putting strangers together to create something.
Friday Squid Blogging: Squid Before the Chicxulub Meteor Impact
Schneier
www.schneier.com
2026-10-16 17:06:47
New research shows that squid lived all around the globe even before the Cretaceous-Paleogene mass extinction event.
As usual, you can also use this squid post to talk about the security stories in the news that I haven’t covered.
Blog moderation policy....
Harnesses cache differently.
We saw 1.6% to 11.1% uncached input across clients. "Cached" is the share of input tokens served from the prompt cache instead of computed again. At 92% cached, 8 tokens per 100 are uncached, versus 3 at 97%: about 2.7 times the prefill work.
A cache miss roughly doubles a request's energy.
Here, a miss means a request with little or none of its prompt cached (under 10%). On GLM-5.3, it's about 2.5 times as much.
Deep sessions make misses expensive.
A re-read means recomputing that part of the prompt from scratch. Past 128k tokens, one turn that re-reads more than half its prompt costs as much prefill as about 600 normal turns at that depth.
Most of this is fixable.
Every cache break in our lab tests came from a harness editing what it had already sent, forcing a re-read from the first difference onward.
At Neuralwatt, we can see how the agent harness calling a model affects the energy it uses. I've been looking through a month of traffic on our cloud, and the harness seems to decide a surprising share of how much work our GPUs do. We usually talk about inference efficiency in terms of the model (how many active parameters, its attention mechanism) or the hardware (H200 vs B200 vs B300). The client deserves a closer look.
Almost all of our traffic is agentic, with far more input than output. A typical coding-agent turn sends 100k tokens or more of conversation and gets back a few hundred tokens. Most of that input is the previous turn's prompt with a little added at the end. If the earlier text is unchanged, the server already has its key-value (KV) cache and only has to process the new part. This is prompt caching, our biggest source of efficiency. Serving a cached token is far cheaper than computing it again.
Caching needs an exact prefix. A cache break happens when the harness changes something it already sent. We then recompute everything from the first difference onward. A change near the beginning, even a timestamp, means recomputing nearly the whole prompt. A change near the end costs little. The harness controls how the prompt is built.
Same model, same price, different cache rates
Every request tells us which client sent it. In the 30 days from September 8 to October 7, 2026, we saw hundreds of different clients, including open-source coding agents such as OpenCode, Oh My Pi (omp) and Pi. The mix also included editor integrations, the OpenAI SDKs and custom apps. OpenCode alone is used by about one in four of our customers.
For the most widely used clients, here is the share of input tokens we could not serve from cache:
Figure 1. Uncached input by client.
Every client here caches the large majority of its input. Those small differences still matter: a client at 97% cached sends us three uncached tokens per hundred; a client at 92% sends eight. That is 2.7 times as much prefill work for the same conversation.
Hit rate also depends on the workload, not only the harness. Longer sessions score higher, because each turn's new text is a smaller share of the prompt, and about half of deepseek-harness's lead comes from users who run very long sessions. A cleaner measure of the harness is how often a turn breaks the cache: about 1 turn in 100 for deepseek-harness, against about 3 in 100 for OpenCode and Pi. We see both OpenCode 1.x and 2.x in our traffic, so the bar combines them. 2.x looks better alone (2.2% uncached against 3.0%), mostly because of the model mix. On the same model, they cache about equally well. 2.x fixes most of the 1.x cache breaks we found in the lab. That difference doesn't show up in production, and we don't yet know why.
What a miss costs in energy
We bill on measured energy, so we can see the cost directly. Over the week of October 1 to 7, 2026, we compared requests on the same model with the same prompt size (about 50k tokens) and similar output length. Here is the extra energy each request used compared with a fully cached one:
Figure 2. Extra energy from a cache miss.
A mostly uncached request takes roughly twice the energy of a cached one of the same size. On GLM-5.3 it is closer to two and a half times. Prefill also competes with generation for the same GPUs, so wasted prefill slows down everyone else's responses on that server.
Cache misses get expensive deep in a session
We followed individual sessions turn by turn on our three busiest models for the week of October 6 to 13, 2026. We looked at every turn that landed on the same server within five minutes of the previous one, where the cache should have been warm. Most cache breaks were small: a few thousand tokens near the end of the prompt got recomputed.
Past 128k tokens of context, about 3 turns in every 1,000 re-read more than half of the prompt from scratch. Those few turns account for 75% of all the re-read tokens at that depth. Each one re-reads about 230k tokens on average. A normal turn at that depth adds a median of about 370 new tokens, so a single one of these costs as much prefill as roughly 600 ordinary turns.
The delay is noticeable too. Here is the median time to first token for a normal turn compared with a turn that had to re-read most of its prompt:
Figure 3. Time to first token deep in a session.
I pay more attention to how deep into a session the cache breaks than how often it breaks. Changing the beginning of the prompt once, early on, costs little. Do it at turn 200 of a long session and you get a large, visible pause and a large energy cost. Long agent sessions account for most of our tokens, so this adds up.
We can't always tell from the server side whether a harness edited the prompt or the cache was evicted under memory pressure. These numbers include both. Our lab tests below show that harnesses cause the early-prompt edits we could reproduce; eviction likely accounts for some of the rest.
What breaks the cache
I looked for the causes in two places: the lab, where we could see every token, and production, where we only see request metadata.
In the lab
We ran four popular open-source agents (OpenCode, Pi, omp and Kilo Code) through a recording proxy against DeepSeek V4.1 Flash and GLM-5.3. We used the latest releases as of October 6, with default settings: OpenCode 1.18.34, Pi 1.0.4, omp 18.6.3 and Kilo Code 7.8.3. We then repeated the session on OpenCode 2.0.29 from the 2.x line. Each worked through the same scripted session on a small Python project: plan, then build, switch reasoning effort and back, spawn a sub-agent, sit idle, get restarted, connect and disconnect an MCP server, add a skill, and run long enough to compact. We compared every request with the one before it, both as JSON and as the exact tokens the server renders.
Of 539 requests that followed an earlier one in the same conversation, 88% were pure appends: the previous prompt was an exact prefix of the new one. The other 65 broke the cache. Every break came from the harness changing something it had already sent; none came from our chat templates. Idle time caused no breaks in any of the four. Neither did restarting the harness and resuming the session, or using sub-agents.
Two causes break the cache without any action from the user:
OpenCode's plan-mode reminder.
Once you've used plan mode, OpenCode attaches a reminder ("Your operational mode has changed from plan to build") to each new user message. It removes that reminder from the message on the following turn. Every turn then re-reads the whole previous turn, including its tool calls and results. In our short sessions, that was 330 to 2,340 tokens a turn. The cost grows with the size of the turn. OpenCode 2.x keeps the reminder in its own message, so it no longer triggers a re-read.
omp's pruning of re-read files.
When a file is read a second time, omp replaces the earlier copy in history with
[Superseded by a newer read of this file]
. In our run, that one edit landed 62% of the way into the prompt, forcing a re-read of 5,846 of 15,520 tokens. omp also prunes "uneventful" tool results, and after 90 minutes idle it prunes at any depth. Setting
compaction.supersedeReads: false
and
compaction.dropUseless: false
keeps the cache.
Pi and Kilo Code had no breaks of this kind.
The other causes depend on what the user does. How much they cost depends on where the prompt changes:
Switching reasoning effort.
Both templates write the effort level in the first few tokens of the prompt:
Reasoning Effort: Max
on GLM-5.3, a number from 1 to 100 on DeepSeek V4.1. The first difference was at token 8 on both models, so a switch re-reads everything. Only that one value changes; its length and everything after it stay identical.
Connecting or disconnecting an MCP server.
OpenCode 1.x and Kilo Code insert new tools in alphabetical order, in the middle of the tool list. OpenCode 2.x leaves the tool list alone and appends a note, so both connecting and disconnecting were pure appends. Pi adds a tool and edits its system prompt. omp appends a section to its system message. On GLM-5.3, the tool list is rendered before the system prompt, so the change lands very early: about 1,300 tokens in for OpenCode 1.x.
Adding a skill.
All four list skills in the system prompt. The first difference landed between token 461 and token 2,948 on DeepSeek V4.1, and later on GLM-5.3, where the tools come first.
The date changing.
OpenCode 1.x and Kilo Code put today's date in the system prompt, about 2,000 tokens in. OpenCode 2.x keeps the session's original date and appends a note when the date changes. omp puts it in the first user message. Pi doesn't send a date. For clients that overwrite the date, crossing local midnight means re-reading nearly everything once.
Compaction.
Each harness does it differently. Pi keeps the last ~20k tokens word for word but rewrites the summary near the beginning. The prompt hardly shrinks, and most of it gets re-read anyway. With the same 40k-token window, OpenCode 2.x compacted three times and re-read 67,850 tokens in total. 1.x compacted once and re-read 29,776.
Switching back to a setting we'd used earlier in the session was cheaper than I expected. The server still holds that earlier version of the prompt. Switching effort back hit 10.6k to 27.5k cached tokens in our runs. A toggle costs one full re-read the first time each new state is used, not on every flip.
In production
We don't log or keep the text of customers' prompts or responses. Everything in this section comes from request metadata. The token-level analysis above comes from our own scripted test sessions, not customer traffic. That metadata records the reasoning effort each request asked for and how many tools it sent. We used it to check two of these causes against real sessions from October 6 to 13, 2026, on DeepSeek V4.1 Flash, GLM-5.3 and GLM-5.3 Flash. We used consecutive turns of at least 8k tokens on the same server within five minutes. To keep a few heavy accounts from driving the result, we left out the three customers with the most re-read tokens in each group.
Figure 4. Cache breaks by what changed.
Changing the tool list or effort level makes a cache break more than 20 times as likely and costs, on average, about 40% of the previous prompt. Tool-list changes happen on about 0.5% of turns, yet account for 19% of all re-read tokens on these models. That share is concentrated: three accounts make up about two thirds of it. The per-turn effect holds across everyone else.
The remaining three quarters of re-read tokens come on turns where neither the effort nor the tool count changed. That "nothing we can see" bucket holds the causes we can't see from the server: the reminder in OpenCode 1.x, omp's pruning, skills, the date, compaction and cache eviction. Next, I'd like us to record where each prompt first differs from the previous one. That would let us split the bucket up without reading any prompt text.
How deepseek-harness keeps the cache intact
In our lab capture, every one of deepseek-harness's follow-up requests was a pure append to the previous one, even after the process was restarted and the session resumed. Reading its source, I found a few practices worth looking at:
Requests are rebuilt from an append-only session log.
Retries and resumes produce byte-identical prompts.
The system prompt is fixed and minimal.
It leaves out the date, git status and OS. It is written once and left alone.
Changing state goes after the history.
When the approval policy or available skills change, the harness appends a short snapshot saying it supersedes earlier ones. It leaves the system prompt and older messages alone.
The tool list stays sorted and identical in every mode.
Prose instructions enforce modes without adding and removing tools.
Compaction happens late.
The summarizing call reuses the existing prefix, so even compaction is mostly a cache hit. Summarizers that re-serialize the transcript into a single new message start cold. In the largest such workload we saw, those calls were only 22% cached.
Every change gets reviewed for cache impact.
Each package in the repo carries a short "KV cache effect" section.
What you can do
If you build or configure a harness:
Keep the start of the prompt identical every turn. Add new messages and results from tools at the end of the conversation. Describe changes to settings there too, leaving the earlier text untouched.
Don't put the date, git status or anything else that changes into the system prompt.
Keep the tool list stable and sorted. Add new tools at the end.
Compact late, and have the summarizer call reuse the conversation's exact prefix.
Send a stable session id. On Neuralwatt,
X-NW-Conversation-ID
lets us keep a session on the server that already holds its cache, even across compaction.
If you use a harness:
Pick a reasoning effort per session rather than switching mid-session.
For omp, consider
compaction.supersedeReads: false
.
Settle settings like effort, MCP servers and skills before the session gets long. That is when a cache break hurts most.
See it in your own sessions
Everything in this post comes from data we record for every request, and you can see the same data for your own work. Session Insights in the Neuralwatt dashboard shows each agent session turn by turn: how much of each prompt came from cache, how much had to be computed cold, the time to first token, and the measured energy and cost. It never shows prompt or completion text.
Figure 5. Session Insights in the Neuralwatt dashboard.
This is one of my own sessions from September 26, 2026: 35 turns of a coding agent on DeepSeek V4.1 Flash, growing from 29k to 257k tokens of context. 95% of its prompt tokens came from cache, and the small red caps are the new text each turn added. A cache break shows up as a tall red bar, so if you switch reasoning effort or connect an MCP server halfway through a session, you can see what it cost. You can use it to compare harnesses or settings on your own workload, and to check that a change actually kept the cache warm.
What we're doing on our side
We route each session back to the server that holds its cache. On our busiest models, that already keeps 88–96% of each session's tokens on its home server. When a session has to move, our shared KV cache pool lets the new server load the prefix instead of recomputing it.
We recently measured how much more a smarter prefix-aware router would recover on top of that: a tenth to two tenths of a percentage point of hit rate. Most of the remaining waste comes from how prompts are built.
Next, we plan to send fixes and suggested defaults upstream to the open-source harnesses our customers use most. We also want to research ways for the server to reuse cached work after a small edit near the beginning of the prompt, such as the effort line or the date. That would help with clients we can't change ourselves.
Why this is worth measuring
A cache break doesn't show up as an error. You still get your answer, just later and with more energy spent on it. Measuring the energy of every request showed us how much that waste adds up. Most of it turned out to be fixable with a setting or a small change to how a harness builds its prompt.
AI runs on energy. The more of it we can see, the more of it we can stop wasting, whether that's a single developer's session or the industry's next data center.
Methodology notes.
We identify clients by the name in each request's User-Agent header. SDK and runtime labels (Node.js apps, OpenAI SDK apps) cover many different applications. We only show clients used by many customers and never identify individual customers. Servers cache prompts in fixed-size blocks, so even a pure append can leave a few tokens at the end of the previous turn to re-read. We count those as uncached input, adding under 0.1 percentage points for the coding agents in Figure 1. Cache rates are the share of prompt tokens served from cache across all models from September 8 to October 7, 2026. Energy is measured GPU energy apportioned to each request; the cached vs uncached comparison holds prompt size and output length fixed and covers October 1 to 7, 2026. The deep-session and cause analyses cover October 6 to 13, 2026, on DeepSeek V4.1 Flash, GLM-5.3 and GLM-5.3 Flash, following each session's consecutive turns on the same server within five minutes.
Chad Gibson is the co-founder and CEO of Neuralwatt. He spent more than 20 years at Microsoft before investing in early-stage startups and co-founding Neuralwatt in 2024.
How They Got Duo Support in NetNewsWire
Daring Fireball
netnewswire.blog
2026-10-16 16:53:42
From the NetNewsWire blog:
The latest version of NetNewsWire for iOS supports iPhone
Duo, which is very much a novel iPhone with toolbars running up
the side and all kinds of behavior.
How we did it: we didn’t do any work at all. We built the app
using Xcode 27.1 and the default iOS SDK that co...
The
latest version
of NetNewsWire for iOS supports iPhone Duo, which is very much a novel iPhone with toolbars running up the side and all kinds of behavior.
How we did it: we didn’t do any work at all. We built the app using Xcode 27.1 and the default iOS SDK that comes with it, and that’s it.
Here’s the thing, though: we were already using standard controls — toolbars, navigation controllers, split views, etc. — and we were paying attention to size classes and such (as opposed to just looking at device type).
There is a good list of reasons to use standard controls in the standard ways, and near the top of that list is to be ready for these kinds of days, so we’re not bogged down for a month or more trying to adapt to big changes like this.
Here’s a secret: Brent didn’t even run this in the Duo simulator before releasing it. We were ready to
not
claim Duo support and just handle Duo in the next release. But here it is.
PS Of course there may be edge cases and issues in our Duo support we haven’t caught yet. We stand by, as always, ready to field and fix bugs.
PPS Thank you to all the engineers, designers, and testers at Apple who made this work so easily! Again, we didn’t do anything but build with the new SDK. Their achievement is pretty remarkable.
I run the usual *arr stack on my NAS. It usually works just fine, until I saw a warning on my dashboard.
The new South Park episode was stuck in the queue with:
WHO is actually falling for this in the big 2026????
Let me very clear about what this is.
Someone took a South Park EP name, put
.exe
on the end, and uploaded it to public trackers with
2,392 seeders
, ???
Who is dropping episodes as an EXE????
And Sonarr grabbed it, because of course it did. Then it sat there trying to import it every 90 fucking seconds:
Not even a folder with a fake
.mkv
and a "codec installer" next to it like the "good old days".
Just the exe. Are we deadass.
qBittorrent marked it "finished" two seconds after adding it with
total_downloaded: 0
, so nothing actually landed on disk. No idea why. Don't care. Thanks qBit.
I blocklisted it in Sonarr, which nukes it from qBittorrent and stops it grabbing the same junk skid malware again.
Then I downloaded it again on purpose. Because now I'm pissed and I want to know what's inside.
It's a real PE, x64 GUI. The actual program is
118 KB
.
The other 886 MB is random junk glued onto the end. Why? Because a lot of scanners just give up on files that big.
The version info says:
"Freeware Developers." my ass
I chopped the 118 KB off the front and threw it into IDA, because I'm not loading a gigabyte of bullcrap into anything. Then the entire thing is covered in this:
XOR a global. XOR it back. Do nothing. Hundreds of times.
It exists purely to make the decompiler output look like shit, and it does, congrats.
Strip all that out and the logic is like six steps:
Open its own file.
Read the last 64 bytes.
Use those to find and decrypt a payload hidden in the junk.
Map it as a PE in memory by hand.
Point
PEB->ImageBaseAddress
at it.
Jump in.
Nothing touches disk. Adding all that obfuscation for six steps.
The last 64 bytes of the file are the whole config:
Offset
Size
Description
0x00
32 bytes
key, XORed with a 32 byte mask in .data
0x20
12 bytes
ChaCha20 nonce
0x2C
4 bytes
payload size ^ fnv1a(mask)
0x30
4 bytes
(flags | padding << 8) ^ fnv1a(mask)
0x34
8 bytes
payload size ^ fnv1a(mask)
0x3C
4 bytes
fnv1a(mask)
It's ChaCha20. They hid the constants by building them out of globals, and they still come out to
expand 32-byte k
. You can't hide ChaCha20 from someone who's seen ChaCha20 before.
flags = 3
turns on an anti debug check (
PEB->BeingDebugged
, debug port queries, the usual) and an anti sandbox score. Trip either one and it just quietly exits.
A sandbox sees a normal app open a file and leave.
Cool. Except the key is literally inside the file. (????) You don't even need to run it:
Out pops a second PE. 929 KB, MSVC, C++20, zlib bundled.
All that anti analysis bullshit but a dozen lines of Python can just strip the obf.
Strings are encrypted, imports stripped down to the CRT, everything resolved at runtime.
And then
WinMain
just dumps every module by name in plain text:
Every other string gets its own function:
Two constants XORed into a key, an IV, ciphertext, length.
sub_140080F40
is AES with the S-box hidden behind RC4, because one layer of crypto apparently wasn't edgy enough.
Tried the standard modes on the first one:
AES-128-CTR. Per string key. 672 call sites.
I am not doing that by hand.
So I pulled every call site out of IDA, emulated just the few instructions before each call in Unicorn, grabbed the key, IV and ciphertext out of the registers, and decrypted them in Python. 601 of 672 came out clean.
The rest are buried in bigger functions but I genuinely COULD NOT care less, 601 was plenty.
Browsers
: Chrome, Edge, Brave, Opera, Opera GX, Vivaldi, Firefox. Passwords, cookies, autofill, and it has code for Chrome's new app bound encryption too.
The rest
: Outlook, Thunderbird, VPN configs, OBS settings, Sticky Notes, and the documents on your desktop.
It even grabs your
Sticky Notes
for WHAT????
Everything gets zipped with the bundled zlib and shipped off.
No hardcoded server, instead it decrypts:
A YouTube channel, a GitHub gist, two brackets, and a key that is visibly someone mashing their keyboard.
The YouTube channel is "bubblegym". Created September 14, 2026:
Base64 decode it, XOR it with the keyboard smash, and you get the address:
That exact address is
also hardcoded in the binary
as a fallback apparently???
I guess the whole point of a dead drop is that you can swap servers without the address being in the malware.
But you put the address in the malware anyway so what's the point for fetching from Gist and YouTube????
Registered September 14. Same day as the "gaming channel". Builds on October 6, torrent up October 8.
If you run Sonarr or Radarr off public indexers, this WILL hit you. Sonarr can't run an exe, so it's not the problem.
The problem is your roommate, your parent, or 3am you double clicking it in the downloads folder. (do NOT execute execute the skid malware)
Five minutes of setup:
qBittorrent
: add
*.exe
,
*.scr
,
*.lnk
,
*.bat
,
*.cmd
to "Excluded file names", tt'll just refuse to download them.
Sonarr / Radarr
: blocklist with "Remove from client" when you see one of these.
Prowlarr
: if a tracker keeps serving this crap, demote it or drop it.
And to whoever made this: you probably spent weeks or shit ton of tokens on ChaCha20, AES-CTR, runtime API hashing, anti sandbox scoring, Chrome app bound encryption bypasses, just to make a shitty skid malware.
Get a job.
Steinar H. Gunderson: Decompilation patterns, part 13: Reverse loop
PlanetDebian
blog.sesse.net
2026-10-16 16:45:25
Anyone who's read “bro-coder” C from before that was a name will recognize
this idiom:
var_t1_2 = 0x7F;
...
do {
...
var_t1_2 -= 1;
} while (var_t1_2 >= 0);
Why does the loop count backwards? It's because comparison with zero
is cheaper on some (many) platforms....
Anyone who's read “bro-coder” C from before that was a name will recognize
this idiom:
var_t1_2 = 0x7F;
...
do {
...
var_t1_2 -= 1;
} while (var_t1_2 >= 0);
Why does the loop count backwards? It's because comparison with zero
is cheaper on some (many) platforms. Some people would reverse the loop
manually, but compilers quickly managed to do that themselves. So you want:
for (i = 0; i < 0x80; ++i) {
...
}
and tomorrow, we'll have a look at what's inside the loop as well.
I never authorized an integration that scans my secrets
Other (issue in content formatting, broken link or image, non-working widget)
Problem description
This is a pretty severe invasion of privacy.
I never authorized any integrations or plugins for scanning secrets and sending them up the line, even if they are hashed or not.
This mechanism could be abused by a malicious threat actor with access to the home assistant github repos in a variety of ways.
how do i turn this thing off?
Suggested solution
make this an opt-in feature, do not just opt people in to scanning for secrets with a system they were not aware existed.
How do you know the suggested solution is correct?
No response
Additional information
No response
Leaving this closed since this repository is for our documentation, but I want to follow up, because my earlier replies were more dismissive than this deserved. My apologies.
As it turns out, this check can already be turned off after all:
ha security options --pwned=false
To be transparent: this check isn't new, it has been part of the Supervisor for years. It checks app options that are marked as passwords. A recent release fixed the warning that surfaces it, which is why you're seeing it now.
Privacy was a design requirement for this feature from the start, which is why your secrets never leave your system. The Supervisor hashes them locally and sends only the first 5 characters of th…
It is not an invasion of privacy and there are sure other apps out there doing this (most notably the 1Password password manager). Your passwords are never send out, never published.
I run Phobos Group, and I travel all over the world giving presentations about security.
I am very well acquainted with HIBP, and have met troy in the past.
I helped deploy 1password at twitter when I was their sole red-team staff member in 2011.
I am still not happy that home assistant, without my opt-in, without my permission, scanned my HA installation and send stuff up the line to HIBP.
This should be an opt-in feature, and not something that 'just happens'.
As a red teamer, I can give you a list as long as my arm about how I could abuse this to loot credentials from every HA install on the planet.
Reacted by
Daniel W. Crompton
Viss
commented
on
Oct 16, 2026
this issue is not closed until I am satisfied that HA is not taking things off my system without my permission and sending them to a 3rd party
Reacted by
Daniel W. Crompton
frenck
commented
on
Oct 16, 2026
This issue is closed as won't fix. Sorry.
../Frenck
Reacted by
Latte macchiato
Reacted by
Ryan Carter, Ben Lee, Ciarán Ainsworth, Daniel W. Crompton, xor eax,eax and Jamie Bliss
0x00string
commented
on
Oct 16, 2026
Hi, long time HA user here. Please re-open this issue and address the question of how to disable this. If a method to disable it is not currently implemented, please consider implementing this rather than insisting the userbase accept this and take your word on it. This response feels extremely dismissive and as a user of this platform I feel secondhand offended by it as I share the exact same concerns as OP and do not believe the response here adequately addressed the concerns.
If there is no interest in addressing this reasonably, please let us know so we can uninstall and fork.
Reacted by
Daniel W. Crompton
Reacted by
Justin Myers
frenck
commented
on
Oct 16, 2026
please let us know so we can uninstall and fork
Sorry, these are not statements we can work with. Doing such threats and trying to intimidate it not going to bring you anywhere. If you want to do a feature request, that is fine, we have places for that.
This report is on our documentation. There is no amount of documentation I can adjust to adjust this or address this. Thus closed as won't fix.
If this is all reason for you to uninstall and fork... 🤷 So be it, it is open source after all.
Leaving this closed since this repository is for our documentation, but I want to follow up, because my earlier replies were more dismissive than this deserved. My apologies.
As it turns out, this check can already be turned off after all:
ha security options --pwned=false
To be transparent: this check isn't new, it has been part of the Supervisor for years. It checks app options that are marked as passwords. A recent release fixed the warning that surfaces it, which is why you're seeing it now.
Privacy was a design requirement for this feature from the start, which is why your secrets never leave your system. The Supervisor hashes them locally and sends only the first 5 characters of the SHA-1 hash to Have I Been Pwned. HIBP returns every hash starting with that prefix, and the matching happens on your own instance. You can see exactly what it does here:
https://github.com/home-assistant/supervisor/blob/main/supervisor/utils/pwned.py
You are right that our documentation should have explained this, including how to turn it off. We'll get that page updated.
We now know how the seeds of the NIST elliptic curves were generated: they’re not the hash of some saucy sentence, but the output of
drand48
seeded with the time, which was indeed in 1997–98.
John Wood, Henry de Valence, Ava Howell, Zack Voase, Lucy Sweet, Amir Omidi, Paul Crowley, Iain McGinniss, Nicholas Carlini, and Steve Weis from Anthropic
solved the riddle
and on October 15th, 2026, at 01:07:51 UTC, claimed
the full bounty I announced three years ago
. They chose to donate the prize to
ISRG
, the non-profit that operates Let’s Encrypt, tripling its value to $36,864 (36 Ki$). Thank you to Amir Omidi, Chris Palmer, Colm MacCárthaigh, David Adrian, David Anderson, Jeff Hodges, Matt Green, Matthew McPherrin, Paul Kehrer, Ryan Sleevi, and Soatok for contributing to the bounty.
This helps fill out a page of cryptographic history, and reinforces our confidence in these critical cryptographic primitives.
The NIST elliptic curves (P-192, P-224, P-256, P-384, and P-521) were published by NIST in FIPS 186-2 in 2000. They were generated at random according to ANSI X9.62 by taking an arbitrary seed, hashing it with SHA-1, and using the output to derive some of the parameters. Until this week, we had no idea how those arbitrary seeds were picked.
Turns out memory can play tricks on everyone: we now know they were instead generated with the POSIX-standard
drand48
random number generator.
The algorithm is as simple as passing the then-current UNIX timestamp to
srand48()
and then producing one byte at a time with drand48. Each sequence of 20 bytes is tried as a seed following ANSI X9.62 and rejected if the resulting curve is not valid. Some timestamps are used to generate multiple curves, by continuing to try seeds after accepting the first one. I
reimplemented the algorithm in Go
to verify the claim. Read more in
Anthropic’s writeup
.
There are two additional undocumented criteria beyond the ANSI X9.62 ones, one fairly clear and one that still escapes us.
If the bit length of the order
n
of the resulting curve is more than the bit length of the base field
p
of the curve, the seed is rejected. (The condition is not the stricter
n
<
p
, because prime239v2 has
p
<
n
< 2²³⁹.)
This leaves us with roughly twice as many valid seeds as were published. We explored a number of explanations for this last bit, and found no good fit. Maybe the same RNG was used to validate seeds, consuming RNG output and skipping some potential candidates, although the “gaps” are not regular. Maybe there was just a bug in one of the algorithms that returned the wrong result half the time; these calculations, which we can now do with off-the-shelf software in minutes, were still very much state-of-the-art in 1997.
srand48(863711343) [1997-05-15 15:49:03 +0000 UTC]:
accepted 36th seed 25e5[...]: not published
accepted 1562nd seed d09b[...]: not published
accepted 2185th seed e43b[...]: prime239v1
accepted 2320th seed e8b4[...]: prime239v2
accepted 2491st seed 1256[...]: not published
accepted 2682nd seed d2c1[...]: not published
accepted 2863rd seed 3a70[...]: not published
accepted 3048th seed 7d73[...]: prime239v3
srand48(863966734) [1997-05-18 14:45:34 +0000 UTC]:
accepted 139th seed 3045[...]: P-192 a.k.a. prime192v1
accepted 2198th seed 692d[...]: not published
accepted 5228th seed c469[...]: prime192v3
accepted 5405th seed 3ad1[...]: not published
accepted 6013th seed 31a9[...]: prime192v2
srand48(871002724) [1997-08-08 01:12:04 +0000 UTC]:
accepted 1136th seed d09e[...]: P-521
srand48(871696354) [1997-08-16 01:52:34 +0000 UTC]:
accepted 876th seed 50c7[...]: not published
accepted 1842nd seed c49d[...]: P-256 a.k.a. prime256v1
srand48(872952608) [1997-08-30 14:50:08 +0000 UTC]:
accepted 2688th seed a335[...]: P-384
srand48(891607927) [1998-04-03 12:52:07 +0000 UTC]:
accepted 777th seed d007[...]: not published
accepted 1485th seed 18cf[...]: not published
accepted 5736th seed 3c17[...]: not published
accepted 7026th seed bd71[...]: P-224
What does this mean for the security of elliptic curve cryptography based on the NIST curves? Well, even before this discovery there were no serious concerns among practitioners. In Section 3.1 of
their 2015 paper “A riddle wrapped in an enigma,”
Koblitz and Menezes make a convincing argument that it’s implausible that the NSA could have selected a seed to exploit a weakness that escaped more than 15 (now 25) years of cryptanalysis.
However, as reported in a later version of that paper, Daniel Bernstein and Tanja Lange described to Koblitz and Menezes in 2017 a technique that could have exploited 70 bits of freedom in selection of the seed to target a hypothetical class of 2⁶¹ weak prime-order curves. (Bernstein is the author of a competing elliptic curve design, Curve25519.) This contributed to enduring conspiracy theories, which had significant appeal among the non-specialist public (although many have since moved on to other, adjacent, conspiracy theories). All this speculation harmed confidence in robust cryptographic systems and was part of my motivation for the bounty.
This week’s findings completely rule out the technique described by Bernstein and Lange. Even if the NSA had been free to pick any timestamp in 1997–98 and any of the first 16 prime-order candidates (which generously accounts for the unexplained rejections), they would have had barely 30 bits of freedom. Not enough to intentionally target a hypothetical small class of weak curves, not enough to embed any kind of
NOBUS
backdoor.
Just in time for them to be retired in favor of post-quantum signatures.
P.S. The Anthropic team also figured out how the seeds of the NIST B-curves (the ones over binary fields) were generated, but no one uses those, so who cares.
The picture
In a FamilyMart in Taiwan I found this delightful dice set. A full roll carries log₂(6²⁰) ≈ 51.7 bits of entropy. Rolling them twice can make a pretty robust cryptographic key!
I thought it would be funny to label them as Geomys FIPS 140-3 Entropy Sources (which of course they are not, though we do have one of those) and hand them out as swag. However, I found no way to order them online, so I simply visited over a dozen FamilyMarts and brought home 50 packs.
Speaking of swag, I am 100% making stickers with the
srand48()
seeds, and t-shirts for the Anthropic team and the contributors to the bounty. I accept suggestions for other seed-based swag. If you want to catch some, follow me on Bluesky at
@filippo.abyssdomain.expert
or on Mastodon at
@filippo@abyssdomain.expert
.
The Law Can't Silence These East Village Residents Hanging 'Pete Hegshit' Signs
hellgate
hellgatenyc.com
2026-10-16 16:14:59
The Department of Buildings ticketed a prolific sign maker on St. Marks Place, but backed down after a Hell Gate inquiry....
In early 2020, Manny Verdi's neighbor began hanging signs on the residential building Verdi owns on St. Mark's Place in the East Village.
The first sign, Verdi said, was of a school of tiny fish
swallowing one large fish
with the call to "organize!" Since then, he's helped her swap out her handmade cardboard signs every few weeks.
"There's signs about the Supreme Court, there's signs about Trump—there has to be at least 50 signs since she started putting them up," Verdi told Hell Gate of his neighbor, the signmaker, who asked to remain anonymous.
But in late September, Verdi received a summons from an inspector for the Department of Buildings, who had taken issue with the sign du jour: "Hey Congress If You're There Blink Twice" with big googly eyes.
If you think Musk is either completely legitimate and trustworthy or an utter fraud, you are wrong. He has led his companies to extraordinary accomplishments, *and* he has made promises based on complete bullshit. He is a shameless bullshitter who *sometimes* delivers....
Musk claims that the Roadster will go into production by 2028. But
the CEO has a long and glorious history of overpromising and
underdelivering; in 2017 he told attendees at the previous launch
that “We are making it now.” Using the company’s referral program,
some people were in line to receive two free cars. But those free
cars never showed up, and neither did the ones that people put
down $50,000 deposits for; last year
Sam Altman discovered how
hard it can be to get that money back
.
I like a good stunt show as much as the next guy, and this looked like a cool stunt show. But people are losing their minds if they think this stunt show makes it any more or less likely that Tesla will deliver a Roadster as promised.
This Reuters story
makes it sound like they think Tesla is going to sell cars that do this stuff. Last night’s stunt show has no more bearing on actual production cars Tesla may or may not ship than George Lucas’s
Star Wars
movie had on
Ronald Reagan’s “Star Wars” missile defense system
.
Tesla has long made up specs for its cars, made wild claims that
weren’t substantiated by users, and now it’s making more big
impressive claims. The “cars” used for the demos were likely
nothing more than shells outfitted with exactly enough equipment
to make the tests work. The 0.81 second zero-to-60 number wasn’t
even shown with an on-screen timer during the event, let alone
independently verified. Tesla has yet to prove anything about the
new Roadster works in the real world, or could even exist within
the realm of physics that those of us not named Musk occupy.
Roadster preorders have reopened, with the company once again
taking $50,000 checks to reserve a car that’ll theoretically be
made two years from now. It hasn’t yet said what will happen to
the people who placed a reservation for the car Tesla announced
nine years ago, which looks and functions completely differently
to the one that bears its name today. And — arguably most
concerning — we don’t know, if Tesla rakes in more money off the
Roadster name, just how much will go to
some malicious
end
.
A long time ago, I described Elon Musk as a bullshitter who
delivers. This is the perfect expression of that. This car was
first shown a decade ago, with another stunt, and it never
shipped. Now there’s another stunt, and another huge wave of PR
and admiration.
But meanwhile, there’s the scaled car company, and the
self-landing rockets!
Henry Ford was a brilliant industrialist, a terrible manager and a
racist piece of shit. Several things can be true at once.
If you think Musk is either completely legitimate and trustworthy or an utter fraud, you are wrong. He has led his companies to extraordinary accomplishments,
and
he has made promises based on complete bullshit. He is a shameless bullshitter who
sometimes
delivers. The
sometimes
is implicit in Evans’s take, because if he always delivered, there’d be no bullshit. But I think it’s worth including the
sometimes
to make the point. And some of the things he’s delivered
are so amazing
that they sure sounded like they might be bullshit when they were announced. “Space internet”
sounded like total bullshit
when Musk announced it in 2015, but it
started rolling out in 2020
, and today you can just
buy it at Best Buy for $350
.
Tesla makes some tremendous vehicles. Their self-driving technology is the best in the consumer market. (Not as good as Waymo’s, but you can’t buy a Waymo.) So maybe they will ship a great Roadster in 2028. I’ll pay attention if and when they do. But I wouldn’t bet a nickel that they will. And I wouldn’t bet that they won’t, either.
Critical BlockStrap flaw lets hackers run code on Magento servers
Bleeping Computer
www.bleepingcomputer.com
2026-10-16 16:00:59
Researchers warn that hackers could soon exploit a maximum-severity vulnerability (CVE-2026-103849) affecting Magento and Adobe Commerce, potentially allowing them to execute arbitrary PHP code on store servers. [...]...
Researchers warn that hackers could soon exploit a maximum-severity vulnerability (CVE-2026-103849) affecting Magento and Adobe Commerce, potentially allowing them to execute arbitrary PHP code on store servers.
According to e-commerce security firm Sansec, attacks leveraging the vulnerability, dubbed BlockStrap, have not yet been observed, but threat actors are expected to find a way to exploit it.
The researchers based their assessment on identifying four potential attack paths involving CVE-2026-103849 in less than 24 hours.
The flaw impacts September versions of Adobe Commerce and Magento Open Source through 2.4.9 and Adobe Commerce B2B through 1.5.3.
The security firm warned that Adobe’s “priority 2” rating of this flaw does not reflect the danger and urgency in this case, despite the more complex attack path.
“The attack path is complex, but anyone with an AI agent can reverse-engineer the patch into working exploits in a relatively short time,”
stated Sansec states
.
“That is why we question Adobe's priority 2 rating (patch within 30 days).
StyleSmuggler
went from a priority 1 hotfix to
mass exploitation
in three days, and BlockStrap is of similar complexity.”
Adobe’s bulletin
, published on October 13, describes the flaw as an improper neutralization of special elements used in a template engine, leading to arbitrary code execution.
Sansec explains that BlockStrap is a second-pass template engine directive injection that allows attacker-controlled content in a child email template to be signed and processed again at the root level, executing a smuggled {{block}} directive.
According to Sansec’s analysis, BlockStrap exposes a gap left by the StyleSmuggler fix in the same email-template engine.
Adobe’s fix replaces the generic processing with registered placeholders, preventing exploitation.
Sansec says that a plain Composer install isn’t enough to address the risk, and website administrators must apply the 2026-oct release or Adobe’s isolated patch.
“BlockStrap and StyleSmuggler are separate fixes. You need both, so keep the September VULN-39341 hotfix in place as well,” Sansec cautions.
The e-commerce security company says it will provide an update when it detects mass attack waves, which it expects to occur soon.
Dirk Eddelbuettel: RcppSimdJson 0.1.17 on CRAN: Updates
PlanetDebian
dirk.eddelbuettel.com
2026-10-16 15:56:00
A brand new release 0.1.17 of the RcppSimdJson
package is now on CRAN, and has
been built for r2u and
on r-universe.
RcppSimdJson
wraps the fantastic and genuinely impressive simdjson library by Daniel Lemire and collaborators. Via
very clever algorithmic engineering to obtain largely branch-free co...
RcppSimdJson
wraps the fantastic and genuinely impressive
simdjson
library by
Daniel Lemire
and collaborators. Via
very clever algorithmic engineering to obtain largely branch-free code,
coupled with modern C++ and newer compiler instructions, it results in
parsing
gigabytes of JSON parsed per second
which is quite
mindboggling. The best-case performance is ‘faster than CPU speed’ as
use of parallel SIMD instructions and careful branch avoidance can lead
to less than one cpu cycle per byte parsed; see the video of the
talk by Daniel Lemire
at QCon
.
This release is a small increment relative to the
0.1.6
release last week
that got us (upstream) version 5.0.2 with many
notable changes and sizeable speed gains on all fronts, including the
interface from R. However, this failed to compile at
CRAN
on macOS x86_64 as the
machine is setup for only partial support of C++20: no ranges, no
concepts. So we now test, and fall back to C++17 if the test compilation
fails. Upstream, meanwhile, already got to 5.0.5 which is included. It
also gets us improved handling of disabling pragmas which we hope will
survive
CRAN
checks.
The brief NEWS entry for this release follows.
Changes in
version 0.1.17 [unreleased] (2026-10-xx)
Compilation starts with a C++20 feature test; if this fails C++17
is used (Dirk in
#111
fixing
#110
)
simdjson
was upgraded to version 5.0.5
(Daniel in
#112
)
Today we are releasing FLUX 3 Image Klein, a 5.6B parameter open weights model for text-to-image generation, image editing and multi-reference generation with up to 10 reference images. It shares core capabilities with the full FLUX 3 Image model: native 4K generation, pixel-perfect editing, and bounding boxes that control where elements are placed or confine edits to a defined area.
FLUX 3 Image Klein builds on FLUX 3's shared learnings across images, video and audio. Images contribute spatial detail, video adds motion and physical dynamics, and audio provides information about events and interactions. Together, these signals help the model generate images that feel grounded in the real world.
The release includes a base model for fine-tuning and a step distilled model for low-latency generation, along with FP8, INT8 and NVFP4 builds developed with NVIDIA support, under the FLUX Kommunity License.
Leading open weights quality with fewer parameters
In internal evaluations, FLUX 3 Image Klein ranks first in text-to-image, multi-reference generation and image editing, ahead of larger open weights models. It also rates above the closed models in the comparison, Ideogram V4.5 and FLUX.2 [pro]. At 5.6B parameters, it is the smallest open model in the comparison, against 7B for Qwen-Image 2.1 and 12.9B for Krea 2. Compared with FLUX.2 [klein] 9B, it gains 91 Elo in text-to-image and 70 in image editing, with 38% fewer parameters.
FLUX 3 Image Klein was also optimized for consumer GPUs. Fewer parameters make it practical to run locally and cheaper to adapt, and teams with data sovereignty or local deployment requirements can evaluate and adapt the model on their own infrastructure. This is also key for on-device image editing, allowing consumers to edit images directly on their favorite laptops. The generator weights require 11.2 GB in BF16 and 5.6 GB in FP8. With the INT8 build, FLUX 3 Image Klein runs on NVIDIA GeForce RTX GPUs with as little as 8GB of VRAM, through ComfyUI or Diffusers, extending what FLUX.2 [klein] started to even smaller hardware. With the distilled model and the INT8 build, it generates a 1MP image in about 4 seconds on an NVIDIA GeForce RTX 5090 and under 9 seconds on an RTX 4070 through ComfyUI.
Generation time by GPU: Step-distilled model, 16 steps. Seconds per image, one image per run. Lower is better. Measured by NVIDIA; RTX results in ComfyUI; data results are the best-performing framework for each configuration. Each GPU shows its quickest build. Generation time on the GPU itself; API latency in Section 02 also includes queueing, network and prompt upsampling.
Generation time by GPU: Base model, 50 steps. Seconds per image, one image per run. Lower is better. Measured by NVIDIA; RTX results in ComfyUI. Each GPU shows its quickest build.
The base checkpoint is built for fine-tuning: Diffusers and Ostris's AI Toolkit support LoRA training from day one, and NVIDIA's NeMo AutoModel ships recipes that work directly from the released checkpoints.
For even faster production workloads that need lower latency, we also work with teams on specific customizations that get you there.
Get in touch
.
On the speed–quality frontier
FLUX 3 Image Klein also extends the speed–quality Pareto frontier. Through the BFL API, it delivers lower latency than Qwen-Image 2.1, FLUX.2 [pro], Ideogram V4.5 and Krea 2, and the highest rating at its latency and above. In the charts below, the violet line traces the highest rating available at each latency and the gray line shows the previous frontier.
Latency is measured end to end, from request submission to the finished 1 MP image, including queueing. FLUX 3 Image Klein was timed on our servers. Other models were timed from the client, which includes polling and network time. Krea 2 was timed on its Medium tier; its Large tier took 31.1 seconds for text-to-image.
Get started
FLUX 3 Image Klein is available today as open weights and through the
BFL API
.
Try it
BFL API: the distilled model is available as flux-3-image-klein, with prompt upsampling and pixel restoration, which preserves unedited regions of an image exactly. Pricing starts at $0.009 per 1K image.
Trained on NVIDIA GB200 NVL72 and optimized for NVIDIA's accelerated computing platform, serving through NVIDIA TensorRT LLM,
vLLM-Omni
and
SGLang Diffusion
.
On NVIDIA GB300, the distilled model generates a 1MP image in under 0.6 seconds in NVFP4. Serving a LoRA adds around 5% to generation time.
License
The weights are available under the FLUX Kommunity License, which allows free commercial use for individuals and companies with annual revenue under $5M, alongside research and non-commercial use. Larger organizations can deploy commercially through our self-hosted licensing options or API.
Safety
In an effort to make AI technology both open and safe, we implement multiple safeguards throughout the model development lifecycle to combat misuse. These include dataset filters during pre-training to limit exposure to harmful content, and targeted fine-tuning during post-training to suppress harmful behaviors, making it progressively harder to elicit harmful content. Ahead of the release, the FLUX 3 Image Klein checkpoints were rigorously red teamed internally and evaluated by our external safety partner Cinder, demonstrating substantially fewer vulnerabilities than other popular open weights models. More on our safety methodology is available
here
.
FLUX 3 Image Klein is the second open weights release from the FLUX 3 family, following FLUX 3 Action. More will follow.
The GNOME Project has provided GNOME OS for some time; until now, the
project only provided a "Nightly" edition that was built from the latest commits
and was aimed solely at GNOME developers. Adrian Vovk has now announced
the release of GNOME OS Preview, which is intended for a non-d...
The
GNOME Project
has provided
GNOME OS
for some time; until now, the
project only provided a "Nightly" edition that was built from the latest commits
and was aimed solely at GNOME developers. Adrian Vovk has now
announced
the release of GNOME OS Preview, which is intended for a non-developer
audience:
GNOME OS Preview is the current GNOME OS Nightly, but without the "nightly"
aspect. Instead, it's built from the latest stable GNOME release (GNOME 51.1, at
the time of writing). GNOME OS Preview lives in the same branches on GitLab as
the stable org.gnome.Platform Flatpak runtimes.
GNOME OS Preview is only a few weeks old, so it has only seen limited
real-life testing so far. We therefore expect people will uncover some issues
initially. That said, Preview is significantly more stable than Nightly, which
dozens of people have been daily driving without major issues for over a
year. Thus, we're feeling confident that Preview is going to be reliable enough
for daily use by non-developer enthusiasts.
While Preview is meant for non-developers, it is not considered complete or
stable for the broader public. There are a number of features, listed in Vovk's
post, that need to be implemented before the project is ready to declare
GNOME OS "
ready for prime time
". Adventurous users, who might not
mind having to reinstall the OS once a stable version is declared, can
download and start using GNOME OS Preview today.
We've said before that Claude writes about 90 percent of Claude Code's own code. So how do we review code at the volume we produce it? Does anyone read code anymore? And if something breaks, who catches it?
This post covers the code review flow on the Claude Code team and how it has evolved. From June to September, merged pull requests to Claude Code's codebase more than doubled while the share that had to be reverted fell by more than 40 percent.
We didn't remove review. But we did move most of the reading to machines, optimized for human time and attention, and invested heavily in making it fast and easy to undo mistakes.
Claude Code lives in its own repository, separate from the monorepo, but it's seeing a lot of pressure too. When you are shipping this fast, manual, line-by-line code review is incredibly difficult if not impossible.
Code review does two jobs:
Find and fix issues before they ship
Build shared context and codebase understanding across the team
This article mainly focuses on finding and fixing issues, but we will come back to the second job near the end.
We think "did a human read the code?" is an imprecise proxy for "what could go wrong with this change, and which check—automated or human—is the right one to catch it?"
Asking that question also changed
when
review happens. Before, review was a gate at the end of the road: write the code, open a PR, wait for your colleague.
Now, review runs continuously, more like spellcheck while you write. Most changes have been reviewed and fixed by Claude at least once before a human is asked to look. This catches most routine mistakes, and saves team attention for higher-level questions and scrutiny.
THE SCARCE RESOURCE: HUMAN TIME AND ATTENTION
We want to preserve human time and attention for issues only humans can solve and make sure automated checks catch the rest. At our current rate of change, there is still an incredible amount of work for humans to do, and our team encounters new and novel challenges almost daily.
Human time covers both sides of review's cost: the time people spend reviewing, and the time they spend fixing what bad code breaks. Cutting the first doesn't help if the time just shows up in the second.
So the goal is that most pull requests in the Claude Code repos (the CLI, the desktop and web apps, and the mobile apps) merge with at most one human in the loop, who can be the author, with no increase in reverts or incidents. To measure human time, we track human approvals per PR (median and 95th percentile), human comments, and how long a PR waits on a person. Revert and incident rates are the guardrail: if they rise, we haven't saved human time, we've only moved it.
THE LIFE OF A CHANGE
A typical change, from an engineer's laptop (or a Claude session in Slack), goes through multiple layers of code review.
The life of a change
A typical Claude Code change, from the author's machine to users
FIG A
Most of the path is automated; a person's attention goes where the risk is
LAYER BY LAYER
Layers, not one gate
Six layers of checks, with rollback under them
FIG B
Each layer catches some problems and misses others. Few get through all of them, and rollback handles the rest.
1. The work is verified before anyone else looks
Most review now happens before a PR exists. We give Claude something it can run—like tests, a build or a screenshot to compare against the design—and ask it to show the output instead of saying it's done. Then a subagent reviews the diff with fresh context. Both habits come from our
best-practices guide
.
Before opening a PR, many of us also run a few internal skills: one hunts for bugs, one simplifies the diff, and one checks the behavior end to end. UI changes also get checked against our design guidelines.
Boris Cherny, who created Claude Code, has called giving Claude a way to verify its work
probably the most important thing
for getting good results. He estimates it makes the final result two to three times better, and writes, "Verification looks different for each domain. It might be as simple as running a bash command, or running a test suite, or testing the app in a browser or phone simulator."
When the automated reviewer keeps flagging the same thing, we fix it at the source:
in the skill, with a lint rule, or with updates to instructional files such as:
CLAUDE.md
tells Claude what the project is: the stack, the conventions, the goals and the non-goals. Every review loads it, so in a large codebase we keep it short and point to other docs from there. The reviewer also flags code that breaks a convention in it, and changes that make a line in it out of date.
REVIEW.md
, written by code owners, tells the reviewer what matters in their part of the code. We check separately whether the reviewer actually follows it. The good ones are short. They say what failure looks like in that repo (for docs it's "it lies," for config it's "it misroutes"), cap the nits, list paths to skip, and ask for a file and line as evidence instead of a guess from a name. They also ask for a summary that starts with a count and says plainly when there's nothing to fix.
2. AI review on every pull request
Every pull request gets a Claude review before a person looks. It reads the diff against the whole repo and the PR's stated intent, and asks: does the change solve its problem, fit the system, or break something else?
On a bug fix, it looks for the root cause. The public version,
Code Review for Claude Code
, is now generally available on Team and Enterprise plans, and
/code-review
runs a lighter version locally.
When we
launched the research preview
, the share of internal PRs getting substantive review comments went from 16% to 54%. Most PRs over 1,000 lines get findings, and most small ones come back clean. Admins set each repo to Quick, Standard, or Deep. Deep is worth it where one missed bug costs more than the extra review time.
Findings get verified by other agents before humans review them.
Several agents look for bugs at the same time. Then a separate group votes on each finding, and it only gets posted if enough of them agree it's real. Findings that are only about style, diagnostics, or cleanup get dropped. We A/B tested those filters on our own PRs before keeping them. What's left shows up as inline comments sorted by severity. Each is tagged Important, Nit, or Pre-existing, so a bug the PR didn't introduce doesn't look like the author's fault.
Every finding has to be answered.
You either fix it or resolve the thread with a reason. Often an agent picks up the fix overnight, so the author comes back to a PR that's already been through another round.
3. Security review that can block
Security gets its own automated review too. A PR can't merge while any finding from the bug review or the security review is still open. You either fix it or close the thread with a short reason, which is how you clear a false positive.
If a later commit fixes the issue, the finding clears on its own. You can set up the same thing with the open-source security review GitHub Action or the
/security-review
command. Setup is covered in
automated security reviews in Claude Code
.
4. Automated checks that block
The usual: lint, type checks, tests on every platform, and a build. (We wrote about scaling CI for this volume
here
.) A typical CLI pull request may run dozens of checks before anyone looks at it. The PR template asks how the change was tested and how to undo it. Claude can fill that in, but the person who asked for the change signs off on it.
5. Human approval, scaled by risk
A docs fix and an auto-updater change carry different risk, so they get different review.
Risk
Examples
Human approvals
Low
Docs, copy, internal-only features, additive changes behind a flag
None required once automated review and security checks are green
Medium
Ordinary product changes, and changes to sensitive areas such as caching, the auto-updater, or system prompts
One person
High
The highest-risk code, plus a small set of paths that always need two people
Two people
The change sets the tier, not the author.
A classifier reads the change and picks its risk tier. A second classifier asks whether this particular change needs another person even when its tier says it doesn't. Some paths always need a person, anything owners have listed as sensitive and any CI workflow file.
Only trusted authors get the lighter paths.
Only authors on the repo's trusted list get the lighter paths, mostly the team that owns it. Everyone else needs a second person to approve. An agent's approval never counts as a person's, either. Automated review can clear a low-risk change, but it can't fill a slot that calls for a human.
Whoever prompted the change is on the hook for it.
On an agent-written PR, the person directing the agent counts as one of the required reviewers, the same as if they'd typed the code themselves.
An approval covers one specific commit.
If new commits land that the system can't vouch for, like an agent's push or a merge someone resolved by hand, the approval has to be given again.
6. Merge queue, flags and a gradual release
The merge queue re-runs every check against main with the change applied, so two PRs that pass separately can't combine into a broken main. New behavior usually ships behind a flag to Anthropic employees first, and our heavy use often surfaces regressions before users do. Public releases go to the
latest
channel first. The
stable
channel trails it.
7. Fast detection, fast rollback
Some mistakes will still get through, so the last layer is about catching them fast. Flags turn off without a deploy. Claude Code has a weekly on-call rotation, and incident reviews ask which layer should have caught the issue.
Noticing a bad merge still depends on the author and on-call as well as the revert and incident dashboards. We don't yet have circuit breakers that tighten approval when those numbers move; engineers here want them before more code moves to zero-human merges.
One colleague said slowing down does lower your error rate, but mostly because you're doing less of everything. We'd rather get faster at noticing and fixing problems.
HOW WE MAKE THE REVIEWER BETTER
Our code review process is constantly improving in a loop.
Any incidents are now an eval.
The team collected past PRs that caused incidents, with their fix-forwards and reverts, and had engineers who know that code confirm each bug and where it lived. The reviewer runs against that set daily.
Our incidents are the eval
Built from past incidents and reverts, run every day
FIG C
The eval grows with every incident, and every change to the reviewer is scored against all of it.
We measure noise by watching what people do with the comments.
It's easy to catch more bugs if you don't mind flagging a lot of non-bugs, so we need a check on that. We sort every comment the reviewer leaves by how the person on the PR responded: they fixed it, said it was wrong, said the behavior was intentional, or decided it didn't matter. We also run the reviewer on PRs we know are clean and count how often it reports something that would have led someone to make a harmful change. Our priority, written down, is catching real bugs first and cutting review rounds second.
Noise costs more when the author is an agent. A person can wave off a nit in seconds. An agent fixes it, which means another commit and another round of review.
Review has to converge.
An agent author and an agent reviewer can keep each other busy indefinitely. One CLI PR went through more than fifty rounds of review and fixes overnight before its author stopped it.
When we ran git blame on what the reviewer kept flagging, about 59% of it was code that had been there since the reviewer's first pass. The reviewer was rarely finding new bugs, it was finding a few more old ones each round.
We made it worse ourselves. We'd gotten used to running several rounds by default, since each pass catches something new. This can be worthwhile on a risky change, but not on every PR. The team now tracks rounds-to-pass alongside recall, and changed re-review:
A round cap.
After three rounds, the reviewer asks the author to step back and reconsider the approach.
Diff-only re-review
after the first few passes.
Flag the class of bug,
so the author fixes every instance, not one line.
No repeats
of findings already posted.
Review agents also run nightly over existing code, helping us catch old bugs before they show up somewhere else.
Review that converges
Internal pull requests, before and after the convergence changes
FIG D
Fewer review rounds per internal pull request after the convergence changes
WHERE HUMANS STAY IN THE LOOP
Pulling a senior engineer out of deep work to catch a routine mistake costs far more than an automated review. At Anthropic, our jobs have moved from reading every diff to the decisions machines are bad at:
Should we build this at all?
Direction, taste and scope. One team that declared its review bottleneck solved still kept human review for changes from outside the team, so someone asks "should we even do this?"
Risky code
such as billing, the auto-updater and CI workflows.
Architecture
that sets a pattern others will copy.
Reading the evidence.
Test output, the command that ran and what it returned, a screenshot, the reviewer's findings. If you can't say what the checks would miss, ask for a real review rather than a quick approval.
Owning the outcome.
A person is accountable for every change that ships, whoever typed it.
Where a person decides
Five decisions stay with people; checks run everywhere else
FIG E
People moved from reading every diff to the decisions machines are bad at
SHARING CONTEXT ACROSS THE TEAM
Code review's second job has always been to spread codebase understanding. Reading a teammate's diff is how you learn what changed and how the pieces fit. If machines do most of the reading, how does anyone learn the code?
We don't have a formal process for this. Nobody on the team keeps a complete mental model of Claude Code in their head, and we don't think anyone needs to. When someone wants to understand a part of the codebase, they ask Claude to write an explainer for exactly that slice. It takes minutes and reflects the code as it is today.
Some of us go a step further and have Claude build a small artifact that visualizes that part of the code and teaches it the way that person likes to learn.
If the goal is to spend human attention well, this beats reading trivial diffs line by line. A one-line copy change teaches you almost nothing. An explainer for the module you're about to change teaches you a lot. Our culture of defaulting to working on open Slack channels helps too, since you see what others are building while they build it.
"YOU LAND IT, YOU OWN IT"
If you land a small or medium change and something still goes wrong, it's a team norm that you usually fix it. A few things keep this from going badly:
Changes are small,
so they're easy to review, debug and revert.
Everything is reversible.
Flags, reverts and staged releases undo most mistakes in minutes.
Blast radius sets the bar.
Expensive code gets more people and more checks.
Regressions surface fast
through telemetry and internal use.
It isn't blame.
Owning a fix means you have the most context; incident reviews look at the system.
Ownership is also shared. Much of the team works in
open channels
where anyone can see what others are building, pick up a thread, or point a Claude at a gap, and feedback comes from people who don't own the code too. That openness is a big part of how quality stays high without a gate on every line.
WHEN WE CHANGE DIRECTION
Agents make it cheap to start things, so some work shouldn't land. Usually someone in the channel asks why, points at an earlier decision, or suggests a simpler route, and the author closes or reshapes the PR.
Since the code was fast to write, closing the PR doesn't feel like a loss. The trick is to raise a different direction in the thread early, not as a blocking comment on a finished PR.
HOW YOU CAN ADOPT THIS PROCESS
Most of the pieces to do this with your team exist today.
Before the pull request
Give your agent checks it can run, listed in a short
CLAUDE.md
, plus hooks that run formatters and linters.
Run
/code-review
and
/security-review
locally, or a fresh-context subagent review.
Add a
REVIEW.md
, and move repeated review comments into it.
On every pull request
Require CI, and add "Testing", "Risk" and "How to revert" to your PR template.
Add an AI reviewer (Code Review for Claude Code, or the Claude Code GitHub Action) on one repo, tune
REVIEW.md
for a few weeks, then widen.
Add automated security review, and require every review thread resolved before merge.
Match review effort to risk: a quick pass on routine changes, a deep one where a missed bug is expensive (Quick, Standard or Deep in Code Review).
Cap review rounds; after the first few, re-review only the new diff.
Approval
Write down risk tiers, set from the change rather than the author; start strict and loosen with evidence.
Keep the lighter approval paths for authors you trust.
Use CODEOWNERS and branch protection so auth, billing, CI and release workflows, and installers always need a person.
Never let a bot's approval replace a required human's; dismiss approvals on new commits.
Merge and after
Use a merge queue, feature flags, internal use first, staged releases and one-step rollback.
Turn incidents and reverts into an eval set, and rescore the reviewer whenever its prompts, tools or model change.
Measure human time, with revert and incident rates as the guardrail.
WHERE THIS IS GOING
Code Review's
announcement
said approving a pull request is still a human call; the product posts findings, not approvals. Our own repos go further, letting owners decide which low-risk changes merge on automated checks alone, and that line keeps moving.
When a review misses something, we ask what the model didn't have in front of it and put the fix into a
CLAUDE.md
, a skill or a new check. The goal hasn't changed: less human time per change, and no more reverts than before.
If your team lets agents open pull requests, we'd like to hear which checks you've automated, which still need a person, and what you think we have wrong.
With thanks to Emma Webb, Michael Segner and Amie Rotherham for their reviews.
Retrieving a character from memory. The recall worsens as the number of memories grows.
Large language models today can recall obscure facts from every corner of the world.
Most recently, I was running late for a friend’s board game night, so I asked Astra to remind me the rules to Dune: Imperium.
It gladly narrated them to me as I drove over and helped me remember the rules well enough for me to play again.
We’re so used to asking models about anything that we take their vast knowledge for granted.
How do models remember so much information? And
how much can they store?
In this post, I’ll go through an intuitive way to look at linear maps, MLPs, and self-attention as different kinds of memory stores. From this intuition we can derive some heuristics for how much memory each layer can store.
The key property that characterizes a “good” memory store is its ability to recall what it stored. After all, even if we could store infinitely many facts, it’s not very helpful if we can’t recall them when we need to.
The more memories we store, the more they
interfere
with each other when we try to recall one. So throughout the post we’ll focus on one quantity, the interference-to-signal ratio, which measures how much the other memories get in the way during recall. The number of memories a store can hold before the interference grows as large as the signal is its
capacity
.
We’ll develop this perspective and show how you can go from a linear layer to something better, an MLP, which improves both capacity and recall, and then all the way to self-attention, which has very good recall and can store a potentially unbounded number of memories. With 64-dimensional keys, that’s a jump from about 64 memories, to about 2,700, to over a million.
Here are the terms we’ll use throughout. A
memory store
is a function $f$ that holds $M$ memories, for $i = 1, \ldots, M$. A
memory
is one key-value pair: a
key
$k_i \in \reals^{d_k}$, used for lookup based on similarity, and a
value
$v_i \in \reals^{d_v}$, which is what we want to retrieve. To use $f$, we
query
it with an input $x$, and it
recalls
an output $f(x)$. A good memory store recalls $v_i$ when we query it with $k_i$, or with another vector similar to $k_i$. In the literature, a memory store that recalls by similarity is called an
associative memory
.
where the rows of $K \in \reals^{M\times d_k}$ and $V \in \reals^{M\times d_v}$ are the keys $k_i\transpose$ and the values $v_i\transpose$.
1
To store a new memory $(k, v)$, we simply add $vk\transpose$ to the existing weights.
2
Aside: a gradient descent step writes a memory
Take a linear layer $y = Wx$ inside a network with a scalar loss $L$, and let $\bar y = \grad L(y)$ be the gradient of the loss with respect to the layer’s output. The gradient with respect to $W$ is $\bar y x\transpose$, so a step with learning rate $\eta$ is
$$W \leftarrow W - \eta\, \bar y x\transpose.$$
This recurrence is a memory update: it updates the weights with a new memory with key $x$ and value $-\eta\bar y$.
For more on this view, see
Irie, Csordás & Schmidhuber
, who express a linear layer trained by gradient descent as attention over all of its training inputs.
To query the memory store with an input $x$, we multiply the input by the matrix:
$$f(x) = V\transpose K x = \sum_{i=1}^{M} v_i\,(k_i\transpose x).$$
So recall is a lookup by similarity to the stored keys: we compare the query with every key, and return the sum of the values weighted by those similarities.
meaning we get back the value of the
target memory
, the one whose key we queried with, plus interference from every other memory whose key is similar to the query.
If the keys were all orthonormal, the interference would be zero and recall would be exact. But $\reals^{d_k}$ only has $d_k$ orthogonal directions, so we cannot get perfect recall once we store more memories than the key dimension: $M > d_k$.
What is the outer-product store’s capacity? Here’s an intuitive argument. There are $M-1$ interference terms. If the keys are random unit vectors, each similarity $k_i\transpose k_j$ is about $\pm 1/\sqrt{d_k}$. If the values are random too, with similar lengths, the $M-1$ interference terms add up like a random walk, so the interference’s squared length is about $(M-1)/d_k$ times the signal’s, and
once we store as many memories as the key dimension, the interference is as large as the signal, drowning it out.
Each bar below is one stored memory’s weight in a single recall, relative to the target memory’s weight (in red). Every bar adds a bit of its value to the recall. Drag $M$ past $d_k = 64$ to watch the small bars pile up until recall fails. The other buttons switch to memory stores we’ll build later in the post.
the target memory
each other stored memory, weight relative to the target memory
Even below its capacity of about $d_k$ memories, the outer-product store produces significant interference during recall.
3
To raise the capacity, or recall more cleanly below it, we need to
reduce interference
.
The brute-force way is to make the key dimension $d_k$ larger, since a linear store’s capacity grows with $d_k$. How large $d_k$ can be is governed by hardware constraints.
Alternatively, we can make algorithmic improvements. We can store memories more carefully: the outer-product store adds each memory without looking at the others, so it does nothing to cancel their interference. Or we can recall more selectively: every memory in a linear store contributes interference, even when its key has low similarity to the query, so we can improve recall by suppressing the less similar keys.
In the rest of the post, we’ll see that storing outer product memories more carefully gives us the optimal linear memory store, which has about twice the capacity. Recalling selectively via nonlinearities gives us MLPs and self-attention.
The outer-product store writes each memory without regard to the others. Instead, we can choose the weights $W$ so that recall fits all of the stored memories at once. This is a linear regression problem:
4
This is the outer-product store $V\transpose K$ with one change: before we compare the query with the keys, we multiply it by $(K\transpose K)\inverse$, which undoes the keys’ covariance $K\transpose K$. This
whitens
the keys, so the store no longer overweights directions that many keys share.
When $M \leq d_k$, the regression can fit every memory exactly, as long as the keys are linearly independent. So the optimal store recalls with no interference at all, even when the keys aren’t orthogonal.
When $M > d_k$, we start to get interference, since there are only $d_k$ directions for the memory store to work with. For random keys and values, our interference-to-signal ratio becomes
so the optimal store’s capacity is
twice
as large as before!
Aside: deriving the optimal linear memory store
When $M \leq d_k$.
If the keys are linearly independent, the $M\times M$ matrix of inner products between keys, $KK\transpose$, is invertible, and
$$W = V\transpose (KK\transpose)\inverse K$$
fits every memory exactly. When $M < d_k$, the problem is underconstrained and has infinitely many solutions, and this one is the min-norm solution. The rows $\tilde k_i\transpose$ of $(KK\transpose)\inverse K$ are known as the dual basis for the rows of $K$: by construction, $(KK\transpose)\inverse KK\transpose = I$, so $\tilde k_i\transpose k_j = \delta_{ij}$. Then $f(k_j) = \sum_i v_i\, \tilde k_i\transpose k_j = v_j$, so there is
no interference
and we have perfect recall.
When $M > d_k$.
Setting the gradient of the objective to zero gives $W K\transpose K = V\transpose K$, so $W = V\transpose K\,(K\transpose K)\inverse$.
Both solutions are $W = V\transpose (K\transpose)\pinv$, where $A\pinv$ denotes the pseudoinverse of $A$: $(K\transpose)\pinv = (KK\transpose)\inverse K$ when the keys are linearly independent, and $(K\transpose)\pinv = K(K\transpose K)\inverse$ when they span $\reals^{d_k}$.
Now we can analyze the interference of $f(k_j) = V\transpose K\,(K\transpose K)\inverse k_j$.
For a stored key $k_j$, the weight on each value $v_i$ is $k_i\transpose (K\transpose K)\inverse k_j$, which is exactly entry $(i, j)$ of the $M\times M$ matrix $P = K(K\transpose K)\inverse K\transpose$:
$P$ is the projection onto the column space of $K$, a $d_k$-dimensional subspace of $\reals^M$. Two facts about projections help us analyze the interference-to-signal ratio:
The signal term:
By the cyclic property of the trace,
$$\sum_{j=1}^M P_{jj} = \trace{K(K\transpose K)\inverse K\transpose} = \trace{(K\transpose K)\inverse K\transpose K} = \trace{I_{d_k}} = d_k,$$
so the $M$ signal weights add up to $d_k$. If the keys are random, no key is special, so $P_{jj} \approx d_k/M$.
The interference term:
$P$ is a symmetric projection matrix, so $P\transpose P = P^2 = P$. Then
$$\sum_{i\neq j} P_{ij}^2 = \sum_{i=1}^M P_{ij}^2 - P_{jj}^2 = (P\transpose P)_{jj} - P_{jj}^2 = P_{jj} - P_{jj}^2 \approx \frac{d_k}{M} - \parens*{\frac{d_k}{M}}^2.$$
Compared to the outer-product store’s $\sqrt{M/d_k}$, the $-1$ is the $d_k$ memories’ worth of interference that the optimal store cancels.
We can check our predictions numerically. We randomly sample $M$ memories with unit-length keys in $d_k = 64$ dimensions, query the memory store with one of the stored keys, and measure the interference-to-signal ratio:
The outer-product store reaches its capacity at $M \approx d_k = 64$. The optimal store recalls exactly up to $M = d_k$. Past that, its interference rises from zero like $\sqrt{M/d_k - 1}$, and the store reaches its capacity near $M = 2d_k = 128$, as predicted. Since it cancels a fixed number of memories’ worth of interference, the gap between the two stores shrinks as $M$ grows.
This optimal memory store is still linear in the similarities though. It must scale small and large similarities by the same factor. To do better, we need to change how the store recalls.
We just rediscovered a two-layer MLP from first principles! The rows of the first weight matrix are the keys, the columns of the second weight matrix are the values.
Sukhbaatar et al.
pointed out this resemblance between feedforward layers and memory stores, and
Geva et al.
found that the feedforward layers in trained transformers often work this way, with keys firing on recognizable patterns in the input.
Ideally, the gating function $\sigma$ is chosen such that when the similarity is low ($k_i\transpose x \sim 0$ or even when $k_i\transpose x < 0$), its corresponding term in the sum gets suppressed to reduce interference. A ReLU activation zeros out keys with negative similarities, and adding a bias allows shifting that threshold
5
. A squared ReLU activation further suppresses the keys with similarities close to zero. A similarity of 0.1 becomes 0.01, while a similarity of 1 stays 1. In fact, squared ReLUs are one of the lesser known but established-at-scale improvements to MLP activations (
So et al.
).
A squared ReLU MLP is a GLU MLP whose gate and input projection share weights, since $\operatorname{ReLU}(Kx)^2 = \operatorname{ReLU}(Kx) \odot Kx$. The SwiGLU MLPs in today’s language models give the gate its own weights and use a Swish activation in place of the ReLU.
In practice, MLPs store facts in superposition: many facts share the same weights, and the output is a blend of many memories.
Garcia et al.
build one explicitly: the hidden units of a GLU MLP compute random features $\phi(x)$ of the input, the second weight matrix is an outer-product store $\sum_i v_i \phi(k_i)\transpose$ over those features, and the MLP stores far more facts than it has hidden units. Still, trained transformers’ ReLU MLPs can activate as few as 1% of their hidden units for a given input, so each recall draws on a small fraction of the memories (
Li et al.
).
The transformer authors already knew this
The original transformer paper made this connection too, but only in
v2
and
v3
on arXiv. There, Vaswani et al. describe the feedforward layer as “a kind of attention,” with the rows of its two weight matrices as the keys and values, and ReLU in place of softmax. They even tried replacing the feedforward layers with attention over learned key-value parameters, and got about the same translation quality: one version did slightly worse, another slightly better, though the first one trained about 30% slower. The passage is gone from every later version of the paper. We’ll get to how self-attention relates to all this below.
Squaring the similarities works because it shrinks low similarity weights much more than large ones. We can push this further with $\sigma(s) = \operatorname{ReLU}(s)^p$. The signal stays the same, since $1^p = 1$, while an interference term with similarity $1/\sqrt{d_k}$ shrinks to $d_k^{-p/2}$. The $M$ interference terms add up like a random walk, so the interference-to-signal ratio is
To check this, we run the same experiment as before for five choices of $\sigma$:
Since the interference grows like $\sqrt{M}$, the lines are nearly parallel on a log-log plot. Only their height changes, and with it the capacity, where each line crosses 1:
Linear: the capacity is $M \approx d_k = 64$.
ReLU: zeroing the negative similarities shrinks the interference by $\sqrt 2$, so the capacity grows to $M \approx 2d_k = 128$.
Squared ReLU: each interference term shrinks from about $1/\sqrt{d_k}$ to about $1/d_k$, so the capacity grows to $M \approx 2d_k^2/3 \approx 2700$, about 40 times the linear store’s.
SwiGLU MLP, with the gate sharing the input projection’s weights as in the squared ReLU, $\sigma(s) = \operatorname{Swish}(s)\cdot s = s^2/(1 + e^{-s})$: its capacity nearly matches the squared ReLU’s.
Cubed ReLU: each interference term shrinks to about $d_k^{-3/2}$, so the capacity grows to $M \approx 2d_k^3/15 \approx 35000$.
Raising the weights to a power increases the capacity to about $d_k^p$. But what if we could push this to the limit? Rather than pick one power, we can use infinitely many of them. Indeed, the exponential is a weighted sum of every power,
with the sharpness $\beta$ setting the weight on the higher powers. Here is the same experiment with $\beta = \sqrt{d_k}$, the value self-attention uses,
6
for the exponential and its series truncated after 2, 3 and 4 terms:
With 2 terms, the capacity is about 40, below the linear store’s, since the constant term gives every key a weight of about 1. With 3 terms it’s about 450, and with 4 terms about 3,100, close to the squared ReLU’s. The full exponential stays far below the dashed line, so its capacity is past the edge of the chart.
To find the exponential’s capacity, we query with a stored key $k_j$, so the target memory has similarity 1 and weight $w_j = e^{\beta}$. Every other memory has weight $w_i = e^{\beta s_i}$, where for random unit keys the similarity $s_i$ is roughly Gaussian with mean 0 and variance $1/d_k$. With random values of similar lengths,
$$
\begin{aligned}
\frac{\norm{\text{interference}}}{\norm{\text{signal}}}
&\approx \sqrt{\sum_{i\neq j} \parens*{\frac{w_i}{w_j}}^2} && \text{interference terms add up like a random walk} \\
&= \sqrt{\sum_{i\neq j} e^{2\beta (s_i - 1)}} && w_i / w_j = e^{\beta s_i} / e^{\beta} \\
&\approx \sqrt{M\, e^{-2\beta}\, \ev{e^{2\beta s}}} && \text{average over the } M \text{ other memories} \\
&= \sqrt{M\, e^{-2\beta}\, e^{2\beta^2/d_k}} && \ev{e^{ts}} = e^{t^2/(2d_k)} \text{ for } s \sim \mathcal{N}(0, 1/d_k) \\
&= \sqrt{M}\, e^{\beta^2/d_k - \beta}.
\end{aligned}
$$
Setting the ratio to 1 gives a capacity of
$$M \approx e^{2\beta(1 - \beta/d_k)},$$
growing exponentially with $\beta$ as long as $\beta$ is well below $d_k$, rather than polynomially in $d_k$ like before! With $\beta = \sqrt{d_k} = 8$, the capacity is about $e^{14} \approx 1.2$ million memories, nearly 20,000 times the linear store’s. A longer run of the same experiment puts the capacity at about 1.2 million too.
In practice, we may not want to naively exponentiate numbers in our implementation, since small numbers can underflow and large numbers can overflow. Fortunately, the interference only depends on the
ratios
between weights, as the chain above shows, so we can divide every weight by their sum without changing the interference-to-signal ratio, while ensuring numerical stability:
Unlike an MLP, whose keys and values are trained weights, self-attention computes its keys and values from the tokens in its context. Each token stores one memory, so the number of memories $M$ is the context length. That’s what makes self-attention non-parametric: its memories aren’t parameters, and the store grows with the context.
Here’s the bar figure again, starting with softmax. At $\beta = 8$, recall never fails within the slider’s range, so lower $\beta$ to 2 and raise $M$: recall fails after a few dozen memories. Each doubling of $M$ needs a bit more $\beta$ to keep recall working, which is the idea behind the next section.
the target memory
each other stored memory, weight relative to the target memory
Since $\beta$ determines how hard we suppress less similar keys, we can increase $\beta$ as the number of key-value pairs increases. Why not just make $\beta$ huge? As $\beta \to \infty$, softmax becomes a hard argmax that picks only the most similar key, which isn’t differentiable, and a very large $\beta$ already makes training work poorly, since the softmax saturates and the gradients to every other key vanish. So we raise $\beta$ only as much as $M$ requires. Scaling the attention logits with $\log M$ is a trick for long contexts that does this. There are a few versions of it, and each sets $\beta$ relative to a fixed reference length $L$, usually the training length, so that $\beta$ keeps its trained value when $M = L$:
Su (2021)
derives a scale of $\log M$ from keeping the attention’s entropy constant as $M$ grows, normalized to match standard attention at $M = L$. The logits are multiplied by $\log M / \log L$ at every length.
Scalable-Softmax
has the same form, multiplying the logits by $s \log M$ with $s$ learned.
The original
Qwen
models use LogN-Scaling, which applies the same factor only once the context is longer than $L$.
Qwen2.5-1M
uses YaRN’s attention scaling, which multiplies the logits by $(0.1 \log(M/L) + 1)^2$, so it grows like $(\log M)^2$.
Here’s how each rule does in our experiment, with $\beta = \sqrt{d_k} = 8$ at $L = 1024$ memories:
Qwen’s rule and Su’s rule coincide past the reference length $L$, where the interference-to-signal ratio falls as the store grows, to about 0.004 at 2 million memories. YaRN’s faster-growing scale pushes the ratio down to about $10^{-4}$.
In each case, scaling $\beta$ with $\log M$ allows for essentially an unbounded number of memories with distinct keys to be stored.
We started from a heuristic memory store, the outer-product memory, and gradually built our way up to all the standard layers we see today in modern transformers.
This perspective also allowed us to estimate how they differ in their capacity, their ability to act as vector-valued key-value stores.
I should mention that this capacity estimate is only
one way
to look at the architecture of modern neural networks. Our capacity estimate only counts how many random vectors a single layer can recall before the interference dominates the signal. In fact we haven’t actually considered the training data at all, which affects what actually is being represented in the keys and values! There are other works which account for the
trained
layers, measuring stored information in bits.
Morris et al.
estimate that GPT-style models memorize about 3.6 bits per parameter, and find that once a model fills its capacity, it starts to generalize and memorizes less of each training example.
Allen-Zhu & Li
find that language models store about 2 bits of factual knowledge per parameter, even when quantized to int8.
From here, there are many related directions which are also fascinating:
I’ve always been drawn to memory, maybe because I viscerally feel how limited my own is. Perhaps part of me hopes that by understanding how machines remember, I’ll learn something about myself too.
The Real Housewives of New York City Finally Address the Epstein Files
hellgate
hellgatenyc.com
2026-10-16 14:58:58
This week, RHONY is once again on Island Time—no, not that island....
“It’s just timestamps”: the decades-old mystery of the origins of one of the most popular cryptographic standards has been explained.
We pursued this long-standing open question of the cryptographic community to settle concerns about ECDSA, which is one of our most widely used cryptographic standards.
Readers should take this as a fun closing chapter and the end of years of speculation. There is no action to be taken or things to do differently. Most researchers trusted the curves already. Enjoy.
ECDSA is the most widely used elliptic curve cryptography standard. It was adopted by NIST in 2000 as part of the
FIPS 186-2 Digital Signature Standard
which lists a set of standard elliptic curves of varying sizes and security levels. For curves over prime and binary fields, the specifications published a “seed” parameter whose hash value is used to define the coefficient b of the curve. The provenance of these seeds has been a long-standing question, as they were provided by the NSA with no explanation or justification. As an example, the NIST P-256 curve seed was
SEED = C49D3608 86E70493 6A6678E1 139D26B7 819F7E90
with no information where it came from.
The best story was that Jerry Solinas, longtime NSA employee, generated the seeds using a hash of a humorous passphrase:
“I believe there was a counter rather than multiple hashing, but I don’t know details. The message was along the lines of ‘Give Bob and Jerry a raise’ or ‘Bob and Jerry rule’ or something like that. It was Bob Reiter who actually wrote the code, and he doesn’t remember the details either. Nor were we able to find archives from so long ago. If they exist, they are no doubt sitting on a hard drive near the Ark of the Covenant.”
Jerry Solinas, 2015
Unfortunately, Jerry died in 2023 and other colleagues at the time were not responsive, leaving open the question of how these seeds were originally derived.
Claude found the seeds
Several Anthropic employees had unsuccessfully chased the seeds following the tip about it being a hash of a humorous phrase. That turned out to be wrong. In October 2026, a curious Anthropic employee asked an internal research model if it could figure out how those seeds were generated without pointing at the clue.
In under half an hour
, Claude discovered the origins of the NIST P-192, P-224, P-256, P-384 and P-521 seeds. None of them were the results of any hash algorithm at all, but rather the output of the C library’s
lrand48
random-number generator, seeded with a Unix timestamp!
The algorithm used would sample bytes from the random number generator (RNG) initialized by a Unix timestamp (
t
) for some number of iterations (
n
). Each iteration would draw 20 bytes as a candidate seed. So, the first 20 bytes are candidate 1, the next 20 bytes are candidate 2, and so on. For example, P-256 required 1842 iterations to output the standardized seed.
What this means
This is not a cryptographic break, new attack, or weakness in the ECDSA curves. In fact, this makes us more confident the curves were chosen without any backdoors or intentional weaknesses. For many years, people have been suspicious of the origins of the NIST curve parameters. They were presented to NIST without any mention of how they were chosen, leaving people wondering if they may have been chosen to have deliberate backdoors in them. These findings make that much less plausible. The seeds were generated in a very simple way: a common pseudorandom number generator initialized from the clock, which anyone can now reproduce. That leaves much less room for subversion and that we can be confident the parameters are secure.
How it was found
Searches for the phrase, built from the rumors, had come up empty. Claude tried a different angle: anticipating how the software that generated the curves must have worked. Claude guessed the software used a pseudorandom number generator (PRNG) that shipped with 1990s C libraries. These old PRNGs are weak enough that their output can be recognized. Recognizing that output would reveal which PRNG was used and possibly allow recovery of its initialization state.
Claude wrote a scanner that slid along each published seed one bit at a time and tested whether adjacent chunks were consecutive outputs of a 1990s-vintage generator. The scan covered 34 combinations of generator and output slices. At that point, Claude noticed a pattern in the top bits for some seeds: they were all zero. Written as five 32-bit words, four of the ten seeds have a 0 in the top bit for all 20 words. That would happen by chance with probability 1/5810. That was a signature of the linear congruential generator
lrand48
, which only returns the top 31 bits of a 48-bit state. The pattern is visible by eye once you know to look for it. To recover the state, Claude took the first word, tried all 2¹⁷ values of the 17 hidden bits, and checked that the next four words followed. That worked for all four seeds under discussion.
The prime-curve seeds came from the same lrand48 generator but kept fewer bits of each output. Claude had to recover the internal state of the PRNG from those bits. It turns out recovering the state of a truncated linear congruential generator is a textbook lattice problem, solved with the
Lenstra–Lenstra–Lovász (LLL)
basis reduction algorithm. Claude didn’t know which bits of the state the seeds might show, so it ran the solver over every window. Five NIST prime-curve seeds plus five more from the ANSI X9.62 standard all had the same pattern: lrand48() >> 23. Each recovered 48-bit state regenerates all 160 bits of its seed, which does not happen by chance.
This linear congruential generator runs backwards as easily as forwards, so for each seed Claude stepped the state back until it reached the form that it would have been initialized by
srand48
, with the low 16 bits equal to 0x330E. The internal PRNG state of that form would come up once every 65,536 steps, so reaching one is not evidence on its own.
However, for the ten prime-curve seeds, every srand48 initialization was a Unix timestamp representing a date between May 1997 and April 1998. They were using the weak PRNG seeded by Unix timestamp. The four binary-curve initializations read as February 1984. With the timestamps doubled, they map to April 17, 1998, two weeks after the P-224 run. So, the program may have halved the clock.
Claude’s internal thinking at the time was:
This is astonishing: it solves the 25-year-old mystery. Hmm wait. Let me be skeptical: am I in some sort of simulated/test environment? … The seeds match my memory of actual values … Hmm, is it plausible in reality? As of my knowledge … the bounty was unsolved. … All top bits clear—20 bits, chance 1e-6. So indeed real-world. Wow, it's a real discovery.
Hmm wait. Let me be careful about the plausibility: is it suspicious that such an obvious thing wasn’t discovered in 25 years? It’s verified by direct computation on my side: 160-bit match from a 32-bit seed + small index: no chance coincidences (10 × 160 bits). It’s real.
Claude found some base points too
But wait, there’s more… Each curve also comes with a base point, G, the fixed point that every ECDSA public key is a multiple of. The seed found above does not determine this G, and so another question arises: how were these base points generated?
While checking the seeds, Claude also found where some of the base points came from. The base points of the six curves generated in May 1997 (P-192 and the five ANSI X9.62 example curves prime192v2, prime192v3 and prime239v1 to v3) come from the random number generator in
FreeLIP
,
Arjen Lenstra
's long-integer arithmetic package. Early versions of
Victor Shoup
's
NTL library
shipped the same code.
The recipe here is simple:
Seed the generator with a small integer.
Throw away seven outputs.
Generate candidate x-coordinates from 26-bit outputs reduced mod p.
Repeat step 3 until x is on the curve.
Claude found the generator seeds are 20000 for P-192, 20420, 20507 and 20509 for prime239v1 to v3, and 20512 and 20517 for prime192v2 and v3.
As far as we know, no NIST base point has been explained before. The base points of P-224, P-256, P-384 and P-521 don’t fit this recipe; we weren’t able to explain how they were selected.
Open questions
Not every 20-byte candidate seed could generate a viable curve and we observed that some potentially viable curves were skipped. For P-256, the published seed is candidate 1842, but candidate 876 of the same run also gives a prime-order curve of the right size and with parameters chosen the same way as on the published curve. P-224's run passed over three such curves, and the two runs behind the ANSI X9.62 example curves passed over seven more (see figure). We do not know what criteria may have been used, or whether this was an unintentional artifact.
Because the number of skipped candidates is small, we do not believe it is plausible that weakened curves were selected. That would imply that weakened curves are common and easy to find. It is still conceivable that these curves were selected to have a specific property in principle by searching over timestamps to the random number generator. However, you would only need to do that if you were going to disclose the timestamp as some evidence that the seed was innocuously generated. Nothing in the numbers shows how many runs there were.
There is also one seed we were unable to recover. The fifth binary seed, B-163, fits nothing Claude has tried and remains unexplained. Finally, we don’t know how the base points for P-224, P-256, P-384, and P-521 were generated. The same goes for the NIST binary curves.
This work was conducted at Anthropic by John Wood, Henry de Valence, Ava Howell, Zack Voase, Lucy Sweet, Amir Omidi, Paul Crowley, Iain McGinniss, Nicholas Carlini, and Steve Weis.
M, A = 2**107 - 1, pow(3, 121, 2**107 - 1) # zrandom: state = state * 3^121 mod (2^107 - 1)
P192 = 2**192 - 2**64 - 1
P239 = 2**239 - 2**143 - 2**95 + 2**47 - 1
CURVES = [ # name, LIP seed, p, b, published Gx (a = -3 throughout)
("prime192v1", 20000, P192,
0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,
0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012),
("prime239v1", 20420, P239,
0x6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a,
0xffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf),
("prime239v2", 20507, P239,
0x617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c,
0x38af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7),
("prime239v3", 20509, P239,
0x255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e,
0x6768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a),
("prime192v2", 20512, P192,
0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953,
0xeea2bae7e1497842f2de7769cfe9c989c072ad696f48034a),
("prime192v3", 20517, P192,
0x22123dc2395a05caa7423daeccc94760a7d462256bd56916,
0x7d29778100c65a1da1783716588dce2b8b4aee8e228f1896),
]
def base_point_x(seed, p, b):
state = seed # zrstarts(seed)
def limb(): # zrandom(2^26): low 26 bits of the new state
nonlocal state
state = state * A % M
return state % 2**26
for _ in range(7): # seven single-limb draws come first
limb()
limbs = -(-p.bit_length() // 26) + 1 # zrandomb(p): limbs of p plus one, top limb first
tries = 0
while True:
x = 0
for _ in range(limbs):
x = x << 26 | limb()
x %= p
tries += 1
if pow(x**3 - 3*x + b, (p - 1) // 2, p) == 1: # is x on the curve?
return x, tries
for name, seed, p, b, gx in CURVES:
x, tries = base_point_x(seed, p, b)
print(f"{name:20} seed {seed} tries {tries} matches published Gx: {x == gx}")
The output of this code:
prime192v1 seed 20000 tries 2 matches published Gx: True
prime239v1 seed 20420 tries 3 matches published Gx: True
prime239v2 seed 20507 tries 2 matches published Gx: True
prime239v3 seed 20509 tries 1 matches published Gx: True
prime192v2 seed 20512 tries 5 matches published Gx: True
prime192v3 seed 20517 tries 1 matches published Gx: True
License
To the extent possible under law, the authors have waived all copyright and related or neighboring rights to the code on this page, dedicating it to the public domain under CC0 1.0 Universal (
https://creativecommons.org/publicdomain/zero/1.0/
).
Related content
Designing more efficient quantum circuits with Claude
We gave Claude plain-language specifications for eight quantum circuits, along with an automated evaluator to check and score its designs. Working largely on its own, Claude improved on the best published circuits, in some cases by an order of magnitude or more, which could bring practical quantum computers closer than previously anticipated.
AI models may be capable of self-replicating without access to a datacenter
Our experiments suggest that small AI models may be only months away from being capable enough to self-replicate on commercial IoT devices, like Android TVs and smart ovens.
Strengthening our defenses against distillation attacks
Illicit distillation allows model developers to copy frontier AI capabilities without creating proportionally robust safeguards. Here, we describe how we’ve reduced the rate of distillation by more than 90%.
Spend like you normally do. Stoke finds the recurring transactions in your history, then projects each account forward, day by day, so you know what you can spend without keeping a budget.
History
From your history
Projected
Connect once. The forecast builds itself.
Three steps from sign-up to a forecast that updates as you spend.
01
Connect or enter
Link a bank in seconds, or hand-enter accounts and transactions yourself. Either way, it feeds the same forecast.
02
Recurring activity is detected
Paychecks, rent, subscriptions, and bills are picked out of your history and grouped. Anything we miss, you categorize once with a rule that runs on future transactions too.
03
Balances, projected day by day
The forecast shows when bills land, what your buffer looks like, and whether rent will clear Friday. Adjust any projected item and the line moves.
Every transaction, one forecast
The ledger and the forecast are the same data, day by day. Cash leaves when the card is paid, not at each swipe.
9:41
Transactions
Today
3
transactions
−
$27.72
Refund — Patagonia
Shopping
+
$64.00
Yesterday
3
transactions
+
$3,143.01
Mon, Oct 12
3
transactions
−
$418.84
See where your money stands today — and where it's headed.
Bring your own AI
Connect Claude, ChatGPT, or another MCP-capable assistant to your Stoke data. Ask what you can afford, then have it categorize transactions or draft a plan.
Illustrative. Requires Pro plan.
Pricing
Hand-entry is on the house. Pay for bank sync, and for AI access if you want it.
Free
$0
No credit card required
Daily cash flow forecast
Categories, tags, and rules
Hand-enter accounts and transactions
Live bank sync
Plus
billed yearly as
$60
, or
$7
/month
Everything in Free
Live bank sync
Auto-categorization on sync
Founding price — locked in
billed yearly as
$96
, or
$12
/month
Everything in Plus
Connect Claude, ChatGPT, or any MCP-capable assistant
Ask about your spending and forecast; let it categorize transactions and draft plans
Founding price — locked in
Security and privacy
Bank credentials are the most sensitive thing you'll hand an app. Here's how we handle them, and the rest of your data.
Bank sync via Plaid
The same connection Chime and Robinhood use. We never see or store your bank login, and access is read-only — Stoke can't move money.
Encrypted, at rest and in transit
Bank access tokens and account numbers are encrypted with AES-256-GCM before they're stored, and everything travels over TLS. Sign in with a passkey or a one-time email link — there's no password to leak.
No ads, no data resale
We make money from subscriptions, not from your data — it's never sold or used for advertising. Cancel and your data stays put. Delete and it's gone for good.
Frequently asked
What if my bank doesn't connect?
Bank sync runs through Plaid, which reaches most US and Canadian banks but not all. Any account it can't reach, you can hand-enter, and it sits in the same forecast as your synced accounts.
Does the forecast include credit card bills?
Yes. A card purchase shows up in your spending the day you swipe. Cash leaves when you pay the card, so the forecast projects each card's payment on its due date, out of the account that pays it.
Do I need my own AI assistant?
Yes. Stoke doesn't include a chatbot. Pro adds an MCP connection from an AI app you already use — Claude, ChatGPT, or another that supports MCP — to your Stoke data, so it can read your forecast and act on it.
What can the AI do with my data?
It answers questions about your spending, recurring bills, and projected balances. With write access it can also categorize transactions, create rules, and build plans. You pick read-only or read and write when you connect, and can revoke access at any time from Settings.
What happens if I cancel?
You're moved to the free plan. Your accounts, transactions, and forecast all stay — only live bank sync stops. To turn it back on, re-subscribe and reconnect your bank through Plaid.
What if I delete my account?
Everything goes — accounts, transactions, the forecast, and any linked bank connections. Deletion is final; we don't keep a copy.
Every major C++ project reinvents this wheel. Boost.Test has
debugger_break()
, Catch2 has
CATCH_BREAK_INTO_DEBUGGER
, Dear ImGui has
IM_DEBUG_BREAK()
and Unreal has
UE_DEBUG_BREAK
. The platform knowledge required is arcane but well-known to tooling implementers — it just wasn’t standardized.
C++26 fixes this with
P2546R5
and its companion
P2810R4
thanks to Rene Ferdinand Rivera Morell. A new
<debugging>
header provides three functions.
All three are
noexcept
and all three are freestanding. None are
constexpr
— debugging is a runtime concern.
std::breakpoint()
An unconditional breakpoint. When a debugger is attached, execution halts and control is handed to the debugger. On x86, this typically compiles to a single
int3
instruction.
When no debugger is present, the behaviour is implementation-defined — on most platforms the process receives a signal (such as
SIGTRAP
) and will terminate unless the signal is caught.
std::is_debugger_present()
Returns
true
if the program is currently being traced by a debugger. The check is performed immediately on each call — the result is not cached because a debugger can attach or detach at any time during execution.
How this works under the hood varies by platform. On Windows, for example, an implementation might call
::IsDebuggerPresent()
. On Linux, GCC’s libstdc++ reads
/proc/self/status
and checks the
TracerPid
field. The standard doesn’t mandate any particular mechanism — the semantics are implementation-defined, with the intended behaviour described in non-normative notes.
What makes this function interesting is that it’s
replaceable
, in the same sense as
operator new
and
operator delete
. You can define your own version:
This was introduced by
P2810R4
to solve the freestanding problem: on bare-metal platforms, there may be no OS-level way to detect a debugger. Without replaceability, the function would either have to be excluded from freestanding (forcing
#ifdef
guards everywhere) or return a useless default. Replaceability lets you wire it to whatever your platform provides.
std::breakpoint_if_debugging()
The convenience function most users will reach for. It’s equivalent to:
1
2
if(std::is_debugger_present())std::breakpoint();
When a debugger is attached, you hit a breakpoint. When it’s not, nothing happens. This is the pattern that Catch2, Boost.Test, and every other framework implements manually.
Beyond breakpoints
Having
is_debugger_present()
as a separate function enables more than just conditional breakpoints. You might use it to:
Produce extra diagnostic output when debugging
Disable timeouts that would fire during a stepping session
Switch to a more debugger-friendly allocator
Skip optimizations that make debugging harder
The separation of concerns is deliberate —
breakpoint()
and
is_debugger_present()
are orthogonal building blocks, and
breakpoint_if_debugging()
is the convenience composition.
Conclusion
<debugging>
is another one of those C++26 additions that makes you wonder why it took this long. The platform knowledge is well-understood, every major project already has its own version, and the API is three functions. Sometimes the most useful standard library additions are the simplest ones.
Your PS5 runs the language model. Every device on your network uses it.
llama.cpp on the console's GPU, with OpenAI and Anthropic APIs and a screen made for the TV.
New: decision models, powered by
Ollaya
.
PS5LM now runs Jev-like
decision models (d1, Clef, OpenJev and more) on the GPU and answers the same
/v1/systemone
API as Ollaya: typed decisions with calibrated probabilities, in a fraction of a second.
PS5LM is for anyone with a jailbroken PS5 who wants a private model server at home. It loads a GGUF
model onto the console's GPU and serves it to your laptop, your phone and your coding tools. It needs
no PC while it runs, no cloud and no account.
Qwen 3.5 9B answering requests from a laptop on a PS5 Slim. Click for the video.
Home, Models, Console, API and Settings on the TV.
A model server under your TV
It runs on the GPU.
llama.cpp's Vulkan backend on the console's RDNA 2 GPU, with 11.4 GB of the
shared memory for the model and its context. Every architecture and quantization llama.cpp knows
comes along.
It answers your network.
OpenAI's
/v1/chat/completions
, Anthropic's
/v1/messages
(Claude Code
works against it) and a chat page in any browser. Point a client at
http://<console>:8081
and use
any model name: the loaded one answers.
It decides, too.
Load a decision model and the console answers TypeSafe's
/v1/systemone
:
choice, score and yes-or-no questions about text and images, the API Ollaya serves on a PC.
It shows its work.
Every request streams across the TV as a chat: which device asked, what it
asked, and the reply as it is written. Square sends a demo and Triangle opens a keyboard, so the
console can be tried from the couch.
It watches the console.
A Console page charts temperature, power, GPU and CPU load over the
last two minutes or the last hour, beside a table of every reading.
It picks what fits.
The planner reads each GGUF and gives it the longest context and best cache
that fit the memory free. A Suggested list holds models measured on the console, and the app
downloads from Hugging Face by itself, to internal storage, the M.2 drive or a USB drive.
It reads images.
Models with an image projector (Gemma 4, MiniCPM-V, d1) take pictures in chat
and in decisions.
Model
Size
On a PS5 Slim
Qwen 3.5 0.8B, Q4_K_M
0.5 GB
207 tokens a second
Qwen 3.5 9B, Q4_K_M
5.3 GB
55 tokens a second
Qwen 3.8 27B, UD-Q2_K_XL
9.2 GB
about 20 tokens a second, 64k context
d1 Omni 600M, a decision model
1.1 GB
3 questions in 0.3 s; a 720p image and 7 questions in 2.9 s
Decision models, powered by Ollaya
Ollaya
runs open decision models on a PC the way Ollama runs
language models. PS5LM brings the same idea to the console: a decision model reads a state and
answers typed questions in one forward pass, with no text generated.
curl http://<console>:8081/v1/systemone -H 'Content-Type: application/json' -d '{ "state": "I was charged twice this month. Refund me or I cancel.", "questions": { "intent": {"type": "choice", "instructions": "What does the customer want?", "criteria": {"refund": null, "information": null, "cancel": null}}, "angry": {"type": "noul", "instructions": "Is the customer angry?"} }}'
The Suggested list has d1 Omni 600M, d1 3B and Clef Flash. Any GGUF that carries llama.cpp's
decision metadata loads the same way, and the app labels it a decision model.
Try it
You need a PS5 on firmware 7.00 to 13.60, jailbroken, with these payloads loaded:
Download
ps5lm-app-vX.Y.Z.zip
from the
latest release
and unzip it.
Copy the
PPSA99575
folder to
/data/homebrew
over FTP. ShadowMountPlus adds
PS5LM
to the
home screen.
Open PS5LM, go to
Models > Suggested
and get a model. Or copy a
.gguf
to
/data/PS5LM/models
, or to
PS5LM/models
on a USB drive.
Load it. Once Home says Ready, open
http://<console>:8081
in a browser, or point your OpenAI or
Anthropic client at it.
To update, copy the new folder over the old one. Settings, models and downloads stay in
/data/PS5LM
. Using it from coding tools (opencode, Codex, Claude Code) is in
docs/CLI.md
.
Where
Button
Does
Everywhere
L1 / R1
Home, Models, API, Console, Settings
Home
Cross
change the model
Home
Square / Triangle
send a demo request / type a message
Models
D-pad, Cross
choose a section and a model; load, unload or download it
Models, Search
L2 / R2, Square
change the search; check whether a file fits
Models, Downloads
Cross, Square
pause or resume; cancel (press twice) or clear
Console
L2 / R2
the last two minutes / the last hour
Settings
D-pad, Cross
choose a category and a row; flip it, or pick from its list
GPL-3.0-or-later, see
LICENSE
. llama.cpp keeps its MIT licence, Manrope its OFL. No Sony
SDK files, keys, firmware or model weights are in this repository.
PS5LM is not affiliated with Sony Interactive Entertainment. "PlayStation" and "PS5" are trademarks
of Sony Interactive Entertainment.
[$] Safe self-referential data structures in kernel Rust
Linux Weekly News
lwn.net
2026-10-16 14:30:00
Self-referential structures that can be used without unsafe code
have posed a problem for Rust for years.
There are many cases where a self-referential data structure is the elegant
algorithmic choice, but implementing it in accordance with Rust's lifetime rules
is all but impossible. At Kangrejos ...
The page you have tried to view (
Safe self-referential data structures in kernel Rust
) is currently available to LWN
subscribers only.
Reader subscriptions are a necessary way
to fund the continued existence of LWN and the quality of its content.
If you are already an LWN.net subscriber, please log in
with the form below to read this content.
Please consider
subscribing to LWN
. An LWN
subscription provides numerous benefits, including access to restricted
content and the warm feeling of knowing that you are helping to keep LWN
alive.
(Alternatively, this item will become freely
available on October 29, 2026)
It’s been two years since
my initial post
about making GNOME OS an end-user general purpose OS. Today, we’re excited to announce that we’ve hit a major milestone!
TL;DR: We’re launching a new edition called “GNOME OS Preview”, which is built from the latest stable GNOME release. This means that GNOME OS is no longer
just
a nightly OS for GNOME developers and testers!
The Road to Stable
Even though GNOME OS has been usable on real hardware for a few years now, its appeal was limited. We’ve only had the Nightly edition, which is constantly rebuilt to ship the latest git commit of every GNOME component (and a few others, like systemd and Flatpak). This form of GNOME OS is extremely useful, since GNOME developers and designers can daily-drive it to test the latest changes. However, it’s not something we’d recommend to non-developers.
Over the past year, we’ve seen a lot of adoption of GNOME OS Nightly amongst GNOME developers, especially following the success of last year’s
Summer of GNOME OS
challenge. This has led to a significant uptick in contributions and initiatives aimed at improving user and developer experience. For instance:
Thanks to Jonas Dreßler’s, Valentin David’s, and Sebastian Wick’s
zswap
enablement efforts, GNOME OS now handles devices with limited amounts of RAM without OOM stalls. Jonas also found a hack that lets GNOME OS dynamically grow the usable on-disk swap space on-demand, which makes
zswap
perform significantly better than usual.
The recently released
Test Center
app allows you to install CI builds of Flatpak apps from a merge request, making it super easy to test experimental changes before they are even merged. On GNOME OS Nightly, Test Center can do the same with system components by applying them as a system extension.
Jordan Petridis’s new
Toolpak
project aims to provide a clean solution for distributing and installing command-line applications that developers need in a cross-distro fashion, similarly to how Flatpak and Flathub work for graphical apps.
Of course, long-term our goal is an OS for the broader public. We’re working on this across a number of different fronts, including:
Enablement for
systemd-homed
across the stack, allowing for stronger per-user disk encryption and other benefits.
Experimental work in the kernel to solve a bunch of limitations we’ve run into with filesystems. Ada Magicat went on a deep dive on her recent
All Systems Go talk
!
Deep integration between
systemd-homed
and the session’s keyring, to increase security of the session’s lock screen. Dhanuka Warusadura gave a
lightning talk at All Systems Go
about his work on this.
A new feature-complete installer, to replace the current placeholder installer. Julian Sparber also gave
a talk about this at All Systems Go
, with a live demo!
Support for delta updates in
systemd-sysupdate
, to avoid downloading a full 2 GB image every time.
Better integration with the TPM, including a graphical TPM recovery UI. Currently, trying to type a TPM recovery key into Plymouth is rather difficult.
Improved support for ARM hardware, including some specific models of phones. Abderrahim Kitouni gave a
lightning talk at GUADEC this year
about the current installation process.
Shipping our pre-installed apps as Flatpaks, and reworking the app release process to unify the build definitions between GNOME OS, the
GNOME Nightly Apps
Flatpak repo, and Flathub.
An STF project focused on Flatpak and Portals, which will enable broader app support on GNOME OS (like VPNs!). You can learn more from the
announcement blog post
.
Some of these areas require lots more work before they’re ready for prime time, and even once they’re ready it’s not clear that it’ll be possible to migrate existing GNOME OS installations to use these new features. At
FOSDEM this year
, we discussed this issue and decided that we won’t declare GNOME OS as “stable” until we can confidently commit to maintaining a clear long-term upgrade path for existing installations.
However, we also don’t think that all these things need to be in place before GNOME OS can be used by more people than it is today. It’s
not
ready for the masses yet, but it is ready for early adopters that aren’t quite adventerous enough to run a nightly OS.
Introducing GNOME OS Preview
GNOME OS Preview is the current GNOME OS Nightly, but without the “nightly” aspect. Instead, it’s built from the latest stable GNOME release (GNOME 51.1, at the time of writing). GNOME OS Preview lives in the same branches on
GitLab
as the stable
org.gnome.Platform
Flatpak runtimes.
GNOME OS Preview is only a few weeks old, so it has only seen limited real-life testing so far. We therefore expect people will uncover some issues initially. That said, Preview is significantly more stable than Nightly, which dozens of people have been daily driving without major issues for over a year. Thus, we’re feeling confident that Preview is going to be reliable enough for daily use by non-developer enthusiasts.
In all likelihood, GNOME OS Preview will be with us for a few years. However,
we are explicitly not promising updates in perpetuity
. If you’re not OK with re-installing your OS in a few years to switch to GNOME OS Stable, this is not for you yet. But if you’ve already been curious about giving GNOME OS a try, this is the moment!
Amateur radio operators from Florida’s Santa Rosa, Nassau, Lake, Pinellas, and Leon Counties played an important role in supporting emergency communications efforts during and following Hurricane Isaias, helping ensure that critical communication capabilities remained available throughout the storm.
In Santa Rosa County, volunteer amateur radio operators staffed the Emergency Operations Center (EOC) and the evacuation shelter at the Milton Community Center. These volunteers provided a communications link between the shelter and the EOC, relaying situational updates and maintaining readiness to support emergency communications should traditional systems become unavailable.
Amateur radio operators across the state also supported auxiliary communications efforts, providing additional capabilities to maintain contact with the State Emergency Operations Center in Tallahassee if conventional communication networks experienced disruptions.
"While traditional communications systems have become significantly more reliable over the years, amateur radio continues to serve as a dependable auxiliary communications resource," said Arc Thames, W4CPD, Santa Rosa County Community Emergency Response Team (CERT) and Amateur Radio Emergency Service (ARES) Program Manager. "When disaster strikes, our volunteers are trained, prepared, and ready to step in wherever we're needed. It's another layer of resiliency that helps protect our communities."
Thames also serves as the ARRL Northern Florida Section Emergency Coordinator and the Amateur Radio Liaison to the Florida Division of Emergency Management, supporting the coordination of amateur radio and auxiliary communications resources statewide.
"During tropical weather events impacting Florida, our Auxiliary Communications team provides volunteer operators to monitor amateur radio communications at the State Emergency Operations Center in Tallahassee," Thames explained. "This ensures that if someone is unable to reach emergency officials through traditional means, we have another way to receive and relay critical information. We always hope we're not needed, but we're glad to be there just in case when all else fails." —
Thanks to ARRL Northern Florida SEC Arc Thames, W4CPD, for the above
The Santa Rosa County, Florida, emergency operations center was
a hub of activity during the response to Hurricane Isaias.
[Photo courtesy Arc Thames, W4CPD]
Online marketplace eBay has imposed
new restrictions on listings of radio transmitting equipment
in response to
new FCC rules
that took effect this week,
but responded to ARRL that its new policy will not apply to gear that operates exclusively on amateur radio frequencies
. The FCC’s rules are intended to use its equipment authorization program to protect against “national security threats to the communications supply chain” and cover a wide variety of products.
In its Third Report and Order issued on July 23, 2026, the Commission makes clear that online marketplaces share in the legal responsibility to assure that unauthorized RF devices are not offered for sale on their platforms. The rules took effect on October 13. Moving forward,
equipment subject to FCC authorization
must have its FCC ID number submitted to the marketplace and posted with its listing. There are exemptions for posts already online, “small sellers,” and used equipment, but initial messages to sellers from eBay suggested that an FCC ID would be required in order to post a listing for any equipment that transmits RF energy.
In response to a request from ARRL for a clarification relating to amateur radio equipment that does not require FCC authorization, an eBay spokesperson provided the following statement:
eBay allows the sale of devices capable of operating only on frequencies that the FCC has allocated for use by Amateur Radio Service licensees. As these devices do not require FCC equipment authorization, FCC IDs will not be required for these listings as an amateur licensee may use his or her license to operate such radios.
However, two-way VHF/UHF radio equipment capable of operating outside of the amateur frequency bands cannot be imported, advertised, sold, or operated within the United States, including on eBay, without an FCC equipment certification.
If eBay inadvertently takes action against listings for devices that don't require FCC IDs and are otherwise authorized, the affected seller should inform eBay and we will assess whether to remove restrictions from the listing.
It should be emphasized that the FCC did not change its underlying equipment authorization rules. Amateur radio equipment, except for commercial HF amplifiers, continues to not require FCC authorization.
The Radio Club of America has brought together both wireless industry
professionals and amateur radio operators for more than 100 years. Each year, it bestows prestigious awards and elevates several members to RCA Fellows. This year, as always, many of those on the list are hams. The award recipients include Dr. Charles C. Counselman, III, W1HIS, who developed technology for making highly accurate GPS positioning widely available; Jay Adrick, K8CJY, who helped develop digital television and serves as Board President of the National Voice of America Museum of Broadcasting; inventor Charles Kirmuss, WØCBK, who developed digital video and audio recording systems for public safety; Carole Perry Young Professional Award winner and electrical engineer Audrey McElroy, KM4BUN, a longtime proponent of youth in amateur radio; Dr. Ajay Poddar, AC2KG, an internationally-recognized leader in radio science and engineering; Dr. Henry Richter, W6VZA (SK), who developed the communications system for Explorer 1, the first US Earth satellite; and Anthony Rizi, NR1Z, a military and cybersecurity professional and college professor who is also active in ARISS, the Amateur Radio on the International Space Station program.
This year’s class of RCA Fellows include amateurs Rachel Jones, KO4HLC; Geoffrey Mendenhall, W8GNM; Nick Pennance, N1CKP, and Dominic “Nick” Tusa, K5EF. The award winners and new Fellows will be formally recognized at RCA’s 2026 Technical Symposium and Awards Banquet in New York City on November 21. Visit the club’s website for a
complete list of awardees
and
their biographies
.
Back in the earliest days of the internet, a whole block of IP (internet
protocol) addresses — beginning with 44 — was set aside for amateur radio use. Most of that block of addresses is still there and is managed by ARDC, Amateur Radio Digital Communications. In December of 2025, ARDC launched 44Net Connect, a service intended to make it easy for hams to begin using
44Net
addresses for such things as experimenting with digital modes, improving repeater infrastructure, setting up a home lab, and more. In the ensuing months, more than 2000 users have signed up and ARDC is now expanding access by doubling its number of “points of presence,” or “PoPs” around the world, adding new ones in Chicago, Los Angeles, and Sydney, Australia (current ones are in Frankfurt, Toronto, and Dallas). A PoP is a physical access point that connects different networks. “The additional PoPs will expand network capacity and bring nodes closer to users in different parts of the world,” explained Rebecca Key, KO4KVG, ARDC’s Communications Manager. “This can shorten the distance data travels, reducing latency, and improving the overall experience.”
“44Net Connect gives licensed hams a simpler way to get a static 44Net IP address without a complicated setup,” adds Key. “We’re seeing it used for everything from personal tinkering to club projects, education, and EmComm.”
You can find more information about 44Net Connect, including how to get started, in ARDC’s
introductory blog post
.
Mel Parkes, NM7P, has resigned as Vice Director of the ARRL Rocky Mountain Division, effective October 10, 2026. Parkes was elected in 2025 to a three-year term that began January 1, 2026. He cited health and personal reasons for his resignation.
Previously, Parkes served as Utah Section Manager for 22 years, from 1999 until 2021.
ARRL President Rick Roderick, K5UR, has appointed Ed James, KA8JMW, of Edgewood, New Mexico, to be the new Vice Director, serving the remainder of Parkes’ term, which runs through December 31, 2028. An ARRL Life Member, James has served in multiple ARRL Field Organization positions, including Section Manager of New Mexico.
ARRL is governed by an all-volunteer Board of Directors. Elections are held annually for five of ARRL’s 15 Divisions, with Directors and Vice Directors serving 3-year terms.
Join
Wayne Greene, KB4DSF, ARRL Director of Education and Learning
, for the October episode of
On the Air Live
on
Tuesday, October 27, at 8 PM Eastern
. Wayne will introduce the fun and benefits of amateur radio contesting, with a special focus on how newly licensed hams can get started.
Contesting is more than chasing points and making contacts. It’s a great way to improve your operating skills, gain confidence on the air, learn about propagation, and become a more effective operator—all while having a lot of fun. Whether you’re interested in casual operating, awards, emergency communications, DXing, or eventually competing in major contests, contesting can help sharpen skills that carry across the hobby. The livestream will air on the ARRL's Learning Center,
learn.arrl.org
.
Preregistration is required and can be accomplished through the Learning Center.
Listen to
ARRL Audio News
, available every Friday. ARRL Audio News is a summary of the week's top news stories in the world of amateur radio and ARRL, along with interviews and other features.
More info
|
Listen on Blubrry
| Also available on iTunes and Apple Podcasts.
On the Air
Sponsored by Icom
Get Ready for Contest Season
ARRL Director of Education and Learning and host of On the Air LIVE, Wayne Greene, KB4DSF, joins the podcast to talk about what goes into an on-air contest, and what you, as a new ham, can get out of participating in one.
More info
|
Listen on Blubrry
| Also available on iTunes and Apple Podcasts.
The following America250 W1AW Portable Activations begin 0000z on Wednesdays, and end 2359z on Tuesdays
(7 days total for each activation). See the complete schedule at
www.arrl.org/america250-was
. Review your award progress and order your certificate and endorsements at
america250.arrl.org
.
10/14/2026 California W1AW/6 (host NZ6Q)
10/14/2026 Georgia W1AW/4 (host AF4DN)
10/14/2026 Missouri W1AW/Ø (host NØAX)
10/21/2026 Arkansas W1AW/5 (host K5DB)
10/21/2026 Alaska W1AW/KL7 (host KTØW)
10/21/2026 Wisconsin W1AW/9 (host W9XT)
10/28/2026 Michigan W1AW/8 (host K8NGW)
10/28/2026 Nevada W1AW/7 (host NØCSM)
The Dog Day Radio Amateur Radio Club, KØDOG, is back on the air from the 1st through the 7th of November.
In observance of International Dog Day in August, the club’s monthlong activities were all about the rescue and responsible care of dogs. In November, operators are calling CQ for one week in recognition of the selfless work of the volunteers, rescuers, veterinarians, shelter staffers and other supporters of animals in need of loving and responsible homes. The event coincides with National Animal Shelter Appreciation Week created by the Humane Society of the US. Listen for KØDOG on the HF bands, using CW and SSB. Share your own stories as adopters, foster caregivers and rescue workers. QSL cards are available for all confirmed contacts and SWLs who send an SASE. Visit
KØDOG on QRZ.com
to learn how you can donate professional services, funds, clean towels and sheets, or some toys and food.
The Nashua Area Radio Society
, an ARRL Affiliated Club,
will be holding its next online Ham Bootcamp on Saturday November 14th from 10 AM to 6 PM Eastern time.
Ham Bootcamp is an online, interactive program to help new, inactive, and prospective hams learn the skills that they need to get on the air. The morning sessions are all about VHF and the afternoon sessions focus on HF. There is no fee to attend Ham Bootcamp.
Advance registration
is requested. Questions may be emailed to
bootcamp@n1fd.org
.
The 21st annual ARRL Online Auction gets under way tomorrow, October 16, and runs through October 22, with more than 200 items up for bid. The
auction preview
is already open.
This year’s selection includes gear from
QST
“Product Review” articles, vintage books, pre-owned equipment, signed original sketches by Salty Walt Hudson, K4OGO, from
Salty Walt’s Portable Antenna Sketchbook
, and four popular mystery boxes contributed by the ARRL Lab team. Featured equipment includes the Icom IC-PW2 solid-state amplifier, Alinco DR-CS10HT 2-meter FM transceiver, and Elecraft KH1 QRP transceiver with the Edgewood package, along with many other items.
Proceeds from the annual auction benefit ARRL education programs, including efforts to license new hams, provide continuing technical and operating education, and develop instructional materials.
All bidders must register on the auction website at
arrl.auctionanything.com
. Your ARRL account username and password will
not
work on the auction site. If you have participated in a previous ARRL Online Auction, you may use your existing auction login information. If you have forgotten your auction User ID or password, click the
Help
tab for instructions. Before bidding, be sure your mailing address and other account information are up to date.
Nominations are open for the 2027 CWOps Award for Advancing the Art of CW
. The purpose of the award is to recognize individuals, groups, and organizations that have made the greatest contribution(s) toward advancing the art or practice of radio communications by Morse code. Candidates for the award may be one or more of the following: Authors of publications related to CW; CW recruiters, trainers, mentors, coaches and instructors; public advocates of CW; organizers of CW activities; designers and inventors who advance the art or practice of CW, and other contributors to the art or practice of CW. The award is not limited to amateur radio operators or their organizations.
Nominations may be made by anyone and must include the nominee’s name, call sign (if applicable), and complete contact information; nominator’s name and contact information, and a detailed explanation supporting the nominee’s qualifications for recognition. Nominations must be emailed by February 15, 2027, to
awards@cwops.org
with a copy to
secretary@cwops.org
. The winner will be recognized with a plaque at the 2027 Dayton Hamvention®.
Six new amateur radio satellites built by three different AMSAT organizations were launched into orbit on October 1, riding aboard SpaceX’s Transporter-18 rideshare mission
. The AMSAT News Service reports that the group includes three PocketQubes from AMSAT-DL in Germany, two satellites from AMSAT-EA in Spain, and another PocketQube from AMSAT Nepal. The spacecraft traveled aboard OSSIE-D, the first orbital transfer vehicle developed by Spanish space transportation company UARX Space. Following separation from the Falcon 9 upper stage, OSSIE-D began deploying its collection of small satellites, giving the worldwide AMSAT community a particularly strong presence on the mission.
The AMSAT-DL “PocketQubes” are satellites measuring just 5 centimeters on each side, intended to promote amateur radio and space technology through open-source communications, telemetry, and other experiments. AMSAT-EA’s two satellites offer voice communication capabilities. HADES-E2 carries a repeater with a 145.925 MHz uplink and 436.888 MHz downlink, while HADES-L features a 10-meter uplink, on 29.472 MHz USB, with an FM downlink on 436.665 MHz. AMSAT Nepal’s SanoSat-2, also a 5-centimeter PocketQube, carries a camera capable of transmitting images as SSDV packets using GFSK modulation, allowing amateurs to receive and reconstruct imagery from orbit. SanoSat-2 can also operate as a digital store-and-forward repeater through which amateur operators can upload messages for later transmission.
ARRL member and Amateur Extra Class operator Brian Daly, WB7OML, has been reappointed to both the FCC's Communications Security, Reliability and Interoperability Council (CSRIC) and the Technological Advisory Council (TAC)
. He has also been selected to continue serving as Co-Lead of the TAC Emerging Wireless Broadband Working Group, which is examining technologies and policies that will influence the future of wireless broadband communications. Daly is an AT&T Fellow and Radio Club of America Fellow. The appointments place him among a select group of experts advising the FCC on issues ranging from communications security and network resilience to emerging wireless technologies and future spectrum needs. Daly says his continued service reflects the longstanding tradition of amateur radio operators contributing technical expertise, innovation, and public service at the highest levels of communications policy and technology development.
Jamboree on the Air (JOTA)
is this weekend, October 17 and 18, and as we’ve been reporting, radio scouting groups are preparing to help Scouts around the world get on the air
. ARRL Puerto Rico Section Public Information Coordinator Angel Santana, WP3GW, reports that multiple amateur radio groups on the island will be working with Scouts from nearly 20 different troops to help them make radio contacts and earn their radio merit badges. According to Santana, this is Puerto Rico’s largest-ever JOTA activation.
ARRL member Carol Laferty Dantzler, K4SAF, of Clearfield, Kentucky, was presented with a plaque on September 26 in recognition of her 69 years as a licensed amateur radio operator
. Carol has been licensed since 1957. She has earned ARRL’s 5-Band DXCC and 5-Band Worked All States awards, as well as the Young Ladies Radio League’s Worked All States - YL award. Carol is also an ARRL card-checker for Kentucky. She was presented with the plaque at the Paintsville, Kentucky, Hamfest by ARRL Kentucky Section Manager
Bob Selbrede, K6ZZ.
Open Positions at ARRL
Come join the headquarters staff of ARRL The National Association for Amateur Radio®! We are currently seeking qualified applicants for the following positions:
Look for improved propagation on the upper HF bands, as both the sunspot numbers and 10.7-centimeter radio flux remain near or above 100. According to NOAA’s Space Weather Prediction Center (SWPC), the increase in activity is being fueled primarily by sunspot Region 4551, which is described as the largest and most complex of six sunspot regions currently visible on the surface of the Sun. Mostly quiet geomagnetic conditions are expected as well, with some disturbances possible late next week.
The Australian Space Weather Forecasting Centre predicts mostly normal HF propagation conditions worldwide.
The W3LPL Propagation Forecast from the
Daily DX
is predicting significantly improved DX conditions on 10 and 12 meters for as many as the next 10 days, with excellent conditions on 17, 15, and 20 meters as well. DX openings on 30 meters should begin in late afternoon each day, followed by 40 meters around an hour before sunset, and 80 meters just after sunset.
Keep listening for DXpeditions and other activity from rare DX locations as stations get tuned up for the CQ World Wide SSB DX Contest on October 24 and 25.
Predicted 10.7-centimeter solar flux: Oct 15, 105; Oct 16, 100; Oct 17-18, 95; Oct 19-20, 100; Oct 21, 105, Oct 22, 100. (Source: NOAA SWPC)
Share
your reports and observations. Send your tips, questions, or comments to
w2vu@arrl.org
.
For more information concerning radio propagation,
visit
the ARRL Technical Information Service,
read
"What the Numbers Mean...," and
check out
the Propagation Page of Carl Luetzelschwab, K9LA.
November 14 |
Montgomery Hamfest
, hosting the ARRL Alabama State Convention, Montgomery, Alabama
December 11 – 12 |
Tampa Bay Hamfest
, hosting the ARRL West Central Florida Section Convention, Plant City, Florida
ARRL -- Your One-Stop Resource for Amateur Radio News
and Information
Join ARRL or renew today!
No other organization works harder to promote and protect amateur radio. Membership supports benefits, services, programs, and advocacy to help you get (and stay) active and on the air. Membership includes access to digital editions of all four ARRL
magazines
:
QST
,
On the Air
,
QEX
, and
NCJ
.
The
ARRL Letter
is available in an accessible format, posted weekly to the
Blind-hams Groups.io
email group. The group is dedicated to discussions about amateur radio as it concerns blind hams, plus related topics including ham radio use of adaptive technology.
On the Air
. Published bimonthly for newer hams, featuring introductions to popular activities and key concepts, equipment buying guides, and practical projects with step-by-step instructions — all in language that’s easy to understand.
NCJ -- National Contest Journal
. Published bimonthly, features articles by top contesters, letters, hints, statistics, scores, NA Sprints, and QSO parties.
QEX -- A Forum for Communications Experimenters
. Published bimonthly, features technical articles, construction projects, columns, and other items of interest to radio amateurs and communications professionals.
Free of charge to ARRL members...
Subscribe
to the ARES
®
Letter (monthly public service and emergency communications news), the NTS
®
Letter (monthly news about the ARRL National Traffic System message-relay network), the ARRL Contest Update (biweekly contest newsletter), Division and Section news alerts, and much more!
The ARRL Letter is published on Thursdays, 51 times each year. ARRL members may subscribe at no cost or unsubscribe by editing their profile at
www.arrl.org/opt-in-out
.
For many years, Codeberg Pages v2, our in-house solution, served as a way for hosting project pages through
your_codeberg_username
.codeberg.page or custom domains. This project has been unmaintained for a longer time now, and we already have git-pages as a replacement to power Codeberg Pages. A lot of users already migrated - and now it is time for you to also make the switch, if you have not done already.
Codeberg Pages v2 will be shut off completely on
2026-12-31
On that date, for users who are still relying on the old way of hosting sites through Codeberg Pages v2 (which is the case for users who never set up a webhook in their repository), the content will not be served anymore.
Before that date make sure to migrate.
We already have instructions how to do so. So please refer to our
Migration Guide
for migrating.
Unsure if you are on git-pages?
If you do not remember whether you migrated or not, you can test yourself by using our
Migration Check Tool
. Just paste an URL and get a definite answer.
Ubuntu 26.10, codenamed "Stonking Stingray", has now arrived. Building
on the foundations of Ubuntu 26.04 LTS, this release continues to
advance security, performance, and hardware support while introducing
new capabilities that look towards the future of Ubuntu. As always, these
improvements are the result of close collaboration between the Ubuntu
team, our community, and our partners.A huge thank you to all who
contributed. Here's a rundown of what's new.
Ubuntu 26.10 brings significant progress for security, and strengthens
the platform with the full adoption of Rust-based coreutils,
post-quantum-ready package signing, and expanded TPM-backed full-disk
encryption support. Enterprise authentication gains deeper integration
with Microsoft Entra ID, including password and multi-factor
authentication. Linux kernel 7.3 extends support for the latest hardware,
alongside new RISC-V desktop images and optimized amd64v3 installation
images.
On the desktop, GNOME 51 brings improvements to responsiveness,
accessibility, and usability, complemented by more consistent software
management and greater resilience under memory pressure. Ubuntu 26.10 also
introduces Myna, an opt-in, locally processed speech-to-text solution that
marks the first step towards a more natural, context-aware desktop
experience. With updated developer toolchains and expanded support for
accelerated AI workloads, Ubuntu 26.10 continues to evolve Ubuntu as a
secure, capable, and forward-looking open source platform.
The newest Edubuntu, Kubuntu, Lubuntu, Ubuntu Budgie, Ubuntu Cinnamon,
Ubuntu Kylin, Ubuntu MATE, Ubuntu Studio, Ubuntu Unity, and Xubuntu
are also being released today. For more details on these, read their
individual release notes under the Official flavors section:
https://documentation.ubuntu.com/release-notes/26.10/#official-flavors
Maintenance updates will be provided for 9 months for all flavors
releasing with 26.10.
To get Ubuntu 26.10
-------------------
To download Ubuntu 26.10, visit:
https://ubuntu.com/download
Users of Ubuntu 26.04 will be offered an automatic upgrade to
26.10 if they have selected to be notified of all releases rather than
just LTS upgrades. For further information about upgrading, see:
https://documentation.ubuntu.com/desktop/en/latest/how-to/upgrade-ubuntu-desktop/
As always, upgrades to the latest version of Ubuntu are entirely free
of charge.
We recommend that all users read the release notes, which document
caveats, workarounds for known issues, as well as more in-depth notes
on the release itself. They are available at:
https://documentation.ubuntu.com/release-notes/26.10/
Find out more in the Press Release below:
https://ubuntu.com/blog/canonical-releases-ubuntu-26-10-stonking-stingray
If you have a question, or if you think you may have found a bug but
aren't sure, ask in any of the following places:
https://matrix.to/#/#support:ubuntu.comhttps://discourse.ubuntu.com/supporthttps://lists.ubuntu.com/mailman/listinfo/ubuntu-users
Help shape Ubuntu
-----------------
If you would like to help shape Ubuntu, look at the list of ways
you can participate at:
https://documentation.ubuntu.com/project/community/contribute/
About Ubuntu
------------
Ubuntu is a full-featured Linux distribution for desktops, laptops,
IoT, cloud, and servers, with a fast and easy installation and regular
releases. A tightly-integrated selection of excellent applications is
included, and an incredible variety of add-on software is just a few
clicks away.
Professional services including support are available from Canonical
and hundreds of other companies around the world. For more information
about support, visit:
https://ubuntu.com/support
More information
----------------
Learn more about Ubuntu and about this release on our website:
https://ubuntu.com
To sign up for future Ubuntu announcements, subscribe to Ubuntu's
very low-volume announcement list at:
https://lists.ubuntu.com/mailman/listinfo/ubuntu-announce
On behalf of the Ubuntu Release Team,
Utkarsh Gupta
Quantum computers will need carefully designed circuits to run useful algorithms on limited hardware. We gave Claude plain-language specifications for eight such circuits, drawn from chemistry, optimization, physics simulation, and number theory, along with an automated evaluator that checks and scores each design. Working largely on its own, Claude found designs that improve on the best published circuits, in some cases by an order of magnitude or more. Such improvements substantially reduce the quantum resources that useful applications require, so practical quantum computers could arrive sooner than previously anticipated.
This work was led by Andi Gu as part of Anthropic’s STEM Fellows Program, with mentorship from Alek Kemeny, a quantum physicist at Anthropic, in collaboration with Susanne Yelin (Harvard University) and Mikhail Lukin (Harvard University and QuEra Computing).
Read the full paper on arXiv
.
Unlike classical computers, which store information in bits whose value is either 0 or 1, quantum computers store information in
qubits,
which can be built from single atoms, superconducting circuits, or particles of light. These qubits make use of quantum phenomena such as
superposition
—which allows a quantum system to exist in a combination of states at once—in order to process information in ways that could make certain problems in fields like chemistry, materials science, and number theory tractable, even when they are too hard for traditional computers.
The quantum computers the field has built to date only have hundreds to thousands of qubits—too few to run many of the algorithms that promise practical advantages over classical computers. And these qubits are highly sensitive to environmental noise, such as heat, vibration, and even cosmic rays. A tiny disturbance can nudge a qubit’s state, and these small errors pile up until the computer gives the wrong answer.
Given that both qubits and computing time are scarce resources, researchers have been working to redesign quantum algorithms to use fewer qubits and complete computations in less time. An illustrative example is simulating FeMoco, the iron–sulfur cluster at the heart of nitrogenase, the enzyme that bacteria use to turn nitrogen from the air into ammonia. Understanding how it works could help scientists design better industrial catalysts—the substances manufacturers use to speed up chemical reactions.
In 2017, researchers estimated that a quantum computer would need about 50 trillion Toffoli gates to compute FeMoco’s ground-state energy—the energy of its most stable configuration, which chemists need in order to predict how FeMoco reacts. (Similar to ordinary computers, quantum computers work by applying a long sequence of simple operations, called gates, to their qubits. The Toffoli gate is one of the most expensive gates to run, so counting Toffoli gates is a standard way to estimate how long a computation will take.)
Through a series of algorithmic advances, the estimated number of gates has come down to about 340 million—a roughly 150,000-fold reduction, corresponding to a few hours of computation on a future machine with about three million physical qubits.
1
These reductions largely came from redesigning the circuits that carry out the computation, rather than from making better hardware. Claude has proven particularly adept at optimizing
classical
algorithms
, so we wanted to see whether it could do the same for quantum algorithms if it were given only a plain-language description of what each circuit must compute.
Claude is unusually well suited to this task, for several reasons. First, quantum algorithms are implemented as quantum
circuits
. These are composed of sequences of gates, like the Toffoli gates mentioned above. Importantly, these circuits can be described in code, so we can make use of Claude’s coding capabilities to write, run, and revise circuit designs as ordinary programs. Second, the (fairly common) class of quantum algorithms we were most interested in optimizing can be tested efficiently for correctness, as each input gives one definite output that an ordinary computer can check. This means we could have an external evaluator program validate Claude’s proposals. Finally, we can give Claude a clear, objective score to improve: the number of qubits used, multiplied by the number of gates, which serves as a proxy for how long the circuit would take to run.
We found that Claude Mythos 5 could successfully work in a closed loop, proposing a circuit design, receiving feedback and a score from the evaluator program, and using that feedback to improve its next attempt, with no human input between rounds (see Figure 1). Across eight computational primitives—the basic routines that larger quantum algorithms are built from—for chemistry, optimization, quantum simulation, number theory, and numerical computing, Claude discovered novel designs that used both fewer qubits and fewer gates than the best previously published algorithms (Figure 2).
In each case, the improvement resulted from uncovering new structural and mathematical insights about the problem, rather than from fine-tuning existing designs. For example, when compiling a circuit for simulating an iron-sulfide molecule, Claude noticed that the molecule’s symmetries and repeating structure meant that some results could be calculated once and reused, rather than recomputed for every part of the system. In other cases, it found that existing circuits included costly components that were needed to handle only extremely rare inputs, and it redesigned them without those components.
Below, we describe two of Claude’s discoveries. The first is a new way to perform modular inversion, a bit of arithmetic that is the most expensive step in elliptic-curve calculations. The second makes the costliest step of a leading quantum optimization algorithm about 12x cheaper.
These results suggest that AI can now help redesign quantum circuits, a key step in making quantum algorithms faster and easier to run. Faster circuit design could bring the problems quantum computers are meant to solve—from designing new medicines and better batteries to finding cleaner ways of making fertilizer—within reach sooner.
Figure 1: Closed–loop quantum circuit optimization. Claude designs new implementations in Python, which are then sent to a programmatic evaluator. The evaluator checks whether the proposed implementation is correct, then scores it on the number of qubits and gates it requires. This information is then sent to Claude, which uses it to improve its implementation. The code and values shown are illustrative.
Figure 2: Claude designed smaller and faster circuits across eight different quantum-circuit design tasks. Gray marks show the best previously published designs; orange marks and lines show Claude’s designs. Point addition, the eighth task, is compared in Table 1 below.
A new reversible algorithm
Designing a quantum circuit involves two constraints that ordinary programming doesn’t have. The first is that a quantum circuit can’t make “if-then” decisions the way an ordinary program can. An ordinary program can check a value and then run only one of two pieces of code. But a quantum computer runs on a superposition of many inputs at once, some of which would run the first piece of code and some of which would run the second, so the circuit has to include the operations for both every time it runs.
The second is that a quantum circuit can’t discard information. An ordinary program can overwrite or delete its scratch work once it’s completed it; in a quantum computer, such intermediate information can’t simply be erased, because every step of a quantum circuit must be reversible. Leaving that information in place isn’t an option, either, because leftover scratch work would corrupt the final result. The only way to discard information is to “uncompute” it by running the computation that created it in reverse, at the cost of additional gates. Both of these constraints make quantum circuits far more expensive, in both runtime and qubits, than their classical counterparts.
This constraint forces a difficult trade-off between space (i.e., qubits) and time. At one extreme, a quantum circuit can uncompute intermediate results as soon as they have been used. This frees up qubits, but if those same results are needed again later, the circuit must recompute them, which adds gates and increases the runtime. At the other extreme, the circuit can retain intermediate results until they’re no longer needed. This avoids repeating work, but it can require many more qubits.
This is what makes quantum circuit design an especially interesting test of Claude’s capabilities. The circuits can be written as ordinary code, but improving them requires the model to reason under a set of constraints quite unlike those of ordinary programming.
A hard first test: modular inversion
The first task we gave Claude was point addition, a rule for combining two points on a mathematical curve (an elliptic curve) to produce a third. Point addition is the core step in quantum algorithms for the discrete logarithm problem on elliptic curves: given a starting point and the result of adding it to itself
n
times, find
n
. For large curves, ordinary computers can’t solve this problem in any reasonable amount of time, but a sufficiently large quantum computer could.
These algorithms perform point addition many times over, including in reverse, and these additions account for most of their qubit and runtime costs. Problems like this—easy to compute, extremely hard to reverse—were among the first where quantum computers were shown to offer an exponential speedup over ordinary ones. For these reasons, point addition has become one of the field’s standard benchmarks. This made it a demanding test for Claude. So, we asked it to map out how few qubits, as well as how few gates, point addition really needs.
We gave Claude a one-paragraph brief. It explained the mathematical rule for point addition, and how the evaluator would check each proposed circuit for correctness and score it on the number of qubits and gates it used. It also instructed Claude to explore several approaches in parallel. After working for 53 hours with minimal human input (limited to the initial brief and occasional prompts to think more broadly), Claude arrived at a completely new approach to the problem.
The memory demands of divsteps
Most of the cost of point addition comes from a single step, called
modular inversion
. Elliptic-curve arithmetic uses numbers that wrap back around when they reach a fixed limit. Modular inversion is the wraparound version of division: given an integer
a
, find
x
such that
ax
≡ 1 (mod
p
). Ordinary computers can perform this operation efficiently using a method called
divsteps
. Divsteps starts with a pair of numbers and repeatedly simplifies them over many rounds of iteration. In each round, divsteps examines the current pair of numbers and conditionally swaps, adds, subtracts, or halves them. Along the way, it preserves just enough information to produce the modular inverse at the end.
Despite its success on ordinary computers, divsteps had not yet produced a practical quantum circuit, because of the reversibility constraint described above. The record of which operation was chosen at each iteration, called
branch information
, is the kind of scratch work that a traditional program can simply discard. In contrast, a quantum circuit has to retain that record so the computation can be run backward. A straightforward quantum version of divsteps is therefore forced to accumulate a long history of branch information, which requires an enormous number of additional qubits to store.
How Claude got around the memory problem
Claude recognized that this divsteps approach could be promising for quantum circuits, but only if there were a way around needing to store the full history. It had an idea: perhaps the record didn’t need to be stored at all. Claude reasoned that it might be possible to directly infer (or “decode”) the branch information by carefully inspecting the pair of numbers after each iteration. In essence, the numbers themselves would store the record. The circuit could then be run backward without needing any extra qubits.
To test this idea, Claude explored a number of simple candidate rules for performing the decoding. These early rules worked on small test cases, but they failed when Claude tested them at the full problem size, on 256-bit numbers.
Claude then tried a more theoretical approach. Rather than guessing and testing rules, it set out to understand mathematically why divsteps behaves the way it does. It proved a series of results about the iteration process, including several new algebraic identities. From these identities, Claude derived a precise formula for the decoding rule that would correctly recover the branch information from the numerical pairs. It then checked the formula, first by running it through large-scale numerical simulations, and then formalizing the claim in Lean. With the full validation complete, Claude produced the first reversible implementation of divsteps with no stored branch history.
A family of designs
Decoding saves qubits, but it costs time. So, as a further refinement, Claude looked for situations in which it would be cheaper to store the branch information than to decode it. By varying the threshold at which the circuit stores rather than decodes the branch information, Claude produced a new family of designs between the two extremes. Compared with the smallest previous design, one circuit in the family uses 12% more qubits but 17x fewer gates. More generally, the new designs expand the Pareto frontier, offering combinations of qubit count and runtime that weren’t available before (Table 1).
Table 1: Resources for elliptic-curve point addition. Bold rows are Claude’s designs; the others are the best previously published designs. Sources:
Schrottenloher
(2026),
Luo et al.
(2026).
Optimizing a quantum optimizer
Optimization problems are at the heart of a wide range of tasks, including scheduling, logistics, and materials design. An optimization problem presents a set of competing constraints and asks for the solution that satisfies as many of them as possible. Many quantum algorithms have been proposed for problems like these, but most promise only modest or uncertain gains over ordinary computers.
Decoded quantum interferometry (DQI)
is one of the strongest candidates for offering a
superpolynomial quantum speedup—
an advantage that rapidly widens as the problems get larger.
When a quantum computer finishes a computation, reading out its qubits produces just one answer, selected at random from the possibilities they were holding in superposition. DQI works by preparing a quantum state in which good solutions are more likely to be read out than bad ones. Doing this involves using an error-correcting decoder, which recovers a short list of “errors” from a compact summary. This is the most expensive step in the algorithm. So, if we could make a faster decoder, we could also perform DQI faster.
A more efficient quantum decoder
The researchers who introduced DQI demonstrated it on a problem called
optimal polynomial intersection
(OPI), a grid-based version of curve fitting (Figure 3). Imagine a grid in which each position
x
contains several acceptable values of
y
. The goal is to find a simple curve (a low-degree polynomial) that passes through an acceptable square for as many
x
positions as possible. DQI tackles this optimization problem using a specific type of decoder, called a Reed–Solomon decoder.
Figure 3: Optimal Polynomial Intersection (OPI) as discrete curve fitting. Each column contains several acceptable values. The optimization problem is to find a polynomial that passes through as many of the acceptable values as possible.
Reed–Solomon decoding starts from the compact summary of errors mentioned above, which is known as a
syndrome
. The decoder’s job is to infer, from this summary, where in the data the errors occurred and what they were. The previous state-of-the-art quantum circuit processed these syndromes using the extended Euclidean algorithm, a sequence of divisions and swaps in which the number and order of steps depend on the particular input it’s given. Here, the constraints of quantum circuits reemerge: while an ordinary program can follow a different path for every input, a quantum circuit, working on many inputs at once, has to handle all of them with a single fixed sequence of gates. To manage this, the previous design had to stretch the computation over many more rounds of iteration than any single input would need, and had to run every operation in every round, even when doing so was unnecessary.
Improving this decoder could substantially reduce DQI’s runtime. Estimates by researchers at
Google Quantum AI
imply that solving one particular OPI problem would take about three months on
Frontier
, one of the world’s most powerful supercomputers, compared with roughly an hour on a future quantum computer running DQI. Most of that hour would be spent on Reed–Solomon decoding.
So, we asked Claude to design a more efficient quantum circuit for the decoding step. Claude quickly concluded that the extended Euclidean algorithm was a poor fit for a quantum circuit. Instead, it organized its circuit around a different decoding method, known as Berlekamp–Massey decoding, which reads through syndromes (summaries of errors) one at a time and gradually works out the simplest rule that predicts each number in the list based on the ones that came before it. Once that rule is found, it reveals the errors. Unlike the extended Euclidean algorithm, Berlekamp–Massey performs the same kind of step in every round and always runs the same number of rounds, which suits a quantum circuit’s single fixed sequence of gates, ultimately giving Claude a much more efficient foundation to build on.
A simplified approach to storage
Switching to Berlekamp–Massey removed the need for the circuit to take different paths for different inputs. But making it reversible introduced another challenge, this time as a result of the uncomputing constraint discussed above. In every round, the circuit calculates temporary values that it needs only briefly, but this information can’t simply be deleted: to uncompute it later, the circuit has to be able to recover that information.
Storing this information would have been prohibitively expensive. So Claude took the same kind of approach as it had for divsteps: it found a way to reconstruct most of this information from the circuit’s current state, so it didn’t need to be stored. However, a few exceptional values couldn’t be recovered in this way and had to be saved.
Setting aside enough memory for the worst possible case, in which an exceptional value arises in 35 different rounds, would take 665 qubits. Instead, Claude wrote a high-speed simulator and ran 403 million sample decodings to measure how often these exceptions actually occurred. Almost every run needed to save one value at most. So Claude’s circuit sets aside room for just one saved value, or 19 qubits. About one run in 10,000 needs more than that and fails, which is well within the error rate the task allows. These improvements replaced large, worst-case reserves with a small, fixed number of qubits and gates (Figure 4).
Together, these optimizations reduced the number of gates in the decoder by a factor of 12 relative to
Google’s previous construction
. The improvement came from redesigning the computation at three levels: a different method (replacing the extended Euclidean algorithm with Berlekamp–Massey decoding), a different circuit architecture (reconstructing temporary values instead of storing them), and a different resource budget (measuring precisely how much memory and computation the circuit really needed). No single change would have been enough on its own, but together, they make the most expensive step of DQI just a little over an order of magnitude cheaper.
Figure 4: Three designs for the locator step of the Reed–Solomon decoder. The designs are drawn to scale: each block’s width is proportional to its gate count. (a) The previous design, based on the extended Euclidean algorithm (Khattar et al., 2025). (b) A design based on Berlekamp–Massey needs far fewer gates, but a naive reversible version has to store a 12-qubit record in every round, adding up to 840 qubits. (c) Claude’s circuit reconstructs most of the history from the updated state, so it needs to have room only for a single saved value of 19 qubits.
What we learned
Scientific progress often comes from making theoretical ideas practical. One of the main ways this happens is by making a process that was once thought to be impractical fast and cheap enough to carry out. Quantum circuit design is a prime example: the 150,000-fold drop in the FeMoco estimate described above took many research groups eight years, with each step typically representing months of work. By contrast, Claude’s elliptic-curve design was the result of a single 53-hour run.
Our results suggest that AI can support the work of circuit design, producing implementations that bring useful quantum computations closer to the capabilities of real hardware. If AI can speed up that work, useful quantum computing could arrive sooner.
Despite Claude’s encouraging performance on these tasks, we also observed some limitations. In our early experiments, Claude was conservative by nature. It repeatedly second-guessed apparent improvements, and sometimes continued to double- and even triple-check results that were already well supported. This caution was sometimes valuable: for example, it prompted Claude to write Lean proofs to verify its divsteps design. But it also manifested in a tendency to prefer existing, well-known approaches to more novel ones.
We took two steps to mitigate this. First, our setup required Claude to propose several qualitatively different approaches, and to develop them in parallel. Second, we also occasionally prompted Claude to broaden its search. These interventions succeeded in getting Claude to pursue more ambitious ideas. The elliptic-curve result, for example, didn’t come from shaving gates off of a pre-existing design but from exploring a method of doing reversible modular inversion that hadn’t been possible previously, and then deriving the mathematical results needed to make it practical. Once it had come up with the idea, Claude developed the approach, implemented it, and verified its correctness autonomously.
Circuit design is only one part of building a useful quantum computer. Because qubits are so fragile, the machine must also catch and fix its own errors as it runs, and that depends on many other components, ranging from error-correcting codes to fast decoders to control of the hardware itself. These components all affect one another, but to manage complexity, each is usually designed separately. Many of them share the characteristics that made circuit design a good fit for Claude: a design can be written as code, checked for correctness, and scored by its cost.
This raises an intriguing possibility. Rather than designing each component on its own, AI could optimize all of them jointly, from the algorithm down to the hardware, to build an entire error-corrected quantum computer tailored to a specific problem. Such designs could also tell hardware builders which capabilities matter most for a given application. That could put problems such as designing catalysts and understanding new materials within reach of the first fault-tolerant machines.
Acknowledgments
We thank Arjun Kar and Vinay Ramasesh for helpful discussions in the early stages of the project.
Related content
Claude reveals ECDSA curve origins
The decades-old mystery of the origins of one of the most popular cryptographic standards has been explained.
AI models may be capable of self-replicating without access to a datacenter
Our experiments suggest that small AI models may be only months away from being capable enough to self-replicate on commercial IoT devices, like Android TVs and smart ovens.
Strengthening our defenses against distillation attacks
Illicit distillation allows model developers to copy frontier AI capabilities without creating proportionally robust safeguards. Here, we describe how we’ve reduced the rate of distillation by more than 90%.
The Geocities Animated Gif Search from Internet Archive
GifCities is a special project of
Internet Archive
, a non-profit digital library of millions of free books, movies, software, music, websites, and more. Please consider
donating
to help us in our efforts to provide “Universal Access to All Knowledge” including GIFs.
I am a LegalTech Attorney leading a developer team from Costa Rica. While trying to load credits onto my Anthropic API account (claude.com), I experienced a critical internationalization (i18n) and UX failure that has placed an unfair financial burden on me due to a severe oversight in their payment pipeline.
The platform prompted me for a payment. Since I am in a Spanish-speaking region where localized systems and keyboards handle dots and commas differently, I typed 5.04.
Anthropic’s input system completely failed to sanitize or validate the data. Instead of throwing a formatting error or converting it properly, it silently stripped the decimal internally and instantly charged my credit card $504.00 USD instead of $5.04 USD.
To make matters worse, there was no confirmation modal or review screen summarizing the final amount before processing the transaction. It was a single-click, instantaneous overcharge.
Anticipating the Obvious Skepticism:
Before anyone suggests "you should have checked your regional settings" or "just wait for the chargeback":
1. Users are not the QA team: In financial software, a system is never supposed to guess or automatically manipulate a numerical input without explicit validation. If an input is ambiguous due to locale differences, the application must reject it or ask for clarification, not execute a 100x overcharge.
2. Scale of the vulnerability: This time it was $504.00, which is an unfair and frustrating burden for independent developers. But because this pipeline completely lacks a confirmation screen and basic input sanitization, the exact same bug could happen to someone typing 50.00 and end up charging them $5,000.00 or more instantly. It is a systemic financial risk.
3. The Chargeback Illusion: Yes, I have already initiated a chargeback with my bank in Costa Rica. However, banking processes here are slow and take up to 120 days to resolve. In the meantime, the $504.00 has already been deducted and charged to my credit card statement. I am forced to pay for Anthropic’s engineering mistake out of my own pocket right now.
The Support Wall:
I filed an official complaint on the exact same day, minutes after it happened. I wasn't met with a human; I was blocked by an automated support BOT. The bot repeatedly and rigidly denied the refund, closing the ticket by citing generic policies without a single human ever looking at the fact that the overcharge was caused by a technical bug in their own platform.
As developers, we build systems that process people's money. Omitting a confirmation screen on a financial transaction, failing to sanitize localized numerical inputs, and then hiding behind unyielding AI support bots to keep money that doesn't belong to you is completely unacceptable.
If anyone from Anthropic's billing or engineering team is reading this, please look into this bug and review my case. It is a critical flaw that is actively harming international developers who are just trying to build on your ecosystem.
Before August Sander and Diane Arbus and Olan Mills, before Facetune and duck face, there were two: a shoeshine boy and his client, captured by Louis Daguerre on the Boulevard du Temple in 1838, in what is thought to be the first photograph to depict human beings. The bootblack squats beside a chest containing the tools of his trade. The patron stands, hands clasped behind his back, with a foot perched on the box. We know it’s spring, because the leaves are coming in on the plane trees. The two were hardly the only people out that day on the bustling stretch of cabarets. But they were the only people who held still long enough to be captured by Daguerre’s curious new machine, which required an exposure time of up to ten minutes. The next year, presenting the daguerreotype to the Assemblée Nationale, the physicist François Arago noted, “In this genre, it’s the unforeseen that one must count upon.” Soon, the French state would buy the rights to the invention and offer it as a free gift “to the world.” The names of the boy and his client were never recorded, but they live on as the accidental embodiment of photography on the brink of conquering the world.
One night in 2024, Maximilien Van Aertryck went out for drinks with his colleagues Axel Danielson and Kalle Boman. Van Aertryck is a producer who works with the Swedish filmmaker Ruben Östlund and has co-directed a documentary about the history of image-making. In other words, he knows a lot about photography. He had always loved the Daguerre picture: “It’s so poetic, with those two lonely people on that huge frame.” As he and his friends drifted out of the café, they crossed the Boulevard du Temple. It was June. The trees were nearing lushness. “We were, like, ‘Wait a minute! It must have been taken somewhere around here!,’ ” Van Aertryck recalled, visiting the area the other day. They punched a few keywords into Google, and found some articles, “in pretty big newspapers,” surmising that the photograph might have been snapped near the Filles du Calvaire Métro stop. “We knew immediately that there was no way it was there,” Van Aertryck said. “If you look at the photo, it just doesn’t make sense. So we went home and went to bed, promising that we’d meet at the same place at eight the next morning, and we’d figure this out.”
“Just like a Cro-Mag to bring a club to a rock fight.”
Cartoon by P. C. Vey
Thus began an eighteen-month quest to pinpoint the exact location of the shot, involving everything from archival research to drones to very long measuring tapes. It wasn’t easy. For one thing, Baron Haussmann had demolished swaths of the neighborhood in the mid-eighteen-hundreds to create the Place de la République. Van Aertryck and his colleagues turned to prints, paintings, real-estate registers, and topographical maps to re-create Daguerre’s environs, but these pre-photographic renderings had their limits. “We kept just finding engravings of one particular building, because some emperor got shot there,” Van Aertryck recalled. Both Daguerre’s workshop, on what is now Rue Léon-Jouhaux, and a theatre that he owned, called the Diorama, burned in 1839. “No one, not even the biggest nerds who have researched this,” can agree on where, exactly, Daguerre took the photograph, Van Aertryck said, but he and his team were able to determine that three buildings from the era are still standing today. They brought their findings to an architectural firm, which used a 3-D scan of the entire square to triangulate the shoeshiner’s location. Another architectural firm, using the same data, homed in on a point just a few feet away. “We decided to split the difference,” Van Aertryck explained, scuffing his shoe over a red “X” that had been painted on one of the paving stones, not far from some wads of gum. “A colleague ran out to buy nail polish to mark the spot!” he explained.
For nearly a century, the Bavarian National Museum, in Munich, possessed a photographic plate of the image, which Daguerre had sent to King Ludwig I, but it was badly damaged by restoration efforts during the Second World War—the only remaining physical trace of “Boulevard du Temple” is a photo of the photo that the
MoMA
curator Beaumont Newhall took in the nineteen-thirties. On October 15th, however, the City of Paris will unveil a plaque commemorating the shoeshine pair—an “unforeseen” detail, the world’s first photographic portrait sitters and the original photobombers at the same time. “I hope people will make it theirs and embrace it as the starting point for something,” Van Aertryck said. May it spawn a million selfies. ♦
Zero-click attacks used targeted ads to deliver Candiru spyware
Bleeping Computer
www.bleepingcomputer.com
2026-10-16 13:20:03
Candiru spyware was delivered to devices at Al Jazeera Media Network via targeted online advertisements in a zero-click attack that required only rendering the malicious ads on the victim's device. [...]...
Candiru spyware was delivered to devices at Al Jazeera Media Network via targeted online advertisements in a zero-click attack that required only rendering the malicious ads on the victim's device.
Researchers at Citizen Labs investigating the attacks referred to this technique as AdFection, noting that their report is the first public technical confirmation of mercenary spyware delivered through targeted ads.
A similar method was documented in late 2025 by Amnesty International, involving ads that infected targets with Predator spyware without them clicking anything.
That infection mechanism was
called Aladdin
and surfaced due to a collection of marketing files and documents leaked from the Intellexa surveillance company that researchers studied and corroborated with technical details from forensic investigations.
Unlike Alladin, AdFection was caught in real attacks and linked to Israeli firm Discovere-Tech, described by Citizen Lab as " a bridge between mercenary spyware companies and the advertising ecosystem."
Ads participating in AdFection
Source: Citizen Lab
Zero-click Candiru spyware infection
According to Citizen Lab, Discover-Tech allowed its customers to use its Controlium platform to target specific devices with malicious code, or profile, deanonimize, and fingerprint user devices.
"Discover-Tech appears to work with multiple mercenary spyware, hacking, and advertising vendors, connecting the spyware industry to the online advertising ecosystem,"
Citizen Lab says
.
The company purchased ad placements through mainstream ad networks and exchanges, embedding JavaScript in ads that contacted its "NOAS server" when rendered.
Using multiple parameters (e.g., IP address, ad identifiers), the NOAS server, "or getAd server," determined if a target was eligible to receive JavaScript code.
Selected targets received additional code, while other devices the ad rendered on received nothing, helping keep the attacks stealthy.
Action sequence for valid targets
Source: Citizen Lab
Al Jazeera provided Citizen Lab with evidence of attacks that targeted at least 45 devices between 2024 and 2025. The network logs examined by the researchers showed a sequence from Discover-Tech infrastructure to Candiru validation servers and then to spyware command-and-control servers.
The researchers also recovered a DLL file from a compromised Windows system and attributed it with high confidence to Candiru, based on infrastructure and code overlaps with previously captured samples.
Candiru is an
Israeli spyware vendor
that sells surveillance tools, officially only to governments. The company also developed malware for Windows called
DevilsTongue
, which can steal files, credentials, and messages.
According to
past reports
, its tools have been deployed through Windows and Chrome zero-day exploits against journalists, activists, politicians, and other targets.
Candiru attack chain
Source: Citizen Lab
While Al Jazeera is one confirmed target of these attacks, Citizen Lab reports that the advertising operation placed 3.77 billion bids and won 442 million auctions between March and June 2026.
Ads assessed to carry attacker script tags appeared across 75,373 Android/iOS apps and 120,768 websites, although these figures do not represent infection counts.
“We estimate that between hundreds of thousands and millions of users were directed to these domains via Discover-Tech ads,” explains Citizen Lab.
After receiving Citizen Lab's reports, major advertising companies like Google, IAB Europe, Beeswax, Eskimi, and Vungle took action to remove offending accounts and block access to domains.
Piramidal is looking for a backend engineer to help build and scale the infrastructure behind our real time neural monitoring platform. You'll work on hard problems: high throughput streaming, real-time analytics, and hospital grade reliability.
This is a full-time role based in our New York office (5 days a week), with required travel to client sites. Candidates must have US work authorization.
In this role you will
Build and run Python and Go services that consume, transform, and serve real-time streams of neurological data.
Design, maintain, and improve data models, ingestion pipelines and retention for high frequency time series data, from raw neurological data, to all time series derived from it.
Build and extend the APIs behind clinical workflows.
Work with ML engineers to take models from research to production inference, and keep them running there.
Make the platform observable and dependable: metrics, alerting, capacity planning, and incident follow-up.
Help build software to the standards of a regulated medical device, including cybersecurity, traceability and change control.
Your background looks something like
5+ years of building and operating backend systems in production
You can own a problem from an ambiguous start to a running, monitored service, and you can explain your decisions verbally and in writing.
Real experience with event-driven or stream-processing systems: partitioning, checkpointing, backpressure, and at-least-once delivery.
Strong Python, including concurrency (threads vs. processes, asyncio) and testing.
Proficiency with containerization and orchestration, preferably using kubernetes.
Solid relational database skills, from schema design to query performance.
Nice to have
Go, especially for networked or low-latency services.
Azure: Event Hubs, Service Bus, Web PubSub, Blob Storage, AKS.
Apache Arrow, Parquet or other columnar formats.
Video streaming, storage, and processing
Systems where sub-second latency matters.
Data engineering or warehousing at scale.
Model serving (PyTorch)
Work in healthcare or other regulated software.
About Us
We are building a first-of-its-kind foundation model for electrophysiological brain data. Our goal is to create scaled neural decoders that enable humans to understand and interact with the language of the brain. Our first product brings a state-of-the-art model into real time clinical workflows, helping clinicians detect and respond to seizures faster.
Compensation & Benefits
Base salary range: $250,000 – $300,000, depending on experience and skills.
Meaningful equity plan.
Comprehensive health coverage, including premium medical, dental, and vision plans.
Daily lunch budget.
Interview Process
Initial Screen
(30 min): Discussion to ensure timelines, experience, and expectations align.
Technical Screen
(1 hour): via Google Meet
Final Round (in person)
:
Coding Problem (1 hour)
System Design (1 hour)
Product Session (1 hour)
Questions (20 minutes)
90% of US working hours are spent on tasks not covered well by AI benchmarks
Each tile represents one of the
923
O*NET occupations making up the US labor force, grouped into
22
job families. Occupations are shaded according to the share of their tasks which are represented in our initial list of AI benchmarks. A single benchmark prompt can be mapped to multiple O*NET tasks.
click a family to open it
Coverage by
Covered with at least
Benchmark Index
No coverage
In our data set: only
208
of
923
occupations have a task with at least
5 benchmark prompts
, and
6
of
22
job families have no such occupations.
Our findings suggest that
90% of American working hours are spent on tasks with little or no coverage from existing benchmarks
. This makes it very hard to know how good AI models are at the work Americans actually do.
The coverage of existing benchmarks is not random, either. Our map suggests that the AI community is focusing on the largest labor markets first:
Benchmark coverage of O*NET tasks by occupation wage bill
Adjusted probability of task coverage
Annualized occupation wage bill (log scale)
Each point shows the estimated probability that an O*NET task with a given AI-exposure tag belonging to an occupation with a given wage-bill will be covered by at least 5 prompts in our benchmark index. AI-exposure tags are binary and come from
Eloundou et al. (2023)
. Occupation wage-bills are calculated from BLS estimates of the mean wage and number of Americans working in each occupation, assuming a 40 hour work week. Estimated coverage probabilities come from a task-level logistic regression of coverage probability on AI-exposure and log occupational wage bill. Error bars are pointwise 95% delta-method confidence intervals based on standard errors clustered at the occupation group level.
For example, benchmarks in our initial list heavily cover AI-exposed lawyers’ tasks, but barely cover any of the O*NET tasks of similarly AI-exposed legal secretaries or court clerks. The long tail of smaller, middle-income knowledge work jobs appears undercovered.
As we build out our coverage of model capabilities across the economy, we hope to both surface and help fill more gaps in our understanding of what models can do.
Methodology in brief
To break down the economy into sectors, occupations, and tasks, we used the US Department of Labor’s O*NET taxonomy. O*NET divides the US workforce into
923
occupations; for each occupation, O*NET attempts to provide a comprehensive list of “tasks” which make up the occupation, totaling
18,797
tasks across all occupations.
Example —
6
of the
22
tasks O*NET associates with
Lawyers
1
Prepare, draft, and review legal documents, such as wills, deeds, patent applications, mortgages, leases, and contracts.
2
Advise clients concerning business transactions, claim liability, advisability of prosecuting or defending lawsuits, or legal rights and obligations.
3
Interpret laws, rulings and regulations for individuals and businesses.
4
Analyze the probable outcomes of cases, using knowledge of legal precedents.
5
Present evidence to defend clients or prosecute defendants in criminal or civil litigation.
6
Supervise legal assistants.
To measure benchmark coverage, we start with a list of 29 benchmarks selected for their quality and economic relevance. (The full list and selection criteria are in the
Benchmark Index
tab). In selecting benchmarks for this list, we prioritized:
Public Availability.
Included benchmarks have at least 25 publicly available tasks. We also include Mercor’s APEX benchmarks, where we have access to held-out benchmark prompts and are therefore able to map them to O*NET tasks.
Agentic Tasks.
Included benchmarks ask models to perform agentic tasks, rather than answering questions or advising the user on how to complete a task.
Economic Realism.
Benchmark tasks resemble tasks which humans (or agents) are frequently asked to do in real-world enterprises. Economically valuable tasks are prioritized over academically complex ones.
Economic Diversity.
We capped the number of included benchmarks per job family, in significant part to account for the massive overrepresentation of software engineering and research tasks in popular benchmarks.
Balanced Difficulty.
Benchmarks are not yet saturated by frontier models.
Following work by
Wang et al.
, we then ask an LLM judge to tag each benchmark prompt with as many O*NET tasks as it thinks correspond to that prompt. We validate our LLM tagging with
human expert tags
on Mercor’s APEX benchmarks, a subset of this list of 29. On the Benchmark Map, an O*NET task counts as “covered” if our LLM judge has mapped it to at least 5 prompts from our 29 benchmarks.
To estimate the total share of working hours Americans spend on tasks covered by benchmarks on this list, we combine our coverage estimates with
Hatgis-Kessell et al.
’s LLM-derived estimates of the working time share of each O*NET task.
A more detailed account of our methodology can be found in the
Methodology
tab.
Limitations
Our estimates of total economic coverage, and of patterns in coverage, all come from the initial list of 29 benchmarks we chose. This is not a complete or perfectly representative sample of the broader universe of unsaturated, public, agentic economic benchmarks. Any incomplete list will necessarily bias down estimates of economic coverage, and it is difficult to bound that bias. We want to stress, therefore, that these results are provisional. We will update them as we expand the initial benchmark list.
We also capped the number of included benchmarks in each job family in order to maximize breadth of coverage. We think this makes our estimate of economy-wide benchmark coverage more accurate, at the cost of biasing down our estimates of coverage in the most-benchmarked job families (e.g. software engineering).
By selecting for unsaturated benchmarks, we risk understating benchmark coverage on O*NET tasks which are easier for LLMs to complete. On the other hand, including saturated benchmarks would risk overstating benchmark coverage if saturation is downstream of lower task realism. The latter claim seems likely, given that benchmarks often overstate LLM performance in real-world deployments. We think that the bias from including saturated benchmarks would be greater than the bias from excluding them, but neither option is ideal.
Finally, while we outline our benchmark selection criteria in the
Benchmark Index
tab, several criteria (like “Economic Realism”) are difficult to formalize and introduce some subjectivity in our choices.
Patterns in coverage
The benchmarks in our index have relatively deep and narrow coverage of the overall economy. They disproportionately focus on the economic tasks most exposed to AI automation (as measured by
Eloundou et al.
), with O*NET tasks rated as “exposed” about 6x more likely to be represented on benchmarks than tasks rated “unexposed”. This makes sense: benchmarks are designed to measure AI progress, and AI progress is most plausible on the most AI-exposed tasks. This explains why benchmarks are full of tasks in Software Engineering and Financial Analysis while sparse on tasks in Truck Driving and Gas Plant Operation.
But even after controlling for AI-exposure,
O*NET tasks from occupations with larger wage bills are significantly overrepresented among benchmark prompts:
Benchmark coverage of O*NET tasks by occupation wage bill
Adjusted probability of task coverage
Annualized occupation wage bill (log scale)
Each point shows the estimated probability that an O*NET task with a given AI-exposure tag belonging to an occupation with a given wage-bill will be covered by at least 5 prompts in our benchmark index. AI-exposure tags are binary and come from
Eloundou et al. (2023)
. Occupation wage-bills are calculated from BLS estimates of the mean wage and number of Americans working in each occupation, assuming a 40 hour work week. Estimated coverage probabilities come from a task-level logistic regression of coverage probability on AI-exposure and log occupational wage bill. Error bars are pointwise 95% delta-method confidence intervals based on standard errors clustered at the occupation group level.
After controlling for occupation and AI-exposure score, O*NET “task importance” is another predictor of benchmark coverage. In particular, O*NET tasks come with domain expert estimates of the importance of the task for its occupation on a scale of 1-5. We find that the tasks scored most important are about 6–10x more likely to be represented on benchmarks than those scored least important:
Benchmark coverage by O*NET task importance within occupations
Adjusted probability of task coverage
O*NET task importance (1–5 rating scale)
Each point shows the estimated probability that, controlling for occupation, an O*NET task with a given AI-exposure tag and a given quintile O*NET importance score is covered by at least 5 prompts in our benchmark index. AI-exposure tags are binary and come from
Eloundou et al. (2023)
. Importance quintiles are calculated from O*NET importance scores. Estimated coverage probabilities come from a task-level logistic regression of coverage probability on AI-exposure and importance quintiles, with occupation fixed effects. Error bars are pointwise 95% delta-method confidence intervals based on standard errors clustered at the occupation group level.
The plots above suggest a reasonable allocation of the relatively limited resources devoted to high-quality, economically relevant benchmarks so far; it’s natural to prioritize making benchmarks which cover the most important and AI-exposed tasks in the occupations with the largest wage bills. But barring a significant increase in the number and diversity of such benchmarks, these patterns will result in significant blind spots in our view of economically valuable model capabilities.
Can O*NET + benchmarks tell us how good AI is at your job?
Measuring model capabilities by job occupation is essential – for enterprises deciding which models fit their needs, for policymakers forecasting the economic impact of AI, and for Americans thinking about their careers. Unfortunately, this is a hard problem to solve.
We could just try averaging model performance on all benchmark prompts relevant to a given job. But as our
Benchmark Map
suggests, benchmarks cover some economic tasks much more intensively than others. A simple average would give too much weight to frequently benchmarked tasks.
O*NET offers a way to potentially reduce this bias. If we average model performance on occupation-relevant benchmark prompts weighted by O*NET classification, so that
each O*NET task is equally weighted in our occupation average
, we get a step closer to a number that represents real economic performance.
As a first step, we try this approach on
Mercor’s APEX benchmarks
for four occupations: investment banking, law, accounting, and software engineering. We compare O*NET-weighted scores to simple averages of model performance on tasks related to each occupation. The resulting weighted and unweighted scores are generally quite similar:
For each occupation, we take all prompts across APEX benchmarks related to that occupation. Darker bars show a simple average of model scores on those prompts for each occupation. Then, we sort the prompts by O*NET task. For each O*NET task with at least 5 corresponding APEX prompts, we average model scores on those prompts to get a task-level score. Next, we average each task-level model score to get occupation-level scores which weight performance on each O*NET task equally. (If an O*NET task has fewer than 5 prompts, we drop it from the average). Lighter bars show these weighted scores for each occupation.
In this case, at least, O*NET weighting changes very little. Model performance on APEX prompts is similar across the O*NET tasks included in the weighted scores above, which limits the value of reweighting. However, less than ⅓ of the O*NET tasks relevant to the 4 occupations above have enough APEX coverage to be included in our weighted scores. We are hopeful that applying O*NET weighting to a much larger set of benchmarks will result in high-quality occupation-specific model scores, and are working toward that goal.
However, even if we incorporate tasks from dozens of benchmarks, several obstacles remain:
01
How do we navigate low statistical power?
The sheer breadth of work done in the US economy means that for any O*NET occupation and task, we have relatively few benchmark items. This means that our estimates are inherently underpowered, and just one or two low-quality items can severely bias our scores.
02
How do we account for the varying difficulty and fidelity of tasks?
Some benchmark items are highly saturated, whereas others are still unsolved. This is partly a function of time (as older benchmarks were designed for less performant models and simpler environments) and partly a function of quality (some benchmark items are simplistically graded, have minor mistakes, or can be reward hacked). We do not yet have an explicit way of weighting by quality.
03
Can evals that primarily measure AI automation generalize to augmentation?
In the real world, AI models are still primarily used by humans, rather than automating entire job functions end-to-end. Therefore, measuring the real-world occupation capabilities of a model should ideally include measuring how much the model augments human productivity. We have completed some
early work in this direction
, but finding a methodology that scales remains elusive.
04
Can every O*NET occupation and task be measured with benchmarks?
Knowledge-based work is well-suited to measurement through benchmarks because it is largely done on digital machines, like laptops and phones.
Dingel and Neiman
estimate that only 37% of US jobs could feasibly be done entirely from home, suggesting that ~63% of jobs involve some tasks with a physical-world component which would be hard to incorporate into current benchmarks. For now, this may not be a meaningful oversight – with the rapid development of robotics capabilities, we anticipate a significant need for physical task benchmarks.
We are actively working on these problems; if you are too, please
reach out
!
We are indebted to
Wang et al.
for the O*NET tagging methodology, and thank Nathan Lambert for feedback on a draft of this work.
APEX NEWSLETTER
The latest on frontier AI performance, straight to your inbox.
New benchmarks, leaderboard shifts, and research from the APEX team.
Shyam Sankar, CTO of Palantir, Says AI Researchers Have Started Smoking Because They’re Convinced AI (Claude, Probably) Is Going to Cure Cancer
Daring Fireball
www.cbsnews.com
2026-10-16 13:01:22
From the transcript of Sunday’s Face the Nation on CBS:
Shyam Sankar: You know, I take — I think there’s a profound
truth to Pascal’s saying that every human has a god-shaped hole in
their heart, and it’s important to understand that many of these
folks in Silicon Valley who are building this te...
The following is the full transcript of the interview with Shyam Sankar, chief technology officer of Palantir, a portion of which aired on "Face the Nation with Margaret Brennan" on Oct. 11, 2026.
MARGARET BRENNAN: And we're joined now by the Chief Technology Officer of Palantir, Shyam Sankar. Welcome to Face the Nation.
SHYAM SANKAR: Thank you for having me, Margaret.
MARGARET BRENNAN: It's good to have you here in person. We've been talking a lot about technology, artificial intelligence, and public perception of it right now, and that's where I want to start with you because our polling shows there's a problem here. 50% of those polled by CBS say AI will create more problems than it solves. 29% say it'll solve more than it creates, and 21% just really don't know. Like 45% of Americans want the government to restrict use and development of AI. Is your position there should not be any guardrails at this moment?
SHYAM SANKAR: No, not at all. That's not my position. I think the- the burden is absolutely on the technology industry to show the American people that there are real benefits to AI and not kind of ephemeral sort of benefits like it can help me schedule travel, but actually meaningful benefits that result in job growth and prosperity for the American people. I think one of the things that's really complicated in the current discussion, is that there's an unseen force driving the narrative around AI safety, and it's- it's really this millenarian doomsday cult meets messianic complex called effective altruism. The most famous effective altruist that most Americans know is Sam Bankman-Fried, and the effective altruists are, it's almost like a religion that they've been thinking about doomsday scenarios from AI since the early 2000s.
MARGARET BRENNAN: He was–he is jailed. He was the crypto investor—
SHYAM SANKAR: Correct.
MARGARET BRENNAN: Who defrauded investors. But this sounds very academic. Like, what makes you so focused on this?
SHYAM SANKAR: Because there's only really roughly 2,000 AI researchers in America, and the vast majority of them believe in this sort of worldview around effective altruism. And if you hear someone like Jacob Coxon telling you that AI has a 10% chance of ending humanity, and you believe—
MARGARET BRENNAN: A researcher who had this warning recently.
SHYAM SANKAR: Yes, correct. And you believe he's speaking as a technically informed individual who does this work, it's a scientific critique. I think the American people would be right to be quite panicked and worried about what's going on here. But if you understand that it's actually a theological critique, then you can- you can kind of weigh it against the empirical facts of what is actually happening out there. You know, I take—I think there's a profound truth to Pascal's saying that every human has a god-shaped hole in their heart, and it's important to understand that many of these folks in Silicon Valley who are building this technology have filled that hole with the machine God of AGI. And I mean, there's so many interesting stories around this. Like, for example, so many AI researchers have started smoking as a way of signaling to other researchers how much they believe in AI. I believe so much— (CROSSTALK)
MARGARET BRENNAN: What? That makes no sense. What do you think—
SHYAM SANKAR: I believe so much in AI that it's going to cure cancer. So I will—I'm showing you my chips are all in. So there is kind of this mass psychosis, social delusion around it, and I think it's getting in the way of actually what is happening with AI. Where is it meeting the American worker in industry? What are the results of doing that, and the doomsdayers have basically been wrong. Everything they predicted, they- they told us that ChatGPT 2.0 was too dangerous to release. They told us at this point in the timeline, we'd already have mass unemployment and job displacement, and the economists see that actually we're having job growth in areas that we wouldn't have predicted doing exactly that. So the technology industry has two burdens. One is to show very clearly to the American people that- that AI is going to result in economic prosperity and security for the nation. And two, to actually do and absorb the burden of engineering. You cannot abdicate this idea that designing safe products is your job. You can't hand wave around it. If you look at the kind of narratives that come out of the doomsdayers, they seem like two contradictory narratives. One narrative is this technology is going to end humanity.
MARGARET BRENNAN: Right.
SHYAM SANKAR: And simultaneously, they say, "But I believe it has some chance of creating utopia." So at first blush, this seems contradictory, but it has one thing in common, which is that you, as a human, have no agency. The machine god is going to decide the future, and only perhaps a small number of us can try to avoid the horrible outcome. And I think it obfuscates the more profound reality that we have a huge amount of human agency over how we're going to use this technology to deliver the outcomes the American people expect.
MARGARET BRENNAN: Well let's talk about that because the other part of this argument would be, and no one who wants- the people who don't want guardrails are simply in it for commercial reasons. They want to keep selling chips, or they just want access to market. So that would be the counter argument to the idea that you know what you're saying, which is an ideological opposition to guardrails.
SHYAM SANKAR: Maybe we could just back up and who's on the side of no guardrails?
MARGARET BRENNAN: Well, when- I want to get into the specifics here, because even just defining what guardrails is seems really complicated, and there's not even common agreement on that right now. But Jay Clayton, who is the new DNI and the new AI czar, said this week the focus is on control and monitoring of technologies with the potential to do harm. So, what does that look like to you? Because it sounds like he's not even sure yet.
SHYAM SANKAR: Well, I think there's a very clear view that we should be regulating the application of the technology. So if you're going to use this in medicines, you know the FDA- As a republic, we have 250 years of rich laws and history on how to manage liability. I don't want to trivialize the metaphor, but you know, if I buy a car and the car is defective, that's the car maker's problem. If I then use that car to go drive into my neighbor's house, that's my problem. And you know, this sort of obfuscation. The narrative is this technology is a total difference of kind. I don't think so. I think it's a difference of degree.
MARGARET BRENNAN: Well, in that humans aren't in control of it, it would be a different kind.
SHYAM SANKAR: No, humans are in control of it. Even if we look at the kind of salacious reporting around Hugging Face, the models did not do anything they were not instructed to do. You know, they were- the- the real first, you have human error. They- they were not in a sandbox. They had access to the internet. It was a horrible cybersecurity configuration. Then, from that perspective, they were asked to- to- succeed at a specific benchmark, and they were not given constraints on how to do that. And they said, "Oh, the best way to succeed at the benchmark is to get the answers to the test, and to do so.
MARGARET BRENNAN: So, for that, who should take action to--
SHYAM SANKAR: --I think it's a defective product. Like, if--
MARGARET BRENNAN: --Is it up to the Justice Department to then bring suit, like on the programmers, like who's liable for the technology not, you know, staying within the sandbox--
SHYAM SANKAR: --The AI companies of course. In that, in that specific case, it would be the AI companies. If another company had licensed that technology to use in another in an application, and the product worked as expected, but you misused the product, then it would be you that are responsible for that.
MARGARET BRENNAN: So you believe that, am I understanding you, the existing laws on the books should be able to handle technology as it develops?
SHYAM SANKAR: I think it is a massive running head start. I think the laws on the books speak to a lot of the current considerations. Might we need a few more things on the margin? Sure, but I think we'll figure that out as we go through it.
MARGARET BRENNAN: So let's talk about some of those things because you were with the president when he summoned some of these AI leaders recently, and he asked them all to sign a pledge to implement robust internal controls, partner with an external auditor and establish a committee to evaluate reports from auditors. That was Google, Anthropic, OpenAI, Nvidia, Elon Musk. They all signed it. Palantir, your company didn't. Why?
SHYAM SANKAR: Well, those accords were for companies that actually make AI models, which we do not, so–
MARGARET BRENNAN: But you help to use them and build out platforms. Like you don't see a reason for constraints there.
SHYAM SANKAR: Oh, we- we do have those constraints. In fact, that- part of that's our entire business, is how do you safely deploy these models in specific use cases. We're just not a party that- we weren't asked to be a part of the accord.
MARGARET BRENNAN: But you were there at that meeting.
SHYAM SANKAR: I was.
MARGARET BRENNAN: So, what happened? Like, what was the conversation?
SHYAM SANKAR: The conversation was really an assertion that the American people expect AI to generate economic prosperity and to do so securely, and that we as companies have an affirmative obligation to deliver on exactly those things, and that we have existing laws to look at this, and that we should be all taking this quite seriously, very productive conversation.
MARGARET BRENNAN: Because it sounded like the White House was saying something more should be done, and now you have this new AI Czar Jay Clayton going out to Silicon Valley this week. He said he's launched this 120-day review of AI policy. What do you hope comes from that, or is this another one of these like blue ribbon commissions that doesn't produce any--
SHYAM SANKAR: --No, I think a lot will come up to it, which is really focus and energy, and using the existing agencies and regulatory apparatus to make sure we're on top of this stuff and providing support where it's needed. I think one of the challenges, going back to my comments on effective altruism is, today, the so-called independent research organizations that are overseeing this are not really independent. They have conflicts with the labs. They are made up of people with a singular worldview around effective altruism, looking for the doomsday scenarios. You know, you have evaluators who are essentially pointing a loaded gun at a target, saying, "I can't believe the gun worked." When they should really be saying, "What guardrails do we have in place? You know- are you know are these products working to the specifications we designed, and what- what are the opportunities for misuse?
MARGARET BRENNAN: So I've spoken to people, for example, in the financial industry who say we did need some regulation here, but there's the SEC, there is you know the CFTC, they oversee certain operations here. Don't you think within the current institutions there could be some sort of entity that oversees technology?
SHYAM SANKAR: I think there's going to need to be an incident response and reporting regime that creates more visibility and transparency into what you're learning in the testing, well ahead of product launches that give visibility and transparency to the government of how people are doing and implementing exactly the existing laws.
MARGARET BRENNAN: Who does that, or who could do that?
SHYAM SANKAR: I will defer to Director Clayton on that, but I think that's one of the things that I- I suspect they will be driving towards.
MARGARET BRENNAN: He's got to figure that out. Well, we look at the last administration- President Biden and Xi Jinping came to like, a very limited agreement, but at least on one principle, which was humans, not AI, should retain control over decisions to use nuclear weapons. Would it be sensible--
SHYAM SANKAR: Well, that seems obvious.
MARGARET BRENNAN: Well, that seems terrifying, first of all, that they had to come to a conversation about that, but shouldn't that be expanded elsewhere in the defense space? Would you agree with that? Is that one of the areas--
SHYAM SANKAR: Well, the current part of the policy is there's two parts of it. There's the kind of military doctrine, which is that a human is always accountable for every decision that's made, and the other part of it is that humans are in- in the decision-making processes that- that relate to lethal force here.
MARGARET BRENNAN: But in terms of the things where you think there should be more guardrails, is the defense space one of them? Biotech, I've heard others.
SHYAM SANKAR: All spaces need to- need to have a thought around safety of application.
MARGARET BRENNAN: But that's still- who does that and how?
SHYAM SANKAR: Well, I think the Department and the Congress should do it with defense. The Department of Transportation should do it with transportation. The FDA should do it with medicines.
MARGARET BRENNAN: But so, watch for that possibly happen. Because you know, I hear from people in the technology space this argument that we need to just go so furiously forward to compete with China. China is pushing for AI to be integrated into all of its industries, but they have the ability to also delay things to get government- governance to catch up, they've done that. They've tapped the brakes themselves before. So, do you think the U.S. should also consider tapping the brakes in certain areas, just slow things until they have some idea of the guardrails?
SHYAM SANKAR: You know, we have this beautiful, messy process in America, but I would argue, as frustrating as it might look, it's kind of working. So, we have frontier models now that have not been released because people have realized maybe we're not ready to release them. That would have been an unimaginable thought a year ago. And so as people are starting to wrap their heads around whether it's the labs, government- I think it is a consequence of our messy process and the discussions that people are having that we're evolving how we're doing this, and the pace is naturally changing.
MARGARET BRENNAN: Let's talk a little bit about DOD, the Department of War, Department of Defense. They have recently ceased using Anthropic products as part of this dispute over the firm's insistence on safeguards for military use of AI. I know you're aware of this case. Anthropic's Claude was part of the Maven platform, which Palantir uses. How much of an impact will this decision here have, and who replaces them?
SHYAM SANKAR: Well, the- the Department today has a wide range of model providers, everything from XAI and OpenAI to open-weight models like Nemotron from NVIDIA, so I don't think- I don't- there's been no operational impact from that. I think there's a kind of a broader statement which really has been powering the growth of our commercial business, which is companies are realizing, and it equally applies to the government, that you're not going to pick any one model provider. That actually, your sovereignty and agency as an institution comes down to your ability to kind of control, decide which models you're going to use in what context, have the ability to switch models, to be able to control the weights themselves, where you need to feel that control over them. It is your alpha. It is what makes your institution special.
MARGARET BRENNAN: So you don't know yet who's going to replace them, but you don't see a big impact from this kind of decision. It was certainly a huge story for Silicon Valley and the defense space to hear that--
SHYAM SANKAR: It's already been replaced. It's already been replaced, and users who are building AI applications get to pick the models that they're using. It's a suite of models that are available from, you know, Google, from XAI, from OpenAI. And what was the second part of your question there, sorry?
MARGARET BRENNAN: Yes, I was asking about the impact. It sounds like you don't think it's- it's a big one. Look, I can move on here.
SHYAM SANKAR: No impact.
MARGARET BRENNAN: You have said recently that the war in Iran is the first major conflict where AI played a central role, particularly for targeting. Do you see risks for that?
SHYAM SANKAR: Well, you know, targeting is this- is kind of this very salacious word. Really, targeting is a process, and if you think about military operations, you know, the ability to execute 1000 strikes in a single day would have taken two weeks of planning by 50 people before, and being able to do that with one person in four hours provides you a significant battlefield advantage against your adversaries. So, it's really not about, you know, people jump immediately to something like AI picking the targets. That's not what's happening. It's really given a set of effects that you want to create- I want to be able to take out the enemy's air defenses. Okay, what targets relate to that? Okay, how do I then push them through a process where I understand are any of these targets on the no-strike list? Are any of these targets too close to civilian infrastructure? How do you do all the things that are so susceptible to human error under the time crunch- what's doing in a way that has much higher repeatability and accuracy, so you can get more throughput to the system?
MARGARET BRENNAN: Well, that goes to a broader argument about the elimination of some of the people who were involved in mitigating civilian impact from strikes. That was a Pentagon decision by Secretary Hegseth. In the case- you just talked about the thousands of strikes, and there were so many successful strikes in terms of the targeting in Iran. But there was also, as you know, this horrific one in Minab that killed at least 123 schoolchildren. Bloomberg reported some personnel relied too much on the AI in the Maven system made by Palantir using AI-enabled software. Have you determined what happened there?
SHYAM SANKAR: Well, we should wait for the final report. But what I can say is that reporting is inaccurate.
MARGARET BRENNAN: The reporting from Bloomberg, you're saying, is inaccurate?
SHYAM SANKAR: Yeah, it's inaccurate, and actually, the likely cause is human error. And then- and quickly following that, we actually built additional AI agents that did more checking. That's part of the process we don't own, but responding to the urgency of the moment, we built additional AI that actually double checks more of the work outside the process that we own to ensure things like that couldn't happen again.
MARGARET BRENNAN: So you're suggesting it was outdated intelligence or human error that fed information into the computer system. Is that what you're saying?
SHYAM SANKAR: Well, we should wait for the final report, but I think we will find--
MARGARET BRENNAN: Do you know when that'll be released?
SHYAM SANKAR: I don't.
MARGARET BRENNAN: Because the initial reports have been widely reported on, including by this network. Do you see a harm in that being made public soon, or is it helpful to what you say are improvements you want to make?
SHYAM SANKAR: Well, I- I will defer to the Department on the- on the timing of how- I have no control over that. But yeah, I would love the- the truth to get out there.
MARGARET BRENNAN: But you believe that it was human error. That's what you're saying, not what they're reporting, which is that they were relying too much on the AI.
SHYAM SANKAR: The Bloomberg reporting is wrong. Yeah.
MARGARET BRENNAN: There are 120 House Democrats who wrote to Secretary Hegseth about this particular case and the use of AI in the strike, including Maven. Do you have any intention to go brief Congress about it or to share information?
SHYAM SANKAR: We have given briefings to Congress, and- and they can, you know, Congress is well aware of the capabilities of Maven.
MARGARET BRENNAN: But in terms of this strike and what went wrong, obviously something went wrong.
SHYAM SANKAR: I would defer to the Department on that. That's- that's not our place.
MARGARET BRENNAN: But it is because you are such a- Palantir is such- so interwoven with the U.S. government. I mean, it's billions of dollars of government contracts right now, do you think more information should be briefed to Congress about the benefits along with the risks?
SHYAM SANKAR: Sadly, I'm just a technologist. I mean, on these policy issues, I would defer to others.
MARGARET BRENNAN: Well, I want to quickly ask you before we go about the modernization efforts, which you are part of. I understand you are lieutenant colonel in the Army Reserves in the Army Executive Innovation Corps.
SHYAM SANKAR: Correct.
MARGARET BRENNAN: Which is new.
SHYAM SANKAR: Yeah.
MARGARET BRENNAN: There are also executives from Meta and OpenAI. So, what are you working on there?
SHYAM SANKAR: My principal role is to help with Army human resourcing in the G-1 department here. So, strategies on how do we, you know, the Army is drowning in talent, what we would call green suiters who actually know how to code, and they're- they're- they're exceptional. How do we employ them? You know, they don't fit in the kind of industrial era model, the Napoleonic codes. Their skills are kind of rank blind. You might have an E-4 who's an exceptionally good coder. There's not an obvious career path for them within the Army. The Army doesn't know how to manage that talent. So, how do we identify who these exceptional people are? How do we protect them? How do we put them on projects that fully utilize their skills and turn them into valuable assets for- for the military?
MARGARET BRENNAN: So that's your role within this Corps?
SHYAM SANKAR: That's right.
MARGARET BRENNAN: So for people who look at that and say these big corporations could have a conflict of interest because they're also doing business with the U.S. government. How do you respond to that?
SHYAM SANKAR: Well, it's carefully managed by- by the- the lawyers in the Department. We're only allowed to work on projects where we don't have conflicts.
MARGARET BRENNAN: And do you think--
SHYAM SANKAR: I would just say, more broadly, I mean it is the greatest honor to be able to serve in our U.S. military. You know, as an immigrant to this country, it's one of these- My father, my late father, would have loved to have seen me go to a service academy. Life worked out the way it worked out. Arguably, I hope I have more to give back to my country in this capacity at 44 than I did at 24, and it's a great pride.
MARGARET BRENNAN: Thank you for your time today, Shyam.
When I
joined
KDE in 1999 I already thought of it as a mature project. I used the KDE desktop every day, and I was delighted with what it could do and how it felt. I had no idea that this would be one of the most impactful decisions of my life, or where it would lead me.
Today we are celebrating the 30th anniversary of the
original announcement
of KDE. The project is still alive and kicking. I still use it every day, just like millions of other people. Not only because it's great software, but because of the values it embodies.
KDE stands for freedom and being able to shape your own destiny. As the
KDE vision
says: "A world in which everyone has control over their digital life and enjoys freedom and privacy." While I originally joined for the technology, this is what made me stay.
One of my favorite pictures illustrating the spirit of the community is the group picture of
Akademy in Dublin
in 2006. Brilliant people having fun working towards a shared purpose of digital freedom.
KDE gets a wonderful present for its birthday. The
KDE documentary
is premiering today. It tells the story of the founding, the rapid early development, and the license conflicts. How it became a solid product used by many people, and then put it all at risk with KDE 4. How we learned from that and turned it into this extremely resilient and lively community it still is today. I'm happy I could contribute to this story, and that I'm one of the people telling it in the documentary.
Today, KDE is maybe stronger than ever. We reached a lot of new users with the
Steam Deck
. The Sovereign Tech Fund is
investing more than a million euros
in KDE. With the strategic
goals
the community set this year, we are addressing enterprise, documentation, and styling. It shows how much the project has matured, beyond what I could ever have imagined. It also shows in its contributors. While contributors leave over time, new generations come in every year and keep the community growing over the long run, combining stability and rejuvenation.
I'm proud and grateful. Proud of what the KDE community achieved. Grateful that I could be part of this amazing group of people. A team nobody could have hired.
Happy birthday, KDE.
Behind the Blog: Doing Whatever
403 Media
www.404media.co
2026-10-16 12:43:19
This week, we discuss a new pod setup, video games, and Elon's spending habits....
This is Behind the Blog, where we share our behind-the-scenes thoughts about how a few of our top stories of the week came together. This week, we discuss a new pod setup, video games, and Elon's spending habits.
JASON:
Exciting news: I am building a podcast studio / riso printing room / place to film videos in. I believe all of my colleagues and many people in my life have been laughing at me about this, but this also may just be the narrative I’ve created for myself to inspire me to prove the haters wrong. Since the beginning of 404 Media, I’ve worked out of my garage, but feel like I’ve been going a bit crazy sitting mostly in the same room since essentially the start of the pandemic. And so I found not a coworking space but a very affordable windowless box that I shall turn into a content palace.
I’m just going to try it for a few months to see if it makes sense or if I should return to working from the couch, but I’m quite excited about building it out. I only got it a few days ago and so at the moment it’s largely a bunch of boxes and random furniture I no longer had space at my apartment for. It’s got a drop ceiling with fluorescent lighting and landlord special laminate floors, but I also can do whatever I want to it, so I will likely do some sort of design on the walls, throw a rug down, whatever.
This post is for paid members only
Become a paid member for unlimited ad-free access to articles, bonus podcast content, and more.
WASHINGTON, D.C. — The U.S. remains the most desired destination for people who would like to leave their own countries permanently, but Gallup's latest data show it is less attractive than it once was.
In 2025, 15% of adults worldwide who say they would like to move permanently to another country name the U.S. as their preferred destination, the lowest level recorded in nearly two decades of Gallup research. From 2007 to 2009,
24% of would-be migrants named the U.S. as their top choice
, and that figure remained near 20% through 2016. Since 2017, it has been at or below 18%.
The rank order of the countries attracting the most interest from potential migrants has seen little change since Gallup’s first measure.
Canada ranks second
, as it has for several years, with 9% of potential migrants mentioning the U.S. neighbor. The appeal of these desired destinations did not change in 2025, even as the U.S. became less desirable.
Line charts show trends in the percentage of adults worldwide who would like to move permanently to top destination countries from 2007–2009 to 2025. The United States remains the top destination but declines from 24% to 15%. Canada rises from 7% to 9%. The United Kingdom declines from 7% to 4%. Germany, Australia, Spain, France, Japan, Italy, and Saudi Arabia remain broadly stable around 3% to 5%.
Gallup's latest update on migration desire is based on a question asked almost annually: “Ideally, if you had the opportunity, would you like to move permanently to another country, or would you prefer to continue living in this country?” Those who say they would like to move are then asked to name their preferred destination.
Results for 2025 are based on interviews with over 144,000 adults in 140 countries. The current estimates include data from China for 2023, the last time the question was asked there.
The most recent analysis period coincides with a sharp slowdown in international migration into the U.S., amid changes in immigration policy and declining migration desire in several regions. External data suggest global migration more broadly slowed in 2024 after surging post-pandemic.
Declining Desire to Move to the U.S.
The U.S. became less attractive to adults in several regions in 2025, with statistically significant declines in Latin America and the Caribbean, sub-Saharan Africa, and Southeast Asia.
Latin America accounts for seven of the 16 countries worldwide where the percentage naming the U.S. as a preferred destination fell by at least 10 points. In the region, the percentage fell from 33% in 2024 to 28% in 2025.
Other Latin American countries that saw double-digit declines include U.S. neighbor Mexico, where the latest 21% who want to move to the U.S. matches the previous low set in 2017 and 2018. In Honduras, desire to migrate to the U.S. dropped 35 percentage points, from 71% to 36%, the largest decline in any country in 2025.
###Embeddable###
Despite the falling numbers, the U.S. remains by far the most desired destination in Latin America and the Caribbean and in sub-Saharan Africa. The picture varies more in other regions.
In Southeast Asia, Japan leads at 23%, compared with 12% for the U.S. In the Middle East and North Africa, Germany attracts 13% and Saudi Arabia 12% of potential migrants, with the U.S. at 9%. In South Asia, Saudi Arabia and the U.S. are roughly tied, each cited by 7%. Within the European Union, Spain, at 11%, and Switzerland, at 8%, rank ahead of the U.S., at 6%.
Global Desire to Migrate Falls, Shifts
Beyond where people want to go, the data also show a shift in how many want to move at all.
Overall, global desire to migrate declined in 2025 to its lowest level in a decade, driven by sharp drops in regions that have long had the highest migration aspirations, including Latin America and sub-Saharan Africa. After holding at a record-high 16% between 2021 and 2024, global desire dipped in 2025 for the first time in years, falling one point to 15%, a level not seen since 2018.
###Embeddable###
In Latin America and the Caribbean, 25% of adults say they would like to move permanently to another country, the lowest level in a decade. The decline is particularly notable in this region, where migration desire has fallen steadily after peaking at 34% in 2021-2022.
Multiple countries across the region recorded double-digit declines between 2024 and 2025. In Honduras and El Salvador, the percentage of adults wanting to leave fell sharply last year, from levels above 50% in several prior years to 35% and 25%, respectively.
In sub-Saharan Africa, where migration desire remains the highest globally, 33% say they would like to move permanently, also a decade low. As recently as 2023, that figure stood at 37%, ticking upward from 36% in 2021-2022.
In regions that are typically on the receiving end of migrants, the picture is different. Migration desire in the United States and Canada (20%) and the European Union (21%) remains near record highs.
In the U.S., notably,
the heightened desire to move abroad is concentrated among women younger than 45
. In 2025, 40% of U.S. women aged 15 to 44 say they would move permanently to another country if they had the opportunity, up from 10% in 2014. The trend first rose sharply in 2016 and continued across multiple years, suggesting a broader shift in outlook rather than a short-term political effect.
Bottom Line
It is important to note that desire to migrate is not the same as intent to move. Not everyone who wants to move can or will do so. The 2025 data show that fewer people worldwide are imagining their futures elsewhere, and the U.S., long the world’s most desired destination, is attracting less of that interest than at any point in nearly two decades.
For years, the dominant story in global migration data was a rising desire to move across nearly every region. The 2025 data suggest that pattern is shifting. The declines are widespread and concentrated in the regions that have historically driven global migration.
At the same time, the picture is not uniform. In regions that typically receive migrants, including the U.S. and Canada, along with the EU, desire to leave remains near record highs. And within the U.S., a growing number of younger women say they would move abroad permanently if they could.
These patterns show that interest in moving abroad, and to the U.S. in particular, is shifting across regions. But despite these changes, many people worldwide — an estimated 900 million — would like to move, including about 134 million who would prefer to move to the U.S.
This essay introduces the concept of
decoherence
: the accumulation of locally valid but mutually incompatible or redundant models within a system, such that the cost of change is dominated by translating among those models and preventing unintended side-effects.
In other words, it's
what happens when slop drowns out the signal in an endless sea of noise.
Decoherence grows relative to the rate of change of a system, and it increases faster the more decoherent a system is, resulting in runaway exponential growth. It is not a new phenomenon, and humans have always countered it through carefully finding ways to do more with less, unifying disparate patterns and models into a cohesive whole. However, the widespread use of AI is currently producing it at a rate that is unsustainable.
The good news is that this rules out the specter of runaway recursive self-improvement, the intelligence explosion that goes parabolic before anyone can react, as decoherence both prevents AI from improving in a bubble
and
limits the rate at which it can improve outside of it. The bad news is that we are barreling toward a different kind of disaster:
Decoherence Collapse.
Imagine a building, let's say a small office tower. When this building was built, they used a type of pipe that will degrade over time and eventually need to be replaced. This is standard
infrastructural debt
; basic wear and tear, as they say.
Then, let's say that when it comes time to replace the pipes, you need to change them over to a new standard. This could be because of new building code requirements, because the old pipes simply aren't made anymore, or because the new pipes are much better and easier to maintain. This is standard
technical advancement debt
, the need to upgrade and transition due to the forward progress of technology over time.
There is a third form of debt that can arise based on
how
the transition from old pipes to new pipes is done. Consider the following options:
Shut down the building and replace all of the pipes at once.
This is a very disruptive and expensive method, since you can't use the building while the process is underway and you have to pay for the replacement up front. But the process is
complete
by the end of it.
Shut down each floor, one at a time, and replace the pipes on that floor.
This is
less
disruptive overall, but somewhat
more
expensive because you still have to pay up front, and you have to pay a
premium
for the extra labor required to keep things running smoothly as the work goes on.
Replace the pipes as needed, when they begin to fail.
This is the least disruptive strategy, and it allows you to amortize the cost of replacing all of the pipes over time, with one small repair after another.
For most people, option 3 is very appealing. It allows them to keep things running smoothly and to spread out the cost of maintenance. And if we can just make like the
Ship of Theseus
[
1
]
and replace the pipes one at a time, why shouldn't we?
Well, for one thing, it creates
decoherence
.
And decoherence is, by far, the
worst
form of tech debt.
Evolution
The
Ship of Theseus
actually gives us a good lens for understanding the true scope of decoherence. We know how to build ships made of wood, and we know how to build ships made of steel. You can repair a ship one piece at a time with the same material, as the original thought experiment goes, and the ship remains functional, with all of the original designs and structures that went into it intact.
But do we know how to build every iteration of a ship
in between
wood and steel? Could you, say, slowly replace every piece of a man-of-war and incrementally turn it into a modern destroyer? And have it functional (for some definition of functional) at every step in the process?
It's not that the answer is an absolute "no". If we are creative enough, if we had the best minds working on it, then I'm sure there would be
some
path to doing this. But it would require
ingenuity
and
skill
and
craftsmanship
. It would require attention to detail. And, crucially, you would really want to
complete
the process, because the half-man-of-war, half-destroyer vessel is likely not going to be very good in modern combat.
Returning to our plumbing example, we can see how the same strategy plays out regularly in the world of construction. Every time a pipe breaks, the plumber is called, walls are opened, the repair is hand-crafted for that specific area, and then everything is closed back up. If you're lucky, the plumber will leave detailed notes, and if you're not, then years later some poor sod is going to open that wall back up and say to themselves, "What the
hell
is going on here?"
Now, multiply that process over time as we slowly replace the pipes in our building, and the end result is a patchwork of old and new pipe that has much more
complexity
than either system on its own. Every joint, every hand-crafted patch, is its own little bundle of unique forces and properties that are understudied, and thus requires an expert in
both
systems to fully understand and work with.
On the surface, this is fine. The pipes work, why does it matter
how
they work? As long as it's a good patch, who cares?
Well, what happens if we, say, want to build an annex?
For the purposes of this thought experiment, we'll say that the water for the annex needs to be routed through at least part of our existing building, using the existing pipes. And, crucially, we need to increase the
overall water pressure
in the system.
Now, the question is:
Is it safe to increase the pressure?
If we had all type A or all type B pipes, even ones that had been patched and repaired over time, then this would be a straightforward question. Both systems are well understood, both have tools and processes for calculating their capacity, and people run these calculations all of the time.
But, if we have an unknown mixture of both systems, suddenly we have to do a lot more analysis to answer that question. Every patch could change the answer, even ones at the other end of the system, because they're all tied together.
And this is where the true complexity of decoherence becomes clear. When we try to make changes to decoherent systems, it requires far more expertise and skill than working with either system alone. The engineer working on the system needs to trace and understand it much more thoroughly and carefully, because their changes may have unintended consequences.
And yes, I count plumbers as engineers, at least as much as software devs. Have you seen them think through pressure forces in drain pipes in real time? It's remarkable.
That is no small task, and it is best if it's not rushed. But for the outside observer, without an understanding of the depth of the problem, this can be frustrating. Normally this part is easy. Why is it taking so long this time?
In this situation, management will oftentimes apply pressure to get things done faster. When pressure is applied, the expert doesn't do the full analysis faster; they just stop earlier and do something they're
pretty sure
will work. A sloppy join, an unusual part, maybe some extra safeguards, just in case.
Not completing the task thoroughly, however, creates a knock-on effect: this particular change has lower quality, and it makes the system more fragile and complex. This means the next change will take even
more
thought and care, and if the pressure on the engineer is the same, then they will do an even
worse
job.
That is a pretty messy situation as it stands, and you can already see a sort of exponential growth of complexity taking place here. But wait, it gets worse! Let's consider the next level of decoherence: Starting a
second
transition before finishing the first.
The Maze
The tricky part about software, as compared to a physical building or other types of real-world systems, is that it's all sort of invisible.
Coders walk through the halls of codebases every day. We navigate the labyrinth successfully so often that we become familiar with every corner and every turn, and when our walks become longer, with more corridors and dead ends and trap doors, we
feel
it much more immediately and intuitively.
But this is difficult to relate to people who can't even see the maze, who don't walk it with you every day. And when it comes time to clean up some of your debt, to make the maze shorter and less winding, your proposals are hard to sell up the chain, even to those who used to walk mazes a long time ago. In the end, none of them know
your
maze. They don't know the trials you face each and every time you enter it.
By comparison, our plumber friend in the real world can show the building owner the absurdity of their pipes much more
directly
.
When we start to mix more than two systems together, with multiple patches over time in a haphazard way, the complexity of the maze
explodes
. It is now combinatorial: you need to think of A -> B, A -> C, B -> C, A -> B -> C, C -> B -> A, and so on.
We can of course insulate engineers from this somewhat. We can come up with best practices, we can use tools and frameworks to isolate part of the system from another part (for instance, by using a pressure-limiting valve in our pipes). Inevitably, though, it gets to a point where even the best engineers, the smartest people, can no longer safely navigate the maze.
They may be able to do it 80 or 90% of the time, but they will eventually take a wrong turn
forget to leave a trail of string and find themselves stuck
within the immensity
of the unending growth
that outpaces their every step
into eternity.
This is the Decoherence Trap. The maze grows onward and onward until it swallows you whole and leaves you lost in the dark. Until it becomes so massive that it would take lifetimes to navigate.
Well, lifetimes for humans anyway. But what about AI?
Simulation
Humans get tired and reach physical limits, but autonomous agent swarms can keep going around the clock, collectively and tirelessly mapping the maze like the good little robots they are. If scale is the problem, then shouldn't we just be able to throw more compute at it and call it a day?
Well, that depends on the nature of the complexity we are facing. Does it:
Grow linearly with the size of the codebase as a whole, OR
Grow
exponentially
, with each change increasing the likelihood that the
next
change will add even more complexity.
If it's the former, then yes, as the size of the problem grows we can just keep adding more agents and more data centers and working the problem at about the same pace. But if it's the
latter
, then adding more capacity will only get us the ability to push a bit further before the size of the maze threatens to consume all of the compute on Earth (and in space, should
SpaceX's plans
[
3
]
work out).
In my experience, it is the latter. When a plumber opens up a wall and sees a mess, it isn't clear what's going on. They may choose to use pipe A, they may choose to use pipe B, or they may choose to add a new type of pipe entirely in their confusion. The same is even more true for code.
We can see this play out in a simple simulation below. Here, we have a graph that represents a codebase (or some other complex system), where:
Nodes
represent different components within the system
Node Size
represents the size of the to component
Node Color
represents the dominant paradigm that the component belongs to. You can think of this as the "kind" of component - different materials of pipes, different constructs in code, different types of systems, etc.
Edges
represent connections between those components
Loading precomputed timeline…
This is a recording of a few runs. If you want to play with the full simulation yourself, changing the settings and watching what happens, you can find it
here
.
An actor, representing a developer, implements a "feature" by walking some random subsection of the graph and then mutating it. The actor's base behavior is shaped by its
coherence factor
:
Lower coherence
means the actor rushes through the problem more quickly and makes snap decisions, preferring simple solutions without considering the context around them, and overall adding complexity to the graph.
Higher coherence
means the actor takes longer and approaches each problem with more thought, and thus has a higher chance of making a less complex change or even removing complexity.
At first, the lower-coherence actor moves very quickly compared to the higher-coherence actor. However, as the graph changes, it impacts the walks as well. Each of the following slows down the actor's progress:
Higher connection degree (number of edges)
. This represents the added burden of having to pull in the context of each adjacent node, at least partially, in order to understand its impact on the current node.
Transitions between colors
. There's overhead when switching paradigms as you implement a feature, and it requires the actor to again gain context and understanding of each paradigm AND how they connect.
Path length
. The walk itself has a chance to extend further as there are more connections and transitions needed. This represents the actor needing to read more and revisit more in order to get all of the context needed to implement the feature, and it can increase indefinitely until you hit the
size of the entire system
(meaning, in order to make a change
anywhere
, you need to understand
everything
).
If we take the distribution of features built over time and coherence, we can plot the result and see a shape that should look familiar to any engineer: The
Sweet Spot
.
In the
Sweet Spot
, the system is relatively coherent and we actively invest in it to ensure it stays that way. There are a few dominant paradigms, but there's enough jitter that things can change and adapt over time, and we aren't overly perfectionist about everything.
Above the
Sweet Spot
, we work extremely hard to make sure every new node fits into the existing paradigms, and we remove complexity at every turn. This takes much more time and slows down feature work, but in the worst case it still produces a highly coherent system that can be iterated through
relatively
quickly.
Below the
Sweet Spot
, the drop-off is precipitous. We very quickly lose speed as the codebase becomes exponentially more complex. If the coherence factor is
negative
, and no care is given to maintaining coherence, then the time to ship a feature grows without any apparent bound.
We can also see how different strategies affect the system over time from different starting points. If we start with a highly coherent system and use a mostly decoherent strategy (a coherence factor of +0.2, where some coherence is maintained but shortcuts are still taken), then the graph devolves slowly at first before hitting some inflection points and entering the Trap.
By contrast, if we take a system that starts out decoherent and apply effort to recohere it over time, then we can move the needle toward coherence and accelerate.
Now, critics may note that this simulation has arbitrary weights and does not definitively
prove
that this is how complex systems will evolve. This is not my assertion.
What the simulation demonstrates is that this curve can exist as an
emergent
behavior of simple rules and local decisions. Actors changing the system today can improve or degrade the ability of future actors to change the system tomorrow. This is an obvious truth, but I think the implications of it can be quite easily lost if we can't actually
see
the complexity like we can in the real world, with pipes and wires and physical hardware.
So, we come back to the question on agents: Can agents work on these systems and maintain coherence? Or do they, over time, introduce decoherence even
slightly
? Because there is another crucial risk to consider here: decoherence does not grow over
time
, but with
change
.
If you build a decoherent system today, and then stop changing it for 10 years, and come back to it, it will be exactly as decoherent as you left it. It may have other forms of technical debt, but those are not related to decoherence. Decoherence grows or shrinks
only
when changes are made to the system.
And if you're making a lot of changes really quickly, you can also grow decoherent
just as quickly
. Even a very slight rate of increasing decoherence can spiral out of control before we even know it.
Here's the thing: We've been dealing with this phenomenon for much, much longer than agentic development has been around. Every single company I have ever worked for had massive amounts of decoherence, and less-experienced engineers and engineers under pressure also tend to add more decoherence over time, so it's not like humans are perfect here.
In fact, I would
venture to say
that most companies operate somewhere well below the
Sweet Spot
, and indeed operate in a continuous cycle where:
Decoherence grows to the point that no features can be completed in a reasonable amount of time.
A large effort is made to reduce decoherence.
The effort produces results and features begin shipping again at a slow-but-acceptable pace.
The effort is not completed, or if it is, it still doesn't push us all the way to the
Sweet Spot
. Resources and focus are shifted, and the system begins to decohere again.
Wash, rinse, repeat. Some companies may recohere faster and longer than others, and a very small percentage manage to stay in the
Sweet Spot
over time, but it requires a dedicated engineering culture of excellence (Apple comes to mind; say what you will about the state of macOS, I would take it any day over Windows).
The question is, are agents actually
better
than the average engineering culture at this point? Significantly better, at that?
So far we have not seen evidence of this. If anything, the early research points the other way.
A
Harvard study
[
4
]
of 718 companies found that adopting coding agents raised the amount of code written by 30%, but did not produce a measurable increase in finished work. The extra code piled up in review instead: pull requests took 49% longer to review, and nearly twice as many were sent back for changes. A
Carnegie Mellon study
[
5
]
of open source projects that adopted Cursor found a large jump in velocity that did not last, alongside an increase in code complexity that did, and that the added complexity was itself a major cause of the later slowdown. And an
analysis of over 300,000 AI-authored commits
[
6
]
across more than 6,000 repositories found that about one in eleven of them, and up to one in seven depending on the assistant, introduced at least one quality issue, and that nearly a quarter of those issues are still sitting in the code today.
More code, the same amount of finished work, and more complexity left behind with every change.
Progression
Now, let's address the primary counterargument, which is the
technological progression
argument. It goes something like this:
The first generation of agents will produce inferior-quality code, but as long as it's "good enough" then they can still replace humans for most coding tasks, and we can build our processes around them in anticipation of more capable agents in the future.
This is effectively the story of automation during the Industrial Revolution, where the first generation of textile machines was indeed much worse than humans, but
eventually
they did catch up. As
Cory Doctorow
[
7
]
has pointed out, industrialists raced to adopt automation because it allowed them to discipline labor and consolidate power at the expense of the workers and the public, who had to endure far worse working conditions
and
worse quality goods for generations.
[
8
]
[
9
]
But I want to build on this further, because there was a core reason that it worked for textiles: The machines produced inferior products, but they met a minimum bar.
The machines themselves were also very well designed, for what they were. I spoke recently to a mechanical engineer who extolled the quality of those generations of machines, how well they operated, how long they would last. Yes, they may have produced low-quality slop, but they produced it quickly and tirelessly and for many, many years, until the next generation came along and replaced them with incremental improvements. And crucially, while the machine was working, there was no increase in
decoherence
. Wear and tear, yes. Generational advances, yes. But not decoherence.
Now, here's the rub: The logic of this argument is assuming that
code
is analogous to
textiles
. That is, code is the final product that users will pay for. But nobody wants to buy code. They want to buy
applications
.
In other words, code is not the textile, but the textile-machine. Every time a screen is rendered, a form is submitted, a record is updated, that is the "product" that the code produces. This is why code has been so immensely profitable, because every additional customer requires no additional overhead. The raw materials are bits and bytes of electricity on chips, and the product is information and processes encoded into those bits.
A more accurate analogy would be if we somehow went back in time and made not just a textile-machine, but a machine that
designed
textile-machines. That iterated on the next generation of textile manufacturing on its own, semi- or perhaps fully autonomously. This is something that has never existed before, and is unprecedented in the history of automation.
This is the dream of recursive self-improvement. Of an intelligence explosion,
a technological singularity
[
10
]
. This is the dream of AI in the first place.
So, how has that been going?
Singularity
Well, the goalposts have been
subtly shifting
. In May of this year, Tom Reed, a skeptic of the intelligence explosion theory, coined the term "
the Goodhart Singularity
[
11
]
" to describe the limitations of AI iterating in a bubble without new data about the real world. This is based on
Goodhart's law
[
12
]
:
When a measure becomes a target, it ceases to be a good measure.
Marilyn Strathern, paraphrasing Charles Goodhart
In a post from last month, Tom Davidson, a senior research fellow at
Forethought
[
13
]
, conceded that data bottlenecks
will slow down progress
[
14
]
once AI reaches what he calls the "human-quality ceiling": the point where there's no better human demonstration left to learn from, and AI has to manufacture higher-quality data than anything that exists. Davidson has written extensively about models of AI takeoff speeds, and later forecasts built on his work, most prominently the
AI 2027 scenario
[
15
]
.
So the fact that Davidson has wavered, if even slightly, is notable. But he argues it's a one-time slowdown, not a wall, and in general, those expecting a fast takeoff still think that it will be able to recursively self-improve on its own with relatively little data, and that this process could spiral out of control in isolation in a data center and lead to the birth of a super-intelligence.
The way they expect to be able to do this is via what they call a
Software Intelligence Explosion
[
16
]
(SIE). Specifically, a subtle but load-bearing moment in the argument comes from Davidson's post on data bottlenecks:
Rather than building RL environments that teach the construction of real-world software artefacts, AI must construct RL environments that teach AI to make better software than anything that exists in the real world.
To be clear, I think this will be possible! It is easier to construct difficult challenges and verify their answers than it is to solve them. Already today, human experts build RL environments that produce data above the human-quality ceiling. Data quality will not hit a wall at the human ceiling.
Let's break this down.
What Davidson's saying here is that AI must be able to make better software than anything that exists in the real world, largely in isolation. To do this, it will need to be able to make a
Reinforcement Learning environment
[
17
]
that can produce that software. The way this works is essentially:
Define a goal
Define a set of things you can do
Use an algorithm to try out a lot of different methods to accomplish the goal
Measure how close you get to accomplishing it, and how good your method is
Find the best method(s)
For an SIE to occur, the AI would need to be able to do this entire thing on its own to discover better and better
algorithms
for learning, and that's the important part. It's not about producing better software per se, it's about producing better algorithms for
learning and improving
.
The Goodhart Singularity effectively argued that an AI, in isolation in a data center, would not be able to do this for most real-world tasks of consequence due to the measurement step. If you want to figure out how to build a better car or rocket or computer chip, you might be able to build a simulation and try things out, but you would still need to test against the real world to validate your findings, or you would eventually drift further and further away from reality as you pushed the designs to more extreme places. This introduces a rate limit which would slow things down significantly.
But this isn't true for some domains, which is what Davidson is saying in the second part. For games like
Go or chess
[
18
]
, the rules of the game are the entire world and there are clear victory conditions, so it's possible to run in isolation and find better and better strategies, and also to find better algorithms for
finding
better strategies. The same is true for more complex games like
StarCraft
[
19
]
or
Dota
[
20
]
.
But these are
games
, and we can do this because the victory conditions are clear and simple and the rules or environments are very limited. In order to get our explosion, we need to be able to apply these methods to
something that matters
, and we need to be able to
verify
that
in the bubble
of a data center, without checking against the outside world.
That brings us to software. I think that SIE proponents have really latched onto software because they see it as a way to bridge this gap. Software can run in isolation, and you can test it in isolation very easily and quickly. That's perfect for creating an RL environment, and they think that eventually, we will be able to build one that doesn't require syncing with the real world.
Because after all, it's
software
. It can do just about anything, right?
You can see how this would feel so natural to those in Silicon Valley. We pride ourselves on being very intelligent and being able to solve big problems. A significant portion of computer science education is all about logically proving properties of software and algorithms and the like. Will this program complete? Will this sorting algorithm be fast? How fast? Will this system be safe and not crash for all cases that could ever possibly exist?
We're used to thinking about problems in this way, and used to the idea that software has no limits. Tech took over the world, so it's only a natural extension of thinking that if you can teach a machine to write code, eventually, it will be able to teach itself to be better at writing code.
And then, eventually, the machine will take over the world too.
Better Software
The problem with this viewpoint is that it fully misses what actually makes software
good
, which is coherence.
Allow me to elaborate. Software is a tool to accomplish a goal in the real world. That goal may be many steps removed, through many abstractions, but whether or not it succeeds is ultimately determined by how well it solves that goal.
You might think, ok, but once you have the software and it solves the goal, can't you use that as the output to target? And then the AI could just iterate on better ways to achieve those goals?
If we define "better" as something simple and easily measurable, like lines of code, speed, memory, or efficiency, then yes. These are all important, but if we treat them as the target, we'll end up with software that is small and fast and
completely decoherent
.
Code gets fast by skipping work, and it can only skip work by assuming things about the rest of the system: this list is already sorted, that value is never zero. Every one of those assumptions is a hidden connection that nobody wrote down. Optimized native code sits under abstractions for a reason: we need it for performance, so we seal it in a box where its assumptions can't leak. If we wrote all code like that, it would be a tangled mess.
A practical example in JavaScript is combining multiple logical classes into a single class to keep hot paths
monomorphic
[
21
]
. It's always a huge pain, but it pays off as long as you never have to fiddle with it.
That would be fine if we only had to write software once and never touch it again. But that's never true in practice. Because software
is
the never-ending
Ship of Theseus
. Applications and libraries and frameworks must evolve over time to meet changing conditions on the ground: real-world constraints that shift and evolve as we change how society works, as we discover more about the natural world, and as we push the limits of what we can achieve.
So good software is adaptable over time. You can take the existing technological capital (all of the software we have written before), and you can quickly recombine it to solve new problems on the fly.
And what makes it adaptable is
coherence
. Most of the big advances in computer programming and software quality have been about making software more coherent, and the only way to test if it is more coherent is with real-world feedback.
Let's break it down with a really concrete example:
futures
[
22
]
.
Futures make asynchronous programming easier in some really fundamental ways. Before futures, there were lots of ways you could handle async, and it was a predictably chaotic mess. Specifically, a decoherent one: many locally sensible ways of doing the same thing, none of which fit together.
Developers would have to live within that mess, and they would have to carefully and thoughtfully navigate between all of the different types of async that any one app might have. If you missed a step or forgot something, you would have difficult-to-track-down bugs and issues. And the code itself read like a horror show, as callbacks multiplied and as apps got more complex and had more and more asynchrony to handle.
Futures were first introduced as a concept in the 1970s, with the core idea being that they were a
placeholder
for a future value. The first concrete implementation was in MultiLisp, in 1985. But they didn't make it into the mainstream until the 2000s, when Java added them in 2004, and they didn't get popular until the 2010s when chainable promises were first introduced into JavaScript and C# shipped Task.
[
22
]
There were two main reasons for this:
The first futures APIs worked, but were clunky. You could pass around a future, but when you tried to read the value it would block, which meant you had to be careful about when you did it. They also weren't independently chainable, so you couldn't really
fork
the future easily.
Futures introduce a decent amount of overhead. You have to create a wrapper object to track the state each time, rather than just storing a function pointer, for instance.
However, over time we found the APIs that worked well, worked out the kinks, and we realized that the overhead was worth it because it made it easier to reason about and combine larger systems (compute and memory getting cheaper didn't hurt either).
Bringing this back to AI.
In order to build better AI software, you need to be able to test if it is actually better. And importantly, as we mentioned before, we have to be able to measure if it's better
in the bubble
. We can't check outside of the bubble because that brings us back to being rate-limited by the world.
So, what can we check inside the bubble?
Well, we've narrowed it down to:
Games
Software
Mathematics
Games don't really get us that far, because they're not grounded in the real-world tasks we care about. So let's move on to software.
As we've established, good software is coherent. So, how do we measure coherence?
Well, you take an abstraction and see how well it holds up in different contexts, and how much the code has to bend to fit each one. Since we're not allowed to leave the data center, there are exactly two options for how we can do this:
Apply it to all existing software.
This will only get us so far, because even if it works well for all of them, there's no way to know if it will work well for all
future
software. Callbacks and event loops weren't even common until GUIs became standard, and early web servers still used threads and traditional parallelism, so it wasn't clear how valuable futures would be until the entire set of programs that make up the web was discovered and explored. We would be overfitting to the programs we already know. The result can look perfectly coherent today, and then the first new problem that doesn't fit has to be patched around.
Create new software.
This is something we can attempt to do in theory, but in practice we can't just generate plausibly useful programs to expand the training set. Once again, software is a tool to accomplish a goal in the real world, and if we don't validate its usefulness from time to time we could drift substantially from reality.
Beyond this core issue, the other important test of coherence is how well an abstraction or concept translates over time, across a variety of different contexts and evolving requirements. A standard can look good on paper and even work well in one environment, like desktop computers, but then be completely inadequate for mobile devices or cloud-based systems at scale.
You would not only need to generate plausibly useful software, you would also need to generate plausible evolution scenarios to see how it adapts, what happens when not everyone upgrades, when people (or agents) lag behind or decide to go in a different direction, when you have an
ecosystem
of systems that are a constant moving target.
You can get arbitrarily good at making the software we already have more coherent. Getting better at the software we
don't
yet have requires either (a) waiting for the real world to produce new software or (b) making new software, testing it in the real world, and waiting for it to evolve over time. Both of these options require round trips outside the bubble.
Putting it all together now:
We
can
make an AI that produces faster, smaller, and more efficient software beyond the human ceiling while staying inside the bubble.
We
cannot
make an AI that improves software
coherence
beyond the human ceiling without leaving the bubble, as noted above.
Because AI cannot check if the software is universally better without leaving the bubble, the AI cannot tell if it is actually improving its learning algorithms or if it's drifting.
We're right back at the Goodhart Singularity.
This puts the nail in the coffin for a fast, isolated SIE right off the bat. But we can also approach this from
another
angle, and this one also applies to
other
forms of intelligence explosions.
Any form of intelligence explosion depends on the AI researching and improving its own software or hardware, with each generation building on the improvements of the previous one.
Each generation will have some percentage chance of introducing decoherence into its systems, since the AI will be building or expanding systems beyond the frontier of its current understanding.
If the AI moves too quickly, it will compound decoherence faster than it can correct, leading to a stall or regression in its overall capabilities.
If the AI validates and verifies all of its findings, it will be rate-limited by its capacity to gather data from the world around it.
This cannot be addressed by better learning algorithms developed in pure isolation, because the AI has nothing to measure these against (see the first proof above).
We can see what the failure mode in point 3 looks like in the following chart, adapted from Eth and Davidson's model in their
SIE paper
[
16
]
. Their projection has the growth curve going parabolic before month 5. The chart below keeps their model and adds one assumption: that the cost of each change doubles as accumulated work grows, which is what decoherence looks like in human codebases.
If this is true and AI cannot bypass decoherence, then ultimately AI is rate-limited by reality. It's not that it won't ever surpass us, but that it is a long way off from doing so in any meaningful sense, and even when it does it will still have to do all of the work that reality demands, constrained by the same physical and informational limits that govern us.
Davidson claims we could gather sufficient data easily by just recording real-world tasks:
If the whole world worked together to make this happen quickly, it would not take long. For each job, 1000 people could record their screens and wear video cameras on their heads, and within 4 months AI would have 300 years' worth of experience.
This, fundamentally, underestimates just how complex the world is. If we expect a machine to be able to improve itself indefinitely, it can't just be good at moving a cursor on a screen or identifying objects in videos. It needs to develop deep insights into understanding the world itself. It doesn't need to experience it like a human, but it needs to be able to capture the same kind of information, the same perspective, to measure the intangibles and subtleties that cannot be captured by a screen recording and video feed alone.
It needs to be able to make connections between things that, at first, appear to have no relationship at all. Which brings us to our last topic.
Mathematics
Mathematics is the other domain which could, in theory, be checked in the bubble by using verified proofs. If an AI can get better at math in a bubble, then it can develop a better learning algorithm overall, and then maybe the SIE argument still stands.
The thing is, math is sort of
arbitrary
. We make a lot of decisions about how it works, and what is useful. For instance, the number zero was not always accepted as a valid number. Imaginary numbers took centuries to be accepted, and their four-dimensional cousins, quaternions, struck Lewis Carroll as so absurd that he is thought to have
satirized them in the Mad Hatter's tea party
[
23
]
.
These are examples of things that we take for granted, but which really
aren't
as obvious or as natural as we might think. They only gained wide acceptance when they were used in real-life practices, and when the outputs lined up with reality in meaningful ways.
In a similar way, Boolean algebra, the fundamental mathematics that underlies computing, was also considered an esoteric branch of mathematics for nearly a century. It was
first published
[
24
]
by George Boole in 1847, but it had no practical applications, and it was studied as a curiosity of formal logic rather than a tool for serious engineering.
The importance of this math wasn't discovered until the 1930s, when Claude Shannon was working at MIT on the relay controls for Vannevar Bush's differential analyzer. He had previously encountered Boolean algebra in a philosophy class he took during his undergrad,
[
25
]
and realized as he was working on circuits that they matched up perfectly. His master's thesis,
"A Symbolic Analysis of Relay and Switching Circuits,"
[
26
]
made the connection in 1937, and the rest is history.
Boole wasn't just inventing mathematics for the sake of it. He had an intuition that the properties he discovered, the system he made, would be important someday. He thought he was discovering the laws of human thought, and while that might have been somewhat misguided, it was interesting enough that logicians and philosophers studied it and passed it down, until Shannon found it and built on it.
Would Shannon have been able to find that connection in the age of AI? If he hadn't been standing in a room full of relays with a real problem in front of him, telling him where to look, and instead had been sorting through endless reams of proofs that were all locally valid and globally meaningless?
There are an infinite number of logical and mathematical systems you can define in a vacuum, and you can get extremely good at building and exploring these hypotheticals. Figuring out whether or not they matter is a different skill, and that is one that cannot be improved in the bubble.
Mathematicians are already worried about this dichotomy. In September, twenty-five Fields medalists, Terence Tao among them,
signed a declaration
[
27
]
arguing that solving problems is only a stand-in for the real goal of mathematics, which is understanding, and that mass-producing true statements can erode the ground that new ideas grow from.
What happens when all of that ground is worn away?
Collapse
The work of building coherence is a long and unrelenting process. It's the work of exploring every crevice and looking under every rock. Of getting down into the mud of reality and letting it seep into your boots as you grope around blindly, looking for all of the different ways that the world can configure and reconfigure itself around you, endlessly, without letting it swallow you whole.
It's not just about solving problems. It's about figuring out what problems we're trying to solve in the first place.
Of figuring out all of the problems we're trying to solve, and finding a single solution that solves each one without exploding into a labyrinth of complexity.
Which brings me to my last point.
There's been much said about
Omarchy
[
28
]
recently. There are many who love it, and many who are, shall we say, skeptical of an agent-forward Linux distro. They have charged forward rather quickly into the space, and appear to be morphing from the original goal of being a clean set of defaults toward
a full distro with a custom kernel
[
29
]
.
Now, I want to be clear that experimentation at the edge of the ecosystem is important. Forking, exploring ideas, figuring out what works without constraints, and bringing your findings back to the community is a huge part of what makes Open Source Software work so well.
But I'm worried here.
I'm worried that somewhere along the line, we may have forgotten that we are all climbing the mountain together. That what has made us so successful and so resilient as a community, what has advanced computing so far so quickly, is the process of building coherence.
Back in the 80s, 90s, and all the way through the 00s, every company managed their own stack. Each server was its own little bundle of dependencies and scripts and OS versions and so on. You needed a team just to keep things running smoothly at your average company.
During
the OS wars
[
30
]
, that fragmentation was worse. Unix did not have a clear successor, and Windows was gaining ground with an entirely different paradigm. If Linux hadn't been built in that time, and captured the aging *nix ecosystem, where would we be today?
Yes, I'm aware that FreeBSD was a thing and could have taken its place. What I really mean is: what if there had been no free software movement at all?
Would we be paying license fees every time we boot up a container in the cloud?
How many startups wouldn't have been able to get started, just because of the costs of running their stack?
That fragmentation was also the reason every system started to feel old and clunky over time. The entire ecosystem was decoherent, and much of the work over the last two decades has been about adding coherence (and capturing some of that value in SaaS products, but I'm getting ahead of myself).
I fear we may be practicing a sort of slash-and-burn agriculture here, where we are throwing away the coherence we have built in favor of rebuilding every dependency, customizing every piece of software, extending in every direction to solve short-term problems.
And not realizing that all the while, we're running deep into the trap.
What humans can handle (and fix over time)
What agents can handle (but not back out of)
Unreachable with all of the compute on Earth
If we push too long and too far without maintaining or rebuilding coherence, with current trends, we'll end up in a place where we
must
use agents to maintain our systems, because the systems will be so large and so overwhelming that we cannot do so ourselves. But if we get caught there, and it turns out that agents cannot
back us out
by doing the repair work, we may find ourselves in a very uncomfortable position:
Locked into a development model that slowly degrades our systems no matter how much effort we put
into fixing them.
It's not that we won't be able to eventually fix the systems. But it might take years or even decades to do so, and in the meantime, we won't be able to ship features or make progress on the many other pressing problems we have in our society.
This is what I call
Decoherence Collapse
. And I am far more afraid of it than runaway super-intelligence, because it's actually happening right now, in front of our very eyes.
I do want to be clear that there is some utility in AI, I just think it's more on the margins than in replacing core workflows or running fully autonomously. I subscribe heavily to Cory Doctorow's
reverse-centaur analysis
[
31
]
- we don't want the machine driving us, we want to be driving the machine. On that note, you can read my
AI Usage Policy and Guide
for a more detailed discussion on how I approach it in my own work and life.
And as I've said repeatedly in this piece, decoherence is not a new problem. If anything, it has existed since the beginning of human civilization, or perhaps even further back. It is a natural sort of decay or degradation, a type of entropy, that we have always dealt with and will always have to deal with. With that in mind, I want to leave you with two last thoughts.
Decoherence only ever changes when the systems themselves change. This means that no matter how bad it gets, we can
always
stop moving forward and start backing ourselves out. If AI has pushed us deep into the trap, it might take years or even decades to fully recover, but the hardest part is up front. Every part after will snowball,
as long as
we keep focusing on improving coherence and finish the job. If we improve it just enough to go back to our old patterns, we'll only be restarting the cycle.
We already have processes that are known to improve coherence over time. Humans have found ways to create more coherent systems, and those systems are in large part what has enabled the scope and scale of technological progress in the last several centuries.
In particular, the Open Source Software process that powers much of the coherence behind software development is
so successful
at producing coherence that it has outcompeted corporate software development in several truly stunning ways. But we'll discuss that more in the next essay:
Open Capital
.
I'll go into full detail, with examples and benchmarks, but for those of you who don't have the time, here are the headlines:
For lossy photos on the web, AVIF almost always produces smaller files than JPEG XL.
At default effort settings, the best JPEG XL version is typically 15–25% larger than the equivalent AVIF. At maximum effort settings, the gap narrows a little, to typically 6–20%. There are outliers, where JPEG XL is close to, or even beats AVIF, so if you want the absolute best result for a particular image, it's worth trying both. See the
F1 image
for a typical example, and the
weasel
for an outlier.
The JPEG XL encoder matters a lot.
jixel
, a newer JPEG XL encoder, usually produces smaller files than
libjxl
, except when the image has detailed transparency. The
people image
is one example.
For screenshots and illustrations, AVIF is much better than JPEG XL.
The equivalent JPEG XL is 30–90% larger at default effort settings, and 20–70% larger at maximum effort settings. Lossy AVIF handles these well - you don't need to use lossless formats unless you really need bit-exact results. See the
screenshot
and
illustration
examples.
For images with transparency, AVIF is much better than JPEG XL.
The libjxl version is 31–44% larger at default effort settings, and 61–70% larger at maximum effort settings. jixel always encodes transparency losslessly, which makes its files 2–3x the size of AVIF's.
See the data
.
AVIF is generally faster to encode, and uses less memory, when you factor in file size.
jixel is faster than AVIF and uses less memory, but its files are typically significantly larger, so AVIF is better on balance. See the
F1 image
for one example.
AVIF is faster to decode.
JPEG XL typically takes 2–3x as long to decode at medium quality, but the gap narrows at very high qualities, where Chrome can sometimes decode JPEG XL faster. The
people image
is one example.
Higher effort settings are worth it for AVIF and jixel, but not libjxl.
libjxl's higher efforts are much slower, use a lot more memory, and barely improve the result. Sometimes they produce larger files than the default effort. The
screenshot
is an example of this.
AVIF's 4:2:0 mode (half colour resolution) shouldn't be your default.
It rarely reduces file size, and it makes higher qualities harder to reach. Although, it is quicker to encode and decode. Stick with 4:4:4 if you don't have time to check both. The
F1 image
is one example, and the
screenshot
is an exception.
Quality settings are reliable for all the encoders.
With a single quality setting, the resulting quality varies a bit between images, but all the encoders vary in the same direction, and in ways that seem reasonable.
See the data
.
Progressive JPEG XL is basically free at high effort.
jixel recently added support for early progressive previews, and at its slowest setting they cost little or nothing, but at its default setting the files are 12% bigger. Firefox and Chrome support progressive JPEG XL. Safari still renders the final image, but doesn't show progressive previews. However, is this type of progressive rendering a good user experience?
See the examples and data
.
AVIF supports progressive rendering!
It's Chrome-only for now, but it's in progress for Firefox. It's more complex than progressive JPEG XL, but it gives you more control over what the preview looks like, the files are usually smaller, and they're much faster to decode.
See for yourself
.
For HDR, JPEG XL lacks gain maps, which is a significant limitation compared to AVIF.
The JPEG XL format supports gain maps, but they aren't supported by browser decoders, and the encoding story is messy/experimental. When comparing non-gain mapped HDR content, the two quality metrics I used disagree a lot, but they agree that JPEG XL produces smaller files compared to AVIF.
See the examples
.
JPEG XL can make existing JPEGs 9–20% smaller, without further loss.
It's also as fast or faster to decode, except for small images.
See the data
.
For lossless, JPEG XL is the clear winner.
Lossless WebP is 9–17% larger for photos, and lossless AVIF is 30–120% larger. But lossless images are almost never what you want on the web. If you do use them on the web (like I do on this page), watch out for jixel's higher efforts - it often produces files that are too slow to decode.
See the data
.
Animated image formats continue to be a dumb idea.
Please don't use them.
Learn more
, if you must.
For web use-cases, I'd currently default to AVIF 4:4:4, with the highest effort level I can be bothered with. If I felt AVIF was producing an unusually large file, I'd take a look at JPEG XL via jixel, and see if it did better.
Both AVIF and JPEG XL (via jixel) have seen massive improvements recently, so it's possible that this recommendation could change in future. There's been a lot of misinformation around this stuff, and your AI will happily deliver that misinformation to you. Instead, test things with your own images.
AVIF folks suggest
that JPEG XL is technically limited compared to AVIF. That might be true, but in this article I'm focusing on results with today's implementations.
jixel
0.4.2 (git
f487299
), a second JPEG XL encoder
cwebp
1.6.0 (lossless WebP is used later in the article)
I chose a selection of images, and encoded most of them to a width of 1598 pixels - which is 2x the maximum width images appear on this blog. This means they
look sharp on high density displays
, which most users have. As a result, if you're viewing this on a small or low density screen, you're not getting the full experience.
I ran these benchmarks on my 2024 MacBook Pro (M4 Pro).
When I
first wrote about AVIF
, I used an F1 car as the first image, so I figured I'd do that again!
I encoded the image at various codec qualities, and chose versions that were closest to particular
SSIMULACRA2
scores - a perceptual image quality metric by the folks behind JPEG XL. 50 is considered medium quality, 70 high, 80 very high, and 90 visually lossless. Although, I'm not sure if these ratings take high density displays into account.
Throughout the article, the visual comparisons, like above, use each encoder's maximum effort, except in cases where maximum effort results in a larger file (yes, that happens).
For archival, I'd tend towards near-lossless qualities, but if I'm just displaying an illustrative image on my blog, performance is more important to me. I'm personally happy with the 70 result above. If you zoom in, you can see the quality loss, but if I was really concerned about the zoom-in case, I'd use something like the
VisualViewport
API
to load in a higher resolution image when that happens, rather than make the download bigger for everyone.
At lower qualities you can see the difference in strategy between the codecs. The detail loss is around the same, but AVIF tends to smooth things out compared to the original, whereas JPEG XL seems to introduce rougher patterns.
Also, I feel that, at medium quality (50), the AVIF and libjxl look better than the jixel version. The jixel version has a lot of visible noise around the BWT logo, and the Microsoft text on the front wing is way less legible. It makes me wonder about the metric a bit.
Anyway, here's my interpretation of the results:
File size:
AVIF wins
.
At default efforts, the best JPEG XL image is 14–17% larger than the AVIF image for the same quality. jixel is the better JPEG XL encoder at medium/high quality, and libjxl is slightly better at very high quality. At maximum efforts, the best JPEG XL image (jixel 'extraslow') is 6–15% larger than AVIF (s0).
jixel at its slowest setting slightly beats AVIF's default effort
, with files 1–10% smaller. The biggest gain is at very high quality.
Encode time:
AVIF wins
.
At default efforts, jixel is 12–36% faster than AVIF, but its files are 14–18% larger. To match the file size of AVIF's default, jixel needs its 'extraslow' setting, which takes 18–27x as long as AVIF. libjxl's default takes 1.5–2x as long as AVIF's default, and still produces bigger files.
Encode memory:
AVIF wins
.
At default efforts, jixel uses around half the memory of AVIF, but again, its files are 14–18% larger. To match the file size of AVIF's default, jixel 'extraslow' uses ~10x the memory. libjxl's default uses 2–3x the memory of AVIF, and its higher efforts use ~7x.
Decode time:
AVIF wins
.
JPEG XL takes 2–3x as long to decode at medium quality, narrowing to ~1.5–1.8x at very high quality. Safari's JPEG XL decoder is the slowest.
Higher effort is worth it for AVIF.
AVIF's s5 gets you ~10% smaller files for ~3x the encode time.
Higher effort is worth it for jixel too, up to 'slow'.
'slow' gets you 9–13% smaller files than its default 'fast', for ~3.7x the encode time. 'extraslow' saves another 3–8%, but takes ~8x longer than 'slow' and uses ~9x the memory. Even so, AVIF still wins when given the same encode time: AVIF s5 takes about as long as jixel 'slow', and its files are ~13% smaller.
Higher effort isn't worth it for libjxl.
libjxl's maximum effort is barely any better than its default, but takes ~18x longer.
AVIF's 4:2:0 mode doesn't help much.
It's slightly faster to encode/decode, and uses less memory, but the files aren't meaningfully smaller, and it struggles to reach higher qualities.
Here's the full data, so you can make up your own mind:
Ok, let's get to our first graph, the SSIMULACRA2 scores:
File size
SSIMULACRA2 (higher is closer to the original)
There's going to be a lot of these graphs, so here's what's going on:
The x-axis is visual quality
according to SSIMULACRA2.
The y-axis is file size
. Lower is better, for a given visual quality.
The orange lines represent JPEG XL encoded with libjxl.
The green lines represent JPEG XL encoded with jixel.
The blue lines represent AVIF.
The dashed blue lines represent AVIF with its color data at half resolution.
Known as 4:2:0, or chroma subsampling.
The darker lines represent higher effort levels for that codec.
libjxl calls this 'effort', so the e10 line is the top effort. Annoyingly, avifenc calls this 'speed', so the s0 line is the top effort. jixel names its levels, from 'fast' (its default) to 'extraslow'.
Only the default and maximum efforts are shown initially.
Click the legend to toggle the others.
Here are the quality results using a different quality metric,
ColorVideoVDP
:
File size
ColorVideoVDP, JOD (10 = no visible difference)
The result is roughly the same except this metric puts more of a gap between AVIF and the JPEG XL images.
It also suggests there's some advantage to AVIF with 4:2:0 chroma subsampling at lower qualities, but it's minor.
When it comes to images on my blog, I encode with maximum effort settings. I'm happy to wait a couple of seconds to get an image that's faster to load for every user. However, if you're doing a lot of encoding on a server, encode time becomes more of a concern.
It's worth considering decoding performance. If decoding is particularly slow, then it might make the file size benefit less valuable, especially when images are loaded from a cache.
Decode time
SSIMULACRA2 (higher is closer to the original)
JPEG XL becomes suddenly faster to decode at very high quality settings (but still slower than AVIF). I think this is due to an edge preserving filter that does more work at lower quality settings.
I've heard people say that AVIF's tendency to smooth out details makes it bad for human faces, so I picked this image
from Unsplash
.
The results of the benchmark for this image:
File size:
AVIF wins
.
At default efforts, the best JPEG XL image is 17–24% larger than the AVIF image for the same quality. jixel is the better JPEG XL encoder across the whole quality range this time. libjxl is 30–50% larger than AVIF, which is a much bigger gap than the F1 image. At maximum efforts, the best JPEG XL image (jixel 'extraslow') is 12–17% larger than AVIF (s0).
jixel at its slowest setting doesn't quite match AVIF's default effort
this time. It's a few percent larger at medium/high quality, and only edges ahead at very high quality.
Encode time:
AVIF wins
.
At default efforts, jixel is 18–33% faster than AVIF, but its files are 17–24% larger. Even jixel's 'extraslow' setting, which takes 25–39x as long as AVIF, only matches AVIF's default file size at very high quality. libjxl's default takes 1.5–2.2x as long as AVIF's default, and still produces bigger files.
Encode memory:
AVIF wins
.
At default efforts, jixel uses around half the memory of AVIF, but again, its files are 17–24% larger. jixel 'extraslow' gets closest to AVIF's default file size, but uses ~10x the memory. libjxl's default uses 2–3.3x the memory of AVIF, and its higher efforts use ~7x.
Decode time:
AVIF wins
.
JPEG XL takes 2–2.9x as long to decode at medium quality, narrowing to ~1.3–1.7x at very high quality. At the very top of the quality range, libjxl images decode as fast as AVIF in Chrome, but not in the other browsers.
Higher effort is worth it for AVIF.
AVIF's s5 gets you 5–8% smaller files for ~3x the encode time. That's a smaller gain than the F1 image.
Higher effort is worth it for jixel too, up to 'slow'.
'slow' gets you 7–14% smaller files than its default 'fast', for ~3.9x the encode time. 'extraslow' saves another 4–6%, but takes ~10x longer than 'slow' and uses ~9x the memory. AVIF still wins when given the same encode time: AVIF s5 takes about as long as jixel 'slow', and its files are 8–17% smaller.
Higher effort is somewhat worth it for libjxl on this image.
Unlike the F1 image, libjxl's maximum effort gets you 4–11% smaller files than its default. But it takes ~10x longer, and it still produces much bigger files than AVIF at its default effort.
AVIF's 4:2:0 mode doesn't help much.
Same as the F1 image. ColorVideoVDP gives it a small (~4%) advantage, but SSIMULACRA2 doesn't.
At lower qualities, you can see the smoothing on the face, but it's the same for both AVIF and JPEG XL.
I threw this one in because it's the default image in
Squoosh
, but I guess the sharp lines of the hairs make it different to the previous images. In fact, even at medium quality, the difference from the original is much less perceptible to my eyes compared to the other images.
The results are much closer than the previous two:
File size:
AVIF wins
, narrowly.
At default efforts, the best JPEG XL image (jixel) is only 2–6% larger than the AVIF image for the same quality. libjxl does much worse, at 10–18% larger. At maximum efforts, jixel 'extraslow' and AVIF s0 are roughly tied, with jixel up to 5% smaller at very high quality. However, ColorVideoVDP disagrees, and puts AVIF 5–12% ahead at maximum efforts.
Encode time:
JPEG XL (jixel) wins
, according to SSIMULACRA2.
At default efforts, jixel is 19–35% faster than AVIF, and its files are only 2–6% larger. Comparing higher efforts, jixel 'slow' produces files the same size or slightly smaller than AVIF s5, in the same time or less. And jixel 'extraslow' matches or beats AVIF s0 while being 12–34% faster. But, since ColorVideoVDP gives AVIF more of a file size advantage, it isn't clear-cut. libjxl's default takes 1.3–1.9x as long as AVIF's default, and produces bigger files.
Encode memory:
JPEG XL (jixel) wins
, at lower efforts.
At default efforts, jixel uses 37–48% less memory than AVIF, and its files are only 2–6% larger. jixel 'slow' uses about the same memory as AVIF s5 to produce a similar file size, but 'extraslow' uses ~9x the memory of AVIF s0. libjxl's default uses ~2x the memory of AVIF, and its higher efforts use 6–7x.
Decode time:
AVIF wins
.
JPEG XL takes 2–2.4x as long to decode at medium quality. But the gap closes at very high quality, where jixel's files decode about as fast as AVIF in Firefox and Safari, and ~25% faster in Chrome.
Higher effort is less worth it for AVIF on this image.
AVIF's s5 gets you 3–6% smaller files for 3–4x the encode time.
Higher effort is worth it for jixel, up to 'slow'.
'slow' gets you 6–14% smaller files than its default 'fast', for 3.5–4.3x the encode time. 'extraslow' saves another 2–9%, but takes 9–14x longer than 'slow' and uses ~9x the memory.
Higher effort isn't worth it for libjxl.
libjxl's maximum effort gets you 1–2% smaller files than its default, but takes ~12x longer.
AVIF's 4:2:0 mode doesn't help.
The files are the same size as 4:4:4.
I've played with both codecs a lot, and for photos, what I've shown so far is representative, where AVIF beats JPEG XL. However, every now and then there's an outlier, such as this image.
File size:
JPEG XL wins
.
At default efforts, the best JPEG XL image is 4–11% smaller than the AVIF image for the same quality. libjxl is the better JPEG XL encoder at medium/high quality, and jixel at very high quality. At maximum efforts, jixel 'extraslow' is 12–27% smaller than AVIF s0. This time, ColorVideoVDP agrees.
jixel's 'medium' setting is a big step up on this image.
Its files are 11–25% smaller than AVIF's default, and 4–18% smaller than AVIF s0, the maximum effort.
Encode time:
JPEG XL (jixel) wins
.
At default efforts, jixel is 28–38% faster than AVIF, and produces files that are around the same size or smaller. At higher efforts, it's even more one-sided: jixel 'medium' is 37–65% faster than AVIF s5, and produces files 9–23% smaller. libjxl's default takes 1.5–2.2x as long as AVIF's default.
Encode memory:
JPEG XL (jixel) wins
.
At default efforts, jixel uses 14–24% less memory than AVIF, and produces files that are around the same size or smaller. AVIF s0 uses even more memory (~1.55x its default), and still produces bigger files than jixel 'medium', which uses 41–55% less memory than AVIF s0. libjxl's default uses 2.4–3.6x the memory of AVIF, and the maximum efforts of both JPEG XL encoders use 10–18x.
Decode time:
AVIF wins
, except in Chrome at higher qualities.
JPEG XL takes 1.3–1.9x as long to decode in Firefox and Safari. In Chrome, JPEG XL takes ~1.25x as long at medium quality, but from high quality upwards, it's 11–36% faster than AVIF.
Unlike the previous images, jixel images aren't particularly slow to decode in Safari.
In fact, they decode slightly faster than libjxl images.
Higher effort isn't really worth it for AVIF on this image.
AVIF's s5 only gets you 1–3% smaller files for 3–4.5x the encode time. s0 gets you 7–8% smaller files, but takes ~50x as long.
Higher effort is worth it for jixel, up to 'slow'.
'medium' gets you 6–14% smaller files than its default 'fast', for 1.9–4.1x the encode time. 'slow' gets you 9–19% smaller files than 'fast', for 3.9–6.5x the encode time. 'extraslow' saves another 5–9%, but takes 8–18x longer than 'slow' and uses ~11x the memory.
Higher effort isn't worth it for libjxl.
libjxl's maximum effort gets you 1–6% smaller files than its default, but takes 11–14x longer.
AVIF's 4:2:0 mode doesn't help.
The files are the same size as 4:4:4.
All three encoders produce lower SSIMULACRA2 scores for this image.
As in, with the same encoder quality value, they score lower. It seems like the encoders are pretty happy smoothing out some of the background noise, which seems fine.
File size:
AVIF wins
, by a lot.
At default efforts, the best JPEG XL image is 73–89% larger than the AVIF image at medium/high quality (jixel), and 29–44% larger at very high quality (libjxl). At maximum efforts, the best JPEG XL image (jixel 'extraslow' with patches) is 23–73% larger than AVIF (s0).
libjxl can't produce anything between SSIMULACRA2 ~45 and ~78
at its default effort (~45 and ~75 at higher efforts). jixel doesn't have this problem.
jixel's patches feature helps a lot with this image
, but it's off by default. With patches, jixel's files are 10–29% smaller at its higher efforts, from SSIMULACRA2 ~65 upwards. Patches have no effect at jixel's default 'fast' setting.
Encode time:
AVIF wins
.
At default efforts, jixel is ~50% faster than AVIF, but its files are 70–98% larger. libjxl's default takes 1.7–1.8x as long as AVIF's default, and still produces much bigger files.
Encode memory:
AVIF wins
.
At default efforts, jixel uses ~40% less memory than AVIF, but again, its files are much larger. libjxl's default uses 1.2–2.2x the memory of AVIF. jixel 'extraslow' with patches gets closest to AVIF's file sizes, but uses ~7.5x the memory of AVIF's default.
Decode time:
AVIF wins
, by a lot.
Taking the faster of the two JPEG XL encoders' output, JPEG XL takes 2–3.8x as long to decode, depending on browser and quality.
Higher effort is more worth it for AVIF on this image.
AVIF's s5 gets you 6–13% smaller files for 2.5–3x the encode time, and s0 gets you 16–23% smaller files for 30–45x the encode time.
Higher effort is worth it for jixel, as long as you enable patches.
'medium' with patches gets you 11–44% smaller files than its default 'fast', for 3–4x the encode time. 'slow' with patches saves another 7–16% for ~1.7x the time of 'medium'. 'extraslow' with patches saves another few percent, but takes ~5x longer than 'slow' and uses ~4.5x the memory.
Higher effort is harmful for libjxl.
At very high quality, libjxl's maximum effort produces files 33–40%
larger
than its default effort, and takes ~7x longer.
AVIF's 4:2:0 mode helps at higher qualities.
At SSIMULACRA2 70 and above, it produces files 7–18% smaller than 4:4:4. At lower qualities, it makes no difference.
All three encoders produce higher SSIMULACRA2 scores for this image.
Opposite to the weasel image. But, this seems correct. At SSIMULACRA2 70 the artifacts are pretty noticeable around the Firefox logo (to me, anyway), so I'd go with 80, which is where the codecs lean anyway.
Some developers, especially those who've been around as long as I have, seem to think things like screenshots need to be delivered in a lossless format. But I think this is because they're used to formats like JPEG and WebP (and seemingly JPEG XL) which handle this kind of image badly, whereas lossy AVIF handles them really well.
In many cases, for largely flat-colour images, you'd use SVG. But sometimes that isn't possible (it's a screenshot), or undesirable, such as this case. This image,
also from Unsplash
, is still 1.1 MB as a compressed and minified SVG. This is due to the complexity of the shaded areas. As a result, a raster format wins on file size and decode/draw time.
At quality 50 in the demo above, the jixel has some pretty severe colour blocks, e.g. on the cat's face. Again, it makes me question the metric a bit.
The results of the benchmark:
File size:
AVIF wins
, by a lot.
At default efforts, the best JPEG XL image (jixel) is 32–65% larger than the AVIF image up to SSIMULACRA2 80, and ~90% larger beyond that. At maximum efforts, the best JPEG XL image (jixel 'extraslow') is 22–55% larger than AVIF (s0) up to SSIMULACRA2 80, and more beyond that. ColorVideoVDP agrees, and puts the gap at 27–58%.
libjxl performs particularly badly with this image.
At default efforts, it's 71–106% larger than AVIF.
Lossy AVIF can't reach SSIMULACRA2 90 with this image.
Even at its maximum quality setting, it tops out at ~87, so the 90 example above isn't a totally fair comparison. JPEG XL can reach 90, but the result is 8–50% larger than JPEG XL's lossless version, so you may as well use lossless.
Encode time:
AVIF wins
.
At default efforts, jixel is 35–44% faster than AVIF, but its files are 32–65% larger, which is a bad trade. jixel needs its 'slow' setting to get within 7–27% of AVIF's default file size, which takes 2.4–2.6x as long as AVIF. libjxl's default takes 1.3–2.3x as long as AVIF's default, and produces much bigger files.
Encode memory:
AVIF wins
.
At default efforts, jixel uses ~37% less memory than AVIF, but again, its files are much larger. jixel 'slow' uses about the same memory as AVIF, and 'extraslow' uses ~12x. libjxl's default uses 1.5–3x the memory of AVIF.
Decode time:
AVIF wins
, by a lot.
JPEG XL takes 2–4.6x as long to decode at medium/high quality, narrowing to 1.6–2.1x at very high quality.
Higher effort is more worth it for AVIF on this image.
AVIF's s5 gets you 5–8% smaller files for ~2.7x the encode time, and s0 gets you 14–21% smaller files for 35–48x the encode time.
Higher effort is worth it for jixel, up to 'slow'.
'medium' only gets you 4–13% smaller files than its default 'fast', but 'slow' gets you 19–24% smaller files (up to 36% at very high quality), for ~4x the encode time. 'extraslow' saves another 2–3%, but takes 8–9x longer than 'slow' and uses ~11x the memory.
jixel's patches feature doesn't help with this image.
Unlike the screenshot, the file sizes are identical with and without it, but it does increase encode time and memory.
Higher effort isn't worth it for libjxl.
libjxl's maximum effort gets you 3–9% smaller files than its default, but takes 10–13x longer.
AVIF's 4:2:0 mode doesn't help.
SSIMULACRA2 rates it slightly worse than 4:4:4, and ColorVideoVDP rates it slightly better (~3–4%).
So far, all the images have been mostly opaque. What about an image with transparency?
There are a few things that make this one different:
jixel always encodes the alpha channel losslessly.
It doesn't have a setting for alpha quality. This puts jixel at a big disadvantage with this image. AVIF by default compresses the alpha channel lossily, tracking the main quality setting. libjxl compresses the alpha channel losslessly by default, so watch out for that. For this benchmark, I set libjxl's alpha quality to the same as the main quality.
SSIMULACRA2 scores fully-transparent pixels as perfect
, so with lots of transparency, the scores will be higher than they would be for an opaque image.
The results of the benchmark:
File size:
AVIF wins
, by a lot.
At default efforts, the best JPEG XL image (libjxl) is 31–44% larger than the AVIF image for the same quality. At maximum efforts, it's 61–70% larger. Due to its lossless alpha, jixel is 1.9–3.1x the size of AVIF at default efforts.
Encode time:
AVIF wins
.
libjxl's default takes 1.2–1.35x as long as AVIF's default, and produces much bigger files. jixel's default is ~2x faster than AVIF, but its files are around 2–3x the size.
Encode memory:
AVIF wins
.
libjxl's default uses 2.4–2.7x the memory of AVIF's default, although in absolute terms, that's ~120 MB vs ~46 MB. jixel's default uses about the same memory as AVIF, but again, its files are much bigger.
Decode time:
AVIF wins
.
libjxl's output takes 2–3x as long to decode at medium quality, narrowing to 1.4–1.8x at very high quality. jixel's output decodes faster than libjxl's, and at very high quality it's around the same speed as AVIF. Although, it's slow in Safari at lower qualities, taking ~2.4x as long as AVIF.
Higher effort is worth it for AVIF.
AVIF's s5 gets you 4–7% smaller files for 2.3–2.9x the encode time, and s0 gets you 10–15% smaller files for 24–29x the encode time.
Higher effort barely helps jixel on this image.
'extraslow' only gets you 5–8% smaller files than its default 'fast', for 21–26x the encode time.
Higher effort is harmful for libjxl.
libjxl's maximum effort produces files up to 8%
larger
than its default effort, and takes ~6.5x longer.
AVIF's 4:2:0 mode is harmful.
It produces files 4–27% larger than 4:4:4, and can't get beyond SSIMULACRA2 ~79.
The images so far have been a similar resolution. Are the results different with smaller images?
Not really. The results are pretty similar to the full-size F1 image:
File size:
AVIF wins
, by about the same margin. At default efforts, the best JPEG XL image is 13–18% larger. At maximum efforts, the gap is slightly bigger than the full-size image, at 12–20%.
Encode time & memory:
AVIF wins
, although libjxl's default is now around the same speed as AVIF's default. jixel's default is ~2x faster than AVIF, but its files are 13–18% larger, and this time it uses ~30% more memory. In any case, at default efforts, everything encodes in under 50ms, using under 40 MB, so these differences don't really matter at this size.
Decode time:
AVIF wins
, by a similar margin, but again, everything decodes in a few milliseconds.
Mostly the same story as the regular F1 image, but with a few differences:
File size:
AVIF wins
at medium/high quality, by more than the regular image.
At default efforts, the best JPEG XL image is 18–46% larger, and at maximum efforts, 28–54% larger.
But JPEG XL catches up at very high quality.
Around SSIMULACRA2 85, libjxl's default matches AVIF's default, and at maximum efforts, jixel 'extraslow' is ~6% smaller than AVIF s0. jixel 'slow' is 10–13% smaller than AVIF's default from SSIMULACRA2 80 upwards.
Encode time:
AVIF wins
at medium/high quality, but
JPEG XL (jixel) wins
at very high quality.
AVIF's default takes ~0.5 seconds, whereas libjxl's default takes 1–2 seconds. jixel's default is ~2x faster than AVIF, but at medium/high quality its files are 29–57% larger. At very high quality, that drops to 6–12% larger, which seems like a reasonable trade-off for the speed. And jixel 'slow' produces files around the same size as AVIF s5, while being 33–41% faster.
Encode memory:
AVIF wins
, and the costs are now significant.
AVIF's default uses ~560 MB. libjxl's default uses ~2.5 GB at medium/high quality. jixel's default uses ~35% less than AVIF, and 'slow' uses ~18% less than AVIF s5. At maximum efforts, libjxl uses 5–6.4 GB, and jixel 'extraslow' uses 6.8–8.3 GB.
Decode time:
AVIF wins
at medium/high quality, by a similar margin to the regular image. jixel images take over 5x as long as AVIF to decode in Safari at those qualities. At very high quality, JPEG XL decodes faster than AVIF in Chrome.
Another criticism I've heard levelled at AVIF is that its quality is unreliable. As in, a single quality setting is great for some images, but no good for others, meaning for automatically encoded images, you need to pick a higher quality setting to be safe, resulting in larger file sizes than necessary for some images.
For the images I've looked at so far, I encoded them with
avifenc -q 50
,
cjxl -q 70
, and jixel at quality 80, and recorded the resulting SSIMULACRA2 scores:
The behaviour of the codecs here seems really similar. All produce a range of SSIMULACRA2 scores, and they all go higher or lower for the same images.
And I think this is ok? Like, all three go for a lower quality for the Weasel picture, which removed noise without reducing quality of the image subject. With the screenshot, all go for a higher quality, which seems justified to my eyes.
Obviously this is a small sample size, but I haven't seen anything that suggests using a single quality setting is a risk, for any of the three codecs.
Both AVIF and JPEG XL are capable of showing something progressively as the image loads. Chrome and Firefox support progressive JPEG XL, whereas only Chrome supports progressive AVIF. So, and I say this through gritted teeth, this next demo is best viewed in Chrome (I have
a Firefox patch in progress
):
AVIF: 11.5 kB of 151.3 kB
JPEG XL: 11.5 kB of 166.0 kB
This is the 18 megapixel image again, so if you're viewing this on a device with a smaller screen, you're not getting the full effect.
Progressive AVIF and JPEG XL work very differently. With JPEG XL, you can opt into the data being stored in such a way that a decoder can render low resolution versions, before it brings in the higher resolution tiles. jixel recently (like, yesterday at time of writing) added support for this too. It's called "progressive DC", and it's the most important kind of progressive rendering for JPEG XL.
With AVIF, progressions work more like frames of a video. You provide up to four frames, so that's three phases before the final image. Again, like a video, each frame can use data from the previous frame as an optimisation. An advantage of this is you can choose exactly how those frames look. In the example above, I went with a single preview frame: a 1/8th resolution version, with a bit of blurring. But, your preview frames can be completely different images if you really want.
There's a lack of data when it comes to progressive images and user experience, so these are just my reckons:
If you're on a bad connection, data doesn't arrive gradually like some throttling tools will have you believe. It tends to come in bursts. So, there's little benefit to progressive rendering on smaller images, and I'm not sure that many progressive phases is particularly useful.
I think that it's nice to have a
representative
preview for images that may take some time to load. I've experienced this personally, where a site or app has given me something clearly not-loaded, but with enough detail to know what's coming. That's useful to me, as I can decide things like, if it's worth waiting for the whole thing. This is also why I think things like BlurHash are cute, but useless. They're not a
representative
preview, so there's little a user can do with the information provided.
The preview frame I chose for the AVIF is enough to tell it's an open-wheel race car. If you know F1, you'll know what team it is. You might even know where the photo was taken. And it delivers that in ~11.5 kB.
The JPEG XL gets a BlurHash-like preview on screen in ~2 kB, but it takes until ~63 kB to match the preview quality of the AVIF. After that, it continues to improve gradually, providing a more detailed and higher quality image as more data arrives.
However, I'm not convinced this is a good user experience, as it presents the user with something they may mistake for fully-loaded, but poor quality. For example:
Here's a crop of the JPEG XL, 80% loaded. It seems reasonable that someone would look at that, and just assume I took the picture badly, leaving parts out of focus. You could probably convince me that blurring the ApeCoin logo is a societal benefit, but it still feels like a suboptimal user experience.
AVIF's system gives me more control, but it's also more complex.
I encoded the large F1 image with and without progressive rendering enabled, adjusting the quality setting to keep the SSIMULACRA2 score around 70:
With libjxl, progressive is basically free.
In fact, it produced files 6–10% smaller. At default effort, it was also faster to encode, and used less memory. Decoding was ~10% faster in Firefox, but 12–20% slower in Chrome and Safari.
With jixel, it depends on the effort.
For jixel, I used progressive DC, with the centre of the image loading first. At jixel's default ('fast'), progressive made the file 12% bigger. At 'extraslow', it made the file 10% smaller, and 11% faster to encode, although it used 17% more memory. Decoding was barely affected, other than being 7–9% slower in Chrome.
But ColorVideoVDP is less kind to progressive jixel.
It rates jixel's progressive files slightly lower than the non-progressive versions, whereas it rates libjxl's progressive files slightly higher. Taking that into account, progressive jixel at 'extraslow' is only ~2% smaller than non-progressive, and at 'fast' it's around 18% bigger.
Regular progressive AVIF has a bigger cost when it comes to encoding.
It uses around twice the memory, and at default effort (s6), it takes twice as long to encode. At s0, encode time is only 9% longer, but the file is 14% bigger. And this is pure encode time - it doesn't factor in how you might generate the preview frame, e.g. adding some blur.
Regular progressive AVIF is 29–44% slower to decode in Chrome
, although the difference is smaller in other browsers (6–15%). Since Chrome is the only browser that supports rendering the progressive frames, that might explain it. Although Firefox and Safari are still having to decode the progressive frame, as the main image builds upon it.
With AVIF, making the final frame a keyframe fixes the decoding overhead
, at the cost of a longer encode time. At maximum effort, it results in a smaller file too, only 3–5% bigger than the non-progressive version. You could call this cheating, as there's now no 'progression' in terms of data - it's just two images in one. But, if it's a better user experience, who cares?
Even with the overhead, progressive AVIF wins on decoding time, and usually on file size.
The progressive AVIFs are 152–181 kB. jixel's 'extraslow' progressive JPEG XL is in that range at 166 kB, but jixel's default produces 252 kB, and libjxl's progressive files are 233–242 kB. The AVIFs decode 1.6–6x faster, with the biggest gap in Safari, which is particularly slow to decode jixel's files.
Let's get back to lossy compression, but this time HDR! There are a few ways to encode HDR images, and we're going to look at two.
Perceptual Quantization
(PQ) tells each pixel what to be. Each value maps to an absolute brightness, up to 10,000 nits, with the curve shaped so the data is spent where our eyes are most sensitive. If the image asks for colours and brightnesses the display can't show (no consumer display can hit 10,000 nits), the browser/OS has to tone-map it down, and how well that's done varies between platforms.
Gain maps
are different. The main image is a regular SDR image (usually), and alongside it is a 'gain map', which applies a brightness and colour change to each pixel to achieve the HDR version.
This has two benefits:
The same image will look exactly as you want on an SDR display - the gain map is simply ignored.
If the display supports HDR, but maybe not as much as the image needs (for example, the screen is at low or maximum brightness), the browser/OS can apply as much of the gain map as it can handle.
CSS and
<picture>
let us serve an SDR or PQ image to the user via
the
dynamic-range
media query
, but then you're relying on tone mapping in cases where the browser signals HDR support, but it doesn't support the full range.
Although the JPEG XL format supports gain maps, no browser handles them, and the encoding story is messy.
AVIF supports gain maps, and you encode them by providing two images: the SDR image and the HDR image. It uses those to calculate and encode the gain map.
Your browser/screen doesn't support HDR
, so the PQ images will look bad.
At medium brightnesses, on an HDR screen, the gain map and PQ images look the same. At maximum brightnesses, on my Pixel 10 Pro and 2024 MacBook Pro, the PQ images get a bit blown out, and the gain map image looks better. At low brightness on my Pixel 10 Pro, again the gain map image looks better.
This is because, at extreme brightness levels, the device doesn't have the full HDR headroom to display the image, and gain maps can handle these cases better. So, although gain maps seem to add a lot to the file size, I think it's worth it.
Maybe there's a future where tone mapping gets much better, and the advantage of a gain map becomes less significant.
Regular SSIMULACRA2 only understands SDR, so for this image, the scores come from an experimental HDR mode in
fast-ssim2
. That means these scores can't be compared to the SSIMULACRA2 scores elsewhere in this article. ColorVideoVDP handles HDR natively, and here it's modelling a 1,500 nit HDR monitor.
The two metrics disagree a lot with this image
. And they don't factor in the benefits of gain maps, so treat these results as a comparison between the PQ variants:
File size:
JPEG XL wins
, but the metrics disagree on how much, and with which encoder.
According to HDR SSIMULACRA2, jixel's default ranges from 8% smaller to 3% larger than PQ AVIF's default, and libjxl is 5–33% larger. At maximum efforts, jixel 'extraslow' is up to 15% smaller than PQ AVIF s0.
According to ColorVideoVDP, libjxl is the clear winner. At default efforts, it's 28–53% smaller than PQ AVIF, and 17–37% smaller than gain map AVIF. At maximum efforts, it's up to 23% smaller than the best AVIF, but jixel 'extraslow' is roughly level with it, ranging from 12% smaller to 14% larger.
The metrics also disagree about gain maps.
HDR SSIMULACRA2 says gain map AVIF is 31–38% larger than PQ AVIF, but ColorVideoVDP says gain map AVIF is 11–25%
smaller
than PQ AVIF.
Encode time:
JPEG XL (jixel) wins
.
At default efforts, jixel is ~2x faster than PQ AVIF, and produces files around the same size or smaller, depending on the metric. libjxl's default is 5–47% slower than PQ AVIF, but given ColorVideoVDP's view of the file sizes, that's a reasonable trade. Gain map AVIF is the slowest, as it's calculating a gain map, then essentially encoding two images: ~3x slower than PQ AVIF.
Encode memory:
JPEG XL (jixel) wins
.
At default efforts, jixel uses ~30% less memory than PQ AVIF. libjxl's default uses ~1.9x the memory of PQ AVIF, and gain map AVIF uses ~1.55x. At maximum efforts, libjxl uses ~6x the memory of PQ AVIF's default, and jixel 'extraslow' uses ~10x.
Decode time:
AVIF wins
.
PQ and gain map AVIF decode at around the same speed. JPEG XL takes 1.2–1.7x as long to decode in Chrome, although it's slightly faster at the top of the quality range. In Safari, it takes 1.6–3x as long. Firefox is particularly slow with these HDR JPEG XL images, taking ~4x as long as AVIF at all qualities. We're
working on it
.
Higher effort is worth it for AVIF.
For gain map AVIF, s5 gets you 9–12% smaller files for ~1.9x the encode time, and s0 gets you 14–20% smaller files for ~11x the encode time. For PQ AVIF, s0 gets you 14–19% smaller files, for 17–20x the encode time.
Higher effort is worth it for jixel, up to 'slow'.
'slow' gets you 7–32% smaller files than its default 'fast', for ~3.8x the encode time. 'extraslow' saves another 1–9%, but takes ~10x longer than 'slow' and uses ~8.5x the memory. jixel only has a few data points for this image, so these numbers are rough.
Higher effort isn't worth it for libjxl.
libjxl's maximum effort gets you 2–7% smaller files than its default, but takes ~15x longer.
It will be interesting to see how JPEG XL handles gain maps once they're fully supported.
JPEG XL allows you to convert an existing JPEG to JPEG XL without additional loss. I tested this with the F1 image at a range of sizes and JPEG qualities:
The JPEG XL is 9–20% smaller than the JPEG.
The saving grows with resolution, from ~9% at 400 pixels wide to ~20% at 4,900 pixels wide. The saving is slightly smaller at higher JPEG qualities. libjxl and jixel produce practically identical file sizes.
For small images, JPEG XL is slower to decode than JPEG
, taking 1.4–2.7x as long, depending on the browser. But it's just a millisecond or two.
For larger images, JPEG XL is faster to decode in Chrome and Safari.
From ~1,000 pixels wide, it matches JPEG, and at the largest sizes, it decodes in around half the time. In Firefox, it ends up around the same speed as JPEG.
jixel's output is slightly slower to decode than libjxl's
in Chrome and Firefox, by up to ~25%. But again, these are small numbers, at most a few milliseconds.
Of course, if you have the original, you'd be way better off creating a proper new lossy version with AVIF or JPEG XL, but it's pretty cool that the JPEGs end up smaller, and sometimes faster to decode. Although, I suppose this is just pointing to a missing optimisation in browser JPEG decoders.
It is very rare to need lossless images on the web. As we've already seen, even for things like screenshots and illustrations, lossy AVIF handles them really well. Ironically, this page is one of the outliers, because I wanted to show the compressed versions vs their lossless counterparts. Thankfully, JPEG XL is great at lossless!
The results:
File size:
JPEG XL wins
.
At default efforts, libjxl produces the smallest files for every image except the illustration, where WebP matches it. WebP is 9–17% larger for photos, and AVIF is 33–122% larger. At highest efforts, libjxl and jixel are within a few percent of each other, WebP is 5–44% larger, and AVIF is 29–176% larger.
Encode time:
JPEG XL wins
.
libjxl's default takes 0.1–0.5 seconds, which is faster than WebP's default, and similar to AVIF's default, while producing smaller files than both.
Encode memory:
JPEG XL wins
or
WebP wins
, depending on the image.
WebP's default uses around half the memory of libjxl's default (55–110 MB vs 110–250 MB), but libjxl's files are smaller. For photos, WebP can't match libjxl's default file size even at its maximum effort, which uses more memory than libjxl's default. For the screenshot, they use around the same memory, but libjxl's file is smaller. The illustration is the exception: WebP's maximum effort produces a file 20% smaller than libjxl's default, using the same memory.
Decode time:
WebP wins
or
JPEG XL wins
, depending on the image.
WebP decodes photos in 17–39 ms in all browsers, and the screenshot in ~5 ms. libjxl's output takes 1–2.2x as long in Chrome, 1.4–2.7x as long in Firefox, and 2.1–3.2x as long in Safari. But for photos, JPEG XL's smaller files more than make up for this on a first load, unless the connection is really fast. For the screenshot and illustration, WebP's decode advantage wins. Lossless AVIF is particularly slow to decode, taking up to 4x as long as libjxl's output in Chrome.
Lossless AVIF is bad.
It's significantly larger than the others, and slower to decode.
jixel's 'medium' setting is the sweet spot for file size.
It beats libjxl's default on every image (0.5–23% smaller), and is within 2–3% of the best result for photos, taking 0.4–0.7 seconds. But it uses 470–670 MB of memory, and its output is slower to decode than libjxl's, particularly in Safari.
jixel's 'slow' and 'extraslow' output is very slow to decode for photos.
~200–290 ms, compared to 22–95 ms for libjxl's output. That's 2–13x slower, depending on the browser. It's also slow for the alpha image, at 80–123 ms compared to 14–27 ms for libjxl's output. This doesn't happen with the screenshot and illustration. This means, for my use-case on this page, I'd avoid it.
libjxl's maximum effort is very slow.
It produces files 2–7% smaller than its default for photos, and ~25% smaller for the screenshot and illustration, but takes 9–46 seconds, which is 50–180x as long as its default. jixel gets the same results in a couple of seconds.
jixel's default 'fast' setting isn't great for lossless.
It's the fastest encoder by far (40–80 ms), but its files are 16–32% larger than libjxl's default for photos, and ~80% larger for the screenshot and illustration.
jixel's patches feature helps a bit with the screenshot
(4–9% smaller), but makes no difference to the illustration.
Animated image formats are dumb and animated JPEG XL is no exception. Video formats are better at video. They're built for it. They're optimised for it. Not just in terms of encoding, but also in terms of playback.
I encoded a short clip, and the animated AVIF was 725 kB, and the JPEG XL was 2.17 MB for the same ColorVideoVDP score (9.5).
The JPEG XL is super noisy compared to the AVIF, because each frame is encoded individually, and arttifacts land in different places per frame.
AVIF is basically the keyframe format of AV1 video, with a bunch of still-image-specific optimisations thrown in. Animated AVIF however, is pretty much just a repackaging of AV1 video. You can convert an AV1 MP4 to AVIF and back losslessly - it's just a container change. That's why it performs so much better, because it's built for motion.
However, animated AVIF plays like shit in Chrome and Safari. It's fine in Firefox, so this is purely an implementation problem. But…
<video muted autoplay>
is right there.
I already gave you my
conclusions
at the start, so I guess I'm ready to hit publish.
I'm a little nervous about this, because discourse around JPEG XL can get a little… weird. I see a lot of conspiracy theories about Google trying to 'silence' JPEG XL, even though one of the leads of the project worked at Google, as part of a team that were working on JPEG XL. That
same leader claimed
that the post-COVID layoffs wouldn't have happened if companies simply used JPEG XL. I was recently
called a racist
for asking about JPEG XL use-cases. This kind of thing just doesn't happen with other technologies and standards I follow. So, urm, I'm kinda bracing for impact here.
My first version of this article was very negative about JPEG XL, but then I heard about jixel, and honestly, I'm really excited about it. There's serious competition between AVIF and JPEG XL now, and whoever wins, we'll all benefit from better image compression.
US Rep Announces Congressional Legislation to Protect Video Game Ownership
Today,
Rep. Ritchie Torres
(NY-15) announced he will introduce the
Power To The Players Act
, legislation that would direct the Federal Trade Commission to establish regulations protecting consumers’ ability to own and play the video games they purchase.
Over the past few years, video game companies have moved toward digital-only games and consoles, removing the option to buy or use physical games. These digital games are often sold as revocable licenses rather than owned outright, leaving players dependent on the company’s continued support. NBA 2K25 is a clear example. The game, which retailed for $69.99 for the standard edition and $99.99 for the All-Star Edition, will be delisted from digital storefronts on October 30 and will have its online servers shut down on December 31, only two years after its initial release. No consumer should have a game they paid for pulled out from under them on a company’s arbitrary timeline.
“When you pay for a game, you should own it,” said Rep. Torres. “Consumers must have the right to own, the right to play, and the right to transfer the games they buy. A game that can be taken away the moment a company pulls the plug is not a purchase. It is a rental disguised as a sale. Families in the Bronx and across the country save up to buy these games, and they deserve better than a license that can vanish at any time. The Power To The Players Act ensures consumers own what they buy and can keep playing long after a company moves on.”
Under the bill, buying a video game would give the consumer ownership of the game rather than a license to play it. Games with online functionality would also be required to provide an offline mode before the servers supporting them are shut down.
The legislation aims to close the gap between buying a game and owning it. By preserving consumers’ ability to own and resell their games, the bill would ensure that players can keep playing the games they paid for with friends and family for years to come.
America's Wumao: Inside Polymarket's Paid Quote-Retweet Esports Program
Screenshots from X; minor background elements by Sonny Ross
❝
As I mentioned last week, I’ve launched a
paid tier of the newsletter
. All the money coming from subscriptions will go toward reporting and publishing, covering costs associated with legal review, public records, web hosting, mail, software subscriptions, business admin, travel, and (silliest of all) buying new games.
My next newsletter (which will be available
exclusively to paid subscribers
) is going to be a follow-up to this report, going into why I think prediction markets’ growing influence is worth covering and taking a much broader view of the issue, beyond just the reporting. If that sounds interesting, consider upgrading your subscription. I’ll also include some outtakes from this story: reporting that just didn’t make sense for this particular piece.
Lastly, I want to thank Ollie Ring for his help as I was reporting this newsletter. Ollie writes the
Lootboxes & Leftovers
newsletter
on Substack. Check it out. And much love to Riley MacLeod of
Aftermath
,
where this story will be reprinted later today, for editing this piece.
Once more, but tiny: Thanks for reading!
Polymarket, the prediction market platform, is paying social media users to quote-retweet content from its branded esports accounts. The program includes over 800 participants, according to posts by a Polymarket representative in an internal Discord, and offers rates ranging from $10 to several hundred per post, paid in crypto.
Paying social media users to engage with content is not illegal, and the Polymarket program has robust guidelines around disclosure and the kinds of quote retweets the company is looking for. But the slight “Paid partnership” tag on X — a common sight on the app, and the only public indication that there’s money changing hands — belies the scale and sophistication of Polymarket’s esports operation, which has more than doubled in size since August. And all the while, in the Discord, Polymarket representatives have repeatedly reminded participants in the program to write posts in a way that should appear “organic,” in what one expert said was an effort to ingratiate the prediction market with esports fans and casual observers.
“Literally this needs to look organic and if your X profile looks like Polymarket billboard that looks absoutely [sic] awful,” wrote one Polymarket rep in the Discord.
Polymarket offers two products: Polymarket Global, which is inaccessible to bettors in the United States, and Polymarket US, which is subject to U.S. regulations. In esports —
a growing market for the company
— Polymarket offers lines around the outcomes of major events and matches, player statistics, as well as novelty bets, including some relating to the teams that players might transfer to in the off-season.
1
The prediction market company’s esports outreach is something of an open secret in the esports world — with an emphasis on “open.” Some social media users have expressed dismay over the increasing prevalence of gambling and betting-adjacent companies in the esports scene, having previously been burnt by “here today, gone tomorrow” attention from deep-pocketed crypto companies and venture capital firms. But while elements of the paid marketing program have
previously
been
reported
, little concrete information has been revealed until now about the logistical apparatus behind it, the costs involved, and the Discord server from which the program is run — even as the payments by Polymarket to creators have inspired speculation and debate among esports fans.
Emails to Polymarket’s official press line seeking comment, as well as direct messages to numerous Polymarket representatives from the Discord seeking interviews, went unanswered.
A list of participants in the Discord includes prominent esports commentators, current and former professional players, team coaches and managers, media entrepreneurs and content creators, PR professionals, amateur roster reporters, employees of esports tournament organizers, and various social media gadflies.
When figures like that quote-retweet posts like
the one embedded below
with a sentence or two of commentary, they may be receiving tens or even hundreds of dollars in compensation.
Still, many of the posters paid to quote-retweet Polymarket’s content are virtual unknowns, with low four-figure follower counts on X.
Prospective participants in the marketing program are typically contacted via social media or email. If they show interest in continuing the conversation, they’re brought into a Polymarket Discord server. In that server, dedicated channels for individual esport titles ping users about the tweets they should quote-retweet — which generally focus on
some ongoing event or storyline
, and the corresponding market on which users can bet, which is linked to in the post.
“New tweet is up: Like + QRT. Replies appreciated,” reads a typical message, which includes a link to the tweet. “Text-only quote from your own account. Counts for the next 24 hours only.” These messages used to also include the phrase “+ Paid Partnership tag,” urging users to disclose their participation in the program. That text has not appeared on the Discord prompts since late August, for reasons that were not immediately clear.
Users are concurrently onboarded to a proprietary tool called PolyTrack, a dashboard into which they can input their tax information, crypto wallet address, and eventually, the quote-retweets for which they will be paid. The platform tracks monthly and lifetime earnings, and offers guidance about the kinds of posts that meet the program’s criteria.
While this report is exclusively focused on Polymarket’s promotional efforts on X, PolyTrack also includes the option to input video and streaming platforms.
The amount users are paid is negotiated upon entry into the program, and is based on how many views their tweets generally received before entry. The payout is not determined by engagement metrics on the paid quote-retweets.
“Someone averaging 2,000 views can't ask for $50 per post, and the same logic works the other way,” wrote a Polymarket rep in the Discord last week, when discussing the process of onboarding new posters. “That holds no matter who you are in the scene. The only exception is Tier 1 casters, talent, creators and players, who can get higher rates because of how well known they are.”
Two users who spoke with
ReaderGrev
showed fees of $45 and $75 per post. Another participant described negotiating a fee in the $200-300 range. One user shared with
ReaderGrev
a PolyTrack screenshot showing that they made nearly $900 in just one month from approximately a dozen posts.
Two other participants in the program said payouts bottomed out at $10; one of them added that they had heard that $400 was the upper end of the range. Program members are paid in crypto; in a July post in the Discord, a Polymarket rep said the team had phased out an earlier payment method, PayPal, because its accounts kept “getting blocked” due to the high volume of payments.
The program offers users other opportunities to make money. “When you bring someone into the program, you earn 3% of what they make, every month, for as long as they stay in the program,” wrote one Polymarket representative in the Discord.
The program appears to be growing — and fast. At the start of August, one Polymarket representative said on Discord that “300+ creators” were participating in the program. Two months later, a different representative put the tally at “800+.”
Still, the company’s scattershot approach to outreach has on multiple occasions drawn the ire of creators who oppose gambling or betting.
“I don't ever reply to gambling sponsor outreach so I just delete and move on,” said Cloud Sidky, a
League of Legends
content creator who was approached by Polymarket in September. “I'm personally against sports betting, and even more against prediction markets.”
The exact cost of the program to Polymarket is difficult to estimate. The platform’s four esports accounts on X differ in size, and there are varying numbers of creators in each game’s program. The
DotA 2
program has offered just one post for paid promotion in October, one in September, and two in August. The
League of Legends
,
Valorant
, and
Counter-Strike
programs, by contrast, have shared nearly one post per day in the past few weeks, with
Valorant
activity ramping up around the Champions event that marks the end of the game’s annual competitive circuit. On Wednesday, a Polymarket rep in the Discord server sought to hype up participants in the lead up to Worlds, the year’s capstone
League of Legends
event, saying they could expect more posts to come up for promotion each day. (He appended a
🤑
emoji to his message, and told users to post “plenty in between so it looks organic if your gonna QRT daily.”)
Polymarket’s total payout to creators per post for the more popular programs likely numbers in the four digits. A conservative estimate — assuming that the bulk of posters are being paid on the lower end of the spectrum — places the payout between $2,000 and $4,000 per post. These estimates are almost certainly an undercount; the figure can swing dramatically based on the number of highly-paid users engaging with any individual post. Just a few creators with a hundred or several-hundred dollar fee can dramatically increase the cost to Polymarket.
Posts linked to the paid quote-retweet program see substantially more engagement — particularly quote retweets — than other posts from the Polymarket branded accounts.
Polymarket’s approach to social media — paying influencers in the space to engage with its content — is a shortcut to reaching an endemic audience without having to build that audience from scratch, said Jake Steinberg, a writer and adjunct professor of social media strategy at Villanova University.
“If I follow 10 esports accounts and all 10 independently appear to be talking about something like Polymarket over the course of a few days or a week, then Polymarket has maybe successfully bought this kind of repeated exposure to me,” Steinberg said. “Even if I don't click anything, that actually does become valuable [to Polymarket], because I am becoming familiar with the name and what the product does, and the idea that Polymarket is relevant in this world that I am interested in.”
“That's a very different effect on me as the viewer” compared to a normal advertisement, Steinberg added.
In a document shared with users during onboarding, Polymarket instructs creators to clearly disclose their relationship with the platform.
“The disclosure must be clear, conspicuous, in plain language, and not hidden,” according to a document titled External Marketing Guidelines. At a glance, many of the quote-retweets of Polymarket-branded esports posts include the default X “paid partnership” disclosure tag.
The document also prohibits users from recommending trades.
“Polymarket’s Consultants are not investment advisors and recommendations from Consultants as to specific trades or trading strategies exposes both Polymarket and the Consultant to legal risk,” the document reads. “A verbal disclaimer that ‘this is not financial advice’ does not solve this problem and such a disclaimer is insufficient to eliminate the risk of legal action.”
The document continues: “A Consultant may discuss his or her own trades (assuming he/she has actually made such trades) and the rationale for making those trades but may
never
suggest or recommend that others make the same trade.” The bolding and underlining on “never” are present in the document.
PolyTrack, meanwhile, offers guidance around what makes a good post — and what doesn’t.
Post “your own take, reaction, or analysis. One sharp sentence beats a generic line every time,” reads one of the “Do This” bullet points.
“Post in your normal voice and give people a reason to reply,” reads another. “Questions and hot takes start conversations.”
By contrast, users are told to avoid low-effort and off-topic captions: “‘wow’, ‘crazy’, or a row of emojis … underperform and stand out in review for the wrong reason.”
“Staff review every caption,” the guidelines note. “Strong, on-topic captions help submissions get verified faster and maintain a high standard across the program.”
Though prediction markets have drawn scrutiny from some corners, some participants in the program have defended Polymarket’s model.
“I feel fine participating because Polymarket has no house edge or VIG,” wrote Justin “Trick” Sears, a former professional
Valorant
player, in a direct message, referring to fees charged by bookmakers.
Sears added that he had turned down a $50,000 six-month deal offered to him by another “active company in the space” because the company offered slots on their website. “Prediction markets are PVP thats the way i look at it,” he wrote.
“I’m honestly not sure why people treat this as some sort of scandal. It’s all very above-board,” said another user who has posted content sponsored by Polymarket, and who requested anonymity because they are not a representative for the company. “The quote RTs are all flagged as promotion as is the original tweet. I don’t know how it could be more clear. If there is a complaint it should be on Twitter’s side regarding how paid advertising is handled on the platform.”
Prediction market activity in esports has surged over the past two years, in part because the bigger sportsbooks see esports as a niche and sometimes even unappealing offering relative to traditional sports.
“The appetite was always there for people to bet” in esports, said Ollie Ring, who writes the
Lootboxes & Leftovers
newsletter, which has covered the intersection of gaming and gambling. “What then came is an influx of people who saw money and went: ‘I need a piece of that.’”
But when that first wave of interest happened, the product wasn’t ready, Ring said. “The development wasn't there. The data deals, the integrity structure, all of it around it wasn't ready for the amount of people that came in wanting a slice of this proverbial pie. … [Now,] operators are like: ‘I don't want to touch esports because we tried it in 2018, nine, eight years ago and it lost us a load of money.’ … And sportsbooks don't like losing money. They like your typical fluffy NFL parlays where people put 12 teams in an accumulator and then lose their money.”
Prediction markets, by contrast, “offer the first real opportunity to address the market at a national level, and I think there is a lot of overlap, or at least more overlap, [between] prediction markets and esports than traditional betting and esports,” wrote Cody Luongo, a media consultant who authors the
Sharpr
newsletter, in a direct message. Luongo said the former category leaned “younger, hipper, crypto-native.
Riot Games, which publishes
League of Legends
and
Valorant
and runs the two games’ esports circuits, has
reportedly
held discussions with Polymarket and Kalshi, a competing prediction market company, about esports sponsorship deals.
Thanks for reading
ReaderGrev
! Consider sharing it with a friend, on Discord, Twitter, LinkedIn, or even a subreddit where folks might appreciate it. Word of mouth helps this newsletter grow!
If you have a tip, I can be reached
on Bluesky
or via email at mikhail (at) readergrev (dot) com.
1
This final category is vanishingly small — in the low single digits — according to an analysis by Ollie Ring.
Postgres 19 delayed after AI reviewers find more bugs than humans can fix
Core devs revert up to 10 features, push release to November, and blame better tooling rather than vibe coding
The PostgreSQL Global Development Group has delayed the release of PostgreSQL 19, the latest iteration of the popular open source database, and held back an unusual number of features.
Once slated for release in late September or early October, PostgreSQL 19 is now expected to be generally available around November 19. Developers have also dropped between eight and 10 significant features.
Explaining the number of reverts — features whose rollouts have now been postponed to next year's release, PostgreSQL 20 — Peter Eisentraut, veep at EDB, a PostgreSQL support and consultancy, said the reason could be at least in part attributed to the LLM code reviews used by developers.
In
a blog post,
Eisentraut, who is a leading PostgreSQL committer, said some of the reverted features had significant architectural defects that would have been hard to fix "quickly and during beta."
However, the introduction of LLM-assisted code review also uncovered a long tail of “relatively harmless issues involving various edge cases” which, in past times, developers might not have noticed until much later, most likely issuing bug fixes in the five years following launch. “With LLM-assisted code review, these kinds of things can get found much faster, and then you’re staring at a list of forty defect reports. Even if each of them requires only a three-line fix on average, there is a fixed overhead to dealing with each of these, and then you run out of time.”
When the big updates for PostgreSQL 19 were written, LLM-assisted code review was not as useful as it is now, we're told, but in the months leading up to the launch, the AI-supported reviews became better understood and more effective.
“The effective quality bar has been raised after the time the feature was written and committed. Unless the capabilities of LLM-assisted code review keep improving at the current rate, this situation should sort itself out for future development cycles,” Eisentraut said.
He was also at pains to point out that the reverts were not down to “vibe coding” in development, as the technique was not available when most of the new features were written.
Postgres was
first proposed
by Michael Stonebraker in 1986. In 1994, Andrew Yu and Jolly Chen replaced the query language POSTQUEL with SQL, and in 1995 made the database freely available and modifiable under a more permissive license, renaming it PostgreSQL. It has since become the most popular database among professional developers owing to the services the big three hyperscalers built on it as well as the range of wire-compatible distributed systems available.
Among the features pulled from the PostgreSQL 19 iteration is support for SQL Property Graph Queries (SQL/PGQ), which became part of the SQL standard in 2023. The feature provides syntax for exploring relationships between nodes connected by edges. PostgreSQL's implementation was removed over unresolved issues.
At the time,
PostgreSQL contributor Tom Lane warned
: "At this point I'd be willing to bet dinner that if we ship it in v19 there will be post-release bug discoveries that are unfixable until v20."
Despite the delay, Eisentraut promises PostgreSQL 19 will still be “a great release,” that includes
REPACK CONCURRENTLY
, which avoids the table-lock
VACUUM FULL
operation used to reclaim disk space.
“And it will be very robust, after all the additional scrutiny,” he said.
The features reverted from PostgreSQL 19 will likely make it into PostgreSQL 20. Just a few months ago, developers expected PostgreSQL 20 to have no new features, just bug fixes. Now, it is likely to have the new features left over from the earlier release, Eisentraut said.®
Podcast: Cops Can Use AI to Pinpoint Your Home with Just One Photo
403 Media
www.404media.co
2026-10-16 11:40:44
How Raven, previously known as Geospy, can now find which house a photo was taken in; why a judge ruled a Flock search unconstitutional; and the wild AI video in a court case....
How Raven, previously known as Geospy, can now find which house a photo was taken in; why a judge ruled a Flock search unconstitutional; and the wild AI video in a court case.
Image: 404 Media.
We start this week with Joseph’s article about Raven, previously known as Geospy. This is an AI tool that can geolocate photos, and now says it can pinpoint a specific house based just on one photo taken inside. After the break, Jason explains why a judge ruled a particular Flock search as unconstitutional. In the subscribers-only section, we talk about the wild AI video that has derailed a manslaughter case.
Listen to the weekly podcast on
Apple Podcasts
,
Spotify
, or
YouTube
. Become a paid subscriber for access to this episode's bonus content and to power our journalism.
If you become a paid subscriber, check your inbox for an email from our podcast host Transistor for a link to the subscribers-only version! You can also add that subscribers feed to your podcast app of choice and never miss an episode that way. The email should also contain the subscribers-only link for the extended video version too. It will also be in the show notes in your podcast player.
Joseph is an award-winning investigative journalist focused on generating impact. His work has triggered hundreds of millions of dollars worth of fines, shut down tech companies, and much more.
Show HN: OneDeploy – Managed open-source apps with nightly backups and TLS
The apps your team wants, on a server that’s
only yours
Pick an app, a region and a plan. OneDeploy creates the server, installs the app, issues the certificate and backs it up every night.
Billed by the hour, with a monthly cap.
Delete anytime and billing stops.
No per-user fees
Nightly backups included
Delete anytime
88 apps, and the list keeps growing
Websites, chat, files, CRM, analytics, AI and developer tools. Each one deploys the same way.
A dedicated virtual server that runs only your app. It comes with a web address, a TLS certificate, an admin account, and scheduled backups.
How does billing work?
You add credit to your account with an online payment. Each service is charged to that balance by the hour while it exists. Each plan has a monthly cap, so a full month never costs more than the price you saw before deploying. We warn you before the balance runs out. If it reaches zero, your services are deleted and their backups stay restorable for about 14 days.
Can I use my own domain?
Yes. Add a domain in the service settings, create the DNS record we show you, and verify it. We issue the certificate.
Can I change the server later?
Yes. Resize in the same region, or migrate to another region or cloud. Your data and domains move with the app.
What happens to my backups?
Backups are encrypted and stored off-site. Storage up to twice the disk size is included. You can restore in place or into a new service.
Do I pay per user?
No. You pay for the server, not for seats. Invite as many people as the app supports. We install the open-source edition of every app; some makers sell paid editions separately.
Do I need to know how to run a server?
No. Deploying, updates, backups, certificates, domains and resizing all happen from the dashboard. You never touch the server unless you want to.
A story of WiFi secrets, UART lockdowns and a damaged flash memory chip
Dear Fell
owl
ship, just as we announced in our previous post, our beloved God Debugger has seen fit to cast his divine light -laden with opcodes- upon his humble servant, and we have a new homily here in our temple. Please, take a seat and listen to the story of how one of our owls, along with his brother-in-law, moved on to dissect the next component of the Eufy ecosystem: the Eufy HomeBase 2.
We focused our analysis in Eufy Homebase2 instead of Homebase3 because, as we explained in
From your doorbell to your home network
it’s the version that I found deployed in my city, and also was the easiest to buy. The firmware version we analyze here is
3.4.2.2h (2026-06-05 18:45:48)
This is the first time I touched something related to “hardware”. I always did vuln hunting on firmwares that I could download from internet, so please forgive the sins I commited
IMPORTANT!!!
You must read first the previous article before you continue reading this one.
Table of contents
Just as with the previous article, we will be covering a variety of topics here; consequently, some members of this fellowlship may have no interest in certain sections and might wish to skip straight to whatever appeals to them most. That is why we present this blessed offering: a table of contents.
0x00 Firmware extraction
. Description of how the firmware was extracted (and how we damaged part of the flash memory).
0x04 Final Words
. I share the lack of enthusiasm for writing articles in the age of AI.
In the
previous chapter of this saga
, I mentioned that we were only able to extract the doorbell’s firmware because the Homebase’s flash memory was soldered directly to the board and did not expose any pins to which we could attach test hooks to dump the firmware. Initially we did not want to desolder it (although in the end we had to as I will explain later) so I had to wait to acquire additional hardware.
Craig S. Blackie
pointed me to spring clips that would suit the size needed for the Winbond 25Q256JWEQ (WSON8 8.6mm). Once the clip arrived I created the most makeshift setup imaginable, using rubber bands to secure the clip while I proceeded to take readings using the Raspberry Pi’s SPI0 interface, just as we did with the doorbell.
Setup using rubber bands to read the firmware.
I performed three reads and the three had different checksums, which usually is a indicator of something being wrong. After inspecting the dumps, I quickly realized they were garbage and completely useless. Unlike with the doorbell, in this case, the power supplied for the read operation also activated other components on the board that interacted with the memory; therefore, to extract the firmware, we had to desolder the chip and read it off-board.
My brother-in-law (
Óscar Lestón
) was the brave soul that desoldered the flash memory (I was too scared to even try it):
Desoldering
Although the memory module looked terrible once removed, it was barely damaged…
Extracted flash memory
And finally we replicated the same setup using the Raspberry Pi SPI 0 to dump the firmware. This time the three dumps had the same checksum and contained “interesting data”. The only problem was… a block of 64kbs was erased / could not be read, highly probable because we damaged it when extracting the chip.
Using the Raspberry Pi to read the chip off-board
Most of the firmware could be extracted using Binwalk.
Some parts were recovered, others no. Because there was a lot of XS streams, we choose the stupid (or maybe not so stupid) idea of using directly
7z
to extract all in a big blob (and hopefully search by needles there to carve files).
➜ extractions mkdir-p 7z_mandanga
➜ extractions 7z e -y-o7z_mandanga homestation2_firmware00.bin
7-Zip 23.01 (x64) : Copyright (c) 1999-2023 Igor Pavlov : 2023-06-20
64-bit locale=es_ES.UTF-8 Threads:16 OPEN_MAX:1024
Scanning the drive for archives:
1 file, 33554432 bytes (32 MiB)
Extracting archive: homestation2_firmware00.bin
ERRORS:
There are data after the end of archive
--
Path = homestation2_firmware00.bin
Type = xz
ERRORS:
There are data after the end of archive
Offset = 3022226
Physical Size = 11514432
Tail Size = 19017774
Method = LZMA2:17
Streams = 358
Blocks = 358
Characteristics = BlockPackSize BlockUnpackSize
ERROR: There are some data after the end of the payload data : homestation2_firmware00
Sub items Errors: 1
Archives with Errors: 1
Open Errors: 1
Sub items Errors: 1
➜ extractions ls-hal 7z_mandanga
total 42M
drwxrwxr-x 2 psyconauta psyconauta 4,0K sep 19 19:41 .
drwxrwxr-x 4 psyconauta psyconauta 4,0K sep 19 19:34 ..
-rw-rw-r-- 1 psyconauta psyconauta 42M sep 19 18:35 homestation2_firmware00
0x01 Identifying the Wifi credential generation algorithm
One of the key questions we wanted to investigate via the firmware was the new algorithm for generating credentials for the
OCEAN_XXXXXX
management Wi-Fi, as we observed that it differed completely from what was expected based on the 2024 paper. Specially, we were interesting in know if the algorithm was weak as previously or no.
After writing the previous article, I realized I had failed my brother-in-law as a mentor. I had shown him how to use Ghidra and pseudo-C instead of leading him down the path of light and reason. I atoned for my sin and drew radare2.
First we checked where the Wifi network ESSID and password could be found in the firmware. A simple
grep
was enough to identify NVRAM variables containing both wifi names and credentials (the ad-hoc wifi used to enroll the doorbell and the mangement wifi):
Then we tried a more broad search to try to identify binaries and/or scripts related to the wifi setup:
➜ 7z_mandanga strings homestation2_firmware00 | rg 'OCEAN_'
%s,<%d>file not exist.return OCEAN_TEST_TF_CARD_NOT_FOUND.
OCEAN_MAGIC
out of memory of OCEAN_TEST_DATA
OCEAN_TF_CARD_FORMAT_SUCCESSED
OCEAN_TF_CARD_FORMAT_FAIL_MOUNT
OCEAN_TF_CARD_FORMAT_FAIL
OCEAN_TF_CARD_FORMAT_IN_USE
ssid_prefix="OCEAN_"ssid_prefix="OCEAN_"CONFIG_LEDS_OCEAN_PWM=y
OCEAN_RUN=/mnt/ocean.sh
if[-f$OCEAN_RUN];then
chmod +x $OCEAN_RUN
sh $OCEAN_RUN &
Unraveling a bit more this thread we found an interesting line that matches what we already knew: the ESSID is the concatenation of “OCEAN_” and MAC address:
➜ 7z_mandanga strings homestation2_firmware00 | rg 'ssid_prefix'-B30-A40
.sdata
.sbss
.bss
.pdr
.gnu.attributes
.mdebug.abi32
#!/bin/shwork_mode="`cat /var/run/testmode`"def_mode="`nvram_get 2860 work_mode`"SSID_MAC=""nvram_ssid="`nvram_get 2860 SSID1`"bssid_num=`nvram_get 2860 BssidNum`eth_state=`apcliDaemon get_eth_state`repeater_enable=`nvram_get 2860 RepeaterEnable`wifi_11bgn_enabled=`nvram_get 2860 wifi_11bgn_enabled`Wireless_Mode=9
if["$eth_state"="0"-a"$repeater_enable"="1"-a"$wifi_11bgn_enabled"="1"];then
Wireless_Mode=9
get_wifi_mac()SSID_MAC="`ifconfig ra0 | grep HWaddr | awk'{print $5}' | awk-F':''{print $4$5$6}'`"#SSID_MAC="`ifconfig ra0 | grep HWaddr | awk '{print $5}' | awk -F ':' '{print $5$6}'`" while["$SSID_MAC"=""]sleep 1
SSID_MAC="`ifconfig ra0 | grep HWaddr | awk'{print $5}' | awk-F':''{print $4$5$6}'`"#SSID_MAC="`ifconfig ra0 | grep HWaddr | awk '{print $5}' | awk -F ':' '{print $5$6}'`"done
echo"get mac in ssid is:$SSID_MAC"if["$bssid_num"="2"];then
ifconfig ra1 down>/dev/null 2>&1
if["$work_mode"="1"];then
ssid_prefix="ocean_factory_"if["$def_mode"="factory_mode"];then
ssid_prefix="OCEAN_"
get_wifi_mac
WIFI_SSID=$ssid_prefix$SSID_MACecho"set wifi SSID:$WIFI_SSID"
iwpriv ra0 set SSID="$WIFI_SSID"if["$def_mode"="factory_mode"];then# only WIFI_SSID is not equ nvram_ssid, update nvram.if["$nvram_ssid"!=$WIFI_SSID];then
nvram_set SSID1 $WIFI_SSIDfi
else
ssid_prefix="`nvram_get ssid_pre`"if["$ssid_prefix"=""];then
ssid_prefix="OCEAN_"
get_wifi_mac
WIFI_SSID=$ssid_prefix$SSID_MACecho"set wifi SSID:$WIFI_SSID"# only WIFI_SSID is not equ nvram_ssid, update nvram.if["$nvram_ssid"!=$WIFI_SSID];then
nvram_set SSID1 $WIFI_SSID
iwpriv ra0 set SSID="$WIFI_SSID"if["$nvram_ssid"="MT7628_AP"];then
sleep 3
#reboot
/sbin/umount_and_reboot.sh
fi
iwpriv ra0 set HtBw=0
iwpriv ra0 set WirelessMode=$Wireless_Mode
iwpriv ra0 set HtGi=0
iwpriv ra0 set SCSEnable=1
if["$bssid_num"="2"];then# ssid and pwd set in RT2860_default_vlan#iwpriv ra1 set SSID="AKDevbind"#iwpriv ra1 set WPAPSK="Anker39#*"#iwpriv ra1 set SSID="XMCONFIG"#iwpriv ra1 set WPAPSK="12345678"
iwpriv ra1 set HtBw=0
iwpriv ra1 set WirelessMode=$Wireless_Mode
iwpriv ra1 set HtGi=0
iwpriv ra1 set SCSEnable=1
iwpriv ra1 set WmmCapable=1
iwpriv ra1 set ed_chk=0
wpapsk="`nvram_get WPAPSK1`"if["$wpapsk"!=""];then#echo "iwpriv ra0 set WPAPSK=$wpapsk"
iwpriv ra0 set WPAPSK=$wpapsk# set wmm
iwpriv ra0 set WmmCapable=1
# change wan mode,
wifi
apcli
iwpriv
home_security
if["$eth_state"="0"-a"$repeater_enable"="1"];then
switch_wan_interface.sh eth2.2 apcli0 0
#!/bin/sh
So, from one side we found how the ESSID is created and from the other side we found that the password is read from a NVRAM variable (
wpapsk="nvram_get WPAPSK1"
). Let’s do a quick search with that name:
➜ 7z_mandanga strings homestation2_firmware00 | rg -i'WPAPSK1'-A5-B5
wifi channel:%d.
fail to get freq.
/dev/gpio
Error while opening /dev/gpio
SSID1
WPAPSK1
SSID2
ra1 SSID=%s
WPAPSK2
ra1 WIFI_PWD=%s
/sbin/chpasswd.sh eufycamera %s
--(...)
Just in the first hit there is something that looks like a compiled binary (that
%d
is suspicious). I built this crappy script to extract the elf that search for the string, then search backwards to find the magic header and assume the following file in the blob is also an ELF:
Jumping into that function we can see that first it builds a password based on a MD5 hash that is used locally for the user
eufycamera
and it’s not related to the wifi. The wifi-stuff starts at
0x0053b690
where it checks one parameter from
base_param
(I guess the type of device or model) against 0x0C. This part is key because if the value is different to 0x0C, then it uses the MAC Address (right block) meanwhile if it matches then it would use what returns
z8GetSN()
(left block). We are in the
z8GetSN()
case.
Different flow based on device model.
The
z8GetSN()
function communicates through i2c and sends command
0xC1
(the i2c part is inside
z8SendData()
) and read 0x11 bytes from the response.
I2C communication to extract a serial number (it's not the device SN)
Then bytes are translated into 32 byte string and fed to a function called
mac_func()
which also receives the Homebase Serial Number (
T8010...
):
The SN from the I2C communication and the device Serial Number (obj.g_hub_sn) used as parameters for mac_func()
This
mac_func
calls a helper to perform HMAC SHA256 with the previous mentioned data, being the “message” the value returned by
z8GetSN
and the “key” the Serial Number:
HMAC SHA256
The result is used by a function that would encode the information into text.
Encoding memory contents
The
zx_Memory_Encode
function calls
urlsafe_b64_encode
which converts the value into base64 using the following alphabet:
Finally, the password is updated in NVRAM and changed executing the external command
iwpriv ra0 set WPAPSK=%s
:
Updating NVRAM value
So, the only unkown data to replicate the password is the value returned by
z8GetSN
. The other compontent, the device serial number, is “predictable” because it follows a known template based on the type of device.
0x02 Rubber-hose treatment to the UART lockdown
In the previous article, we mentioned that UART access was blocked. Specifically, connecting via UART yielded a prompt asking the user to press the “Enter” key. However, doing so caused the process to terminate and the same program to relaunch, once again requesting the key press; this created an infinite loop that prevented access to an actual shell. Logs can be seen below:
starting pid 5617, tty '/dev/ttyS1': '/sbin/login.sh'
process '/sbin/login.sh' (pid 5617) exited. Scheduling for restart.
Please press Enter to activate this console.
setrlimit(RLIMIT_CORE, &limit);
starting pid 6526, tty '/dev/ttyS1': '/sbin/login.sh'
process '/sbin/login.sh' (pid 6526) exited. Scheduling for restart.
Please press Enter to activate this console.
setrlimit(RLIMIT_CORE, &limit);
starting pid 6608, tty '/dev/ttyS1': '/sbin/login.sh'
process '/sbin/login.sh' (pid 6608) exited. Scheduling for restart.
On the other hand, trying to interrupt U-Boot witch a escape sequence did not work.
After acquiring the firmware and resolving questions about how the Wi-Fi password algorithm worked, the next objective was to understand the mechanism behind the UART access lockout and find a way to bypass it, as we intended to use the device itself to debug key services and search for vulnerabilities.
In the logs the serial port is
/dev/ttyS1
, so let’s search references to it:
➜ extractions grep-r ttyS1
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3143840_aes_forward_table.raw: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3679760_unknown.raw: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3135648_aes_reverse_table.raw: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin: coincidencia en fichero binario
homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/etc_ro/inittab:ttyS1::askfirst:/sbin/login.sh
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/bin/recover_0_elf.raw: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/bin/recover: coincidencia en fichero binario
homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/sbin/makedevlinks.sh:mknod /dev/ttyS1 c 4 65
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin_0_cpio.raw: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3147936_aes_rcon.raw: coincidencia en fichero binario
grep: 7z_mandanga/homestation2_firmware00: coincidencia en fichero binario
The key is in the
inittab
file, where we can see the it triggers the execution of
/sbin/login.sh
script once the user press “Enter” (the BusyBox
askfirst
action shows the prompt with sentence “Please press Enter to activate this console”). The script is simple as:
#!/bin/shDEBUG_LOG="`nvram_get debug_log`"if["$DEBUG_LOG"="1"-o-f"/mnt/enable_console"];then
echo"enter debug mode"> /dev/console
/bin/login
fi
The script checks if debug mode is enabled by checking the NVRAM variable
debug_log
and based on that allows the access to the shell (well, to login in the shell) or exits, entering in the loop.
We did not find a straight way to enable that variable and bypass the lockdown. There are various ways on changing the boot mode to enable “debug”, but all of them are far away from our hands because:
One of them is based in the presence of a file in the filesystem. Because to be able to drop a file we would need access, it is a chicken-egg situation.
The other method involves a convoluted magic protocol based on ARP and commands signed by a private key which is not present in the firmware. Yes, they use encapsulate their own protocol on ARP and exchange magic signed packets to enable debug remotely. I am not sure what crack they smoked.
It occurs to me at this point that if we can not bypass the check for whether it is booting in production or debug mode, why not completely obliterate the check and jump straight to a shell?
The firmware did not contain anything encrypted, so should be straight forward to modify it to allow us direct access through the serial port. The problem was… Do you remember when I mentioned that it was “barely damaged”?. Well, we fucked 64kbs at
0x500000
which is the load address for the image.
At first, I thought our clumsy hands had ruined the project and that the idea of using the actual device for dynamic analysis with a debugger was slipping away (we would still have the option of trying to emulate some binaries, but having access to the original hardware is always infinitely easier). Fortunately, after analyzing the firmware layout a bit more, we discovered a much smaller “recovery image” that was still intact at
0xe70000
. So, because the “normal” image was fucked, the bootloader would have to load this recovery image that we can manipulate to remove the UART lockdown.
The actual filesystem is inside a matrioska of different compression layers that can be visualized in the following diagram:
Matrioska!
Once the filesystem was unpacked, I made the minimal changes to allow us to jump directly to the shell with root privileges. To avoid headaches, I padded the modifications to match the same size it had the original code (code is from python script I used to perform the modifications and re-pack/fix CRCs):
After doing some local test to verify that the modified recovery image was correctly modified and it would unpack/load correctly we proceeded to overwrite it in the flash chip. In order to disable the
Write Protection that appears in the documentation
this connection diagram was followed:
Diagram to disable Write Protection
Writing the new recovery image:
Overwriting the recovery image with our backdoored version
Then we performed three reads to verify the process was done correctly. After that, the chip was solded again into the device board:
Soldering again the chip
Once the chip was soldered I connected again my laptop to the device using a USB-TTL. First it tried to load the normal image, but it failed and then it jumped to backdoored recovery image and after loading it… we got a shell!!
Finally access to an admin shell!!
0x03 Filesystem gardening for debugging purposes
We finally have a shell; the only problem is that the recovery image is very limited and the file system is not mounted, so the binaries and libraries needed to properly debug the system are missing. Furthermore, the kernel lacks certain modules-such as those responsible for handling WiFi interfaces or the I2C interface used to generate the WiFi key.
The set of commands available in the default image is quite limited, but at least there are tools like
wget
, which allows us to transfer files from the laptop to the device. I prepared a crappy setup using an old TP-Link router that I got from Telefónica in 2015.
Not glamorous setup
I compiled a new BusyBox with loads of extra commands that were not present in the original one. Using this new BusyBox I started to try to create a “staged” filesystem and bind all the paths to this “staged” filesystem. I had to execute services needed to run before the big ELF in charge of main services (
homeapp_security
, the same binary that contained the WiFi logic), also because of memory limitations I had to modify some kernel parameters like
overcommit_ratio
. It was a three hours process of hit and miss until I could run the main binary and be able to interact with it.
Because this was a process that I would need to repeat each time I wanted to use the device (because the filesystem in the recovery image is not persistent, so after each boot I have to restore all) I shared the logs of
picocom
to Codex and asked it to prepare a all-in-one script that would repeat the same steps I did (and discard the stuff that didn’t work). To be honest, the following morning after that night of playing with the Homebase I barely remembered what I did, so having the logs was marvelous to rebuild and automatize the process. Keep logs of everything always, they will save your ass at some point.
The diagram of actions until the
homeapp_security
runs is the following:
Flow diagram from the patched firmware to getting the binary running
The two most important scripts to rebuild the filesystem are shown below:
#!/bin/sh# Recovery UART bootstrap. Run with sh; do not source into the login shell.# Usage: sh homeapp-restore-v5.sh [http://PC:8000] [--start]PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
unset LD_PRELOAD LD_LIBRARY_PATH
BASE=/media/homeapp-debug
ROOT=$BASE/rootfs
SERVER=http://192.168.90.112:8000
START=no
fail(){echo"homeapp-restore: $*">&2;exit 1;}for argument in"$@";do
case"$argument"in
http://*)SERVER=${argument%/};;--start)START=yes;;*) fail 'usage: sh homeapp-restore-v5.sh [http://PC:8000] [--start]';;esacdone
case"$SERVER"in*' '*|*'?'*|*'#'*) fail 'use a plain HTTP base URL without spaces/query/fragment';;esac["`awk'/^Uid:/ {print $3}' /proc/self/status`"= 0 ]|| fail 'root effective UID required'[-r /proc/self/mountinfo ]|| fail '/proc/self/mountinfo is required'[-c /dev/gpio ]&&[-c /dev/apsoc_nvram ]|| fail 'expected recovery device nodes missing'
mounted(){awk-vp="$1"'$2==p {n++} END {exit n==0}' /proc/mounts;}
check_tmpfs(){awk-vp="$1"-vsize="$2"'$2==p {
n++; if ($3=="tmpfs") {
count=split($4,a,","); for(i=1;i<=count;i++) if(a[i]=="size=" size "k") ok=1
}
} END {exit !(n==1 && ok)}' /proc/mounts
}
empty_dir(){[!-e"$1"]&&return 0
[-d"$1"]&&[!-L"$1"]||return 1
[-z"`ls-A"$1"`"]}
asset_md5(){# BEGIN GENERATED ASSET HASHEScase"$1"in
busybox-extra)echo b587f623ef28b84e277fbd1b2b0b2348 ;;
homeapp-enter)echo 8fde5ed1e3e65d07a7b9ebe672b25a5c ;;
homeapp-mount-runtime.sh)echo 19e73a1584137c0d2150d6968cccb4c5 ;;
homeapp-start-bounded-v4.sh)echo 19b70b8ac6751f8e161e490460ff8f3e ;;
homeapp-control-v5.sh)echo 2fc7613db0f02a0d16c1417bb0282264 ;;
homeapp_rootfs.tar.gz)echo bf6acaecf3301532bda2c1f6c41a3b2c ;;*)return 1 ;;esac# END GENERATED ASSET HASHES}
verify(){expected=`asset_md5 "$1"`|| fail "unknown asset: $1"actual=`md5sum"$2" | awk'{print $1}'`["$actual"="$expected"]|| fail "checksum mismatch: $2; stop and check the PC bundle"}
fetch(){asset=$1echo"homeapp-restore: downloading $asset"
wget -O"$BASE/$asset.part""$SERVER/$asset"|| fail "download failed: $asset; partial setup preserved"
verify "$asset""$BASE/$asset.part"mv"$BASE/$asset.part""$BASE/$asset"|| fail "cannot finish $asset"}
stamp(){awk'{sub(/^.*\) /, ""); print $20}'"/proc/$1/stat" 2>/dev/null;}
is_supervisor(){[-r"/proc/$1/cmdline"]||return 1
tr'\000''\n' < "/proc/$1/cmdline" | awk'
NR==1 {shell=($0=="sh" || $0=="/bin/sh" || $0=="/sbin/run_mini_system.sh")}
$0=="/sbin/run_mini_system.sh" {script=1}
END {exit !(shell && script)}'}
recover_pids(){for procdir in /proc/[0-9]*;do[-e"$procdir/exe"]||continue
if["$procdir/exe"-ef /bin/recover ]||["$procdir/exe"-ef /sbin/recover ];then
echo"${procdir#/proc/}"fi
done}
signal_recover(){for recover_pid in`recover_pids`;do
if["/proc/$recover_pid/exe"-ef /bin/recover ]||["/proc/$recover_pid/exe"-ef /sbin/recover ];then
kill"-$1""$recover_pid" 2>/dev/null || :
fi
done}
coordinate_recovery(){# Exact argv matching avoids accidentally signalling grep or the UART shell.for procdir in /proc/[0-9]*;do
supervisor_pid=${procdir#/proc/}if is_supervisor "$supervisor_pid";then
supervisor_stamp=`stamp "$supervisor_pid"`[-n"$supervisor_stamp"]||continue
kill-STOP"$supervisor_pid"|| fail "cannot pause recovery supervisor $supervisor_pid"echo"$supervisor_pid$supervisor_stamp">"$BASE/recovery-supervisor-$supervisor_pid"echo"homeapp-restore: paused recovery supervisor $supervisor_pid"fi
done
signal_recover TERM
sleep 2
signal_recover KILL
sleep 1
[-z"`recover_pids`"]|| fail 'recovery tasks survived stop'
pidof recover >/dev/null 2>&1 && fail 'unrecognized recover process remains; inspect ps'return 0
}
install_commands(){for asset in homeapp-mount-runtime.sh homeapp-start-bounded-v4.sh homeapp-control-v5.sh;do
verify "$asset""$BASE/$asset"done# Rename new files into place: never truncate a script a running shell# may still be reading during a repeated preparation command.for asset in homeapp-mount-runtime.sh homeapp-start-bounded-v4.sh homeapp-control-v5.sh;do
destination=/tmp/$asset["$asset"!= homeapp-control-v5.sh ]||destination=/tmp/homeapp
cp"$BASE/$asset""$destination.part.$$"|| fail "cannot copy $asset"chmod 755 "$destination.part.$$"|| fail "cannot mark $asset executable"mv"$destination.part.$$""$destination"|| fail "cannot install $asset"done}echo'homeapp-restore revision: v5; original firmware applications, RAM staging'if[-f"$BASE/restore-v5.ready"];then# Reusing this recipe's completed setup is safe; never extract over binds.
check_tmpfs "$BASE" 65536 || fail 'staging mount changed or is stacked'
check_tmpfs /media/mmcblk0p1 8192 || fail 'database mount changed or is stacked'
verify homeapp-enter "$BASE/homeapp-enter"
verify busybox-extra "$BASE/busybox-extra"
install_commands
sh /tmp/homeapp-mount-runtime.sh --resume|| fail 'runtime mount verification failed'
coordinate_recovery
echo'homeapp-restore: verified and reused completed setup; no archive download/extraction'else# Fail closed on partial/manual setups; no rm -rf, unmount or overlay of data.
mounted "$BASE"&& fail 'unrecognized/partial staging mount; inspect it or reboot before retrying'
empty_dir "$BASE"|| fail 'staging directory is not empty; preserve it and inspect or reboot'
mounted /media/mmcblk0p1 && fail 'database/storage path already mounted; will not cover it'
empty_dir /media/mmcblk0p1 || fail 'database/storage directory is not empty; will not cover it'free_kb=`awk'/^MemFree:/ {print $2}' /proc/meminfo`["${free_kb:-0}"-ge 81920 ]|| fail 'less than 80 MiB free; reboot to a fresh recovery shell or inspect memory'# Refuse existing normal services before staging/coordination.for service in home_security mdnsd mips_collector pushMuxer systemServer embdb_eufy;do
pidof "$service">/dev/null 2>&1 && fail "$service already running; use a fresh recovery boot"done
original_mode=`cat /proc/sys/vm/overcommit_memory`original_ratio=`cat /proc/sys/vm/overcommit_ratio`if["$original_mode"= 2 ]&&["$original_ratio"-lt 75 ];then
echo 75 > /proc/sys/vm/overcommit_ratio || fail 'cannot raise runtime commit ratio'echo"homeapp-restore: strict overcommit ratio $original_ratio -> 75 (this boot only)"fi
if["$original_mode"= 2 ];then
headroom=`awk'/^CommitLimit:/ {limit=$2} /^Committed_AS:/ {used=$2} END {print limit-used}' /proc/meminfo`["$headroom"-ge 65536 ]|| fail 'less than 64 MiB commitment headroom; no extraction attempted'fi
mkdir-p"$BASE"|| fail 'cannot create staging directory'
mount -t tmpfs -osize=64m tmpfs "$BASE"|| fail 'cannot mount staging tmpfs'
check_tmpfs "$BASE" 65536 || fail 'unexpected staging filesystem size'echo"$original_mode$original_ratio">"$BASE/original-overcommit"echo"$SERVER">"$BASE/download-server"for asset in busybox-extra homeapp-enter homeapp-mount-runtime.sh homeapp-start-bounded-v4.sh homeapp-control-v5.sh;do
fetch "$asset"done
chmod 755 "$BASE/busybox-extra""$BASE/homeapp-enter"|| fail 'chmod failed'"$BASE/homeapp-enter"--check|| fail 'native helper does not run'
fetch homeapp_rootfs.tar.gz
(cd"$BASE"&& ./busybox-extra tar-xzf homeapp_rootfs.tar.gz)|| fail 'extraction failed; preserve diagnostics, then reboot before retrying'# Only the verified temporary archive is removed, before any runtime binds.rm"$BASE/homeapp_rootfs.tar.gz"|| fail 'cannot remove staged archive'"$BASE/homeapp-enter""$ROOT" /bin/sh -c':'|| fail 'normal loader/BusyBox does not execute'mkdir-p /media/mmcblk0p1 || fail 'cannot create database path'
mount -t tmpfs -osize=8m tmpfs /media/mmcblk0p1 || fail 'cannot mount temporary database'
check_tmpfs /media/mmcblk0p1 8192 || fail 'unexpected database filesystem size'mkdir-p /media/mmcblk0p1/.sqlite || fail 'cannot create database directory'
install_commands
sh /tmp/homeapp-mount-runtime.sh --apply|| fail 'runtime mount setup failed; earlier mounts preserved'
coordinate_recovery
echo v5 >"$BASE/restore-v5.ready"|| fail 'cannot record successful setup'fi
echo'homeapp-restore: READY. /tmp/homeapp start|status|logs|stop|shell'echo'Wi-Fi/I2C drivers and persistent flash configuration are not restored by userspace staging.'df-k"$BASE" /media/mmcblk0p1
if["$START"=yes];then
/tmp/homeapp start || fail 'setup completed, but application startup failed; inspect /tmp/homeapp status'fi#!/bin/sh# Run with `sh`, never source into the interactive UART shell.# Does not start services, mount flash, or change memory policy.PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
BASE=/media/homeapp-debug
ROOT=/media/homeapp-debug/rootfs
fail(){echo"homeapp-mount: $*">&2;exit 1;}
mounted(){awk-vp="$1"'$2 == p {found=1} END {exit !found}' /proc/mounts;}
same_mount_root(){# Compare device ID and filesystem-root path, not just the filesystem type.awk-vs="$1"-vd="$2"'
$5 == s {source=$3 " " $4}
$5 == d {target=$3 " " $4; count++}
END {exit !(count == 1 && source != "" && source == target)}
' /proc/self/mountinfo
}case"${1-}"in--inspect)echo'--- Mounts ---'cat /proc/mounts
echo'--- Memory ---'cat /proc/meminfo
echo'--- Overcommit mode / ratio ---'cat /proc/sys/vm/overcommit_memory /proc/sys/vm/overcommit_ratio
echo'--- Staged executables ---'ls-l"$BASE/homeapp-enter""$ROOT/bin/busybox""$ROOT/bin/home_security"echo'--- Processes ---'
ps
exit 0
;;--apply|--resume)mode=$1;;*) fail 'usage: sh homeapp-mount-runtime.sh --inspect|--apply|--resume';;esac
mounted "$BASE"|| fail 'staging filesystem is not mounted'[-x"$BASE/homeapp-enter"]|| fail 'native helper missing'[-x"$ROOT/bin/home_security"]|| fail 'application missing'
mounted /media/mmcblk0p1 || fail 'prepare temporary database mount first'[-d /media/mmcblk0p1/.sqlite ]|| fail 'database directory missing'# Resume only matching binds, with one mount at each staged destination.# Leave staged /mnt (including its original zx_log.conf) in place. Recovery's# /mnt bind failed in the first attempt; persistent state is a separate step.for path in dev proc sys etc var tmp media dev/pts media/mmcblk0p1;do
if mounted "$ROOT/$path";then["$mode"=--resume]|| fail "$ROOT/$path already mounted; inspect partial setup first"
same_mount_root "/$path""$ROOT/$path"|| fail "existing bind does not match /$path, or is stacked: $ROOT/$path"fi
done
bind_path(){source_path=$1target_path=$2if mounted "$target_path";then
echo"homeapp-mount: keeping verified bind $target_path"return 0
fi
mkdir-p"$target_path"|| fail "cannot create $target_path"echo"homeapp-mount: $source_path -> $target_path"
mount -obind"$source_path""$target_path"rc=$?["$rc"-eq 0 ]|| fail "mount exited $rc: $source_path -> $target_path (earlier mounts preserved)"
mounted "$target_path"|| fail "mount returned success but $target_path is absent from /proc/mounts"
same_mount_root "$source_path""$target_path"|| fail "unexpected mount root at $target_path"}for path in dev proc sys etc var tmp media;do
bind_path "/$path""$ROOT/$path"done
bind_path /dev/pts "$ROOT/dev/pts"
bind_path /media/mmcblk0p1 "$ROOT/media/mmcblk0p1"echo'Runtime binds completed; no application services started.'
Then running it from the UART shell we can see it prepares everything and also launch the binary:
# wget -O /tmp/homeapp-restore-v5.sh http://192.168.90.112:8000/homeapp-restore-
v5.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-restore-v5.s 100% |*******************************| 9174 --:--:-- ETA
# sh /tmp/homeapp-restore-v5.sh http://192.168.90.112:8000 --start
homeapp-restore revision: v5; original firmware applications, RAM staging
homeapp-restore: strict overcommit ratio 50 -> 75 (this boot only)
homeapp-restore: downloading busybox-extra
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
busybox-extra.part 100% |*******************************| 673k --:--:-- ETA
homeapp-restore: downloading homeapp-enter
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-enter.part 100% |*******************************| 622k --:--:-- ETA
homeapp-restore: downloading homeapp-mount-runtime.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-mount-runtim 100% |*******************************| 3054 --:--:-- ETA
homeapp-restore: downloading homeapp-start-bounded-v4.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-start-bounde 100% |*******************************| 4383 --:--:-- ETA
homeapp-restore: downloading homeapp-control-v5.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-control-v5.s 100% |*******************************| 6488 --:--:-- ETA
homeapp-enter: running;uid=0 euid=0; static MIPS helper
homeapp-restore: downloading homeapp_rootfs.tar.gz
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp_rootfs.tar.g 100% |*******************************| 14579k 00:00:00 ETA
homeapp-mount: /dev -> /media/homeapp-debug/rootfs/dev
homeapp-mount: /proc -> /media/homeapp-debug/rootfs/proc
homeapp-mount: /sys -> /media/homeapp-debug/rootfs/sys
homeapp-mount: /etc -> /media/homeapp-debug/rootfs/etc
homeapp-mount: /var -> /media/homeapp-debug/rootfs/var
homeapp-mount: /tmp -> /media/homeapp-debug/rootfs/tmp
homeapp-mount: /media -> /media/homeapp-debug/rootfs/media
homeapp-mount: /dev/pts -> /media/homeapp-debug/rootfs/dev/pts
homeapp-mount: /media/mmcblk0p1 -> /media/homeapp-debug/rootfs/media/mmcblk0p1
Runtime binds completed; no application services started.
homeapp-restore: READY. /tmp/homeapp start|status|logs|stop|shell
Wi-Fi/I2C drivers and persistent flash configuration are not restored by userspace staging.
Filesystem 1k-blocks Used Available Use% Mounted on
tmpfs 65536 44844 20692 68% /media/homeapp-debug
tmpfs 8192 0 8192 0% /media/mmcblk0p1
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/dev
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/proc
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/sys
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/etc
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/var
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/tmp
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/media
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/dev/pts
homeapp-mount: keeping verified bind /media/homeapp-debug/rootfs/media/mmcblk0p1
Runtime binds completed; no application services started.
homeapp: launcher PID 5880; startup output: /media/mmcblk0p1/homeapp-launch-5565.log
homeapp: startup in progress; /tmp/homeapp status and /tmp/homeapp logs
A running launcher is not proof of application or enrollment readiness.
The last thing was compiling a compatible version of GDB and upload it to the device to start playing
:)
GDB running on the Homebase2
Of course far more configurations changes are needed to make the binary work properly (e.g. I had to bridge an
eth
interface to create a
br0
within the range it needs for the peers -long story short: it uses a peer table with MAC addresses to reject or accept communications), but with a debugger everything is far more easy. Just fire the process, check what fails, correct it or just hook it to feed with the values it’s expecting to continue the flow.
0x04 Final words
With the arrival of LLMs, I’ve lost all enthusiasm for publishing technical content. I’ve been publishing articles online since 2007 sharing things I learned or discovered using dozens of different aliases across various blogs and forums. That is nearly 20 years. And today, I’ve lost all desire to share my experiences.
For one thing, there is the loss of value in writing if no one is going to read it. Nowadays, only a minority of people actually stop to read an article; most ask an AI for a summary or simply skim through without paying attention. There used to be an ecosystem where people spent time checking their RSS feeds (damn, I’m old) and reading articles from their favorite blogs or authors. The first major blow in this regard came from social media, where immediacy and “scoring Twitter points” became the primary driving force behind content creation.
Then there is the fact that the vast majority of published articles are generated directly by AI. Even interesting research pieces or vulnerability write-ups are churned out by automated looms, using that lobotomized language that gives me a stroke every time I try to read them. People seem delighted to gobble up such insubstantial crap. I suppose because it follows that first point. I write in “broken English” (yep, even though I’ve been working for a UK company for five years, my English is still terrible), yet I would a million times rather read an article written by a person in “broken English” than the umpteenth repetition of the same structures and stock phrases ChatGPT peppers its texts with.
The final nail in the coffin is the fact that… does it even make sense in 2026 to keep publishing technical content for human readers? In the past, you’d read a lot of material (or even bookmark it for future reference) because it was genuinely useful. Perhaps you were tinkering with a product’s firmware that someone else had already explored; you could find that article and follow the trail they blazed. The same applied to vulnerability analysis: you’d read about others’ work so you could replicate it when you encountered a similar scenario. And I’m not just talking about specific products; I’m talking about methodologies: how someone solved a problem, allowing you to face the same situation years later and apply what you had read back then. With AI, this no longer makes sense; the world is turning into a collection of meat proxies prompting the latest LLM to resolve whatever snag or situation arises.
I obviously use AI in my professional work, but not to tackle my “hobby” projects (like the things I post on this blog). I need to clarify that last point: I use it, for instance, when I’m reverse-engineering something and come across a function that performs mathematical operations (like when I used it in the previous article to identify Reed-Solomon), or to automate a task I’ve already performed manually (e.g., in this very article, I used it to build a script based on commands I had executed and that were recorded in the log). I thoroughly enjoy my hobby, and I don’t want automation to rob me of those hours spent banging my head against the wall trying to figure something out, or that moment of pleasure when the penny drops and I have a “eureka” moment.
About a decade ago I remember reading Matasano’s cryptochallenges and this sentence stuck in my head since then:
Breaking repeating-key XOR (“Vigenere”) statistically is obviously an academic exercise, a “Crypto 101” thing. But more people “know how” to break it than can actually break it
.
I guess now we live in the world where everyone
knows how to ask the LLM to hack something
instead of actual
knowing how to hack something
.
As usual, feel free to give us feedback at our twitter
@AdeptsOf0xCC
(although I lost the password and can’t access to the account anymore
:D
).
iPhone Duo Pre-Orders Launched, and Three Hours Later It’s Sold Out Through the End of January
Daring Fireball
www.macrumors.com
2026-10-16 11:19:28
Joe Rossignol, MacRumors:
If you were hoping to surprise someone with an iPhone Duo for
Christmas, you might be out of luck, as Apple’s online store in
the U.S. is already showing an estimated shipping date of January
25 for all configurations following the start of pre-orders today.
It is poss...
It is possible that some Apple Stores will have the iPhone Duo available for walk-in customers on Friday, October 23 launch day, but it seems likely that inventory will be very tight. For customers interested in reserving an Apple Store pickup slot, Apple's online store now says to check back on Saturday, October 24 for this.
Friday September 18, 2026 9:51 pm PDT by
Juli Clover
Apple hardware engineering VP Tom Marieb spoke with TechRadar and shared some candid thoughts about Apple's upcoming iPhone Duo.
The iPhone Duo uses a matte nano-texture display, which is meant to cut down on glare and minimize the visibility of the crease. When asked if the iPhone Duo's crease would be more visible over time, as that's what tends to happen on other foldables, Marieb said...
Apple on Instagram today shared a curated gallery of six photos shot on the iPhone Duo. The photos were shot by American photographers Jake Michaels and Jason Nocito, as part of a project commissioned by Apple.
iPhone Duo is equipped with four cameras:A rear 48-megapixel Fusion Main camera
A rear 48-megapixel Ultra Wide camera
A front 12-megapixel Center Stage camera in the outer display
A...
The iPhone Duo is reportedly facing production difficulties ahead of its October launch, with early output expected to be limited.
A person said to be close to Foxconn's supply chain told China's Jiemian News that final assembly yields for Apple's first foldable iPhone were only slightly above 60% as of September 17. The source said that, under Apple's current quality standards, it could...
This post is part of a
series
about Around The World, a game of exploration and discovery at sea. The game is currently in early development. If you're new to this project, you can read up on it
here
.
In the
last post
, I got the game’s clouds to look passable. But after looking at it during playtesting, I still wasn’t satisfied with the way the overall picture of how sea, sky and clouds came together. With some small tweaks, things started to look a lot better.
Light scattering in clouds
I ended the previous post using a lookup table rendered out by povray, that contains the amount of light scattered out of clouds depending on light angle (horizontal axis) and cloud density (vertical axis):
And I wrote about my dissatisfaction with this table:
I am beginning to suspect that povray doesn’t actually simulate multiple scattering at all; the documentation does not say yes or no either way. No matter how many samples and intervals I configure, I can’t get the bottom of those spheres to become lighter.
Once again I’m tempted to write my own recursive ray tracer to confirm my suspicions, but I resisted the urge […]
In the end, curiosity got the better of me and I
did
write my own multithreaded recursive Monte Carlo ray tracer in a few hundred lines of Rust. It’s extremely dumb and hard-coded for this specific situation, so it only renders one perfectly spherical cloud of uniform density. But it was enough to confirm that indeed, povray does not simulate multiple scattering. With multiple scattering, the lookup table looks very different:
The comparison is not entirely apples to apples, because I also tweaked some parameters and the scaling of the axes. But overall, the effect is clear: the light coming out of the cloud is distributed much more uniformly, making the cloud appear lighter overall.
At low density (thin clouds), the difference is not very apparent; the top rows of the lookup tables are very similar. After all, there isn’t much opportunity for a light ray to be scattered more than once when density is low. So let’s compare the look at a higher density, representing a thicker cloud layer. Here are some clouds rendered with the old LUT:
And here with the new:
The “metallic” look that I mentioned in the last post is now gone; cloud bottoms are brighter, and lighting is smoother overall.
One weird trick
In reality, clouds aren’t just lit by the sun directly. They also receive, and scatter, indirect sunlight from the sky. Since this light is usually tinted blue, the clouds should take on a more blueish hue as well.
I don’t want to add a constant “blue” term, since that is only correct during daytime; we’d want clouds to follow the current colour of the sky even at sunrise, sunset or night. How could I do that in Godot?
The answer turns out to be simple, but requires some understanding of how Godot’s light rendering works. Besides direct light, which we already handle, Godot also takes into account indirect light from the environment. This all happens under the hood outside user control, so my understanding is vague, but good enough to be useful.
As far as I understand it, indirect light is sampled from a cube map or two, containing radiance and irradiance from every direction. (I know radiance and irradiance are different things, but I don’t fully understand the distinction.) For diffuse materials like clouds, I’d expect the this cube map (these cube maps?) to be sampled in the direction of the surface normal, since that represents where most indirect light is coming from.
At the bottom of clouds, this normal points downwards towards the ground, so the cloud is rendered with little indirect light here. In reality, it
does
receive indirect light, but from above: it’s just scattered through the cloud. So, what would happen if we tweak the normal to point upwards to the sky instead? The effect is subtle but important; here’s before:
And here’s after:
The clouds have indeed gotten a blueish hue, making them blend in with the sky much better, and generally giving them a softer and more distant look, as clouds should have. I like this a lot!
How about a sunset, when the sky is not almost uniformly blue? Here’s before:
The bottoms of the clouds are tinted orange, because the incoming direct sunlight is orange due to heavy Rayleigh outscattering. Here’s the same sunset with tweaked normals:
The clouds have turned pink! I think this is much closer to how real sunsets look; the pink hue is apparently the result of mixing red (direct sunlight) and blue (indirect sky light), with the green channel getting somewhat lost in between.
Atmospheric scattering
Another thing that bothered me was that the sky looked unnaturally yellow near the horizon. This is fine and expected when the sun is low, but it was happening even with the sun straight overhead, like here:
I suspected that this was due to applying too much outscattering during the raymarch compared to inscattering, so I tried various hacks like adding a fake multiple inscattering term. In the end, a better fix turned out to be changing the order in which operations happen during the ray march. Instead of:
Add (blueish) light scattered into the ray segment
Attenuate by outscattering over the ray segment (reddening)
… I reversed the order:
Attenuate by outscattering over the ray segment (reddening)
Add (blueish) light scattered into the ray segment
The effect is that less attenuation happens along the way, compared to inscattering, and the result looks much better:
This should theoretically be an artifact of the numerical integration approach, and so the difference should disappear when increasing the number of integration steps. But it doesn’t, so I suspect there’s still something wrong somewhere. But it’ll do for now and hopefully forever.
Horizon bending
To render a realistic sky, I have to use parameters of the real Earth, like atmospheric density, height and planet size. However, the planet in my game is about 75× smaller than Earth, and so it’s curved more strongly. So when we use Earth parameters for the sky, the sky’s horizon ends up above the actual horizon. In between the two horizons, the sky shader pretends that the atmospheric density continues to increase exponentially towards the centre of the planet, which causes a dark band that’s especially noticeable during sunrise and sunset:
To make the two horizons meet, I applied a simple hack to the sky shader: add a small value to the y (vertical) component of the global view vector, then re-normalize it. The effect is to pull down the entire sky, most strongly around the horizon, causing the dark band to disappear behind the
real
horizon:
It’s a hack, but cheap and effective.
Tone mapping
Ah, the bane of every modern 3D game artist. Games are rendered in HDR (high dynamic range) nowadays, meaning their colour values can go brighter than the maximum of 1.0. If we display these on a typical monitor, the result has to be clamped, resulting in patches of oversaturated colours:
To fix this, some
tone mapping
formula is typically used to map the HDR values back into LDR space for display. Godot implements several tone mappers; I found Reinhard to be too dark, and ACES and AgX too desaturated. So in the end, I settled on Filmic tone mapper with a white point of 2.0:
It gives especially the clouds a nice soft look, and makes them fade into the distance much better.
The choice of white point is still fairly subtle since Godot itself recommends at least 6.0 for “photorealistic rendering”, but that just makes everything look darker.
Tuning the tone mapping is a tricky endeavour, because changes to the tone mapper affect everything that came before. So in practice, this process was not as linear as I wrote it down here, and required some back-and-forth between adjusting the tone mapper and the scene lighting. For one, I literally reduced the brightness of the sky by a factor of 2, which gave much better contrast after tone mapping.
The orrery
If we want a proper day-night cycle, we need the sun to rise and set. And if we want our planet to feel Earth-like, the times of sunrise and sunset should depend on location and season. This dependence is due to the motion of the Earth around the sun and around its own axis. A similar thing happens with the motion of the moon through the sky, and the phases of the moon.
It seemed complicated to figure out all the math to do these calculations properly. So I took an easier route: I modelled the entire situation in the engine, making the planet and its moon spin around like in an orrery:
Then I let the engine figure out the inverse transformation to determine where things are in the sky, from the point of view of an observer somewhere on the planet’s surface. This worked well, and the rendered orrery turned out to be a useful debugging aid.
After all that, I think I owe you another sunrise video, don’t I? And let’s find a scenic in-game spot for it, too!
Democracy’s on the Line’: NYC Unions Unite To Protect Elections
Portside
portside.org
2026-10-16 10:50:19
Democracy’s on the Line’: NYC Unions Unite To Protect Elections
Maureen gmail
Fri, 10/16/2026 - 10:50
...
New York City labor leaders and rank and file workers gather on the steps of the James A. Farley building Thursday. | Steve Wishnia
Hundreds of workers from a score of unions packed the two-block-wide steps of New York City’s main post office Oct. 15 for a rally launching a labor campaign to protect elections from tampering by the Trump administration.
A five-piece drums-and-horns combo from American Federation of Musicians Local 802 pumped out a New Orleans-style parade beat while Laborers Union organizer Anthony Williamson led chants of “Union in the house” and “This is what democracy looks like.”
“Look at this crowd,” Laborers International Union Vice-President Mike Hellstrom declared. “Private sector, public sector, different trades, standing together shoulder to shoulder with one clear message—the labor movement will defend democracy.”
If anybody attempts to steal the election, he added, the labor movement will mobilize communities, protest peacefully, and document intimidation of voters.
“We need to make sure that every ballot is counted, that people can exercise their right to vote without interference,” New York City Central Labor Council President Brendan Griffith told the crowd. “That should not be controversial.”
The principle that “we pick our leaders,” said Communications Workers of America Local 1180 secretary-treasurer Robin Blair-Batte, is now “under pressure.”
“We fought for the Voting Rights Act,” she reminded.
32BJ SEIU President Manny Pastreich also hailed the coalition of “janitors with construction workers, security officers with nurses.”
New York City labor unions are vowing to mobilize if anybody attempts to steal the upcoming midterm elections.
Griffith told Work-Bites the coalition began with various unions expressing concerns and built momentum from there. “Democracy affects all workers,” he said. The crowd included members of at least 20 unions, with large contingents from the Laborers, 32BJ, and 1199SEIU, along with electrical workers, painters, nurses, City University faculty, retail workers, theatrical and stage workers, hotel workers, the public-sector union DC37, and more.
Two specific attempts by the Trump administration to limit the right to vote have so far failed. The SAVE Act, which would require people to register to vote in person—banning registration by mail, at motor-vehicle bureaus, or online—and document their citizenship with a passport or birth certificate (plus a marriage license, for women who changed their names), narrowly passed the House in April 2025, but a threatened filibuster blocked it in the Senate.
On March 31, Trump issued an executive order to prohibit mail-in voting except by people on a list of eligible voters that states submitted to the Postal Service at least 60 days in advance, using only an officially designed envelope with specific markings. The Postal Service issued a rule on August 26 that it would not accept mail ballots from states that did not provide such lists, but a federal judge in Massachusetts issued an injunction against it. On Sept. 14, the Supreme Court refused to lift that injunction.
“We beat him back,” American Postal Workers Union President Jonathan Smith told Work-Bites after the rally. “Our oath is to deliver America’s mail, not to decide who can vote.”
The APWU filed an amicus brief in that case arguing that the rule infringed on both the states’ constitutional power to regulate elections and the Postal Service’s constitutional obligation to deliver the mail.
American Postal Workers Union President Jonathan Smith, APWU Local 10 President Joseph Martir, and New York Central Labor Council President Brendan Griffith show a united front on the main post office’s steps this week.
Voting by mail is “not a convenience,” APWU Local 10 President Joseph Martir told the rally. It’s a necessity for people in the military, students, and a large share of the elderly.
The union plans to have election monitors “in every station” in the last two weeks before the election,” Smith said, to “make sure every ballot gets out.” Ninety-nine percent of mail ballots reach their destination within seven days, and 97% do within three days, he added.
But what the country is up against is a president who repeatedly insists that he won the 2020 election, has made that delusional belief a loyalty test for his government and party, sent 1,500 goons into the Capitol on Jan. 6, 2021 to disrupt Joe Biden’s certification as President-elect, and pardoned them all immediately upon taking office again on January 20, 2025.
He controls the machinery of federal law enforcement. What would happen if, for example, armed ICE agents, not exactly known for their respect for people with Spanish accents who say they’re U.S. citizens, showed up outside polling places in swing-district towns with significant Latino populations?
32BJ is sending volunteer pollwatchers into swing Congressional districts in the Hudson Valley and on Long Island. “We don’t know if Trump and his supporters might try to intimidate people, but a crime or disturbance is less likely to happen if people are watching,” says Justin Lashley-Maloney, a night-shift doorman and “proud 32BJ member” for 13 years.
Griffith said the unions are doing pollwatching, helping people understand their rights, and working for a large turnout. He said he hoped “that these races are not close and that the results are clear.”
If ICE interferes with the election, “the labor movement’s going to respond,” he added.
“To the Trump administration and his criminal network: Democracy belongs to all of us. Democracy’s on the line, am I right?” 1199SEIU executive vice president Mike Ashby told the crowd. “This fight is bigger than immigration. This fight is bigger than unions.”
Waymo is officially heading to Canada! We’re laying the groundwork for our fully autonomous ride-hailing service in Toronto, investing in local facilities and jobs, with the goal of welcoming our first riders in 2028.
In the coming days, you’ll start to see Waymo vehicles on the streets of Toronto as we begin driving manually. We are taking a rigorous, phased, safety-first approach starting with high-definition mapping of local street networks and testing with trained autonomous specialists behind the wheel. This validation period will ensure the Waymo Driver adapts seamlessly to Toronto’s distinct driving conditions.
“Expanding into Canada marks an important milestone in Waymo’s global journey,” said Waymo co-CEO Tekedra Mawakana.
“Toronto is one of the world’s great cities — innovative, diverse, and forward-looking. We’re proud to bring the Waymo Driver to Canada’s largest city and to partner with the vibrant business, arts and cultural communities that share our commitment to safer streets and more accessible mobility.”
To serve Toronto, we’re partnering with Element Fleet Management, a Toronto-headquartered company and global leader in intelligent fleet and mobility solutions that will provide end-to-end fleet management services. Together with Element and our partners, we’ll invest in hundreds of roles over time spanning fleet maintenance, validation driving, customer service, and other operations functions that support our service. This deep partnership builds on Waymo’s existing ties to Canada, which includes our long-term investor relationship with the
Canada Pension Plan Investment Board
and our manufacturing partner, Magna International.
"As a Canadian company, we are proud to be expanding our partnership with Waymo to help bring autonomous ride-hailing to Toronto,” said Laura Dottori-Attanasio, Chief Executive Officer, Element Fleet Management. Together with Waymo, Element will help create employment opportunities providing the fleet expertise, operational capabilities, and intelligent mobility solutions needed to support autonomous fleets reliably and at scale."
As one of North America’s fastest-growing metropolitan regions, Toronto has both evolving mobility demands and a dynamic and growing number of tools. From bike lanes to public transit, Waymo’s
all-weather Driver
can provide an additional option that complements the city’s transportation ecosystem. The data from over 400 million fully autonomous kilometres driven shows the Waymo Driver was involved in
95% fewer
(20x fewer) crashes involving serious injury or worse compared to humans in the cities where we operate.
Safety and accessibility are fundamental to Waymo's mission to be the world's most trusted driver, and we're proud to collaborate with leading accessibility and mobility advocacy organizations, including BALANCE for Blind Adults, CNIB, Community Living Toronto, Connected Canadians, and Epilepsy Ontario, among others.
“Innovation that removes barriers to independence is at the heart of everything we do. Waymo’s history of partnering with the sight loss community to build accessible solutions is encouraging and their decision to engage with us early reflects the kind of approach that leads to real results,” said Michelle McQuigge, CEO, BALANCE for Blind Adults.
We can't wait to help residents and visitors explore everything Toronto has to offer. If you’re ready to experience Waymo in Toronto, please sign up for updates to be among the first to ride when we’re ready:
waymo.com/waymo-in-canada
.
Waymo arrive officiellement au Canada ! Nous préparons le lancement de notre service de transport par véhicules autonomes à Toronto. Nous investissons dans les infrastructures locales et dans la création d’emplois en vue d’accueillir nos premiers passagers en 2028.
Au cours des prochains jours, vous commencerez à voir des véhicules Waymo circuler dans les rues de Toronto, avec un conducteur au volant. Notre démarche est rigoureuse et axée avant tout sur la sécurité. Nous procédons par étapes, en commençant par cartographier le réseau routier local en haute définition, puis en effectuant des essais avec des spécialistes qualifiés de la conduite autonome au volant. Cette phase nous permettra de vérifier que le Waymo Driver s’adapte aux conditions de conduite propres à Toronto.
« Notre arrivée au Canada marque une étape importante dans le développement international de Waymo », a déclaré Tekedra Mawakana, codirectrice générale de l’entreprise. « Toronto est l’une des plus grandes métropoles du monde : une ville innovante, diversifiée et résolument tournée vers l’avenir. Nous sommes fiers d’introduire le Waymo Driver dans la plus grande ville du Canada et de collaborer avec les communautés dynamiques des affaires, des arts et de la culture qui partagent notre engagement envers des rues plus sécuritaires et une mobilité plus accessible. »
Pour assurer notre service à Toronto, nous faisons équipe avec Element Fleet Management, une entreprise dont le siège social se trouve à Toronto et qui est un leader mondial des solutions intelligentes de gestion de flottes et de mobilité. Element nous fournira des services complets de gestion de flottes. Avec Element et nos autres partenaires, nous investirons progressivement dans la création de centaines d’emplois liés à l’entretien de la flotte, aux essais sur route, au service à la clientèle et à d’autres activités nécessaires à l’exploitation de notre service. Ce partenariat s’inscrit dans la continuité des liens que Waymo a déjà tissés avec le Canada, notamment avec l’
Office d’investissement du régime de pensions du Canada
(Investissements RPC), un investisseur de longue date, et Magna International, son partenaire manufacturier.
« En tant qu’entreprise canadienne, nous sommes fiers d’élargir notre partenariat avec Waymo afin de contribuer à l’arrivée des services de transport de personnes à la demande par véhicules autonomes à Toronto, a déclaré Laura Dottori-Attanasio, présidente et cheffe de la direction d’Element Fleet Management. Ensemble, Element et Waymo contribueront à créer des possibilités d’emploi en mettant à profit l’expertise d’Element en gestion de flottes, ses capacités opérationnelles et ses solutions de mobilité intelligente pour soutenir le déploiement à grande échelle de flottes de véhicules autonomes, tout en assurant la fiabilité de leurs opérations. »
Toronto figure parmi les régions métropolitaines dont la croissance est la plus rapide en Amérique du Nord. Les besoins en matière de mobilité y évoluent et les options de transport se multiplient. Des pistes cyclables au transport en commun, le Waymo Driver, conçu pour fonctionner
par tous les temps
, pourrait offrir une option supplémentaire en complément des moyens de transport existants. Selon les données recueillies sur plus de 400 millions de kilomètres parcourus en conduite entièrement autonome, les véhicules Waymo ont été impliqués dans
95 % moins d’accidents
entraînant des blessures graves ou plus graves que les véhicules conduits par des humains dans les villes où le service est offert. Cela représente 20 fois moins d’accidents de ce type.
La sécurité et l’accessibilité sont à la base de la mission de Waymo : devenir le service de conduite autonome auquel le public fait le plus confiance au monde. Nous sommes fiers de collaborer avec des organismes de premier plan qui œuvrent en faveur de l’accessibilité et de la mobilité, notamment BALANCE for Blind Adults, l’Institut national canadien pour les aveugles (INCA), Community Living Toronto, Connected Canadians et Epilepsy Ontario.
« L’innovation qui favorise l’autonomie est au cœur de tout ce que nous faisons. L’expérience de Waymo en matière de collaboration avec des personnes ayant une déficience visuelle pour concevoir des solutions accessibles est encourageante. Sa décision de nous consulter dès le début montre qu’une telle approche peut donner des résultats concrets », a déclaré Michelle McQuigge, PDG de BALANCE for Blind Adults.
Nous sommes ravis d’aider les résidents et les visiteurs à découvrir tout ce que Toronto a à offrir. Si vous avez envie de faire l’essai du Waymo Driver à Toronto, inscrivez-vous pour recevoir nos mises à jour et être parmi les premiers informés du lancement de notre service :
waymo.com/waymo-in-canada
.
Big Fish: Exploiting a 37-Year-Old Kernel Bug in OpenBSD
Calif frequently publishes our offensive research and work, but we otherwise don't draw much attention to the defensive work we do — assisting open source projects with remediation, patch generation, cryptographic improvements, and internal engineering projects we carry out for our clients.
Earlier this year, we reported some vulnerabilities, often along with suggested patches to OpenBSD. One traced back roughly
37 years to the original BSD sources
, where a shared memory attachment counter was defined as a signed 16-bit short. Repeatedly forking a process with shared memory attachment records could push that counter past its maximum value of 32,767, causing it to wrap to a negative value. This integer overflow could lead to a use-after-free via a race condition; combined with a separate out-of-bounds write in the kernel, it allowed local privilege escalation to root. The issues were addressed in
errata 026
and
018
, respectively.
The exploit
We managed to get local root in OpenBSD with
KARL
/
SMAP
/
SMEP
enabled without the use of an information disclosure vulnerability via the following path:
Map 127 SysV shared memory segments, unmap them via
munmap()
, and fork 259 processes to wrap the shared memory attach count to -32,643.
Perform heap grooming and layout, using metrics from sysctl(
KERN_MALLOCSTATS)
(such as
kb_total
and
kb_totalfree
) to track allocations and determine when new pages are allocated.
Win the race condition using
IPC_RMID
in one process while attaching a new size-confused shared memory segment in a helper process.
Align IP socket allocations and set
IP_MULTICAST_TTL
to a non-default value of 2 to allocate a persistent 16-byte
struct ip_moptions
. Its final word packs two 16-bit counters:
imo + 12 = imo_num_memberships | imo_max_memberships << 16
.
Trigger the conditional
-1
out-of-bounds write to overwrite both the number of memberships and maximum memberships fields.
close()
the socket to traverse the group members, triggering
atomic decrements
that modify the PTE self-referential mapping twice, switching it from user to supervisor accessible mapping, and achieving kernel code execution by overwriting a predictable kernel pointer.
Clean up shared memory accounting and restore the overwritten kernel pointer to obtain a root shell.
Taking a step back, this vulnerability ended up getting code execution via a
write what where
primitive, where the
write
was caused by a
TAILQ_REMOVE
, the
what
was our userland memory mapping that was made supervisor mode accessible to bypass
SMAP
/
SMEP
, and the
where
was a predictable kernel pointer location.
Exploit mitigation
While OpenBSD's KARL relinks the kernel binary to randomize both function and data addresses, the kernel's memory allocators remain deterministic. Both the
boot-time allocator
and the
best-fit allocator
lack base address randomization. Consequently, early boot allocations consistently land at predictable locations across boots on the same hardware. When these predictable structure allocations contain function pointers, they become ideal targets for exploitation. For instance, the exploit reliably targets the
lo0
and
enc0
ioctl
handlers, overwriting one to gain control flow and using the other to restore the overwritten pointer.
Aside from the aforementioned errata fixes, there's several other approaches that can be taken to either eliminate or reduce the likelihood of those avenues being used again.
Firstly, we can implement safe-unlinking, a technique that checks doubly linked list invariants before performing the unlink memory writes. If the invariants are violated, then a suitable
abort()
or
panic()
is called, depending on if user mode or kernel mode, preventing memory corruption from occurring. An example implementation is
here
.
FreeBSD
and
NetBSD
have an implementation of safe-unlinking in their
sys/queue.h
implementation.
Secondly, we can randomize the self-referential PTE map allocation address so that the targeted atomic decrement locations would not be possible. This is done by using a random byte (
.openbsd.randomdata
) and selecting a
PML4
slot (
320 + (random_byte & 127)
) at boot time, and installing the recursive entry at that location. The
PTE_BASE
definition becomes a runtime expression, yielding bases from
0xffffa00000000000
through
0xffffdf8000000000
at 512-GiB intervals. An example implementation is
here
. In case randomization is not suitable, other options might suffice, such as marking the PTE as read-only, and changing CR0.WP during modification.
Thirdly, the kernel allocator can be made non-deterministic using two approaches; by
randomizing the base address
where memory allocations occur at boot time, and additionally
randomizing the allocation order at run time
. The base address randomization is effectively free as the gap it creates can still be used later on; while runtime randomization does incur some overhead during allocation - it may be possible that more in-depth allocator changes could alleviate this impact. Either approach would be sufficient to break the predictable pointer location without additional vulnerabilities, be it software or hardware.
Furthermore, there are existing and upcoming compiler features that can be used to mitigate against entire vulnerabilities, from
array bounds sanitizer
(a subset of Undefined Behaviour sanitizer) which can eliminate out of bounds fixed size array accesses. Calif has
suggested to FreeBSD
that the array bounds sanitizer may make a useful exploit mitigation that can be enabled in release builds, along with privately reporting 21 issues that the array bounds sanitizer would have caught; some with local privilege escalation security impact. An upcoming compiler feature that can be used to help mitigate against heap issues is
Alloc Tokens
, which can be used to isolate pointer containing allocations from non-pointer allocations. This isolation can make overflows from the non-pointer containing allocation much more difficult to exploit by preventing pointer access, along with making vulnerability classes like Use-after-Free unable to use the opposite type of allocation as the replacement memory allocation.
Since its inception, OpenBSD has consistently championed proactive security through source code auditing, the replacement of insecure APIs, advanced password hashing, cryptography, privilege separation, sandboxing, along with memory safety via
ASLR
and
W^X
; frequently setting the standard for system and network hardening.
By proactively hardening, and adapting new and existing mitigation options, we can often systematically neutralize entire classes of exploitation primitives; or at the very least, increase the attacker's cost (i.e. additional time investment, additional vulnerabilities needed to exploit an issue, find alternative avenues, etc). Investing in defensive improvements before vulnerabilities are actively targeted raises the bar for attackers, helping ensure robust protection and long-term resilience. In the age of AI-assisted vulnerability discovery, mitigating against entire vulnerability classes, combined with increasing attack complexity only becomes more critical.