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...
Original Article

The GDPR symbol with a torn Authy logo in the lower right corner.

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:

Authy ID: [Your Authy ID]
Phone number: [Your phone number]
Contact email: [Your contact email]

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:

  • CXF: The FIDO Credential Exchange Format , unencrypted, for password managers that import it.
  • 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).

TOTP Vault PWA screenshot with several apps and their generated TOTPs.

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

Hacker News
doctor-seo.net
2026-10-17 16:07:33
Comments...
Original Article

The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.

Additionally, a 503 Service Unavailable error was encountered while trying to use an ErrorDocument to handle the request.

Steinar H. Gunderson: Decompilation patterns, part 14: Strength increase

PlanetDebian
blog.sesse.net
2026-10-17 15:45:25
Let's look at the entire loop from yesterday: u16 spE10; u16 *var_v0_2; ... var_t1_2 = 0x7F; var_v0_2 = &spE10 + 0xFE; do { *var_v0_2 = 0; var_t1_2 -= 1; var_v0_2 -= 2; } while (var_t1_2 >= 0); What's going with the pointer arithmetic h...
Original Article

Let's look at the entire loop from yesterday:

    u16 spE10;
    u16 *var_v0_2;

    ...

    var_t1_2 = 0x7F;
    var_v0_2 = &spE10 + 0xFE;
    do {
        *var_v0_2 = 0;
        var_t1_2 -= 1;
        var_v0_2 -= 2;
    } while (var_t1_2 >= 0);

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:

    u16 spE10[0x80];  // Modified.
    u16 *var_v0_2;

    ...

    var_t1_2 = 0x7F;
    var_v0_2 = spE10 + 0x7F;  // Modified.
    do {
        *var_v0_2 = 0;
        var_t1_2 -= 1;
        var_v0_2 -= 1;  // Modified.
    } while (var_t1_2 >= 0);

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:

    var_t1_2 = 0x7F;
    do {
        var_v0_2 = spE10 + var_t1_2;
        *var_v0_2 = 0;
        var_t1_2 -= 1;
    } while (var_t1_2 >= 0);

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

Hacker News
www.cs.cmu.edu
2026-10-17 14:45:07
Comments...
Original Article

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."

A man and various inside furnishings are silhouetted against tall windows looking out over an area filled with buildings.
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."

To learn more about the program, visit Microsoft's Command Line .

Owner of Former UWS Barbecue Restaurant Indicted for Wage Theft: Manhattan DA

Hacker News
www.westsiderag.com
2026-10-17 14:34:33
Comments...
Original Article
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 .

Pattern Matching Beats Narrative Reasoning

Hacker News
blog.scottstevenson.net
2026-10-17 14:34:13
Comments...
Original Article

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

Abolish AI! Manifesto

Lobsters
abolish-ai.net
2026-10-17 14:25:58
Comments...
Original Article

PwnEscape: Guest-to-Host KVM Escape (CVE-2026-99999)

Lobsters
pwn.ai
2026-10-17 14:24:39
Comments...
Original Article

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. Diagram showing guest-origin packet bytes and checksum metadata crossing through virtual networking into the host Linux networking stack.
Figure 1. Diagram showing guest-origin packet bytes and checksum metadata crossing through virtual networking into the host Linux networking stack.

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. Diagram comparing frame-relative and network-header-relative packet coordinates before and after link-layer decapsulation.
Figure 2. Diagram comparing frame-relative and network-header-relative packet coordinates before and after link-layer decapsulation.

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. Bit-level diagram of the first IPv4 byte changing from 0x45, IHL 5 and 20 bytes, to 0x4f, IHL 15 and 60 bytes.
Figure 3. Bit-level diagram of the first IPv4 byte changing from 0x45, IHL 5 and 20 bytes, to 0x4f, IHL 15 and 60 bytes.

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. Memory-layout diagram showing a 28-byte logical skb linear head, a later 60-byte header copy, and the 32-byte disclosure beyond logical packet data.
Figure 4. Memory-layout diagram showing a 28-byte logical skb linear head, a later 60-byte header copy, and the 32-byte disclosure beyond logical packet 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. Evidence ladder separating source hypothesis, controlled mutation, host-memory disclosure, selected kernel writes, and bounded host execution on owned machines.
Figure 5. Evidence ladder separating source hypothesis, controlled mutation, host-memory disclosure, selected kernel writes, and bounded host execution on owned machines.

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 :

  1. Origin trust: a less-trusted guest or process describes an operation the host will later perform.
  2. Interpretation trust: the packet changes representation as link-layer headers are processed, and the kernel parses fields under a particular layout.
  3. 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. Diagram of ip_check_csum_start guarding five IPv4 checksum-completion consumers across the six files changed by the accepted Linux patch.
Figure 6. Diagram of ip_check_csum_start guarding five IPv4 checksum-completion consumers across the six files changed by the accepted Linux patch.

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.

Technical references

★ HomeView Thoughts and Observations

Daring Fireball
daringfireball.net
2026-10-17 13:25:13
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...
Original Article

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:

The “Introducing HomeView” title card shot from Apple’s video. It shows a HomeView sitting atop a kitchen island.

We see a wee bit of the cable when the dad reaches to touch the screen to start the French toast recipe:

The HomeView, centered on the kitchen island, with about 2 inches of cable visible, disappearing into the island right behind the HomeView base.

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:

A view from behind the HomeView, which has been rotated to face the mom, showing about 4 inches of the USB cable disappearing into a convenient hole in the center of the island.

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:

Same view as the previous shot, except the camera has been tilted up about an inch, such that the cable just runs off the bottom of the frame, no longer showing that it disappears into a hole in the island that no kitchen island I’ve ever seen actually has.

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.

Principles of Anchor Engineering

Lobsters
nappingtoheavymetal.com
2026-10-17 13:08:33
Comments...
Original Article

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.

In 2024, I wondered how new abstractions would change the code we write . That distinction between designing software and writing its code is central to Anchor Engineering.

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.

It took me nine years to hack my Xbox 360

Lobsters
kennedn.com
2026-10-17 12:13:32
Comments...
Original Article

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.

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 :

$$\frac{1}{133\text{ MHz}} \approx 7.52\text{ns}$$

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.

LPT NAND dumper wiring diagram 11 .

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.

Similarly I flashed Pico-dirtyJTAG onto a Pi Pico and was able to program the CoolRunner’s timing files using Octal450’s Timing Files and installing the urjtag project from source.

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. [...]...
Original Article

Hackers breach Microsoft 365 tenants via ConnectWise supply-chain attack

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:

  • ConnectWise Cloud Backup (506e08f9-6e9a-4da4-942b-a099a03644ae)
  • ​ConnectWise Cloud Management (2399d300-6fca-4e6a-a686-399fefe75b83)
  • ​ConnectWise Cloud Management - MS Teams (24205314-2b89-4e07-a2a4-579e898a5640)
  • ​ConnectWise Cloud Management - Exchange Online (b78f6a77-d4e5-46fb-87e5-d1648bd02519)
  • ​ConnectWise Cloud Management - MS Graph (0de14c77-b9b0-4137-9360-34878a929827)
  • ​ConnectWise Cloud Management - Partner Center (412dcf96-176d-4b3a-a1b0-4981ad66971e)
  • ​ConnectWise Cloud Management - SharePoint Online (b2b55f5b-7758-4719-8d8f-88ae172e6bdb)

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.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

AI Can Write the Code. Who Verifies It?

Hacker News
mihaisplace.com
2026-10-17 14:31:30
Comments...
Original Article

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.

Diagram of an automated software verification stack: a code change passes code quality and build checks, automated tests, security and dependency scans, AI code review, infrastructure and database checks, architecture and maintainability review, and human review before production, with production monitoring feeding back into the code, tests and architecture. A legend separates deterministic checks from AI-assisted ones, and a bar shows verification depth growing with the risk of the change

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 Verification

on:
  pull_request:

permissions:
  contents: read

jobs:
  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.

Diagram of when each check runs: pre-commit (format and lint, types and unit tests, secret scanning), post-commit or push (AI commit review, integration tests, SAST and dependencies), pull request (AI and spec review, required checks, human approval), pre-production (end-to-end tests, migration validation, smoke tests) and production (monitoring, anomalies, rollback), going from fast, inexpensive checks to deeper, risk-based verification

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.

Diagram of Mihai’s workflow in three phases: plan (feature request, spec, plan); implement, repeated per commit (the agent implements a commit, a separate AI reviews it, tests run, findings get fixed); and verify and release (a whole-change review against the spec, human PR review alongside CI and security checks, a manual smoke test, then deploy and monitor)

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.

  1. Faros — The Acceleration Whiplash (Q2 2026): 2026 AI engineering report . Study scope, throughput, review load, bugs, and incidents.
  2. Faros — The Speed Trap (Q3 2026): Latest report takeaways . Nuance on later AI-adoption patterns and downstream costs.
  3. Superpowers (Jesse Vincent / obra): GitHub repository . Skills-based development workflow, planning, TDD, debugging, reviews.
  4. RoboRev: Official website and documentation . Local continuous code review, Git hooks, review lifecycle.
  5. Wes McKinney: GitHub profile . pandas creator and Kenn Software founder.
  6. Anthropic: Set up Code Review for Claude Code . Hosted review architecture, eligibility, pricing, and triggers.
  7. Anthropic: Claude Code /code-review plugin . Plugin features and workflow.
  8. OpenAI: Review GitHub pull requests with Codex and Codex PR review help . PR reviews, prompts, and follow-up actions.
  9. GitHub: Using GitHub Copilot code review . Automatic reviews, suggested changes, review status, and customization.
  10. Cursor: Bugbot and Bugbot Autofix . PR review and assisted fixes.
  11. NIST: Secure Software Development Framework (SSDF), SP 800-218 . Security practices across the software-development lifecycle.
  12. GitHub: GitHub Actions documentation , repository rulesets , and secure pull_request_target usage . Workflows, status checks, and trust boundaries.
  13. OpenAI: Codex GitHub Action and security guidance . Action configuration, read-only permissions, and secret-handling cautions.
  14. 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)

Hacker News
twitter.com
2026-10-17 14:10:21
Comments...
Original Article

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.

OpenCode Hacked: User credentials leaked

Hacker News
twitter.com
2026-10-17 14:01:41
Comments...
Original Article

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

I Became a Citizen of Japan

Hacker News
www.derekwessman.com
2026-10-17 13:36:17
Comments...
Original Article

I became a citizen of Japan.

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

Hacker News
lwn.net
2026-10-17 13:14:12
Comments...
Original Article
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:
[Line plot of
	developers per release]

(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:

[Reviewed-by tags per
release]

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:

[First-time developers by
release]

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) :

[Fixes tags for 7.2]

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).

Index entries for this article
Kernel Development tools/Large language models
Kernel Releases/7.2


tsc-ts: TypeScript written in TypeScript

Hacker News
github.com
2026-10-17 13:10:27
Comments...
Original Article

Vercel Labs Experiment License: Apache-2.0

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 .

See CHANGELOG.md for release notes and GitHub Releases for package archives.

To build the packages for the current platform:

npm run pack:npm -w tsc-ts             # packages/tsc-ts/dist/npm/*.tgz
npm run pack:npm -w tsc-ts -- --check  # also install the tarballs and compile a project

-- --binary dist/tsc packs an existing native build, relative to packages/tsc-ts , instead of building one.

Packages

Package Description
packages/tsc-ts The compiler, written in TypeScript, with the tsc-ts command line and --api server.
packages/tsgo Reference builds of tsgo (its command line and per-stage drivers) that the tests compare against.

Tasks run with Turborepo .

Documentation

apps/web contains the tsc-ts compiler guides.

npm run dev:web
npm run build:web

Requirements

  • Node.js 24+ and npm
  • Go 1.26
  • 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

License

Apache-2.0 . See THIRD_PARTY_NOTICES.md for TypeScript-Go and other third-party notices.

Gold is now the top U.S. export

Hacker News
www.numismaticnews.net
2026-10-17 13:06:07
Comments...
Original Article
Image: AdobeStock

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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

Hacker News
www.artie.com
2026-10-17 13:02:50
Comments...
Original Article

Open roles

Join us in building the future of real-time data streaming. We're looking for exceptional people who care about craft, speed, and impact.

Open Positions ( 5 )

Engineering

Sales

Powered by Ashby

OpenAI discloses four more rogue incidents

Hacker News
fortune.com
2026-10-17 12:31:12
Comments...
Original Article

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.

GLP-1 may slow biological aging

Hacker News
www.universityofcalifornia.edu
2026-10-17 12:10:21
Comments...
Original Article

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

Hacker News
www.opendemocracy.net
2026-10-17 12:04:23
Comments...
Original Article

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).

A survey on a screen posed to an Amazon US employee asks to what extent the reader agrees with the statement "I am optimistic about the future of AI at Amazon."
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.”

Pele – Mermaid diagrams as themeable SVG

Hacker News
pele.run
2026-10-17 11:55:09
Comments...
Original Article

How it works

Write Mermaid syntax, Pele renders it to SVG. Try editing the example below.

Mermaid

flowchart TD  A[Mermaid text] --> B{Flowchart?}  B -- Yes --> C[Pele]  B -- No --> D[Mermaid]  C --> E([SVG])  D --> E
Yes No Mermaid text Flowchart? Pele Mermaid SVG

Use CSS variables to set colors and fonts. Color changes apply without re-rendering.

CSS

.pele {  --pele-bg: #fffcf0;  --pele-fg: #100f0f;  --pele-muted: #6f6e69;  --pele-line: #100f0f;  --pele-surface: #f2f0e5;  --pele-surface-alt: #e6e4d9;  --pele-border: #cecdc3;}

Pele

Themes Variables Light Dark

Why Pele?

Zero dependencies, 6× smaller, and up to 500× faster than Mermaid.js. Pele supports every diagram type built into Mermaid 12.1.0.

Pele Mermaid.js
Bundle size gzip 230 kB 1.6 MB
Render time 0.05–0.3 ms 6–82 ms
Direct dependencies 0 23
Small screens Adapts the layout Scales the diagram
Theming CSS variables Theme configuration

Pele in your app

Add Pele to your app using the API .

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.

Future of Programming

Lobsters
www.youtube.com
2026-10-17 11:42:25
Comments...

Ad-tech company was a delivery system for "mercenary spyware"

Hacker News
pluralistic.net
2026-10-17 11:17:32
Comments...
Original Article


Today's links



A lonely country road with a large roadside billboard. Thrusting out of the billboard is a punching fist with bloody, spiked brass knuckles; it is surrounded by scabrous craters. The sky is a psychedelic roil of red-brown clouds, from behind which loom indistinct, vast tropical flowers.

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:

https://citizenlab.ca/research/how-discover-tech-turned-targeted-ads-into-a-pipeline-for-spyware/

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:

https://pluralistic.net/2026/07/21/dickovers/#block-element

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:

https://noyb.eu/en/noybs-pay-or-okay-report-how-companies-make-you-pay-privacy

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"):

https://pluralistic.net/2024/08/07/revealed-preferences/#extinguish-v-improve

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:

https://en.wikipedia.org/wiki/Jedi_Blue

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:

https://pluralistic.net/2023/05/31/context-ads/#class-formation


Hey look at this ( permalink )



A shelf of leatherbound history books with a gilt-stamped series title, 'The World's Famous Events.'

Object permanence ( permalink )

#25yrsago Linux on a Big Mouth Billy Bass https://web.archive.org/web/20010927153043/http://bigmouth.here-n-there.com/

#20yrsago No-Fly lists even stupider than suspected https://web.archive.org/web/20061019002553/http://rawstory.com/showoutarticle.php?src=http%3A%2F%2Fwww.cbsnews.com%2Fstories%2F2006%2F10%2F05%2F60minutes%2Fmain2066624.shtml

#20yrsago Canadian MP booted for his blog https://web.archive.org/web/20061026153747/http://www.cbc.ca/canada/story/2006/10/18/turner-caucus.html

#20yrsago Recording industry shuts out Brazilian legal scholars https://web.archive.org/web/20061103225020/http://www.a2kbrasil.org.br/ENG/SIGN-A-PETITION-FOR-AMENDING-THE

#20yrsago How pickpockets work https://web.archive.org/web/20070110023812/http://www.kiplinger.com/magazine/archives/2006/11/mystory.html

#15yrsago Why are more people opting for legal name-changes than ever before? https://web.archive.org/web/20111020163908/http://www.bbc.co.uk/news/magazine-15333140

#15yrsago Advice to the 1% from Lemony Snicket https://occupywriters.com/works/by-lemony-snicket/

#15yrsago Proposed Australian law makes it an offense to insult Gaming Minister Michael O’Brien https://web.archive.org/web/20120507161803/http://www.heraldsun.com.au/news/more-news/surely-this-is-a-joke/story-fn7x8me2-1226167552466

#15yrsago Aloha From Hell: Sandman Slim goes back to Hell and kicks more ass https://memex.craphound.com/2011/10/18/aloha-from-hell-sandman-slim-goes-back-to-hell-and-kicks-more-ass/

#10yrsago California DMV thinks “INFOS3C” is a dirty word https://www.techdirt.com/2016/10/17/california-dmv-rejects-1nfos3c-vanity-plate-because-sexual-connotation/

#10yrsago Howard Stern won’t release Trump tapes https://www.billboard.com/music/music-news/howard-stern-on-replaying-his-donald-trump-interviews-it-would-be-a-betrayal-7542079/

#10yrsago Kim Stanley Robinson says Elon Musk’s Mars plan is a “1920s science-fiction cliché” https://web.archive.org/web/20161018043554/http://www.bloomberg.com/news/articles/2016-10-17/why-elon-musk-s-mars-vision-needs-some-real-imagination

#10yrsago UK’s Investigatory Powers Tribunal says GHCQ illegally spied for 17 years https://www.theverge.com/2016/10/17/13305270/uk-illegal-surveillance-gchq-investigatory-powers-tribunal

#10yrsago Project Include cuts off Y Combinator because Peter Thiel is a part-time investor there https://web.archive.org/web/20161019043240/https://motherboard.vice.com/read/horrified-by-trump-silicon-valley-leaders-debate-cutting-ties-to-peter-thiel

#10yrsago Islamophobic terrorist cell planned a “bloodbath” in Kansas, wanted to kill Muslim babies https://web.archive.org/web/20161018144035/https://www.washingtonpost.com/news/post-nation/wp/2016/10/15/it-will-be-a-bloodbath-inside-the-kansas-militia-plot-to-ignite-a-religious-war/?utm_term=.a9d769256cf6

#10yrsago Everything Belongs to the Future: a tale of pharmadystopian, immortal gerontocrats https://memex.craphound.com/2016/10/18/everything-belongs-to-the-future-a-tale-of-pharmadystopian-immortal-gerontocrats/

#10yrsago UK government proposes issuing Britons with unique porn-viewing ID numbers https://www.openrightsgroup.org/blog/a-database-of-the-uks-porn-habits-what-could-possibly-go-wrong/

#10yrsago Donald Trump’s mail-servers are running Windows 2003 https://pluralistic.net/2021/10/18/labor-shortage-discourse-time/#core

#5yrsago Copyfraudster censors investigation of implausible covid gadget https://pluralistic.net/2021/10/18/labor-shortage-discourse-time/#copyfraud

#5yrsago Corporatism made John Deere ripe for a strike https://pluralistic.net/2021/10/18/labor-shortage-discourse-time/#deere-dash


Upcoming appearances ( permalink )

A photo of me onstage, giving a speech, pounding the podium.



A screenshot of me at my desk, doing a livecast.

Recent appearances ( permalink )



A grid of my books with Will Stahle covers..

Latest books ( permalink )



A cardboard book box with the Macmillan logo.

Upcoming books ( permalink )

  • "The Post-American Internet," a geopolitical sequel of sorts to Enshittification , Farrar, Straus and Giroux, 2027
  • "Unauthorized Bread": a middle-grades graphic novel adapted from my novella about refugees, toasters and DRM, FirstSecond, April 20, 2027

  • "Enshittification, Why Everything Suddenly Got Worse and What to Do About It" (the graphic novel), Firstsecond, 2027

  • "The Memex Method," Farrar, Straus, Giroux, 2027



Colophon ( permalink )

Today's top sources:

Currently writing:

  • “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.

https://creativecommons.org/licenses/by/4.0/

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.


How to get Pluralistic:

Blog (no ads, tracking, or data-collection):

Pluralistic.net

Newsletter (no ads, tracking, or data-collection):

https://pluralistic.net/plura-list

Mastodon (no ads, tracking, or data-collection):

https://mamot.fr/@pluralistic

Bluesky (no ads, possible tracking and data-collection):

https://bsky.app/profile/doctorow.pluralistic.net

Medium (no ads, paywalled):

https://doctorow.medium.com/

Tumblr (mass-scale, unrestricted, third-party surveillance and advertising):

https://mostlysignssomeportents.tumblr.com/tagged/pluralistic

" 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....
Original Article
technology for society

Concrete possibilities for broader governance and popular participation.

DPI and the Homeless Workers Movement in Brazil
Photo by Cyndel Cardoso / Unsplash

By Alexandre Costa Barbosa . Originally published on irl.works .

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.

The MTST’s Tech Sector demonstrates, in practice, that it is possible to build digital infrastructure through communitarian governance , transparent and guided by social justice values. However, without the economic strength and organizational power of the state, popular movements cannot compete with Big Tech and the governments at the core of capitalism. That is precisely why the relationship between bottom-up experiments and state-led DPI must be rethought.

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.

Want to appear here? Sponsor a newsletter.

Support the Internet Exchange

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 .

Become A Paid Subscriber

🚨

Stop press! Do you enjoy our links? Links are now available to paid subscribers only. Become a paid subscriber today.

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...
Original Article

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.

skip past newsletter promotion

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.

Michael Wooldridge, a professor of AI at the University of Oxford, says it is not unreasonable to assume data inputted into the chatbot could be shared with the Chinese state .

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. [...]...
Original Article

Drupal patches critical RCE flaws, warns exploits may emerge soon

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.

According to the project’s website, more than one million websites run on Drupal.

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.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

US federal budget deficit jumps 12% in one year to nearly $2 Trillion

Hacker News
finance.yahoo.com
2026-10-17 10:22:05
Comments...
Original Article

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.

These final numbers came in the Treasury Department's Monthly Statement for September, which covers the final month in the US government's fiscal calendar.

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

Read more: How the soaring federal debt affects you personally

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.

Treasury Secretary Scott Bessent has focused on the Supreme Court-ordered tariff refunds that have turned a revenue stream into a cost center for the government in recent months.

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.

Ship Your Interpreter

Lobsters
www.basis.ai
2026-10-17 10:16:33
Comments...
Original Article

Published:

Article: Kiran Gopinathan , Nikhil Pimpalkhare , Yiyun Liu , Zenna Tavares

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:

[x ↦ 5], {x} ⊢ (1 + 1) ⇓ 2, [x ↦ 5]    [x ↦ 5], {x} ⊢ x ⇓ 5, [x ↦ 5]
                              2 + 5 = 7
─────────────────────────────────────────────────────────────────────
              [x ↦ 5], {x} ⊢ (1 + 1) + x ⇓ 7, [x ↦ 5]

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:

[x ↦ 5], {x} ⊢ 1 ⇓ 1, [x ↦ 5]    [x ↦ 5], {x} ⊢ 1 ⇓ 1, [x ↦ 5]
                           1 + 1 = 2
───────────────────────────────────────────────────────────────
              [x ↦ 5], {x} ⊢ 1 + 1 ⇓ 2, [x ↦ 5]

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 + :

static char *stringify(Value v) {
    ...
    char buf[64];
    switch (v.kind) {
    ...
    case VAL_FN: {
        const char *name = v.as.fn->fn_expr->as.fn.name;
        if (name)
            snprintf(buf, sizeof buf, "<fn %s>", name);
        else strcpy(buf, "<fn>");
        break;
    }
    default: strcpy(buf, "<native fn>"); break;
    }
    ...
}

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.

The theorem we proved is this one:

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.

The top arrow relates program p to output out through BigStep. The bottom arrow relates machine state c to out through Halts. Loaded connects p and c on the left; a double line marks equal outputs on the right. An orange arrow returns failed proof obligations to the semantics for correction.
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.

Two runs of malloc from the same heap. malloc(32) writes the new top chunk's header at 0x82000238; malloc(64) returns the block from 0x82000210 to 0x82000250, which contains 0x82000238.
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.

The development in three lanes: fixed inputs (the interpreter, its binary, the Sail model, Lean's kernel), what LLMs wrote (the semantics, the representations, the separation-logic proof), and what is checked and read (boot witnesses and the refinement theorem).
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

A memory map of the machine at the interpreter's entry, from 0x80000000 to 0x88000000: the ELF's code and constants byte for byte, runtime state in .data and .bss, the dlmalloc arena in its initial state holding the global frame and the AST of p, an 8 MiB stack with the interpreter object, and the registers pc, sp, gp, a0 to a3 at interp_run's entry.
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.

A stack: the binary on Sail at the bottom, the refinement theorem above it, the semantics above that, and four tools on top: a type system, a program logic, an abstract interpreter and a verified compiler.
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.

Paired bars on a log scale of instructions retired per test program, interpreted versus compiled: arithmetic 2.7 times fewer when compiled, strings 3.1, functions 6.5, scope 6.7, for 6.9, recursion 8.0, while 8.2.
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...
Original Article
apple tv

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.

Glenn Fleishman

— 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

Hacker News
www.pv-magazine.com
2026-10-17 10:01:01
Comments...
Original Article

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] .

Making Chicken Transparent Using Dorito Dust

Hacker News
chillphysicsenjoyer.substack.com
2026-10-17 09:55:28
Comments...
Original Article

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: 0 g, Tap water: 20 g, w/w: 0%, Molality (mol/kg water): 0, Tartrazine (mmol): 0, Molarity (approx.): 0 M (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) = E_0 \cos\!\left(\frac{\omega z}{c} - \omega t\right)\)

But for convenience we use complex numbers

\(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.

from [http://hyperphysics.phy-astr.gsu.edu/hbase/electric/dielec.html#c1 ]

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.

\(x(t) = \frac{-e/m}{\omega_0^2 - \omega^2 - i\gamma\omega}\; E(t)\)

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,

\(\chi(\omega) = \frac{N e^2/(\varepsilon_0 m)}{\omega_0^2 - \omega^2 - i\gamma\omega}\)

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.

\(\mathbf{D} = \varepsilon_0 \varepsilon_r \mathbf{E} = \varepsilon_0 \mathbf{E} + \mathbf{P}\)

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

\(\mathbf{D} = \varepsilon_0\,\varepsilon_{r,\mathrm{water}}\,\mathbf{E} = \varepsilon_0\mathbf{E} + \mathbf{P}_{\mathrm{water}}\)

Then when we add the dye, we get

\(\mathbf{D} = \varepsilon_0\mathbf{E} + \mathbf{P}_{\mathrm{water}} + \mathbf{P}_{\mathrm{tartrazine}}\)

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

\(\mathbf{D} = \varepsilon_0\left(1 + \chi_w + \chi_d\right)\mathbf{E}\)

Comparing with D = ε₀εᵣ E , and using that water alone has εᵣ(water) = 1 + χ(water) = n(water)², the relative permittivity of the dyed water is

\(\varepsilon_r = \varepsilon_{r,\mathrm{water}} + \chi_d = n_w^2 + \chi_d\)

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 = \sqrt{n_w^2 + \chi_d} = n_w\sqrt{1 + \frac{\chi_d}{n_w^2}} \;\approx\; n_w + \frac{\chi_d}{2 n_w}\)

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

\(\Delta n' = \frac{N e^2}{2 n_w \varepsilon_0 m}\,\frac{\omega_0^2 - \omega^2}{(\omega_0^2 - \omega^2)^2 + \gamma^2\omega^2}, \qquad \kappa = \frac{N e^2}{2 n_w \varepsilon_0 m}\,\frac{\gamma\omega}{(\omega_0^2 - \omega^2)^2 + \gamma^2\omega^2}\)

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.

\(\nabla \cdot \mathbf{D} = \rho_f, \qquad \nabla \cdot \mathbf{B} = 0, \qquad \nabla \times \mathbf{E} = -\frac{\partial \mathbf{B}}{\partial t}, \qquad \nabla \times \mathbf{H} = \mathbf{J}_f + \frac{\partial \mathbf{D}}{\partial t}\)

\(\mathbf{D} = \varepsilon_0 \mathbf{E} + \mathbf{P} = \varepsilon_0 \varepsilon_r \mathbf{E}, \qquad \mathbf{B} = \mu_0 \mathbf{H} \quad \text{(non-magnetic)}\)

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

\(\nabla \times (\nabla \times \mathbf{E}) = -\frac{\partial}{\partial t}\,\nabla \times \mathbf{B}\)

Ampère–Maxwell with J = 0:

\(\nabla \times \mathbf{H} = \frac{\partial \mathbf{D}}{\partial t}\)

Substitute B = μ₀ H and D = ε₀ E + P = ε₀εᵣ E :

\(\nabla \times \mathbf{B} = \mu_0 \frac{\partial \mathbf{D}}{\partial t} = \mu_0 \varepsilon_0 \frac{\partial \mathbf{E}}{\partial t} + \mu_0 \frac{\partial \mathbf{P}}{\partial t} = \mu_0 \varepsilon_0 \varepsilon_r \frac{\partial \mathbf{E}}{\partial t}\)

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)

\(\nabla \times (\nabla \times \mathbf{E}) = -\frac{\partial}{\partial t}\,\nabla \times \mathbf{B} = -\mu_0 \varepsilon_0 \varepsilon_r \frac{\partial^2 \mathbf{E}}{\partial t^2}\)

\(\nabla \times (\nabla \times \mathbf{E}) = \nabla(\nabla \cdot \mathbf{E}) - \nabla^2 \mathbf{E} = -\nabla^2 \mathbf{E}\)

Then if we equate both sides, we get a plane wave equation

\(\Rightarrow \quad \nabla^2 \mathbf{E} = \frac{\varepsilon_r}{c^2}\frac{\partial^2 \mathbf{E}}{\partial t^2}, \qquad c^2 = \frac{1}{\mu_0 \varepsilon_0}\)

Plane wave E = E ₀ e^(i(kz − ωt))

\(k^2 = \varepsilon_r \frac{\omega^2}{c^2}\)

Comparing with k = (n′ + iκ) ω/c from the attenuating wave written earlier,

\(\varepsilon_r(\omega) = n_c(\omega)^2 = (n' + i\kappa)^2 = n'^2 - \kappa^2 + 2 i n' \kappa\)

Discussion about this post

Ready for more?

Show HN: Esp32sim – Run ESP32 firmware in the browser

Hacker News
github.com
2026-10-17 09:51:08
Comments...
Original Article

esp32sim — a smiling chip in an emulator window

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.

ESP32-S3 ESP32-C3 ESP32-C6
CPU 2 × Xtensa LX7 @ 240 MHz 1 × RISC-V RV32IMC @ 160 MHz 1 × RISC-V RV32IMAC @ 160 MHz
Command esp32sim esp32sim-c3 esp32sim-c6
Core crate xtensa-lx7 riscv-rv32 riscv-rv32 (+ the A extension)
Reported full-listing decoder checks 977 k instructions, 0 mismatches 161 k instructions, 0 mismatches 126 k instructions, 0 mismatches
Boots ROM → bootloader → FreeRTOS → app ROM → bootloader → FreeRTOS → app ROM → bootloader → FreeRTOS → app
Boards / displays ST7735, ST7701S 480×480 + touch, WS2812, camera, audio none — console only ST7789 172×320 over SPI+DMA, WS2812, an 802.15.4 energy-detect stand-in
WiFi virtual AP, WPA2, DHCP/DNS/NTP, NAT to the real network, HTTPS the same virtual AP and network: scan, WPA2, DHCP, NAT (one station) the same virtual AP and network: scan, WPA2, DHCP, NAT (one station, legacy rates)
Speed block interpreter + AArch64 JIT , ~150–240 Minsn/s plain interpreter (no block cache or JIT yet) — still well above real time on hello_world same interpreter
In the browser yes (WebAssembly) yes (WebAssembly) yes (WebAssembly)
Reported hardware comparisons JTAG trace, 8000 steps after timing-loop resynchronization console diff, 205/208 lines identical console diff, 203/204 lines identical
Status mature draft — see docs/esp32c3.md draft — see docs/esp32c6.md

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 ):

H=examples/hello_world/build
./target/release/esp32sim --board none --boot rom --console uart0 \
    --bootloader $H/bootloader/bootloader.bin --ptable $H/partition_table/partition-table.bin \
    --app $H/hello_world.bin --elf $H/hello_world.elf --elf $H/bootloader/bootloader.elf --max-seconds 26

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.

H=examples/hello_world-c3/build
./target/release/esp32sim-c3 --boot rom --flash-mb 4 \
    --bootloader $H/bootloader/bootloader.bin --ptable $H/partition_table/partition-table.bin \
    --app $H/hello_world.bin --elf $H/hello_world.elf --max-seconds 26

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.

H=examples/hello_world-c6/build
./target/release/esp32sim-c6 --boot rom --flash-mb 4 \
    --bootloader $H/bootloader/bootloader.bin --ptable $H/partition_table/partition-table.bin \
    --app $H/hello_world.bin --elf $H/hello_world.elf --max-seconds 27

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.

./target/release/esp32sim --board waveshare-lcd4b --boot rom --flash-mb 16 --psram-mb 8 \
    --bootloader $P/bootloader/bootloader.bin --ptable $P/partition_table/partition-table.bin \
    --app $P/energy_panel.bin --console usb --wifi "ssid=home,psk=secret" --max-seconds 45

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):

B=examples/c6-wifi-station/build-emu
./target/release/esp32sim-c6 --boot rom --flash-mb 4 --board waveshare-c6-lcd147 --console usb \
    --bootloader $B/bootloader/bootloader.bin --ptable $B/partition_table/partition-table.bin \
    --app $B/c6_wifi_station.bin --elf $B/c6_wifi_station.elf --stub bb_init=0 \
    --wifi ssid=esp32sim,psk=esp32sim-pass --max-seconds 14

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

docs/ — architecture , peripheral coverage , boards , CLI reference , web UI protocol , design decisions & gotchas , roadmap , networking how-to , the WiFi and networking design notes, and the testing plan.

Provenance

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.

License

esp32sim is released under the MIT License , copyright Joakim Eriksson ( @joakimeriksson ), Alice ( @aliceisjustplaying ), and ( @mfiumara ) Mattia Fiumara.

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 .
  • Mask ROM ELFs ( espressif/esp-rom-elfs , Apache-2.0), fetched, not committed.
  • xterm.js ( xtermjs/xterm.js , MIT), fetched, not committed.
  • Linux image ( svermigo/Linux-on-esp32-S3 , GPL-3.0), fetched, not committed.
  • 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....
Original Article

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.

As always, for more of my work, check out my book First Contact: The Story of Our Obsession with Aliens , or subscribe to my personal newsletter The BeX Files .

Lethal Weapon meets Ice Age

Pomeroy, Emma et al.  “Evidence for funerary behaviour and lethal trauma in a new Neanderthal individual from Shanidar Cave.” Scientific Reports.

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.

In other news…

The truth is out there

Bruehl, Stephen et al. “Use of machine learning to enhance detection of transient astronomical phenomena in historical observatory images.” Scientific Reports.

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.

Inequality is in our bones

Li, Dongdong et al. “How inequality became durable before states: Evidence from 6000 years in the Central Plain of China.” Science Advances.

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.

The view from Ganymede

Royer, Clement et al. “Ganymede’s surface composition from 0.5 to 5.3 µm using combined VLT and JWST datasets and the resulting lessons learned.” Astronomy & Astrophysics.

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.

Thanks for reading! See you next week.

Show HN: High-quality duck audio synthesizer

Hacker News
celphase.github.io
2026-10-17 09:28:46
Comments...
Original Article

The Duck Pond

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.

Intuitive concurrent programming in any language

Lobsters
www.lf-lang.org
2026-10-17 08:17:20
Comments...
Original Article

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.

A B C

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
}

Lingua Franca Diagram for the RockPaperScissor Program R o c k P a p e r S c i s s o r s p l a y e r 2 : P l a y e r o b s e r v e r e v e a l p l a y e r 1 : P l a y e r o b s e r v e r e v e a l

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.

A world map showing where key Lingua Franca contributors reside. A world map showing where key Lingua Franca contributors reside.

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.

A world map showing where key Lingua Franca contributors reside.

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...
Original Article

“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 speaks at the conference, looking very animated with his hands raised.
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 gives a speech at a podium with a union jack flag behind him.
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 gives a speech, holding his hands to gesticulate. A sign on the wall behind him reads Security Service, MI5.
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 speaking last year in the House of Commons.
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.

skip past newsletter promotion

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.

A sign in front of the entrance at Porton Down. It says Porton Down Science Campus, and is in front of a high wire fence.
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)

Hacker News
dl.acm.org
2026-10-17 07:20:52
Comments...

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...
Original Article

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.

Head and shoulders shot of Geddes speaking at Hay festival
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.

Closeup of Topol during a conference in 2024.
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.

Sara Novak, a journalist, smiles slightly in a black top against a grey backdrop
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

Hacker News
www.engadget.com
2026-10-17 06:59:31
Comments...
Original Article

You can see the locations of known outdoor surveillance cameras in the app.

A Flock surveillance camera next to a road.

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 app now has another handy tool . You can toggle a layer that shows known outdoor surveillance cameras and license plate readers.

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...
Original Article

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.

Relations between Washington and Kyiv deteriorated sharply this week after Donald Trump waived a number of economic sanctions on Russia and suggested Ukraine needed a new leader.

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.

skip past newsletter promotion

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....
Original Article

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

Hacker News
nos.nl
2026-10-17 05:08:16
Comments...
Original Article

Aan het laden

NOS Nieuws

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.

Aan het laden

Is MCP becoming the common foundation of smart, decentralised search?

Hacker News
contextetech.com
2026-10-17 05:01:30
Comments...
Original Article

Is the MCP protocol becoming the common foundation of smart, decentralised search?

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

  1. Up-to-date answers : the assistant reads the data as the server publishes it at the moment of the question, not a training memory.
  2. Verifiable sources : every answer can link back to the original page.
  3. Clear rights : when the server states the licence, it travels with the data and you know what you may do with it.
  4. 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: DeepSeek v4.1 Flash 1017

Hacker News
openrouter.ai
2026-10-17 04:37:46
Comments...
Original Article

ElevenLabs launch offer: every ElevenLabs model is 50% off through October 19, 2026.

See ElevenLabs models

DeepSeek-v4.1-Flash-1017

Hacker News
huggingface.co
2026-10-17 04:21:25
Comments...
Original Article

DeepSeek-V4.1


Homepage Chat

Hugging Face Twitter Follow

License

Technical Report 👁️

Introduction

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 .

Developing for Debugging (2025)

Lobsters
www.davepacheco.net
2026-10-17 03:21:14
Comments...
Original Article

Written by dap
on

Developing for Debugging

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.)

Diagram: DNS propagation

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

Hacker News
github.com
2026-10-17 03:01:07
Comments...
Original Article

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.

CI Latest release Apple Silicon M1 to M5 License: MIT OR Apache-2.0

siltop during a build: CPU, GPU, memory, heat, network and power beside the process table

The Glance surface during a GPU inference spike siltop on a light terminal

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)

mkdir -p ~/.local/bin && curl -fsSL https://github.com/CLoaKY233/siltop/releases/download/v1.2.1/siltop-v1.2.1-macos-arm64.tar.gz | tar -xz --strip-components 1 -C ~/.local/bin siltop-v1.2.1-macos-arm64/siltop

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 .

From source (Rust 1.98 or newer)

cargo install --git https://github.com/CLoaKY233/siltop --tag v1.2.1 siltop --locked

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):

Crate Role
siltop-core Snapshot types, history store, config, verdicts
siltop-metrics Collectors (SMC, IOReport, IOHID, Mach, sysctl) and the sampler. No UI types
siltop-ui Themes, braille graphs, layout, widgets. No metrics imports
siltop 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.

License

Licensed under either of

at your option. Copyright © 2026 Lay Sheth.

Some quick thoughts on Unit Testing ActivityPub

Lobsters
shkspr.mobi
2026-10-17 02:12:46
Comments...
Original Article

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:

  1. Feed a function some data
  2. 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.

Basic text validation

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!

Message validation

What does a WebFinger response look like? Which parts are mandatory and what values can they contain?

With any message that your project generates, how can you be sure that other ActivityPub servers will understand it?

Similarly, when we receive a follow message from an external server, what should it look like?

There are some JSON Schemas which can be used to validate some type of messages.

But, again, there are many scattered specifications.

Signature verification

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…

Communicating with others

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.

Putting it all together

I'm putting all my tests online . I'm also sharing a collection of messages and signatures which you can use in your tests.

I'd love to know if you find them useful.

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...
Original Article

The questions

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?

Elvis Presley performing on the Elvis comeback TV special on 27 June 1968, wearing black leathers and with his back to the camera, smiling at the crowd to his left
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...
Original Article

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.
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

Hacker News
www.theguardian.com
2026-10-17 01:44:22
Comments...
Original Article

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 drifts among the trees
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 from a hospital bed with a bandage on her fingers.
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.
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

Lobsters
docs.stacresearch.com
2026-10-17 01:08:50
It's using https://lv1.sh/ Comments...
Original Article

Type: Audited

Specs: STAC-M3™ Benchmarks (Antuco Suite)

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

Hacker News
llmspeed.dev
2026-10-17 00:36:53
Comments...

orib: Bringing back the old Reddit interface, with a few new enhancements

Lobsters
github.com
2026-10-17 00:22:50
Comments...
Original Article

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

  1. Open chrome://extensions (or the equivalent page in another Chromium browser).
  2. Turn on Developer mode.
  3. Choose Load unpacked and select the extension directory.
  4. 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.

The Chrome Web Store and Firefox Add-ons copy, plus the privacy policy, are in store/LISTING.md and store/PRIVACY.md .

Project layout

Path Role
extension/manifest.json Extension manifest
extension/renderer.js Routing, data fetch, HTML, and interactions
extension/classic.css Classic visual system
extension/icons/ Toolbar icons
scripts/pack.ps1 Builds the store zip
store/ Listing text and privacy policy
ARCHITECTURE.md Runtime flow and API usage
DESIGN.md Visual rules for the classic UI
CONTRIBUTING.md Contribution workflow and Conventional Commits guide
AGENTS.md Notes for coding agents working in this repo

Docs

  • Architecture — how a page is replaced and which endpoints are called
  • Design — colors, type, and layout that keep the UI looking like old Reddit
  • Contributing — development setup, coding guidelines, and commit standards

"In every study that considered the question"

Hacker News
unsung.aresluna.org
2026-10-17 00:08:27
Comments...
Original Article

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:


Seeing all this, I was reminded of this old post from Dmitry Fadeyev , titled “False simplicity”:

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,
  • many icons are never understood, but people can still to some extent use them without ever understanding them ,
  • 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...
Original Article

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.”

An employee sorts boxes of perished goods beside red crates outside a Paris supermarket
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
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 sort jars and crates of food in bins and crates outside
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.”

DeepSeek v4.1 flash on OpenCode pretty good

Hacker News
github.com
2026-10-16 23:47:50
Comments...
Original Article

shev — decisions, without the hype

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.

Install

One line, copy-pasteable:

curl -fsSL https://raw.githubusercontent.com/aditauqir/shev/main/install.sh | bash

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:

npm install -g git+https://github.com/aditauqir/shev.git

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

Got Rust already? Same thing, just as short:

cargo install --git https://github.com/aditauqir/shev

Uninstall

For full cleanup, whether installed with curl or npm, close other running shev sessions first:

shev --uninstall --dry-run  # preview paths; delete nothing
shev --uninstall            # confirm before removal
# or: shev --uninstall --yes

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

  1. 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 .
  2. Type or paste the whole message. enter sends it, ctrl+j drops a new line in the middle of a multi-line one.
  3. Say what you want done with it — "draft a short reply", "does this need me today", "where's the risk here".
  4. 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.

shev home screen

shev decision view

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):

opencode mcp add shev --global -- "$HOME/.local/bin/shev" --mcp --file "$HOME/shev-responses.json"
opencode mcp list

The equivalent OpenCode V2 configuration is:

{
  "mcp": {
    "servers": {
      "shev": {
        "type": "local",
        "command": ["/absolute/path/to/shev", "--mcp", "--file", "/absolute/path/to/responses.json"],
        "enabled": true
      }
    }
  }
}

For Codex, add this to ~/.codex/config.toml (or your CODEX_HOME config), replacing the paths, then restart Codex and check codex mcp list :

[mcp_servers.shev]
command = "/absolute/path/to/shev"
args = ["--mcp", "--file", "/absolute/path/to/responses.json"]

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.

License

Apache-2.0. See LICENSE .

Source code of the Estonian online voting system

Hacker News
github.com
2026-10-16 23:18:39
Comments...
Original Article

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.

A skeptic's first contact with Kubernetes (2024)

Hacker News
blog.davidv.dev
2026-10-16 23:16:25
Comments...
Original Article

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.

A "standard" description

Kubernetes allows you to run arbitrary workloads, and provides you with the ability to:

  • specify requirements (cpu, disk, memory, instance count, ..)
  • dynamically scale instance count

but the more important part, is what it does for you:

  • picking which host an application runs on
  • "self-healing" (crashed instances get restarted, instances automatically moved out of faulty hosts)
  • exposes services for DNS-based discovery

and it only requires you to package your workload as a Docker image , which seems like a reasonable price to pay.

The basic building blocks that compose a cluster can be defined as follows:

  • Pod : a unit of work, consisting of a set of Docker images and their configuration
  • Node : a computer running the kubernetes node agent (kubelet). executes Pods.
  • Cluster ; a logical collection of Node s along with the Control Plane.
  • Service : logical grouping of a set of pods
  • 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

What I found important

My opinion is that a large part of Kubernetes' value is derived from just two concepts:

Control loops

Workloads are managed by a set of control loops (named Controllers ).

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
  • Generic Health monitoring
    • Desired state: All Nodes are healthy
    • Sensor: Health metrics from nodes
    • Control Element: Remove Nodes from the cluster

Services

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:

  1. A Virtual IP will be assigned to it
  2. 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":

Workload management

or "how, when and where things run"

You can create a Pod manually, using a YAML definition like this one:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

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.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx-replicaset
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2

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.

Storage management

or "how data persists and moves with your Pods"

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:

  1. Log shipping from a sidecar
  2. 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:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

and you can then use it in a Pod like this:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-pv
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: html-volume
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html-volume
    persistentVolumeClaim:
      claimName: nginx-pvc

Some things seemed interesting:

  • 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:

  1. Pods have stable hostnames ( nginx-0 , nginx-1 , ..)
  2. Deployments are executed in order:
    1. Creation of Pods in ascending order (0, 1, ..)
    2. Deletion of Pods in descending order (3, 2, ..)
    3. 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?

The scorecard

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

The Controller docs say:

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
    • Basically, Horizontal Pod Autoscaler but with sensors which are not just "CPU"
  • Why are the storage and networking implementations "out of tree" (CNI / CSI)?
    • Assuming it's for "modularity" and "separation of concerns"
  • Given the above question, why is there explicit support for Cloud providers?
    • eg: LoadBalancer supports AWS/GCP/Azure/..

And for the largest open topic, even though this is not Kubernetes' fault, I have a rant I need to get out

Stringy types

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 }}

or

{{- toYaml { "rollingUpdate": {}, "type": "RollingUpdate" } .Values.updateStrategy | nindent 4 }}

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.

Butlerian Jihad

Hacker News
dune.fandom.com
2026-10-16 22:21:08
Comments...

The Late Charlie Munger on Elon Musk and Tesla

Daring Fireball
www.cnbc.com
2026-10-16 21:22:34
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...
Original Article

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.

At the annual shareholders meeting for newspaper company Daily Journal on Wednesday, a shareholder asked Berkshire Hathaway vice chairman Munger what he thought about Musk, based on Tesla's recent ups and downs.

"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."

Currently, Tesla's market cap is over $140 billion , first hitting the $100 billion mark in January.

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.

Like this story? Subscribe to CNBC Make It on YouTube!

Don't miss:

3 psychological habits Buffett's partner Charlie Munger warns can hurt your career

Interactive refactoring in gopls

Lobsters
go.dev
2026-10-16 21:12:09
Comments...
Original Article

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.

Our LSP interactive refactoring proposal ( microsoft/language-server-protocol#1164 ) solves this by establishing a standard mechanism for language servers to collect user input before computing text edits. For Go developers, this unlocks a suite of long-awaited refactorings, including:

among many others.

Interactive refactorings in action

Adding and removing struct tags (gopls v0.23.0)

When configuring serialization formats, developers frequently need custom tags and casing conventions. Previously, running “Add struct tags” unconditionally injected json tags using camelCase formatting.

With interactive refactoring:

  1. Place your cursor on any struct definition and select the “Add struct tags” code action.
  2. An input dialog appears, pre-filled with json , allowing you to customize any combination of tags (such as json,yaml,db ).
  3. A second dialog lets you select your desired naming convention (such as camelCase , snake_case , or PascalCase ).
  4. Gopls generates and applies the formatted struct tags across your type definition.

Interactive "Add struct tags" in VS Code

Here is the before-and-after transformation:

type UserProfile struct {
    ID        int64
    FirstName string
    LastName  string
    EmailAddr string
}
type UserProfile struct {
    ID        int64  `json:"id" db:"id"`
    FirstName string `json:"first_name" db:"first_name"`
    LastName  string `json:"last_name" db:"last_name"`
    EmailAddr string `json:"email_addr" db:"email_addr"`
}

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:

  1. Place your cursor on any concrete type and select the “Add methods to X to implement an interface…” code action.
  2. 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 ).
  3. If the selected interface has type parameters, gopls asks for a concrete type argument for each type parameter (such as Foo ).
  4. Gopls generates complete method stubs with appropriate receiver names and instantiated method signatures.

Interactive "Add methods to implement an interface..." in VS Code

type Foo struct{}

type MyHasher struct{}
type Foo struct{}

type MyHasher struct{}

// Equal implements [maphash.Hasher].
func (m *MyHasher) Equal(x Foo, y Foo) bool {
    panic("unimplemented")
}

// Hash implements [maphash.Hasher].
func (m *MyHasher) Hash(*maphash.Hash, Foo) {
    panic("unimplemented")
}

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:

  1. Place your cursor on any top-level declaration and select the “Move declaration X” code action.
  2. A file picker dialog lets you choose an existing destination .go file or specify a new file path.
  3. 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:

(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

Hacker News
www.flexport.com
2026-10-16 21:01:51
Comments...
Original Article

Build the future of global trade.

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.

Join the team

WHY FLEXPORT

The most interesting job in the world's biggest industry.

  • Lorem ipsum placeholder image

    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.

World map with pinpoints marking global locations and network connections.
  • 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.


Placeholder feature image

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...
Original Article

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.

Apple TV 69
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.

Follow the rest of our March 2015 event coverage for the latest information.

Popular Stories

New Apple TV 4K Leaked

Friday September 25, 2026 8:16 am PDT by

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...

New Apple TV 4K, HomeView, and HomePod Mini: 16 Details Just Leaked

Sunday October 11, 2026 12:56 pm PDT by

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 ...

iPad Mini With A20 Pro, New HomePod Mini Colors, and New Apple TV 4K All Just Leaked

Friday September 25, 2026 8:18 am PDT by

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 ...
Original Article

Friday Nite Videos | October 16, 2026

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?

Portside Portside

Show HN: Things to Do API

Hacker News
thingstodoapi.com
2026-10-16 19:58:34
Comments...
Original Article

Fast, accurate, localized events API for agentic applications.

The knowledge base for shows, talks, pop-ups, markets, festivals, and more.

Ask in plain words

The way you'd ask a friend.

curl "https://api.thingstodoapi.com/v1/search?q=comedy+in+san+francisco+this+weekend"

{
  "title": "Drag-Up Comedy",
  "category": "arts",
  "starts_at": "2026-10-19T02:00:00.000Z",
  "local": {
    "date": "2026-10-18",
    "time": "7:00 PM"
  },
  "venue": {
    "name": "Cobb's Comedy Club",
    "city": "San Francisco"
  },
  "links": {
    "source": "https://www.ticketmaster.com/dragup-comedy-san-francisco-california-10-18-2026/event/1C0064D823FC0B87",
    "tickets": "https://ticketmaster.evyy.net/c/253185/264167/4272?SharedId=DoStuff&u=https%3A%2F%2Fwww.ticketmaster.com%2Fdragup-comedy-san-francisco-california-10-18-2026%2Fevent%2F1C0064D823FC0B87"
  }
}

REST and MCP

Agent-ready knowledge base.

# REST
GET https://api.thingstodoapi.com/v1/search?q=...

# MCP
claude mcp add --transport http thingstodo https://api.thingstodoapi.com/mcp

Supported regions

Pricing

Free

$0

  • 1,000 calls a month
  • 60 calls a minute

Get a key

Pay as you go

$5 per 1,000 calls

  • First 1,000 a month free
  • $3 per 1,000 after 100,000
  • $2 per 1,000 after 1 million
  • No cap unless you set one
  • 300 calls a minute

Start paying as you go

Enterprise

Custom

  • Every city
  • Bulk access and an SLA
  • Any rate

Contact us

Get started.

Try it without a key: 50 queries a day.

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...
Original Article

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

Hacker News
fakeipedia.org
2026-10-16 19:52:04
Comments...

Dam removals are bringing fish back across the northeastern United States

Hacker News
www.smithsonianmag.com
2026-10-16 19:47:31
Comments...

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...
Original Article

October 16, 2026

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.

For complete details, see the App Review Guidelines .

Changes

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

Hacker News
www.nature.com
2026-10-16 19:38:27
Comments...
Original Article
Short video sequence showing the fusion of a healthy coral and a bleached coral in a laboratory set-up over 9 weeks.

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.

Composite image showing early-stage recovery, showing the symbionts spreading from the healthy coral into the bleached coral.

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...
Original Article

See what’s happening and join the conversation

or

Log in with username or email

Axios-Ipsos Poll: “Medicare for All” Support Surges

Portside
portside.org
2026-10-16 19:30:12
Axios-Ipsos Poll: “Medicare for All” Support Surges barry Fri, 10/16/2026 - 19:30 ...
Original Article
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.

is Axios' senior contributor. She leads newsroom polling and focus group partnerships. She previously served as managing editor for politics. emailmargaret.talev@axios.com twitter@margarettalev


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 ...
Original Article

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 ...
Original Article
Trump Is Begging To Be Impeached Published

"Impeachment Rally" | by Phil Roeder ( CC BY 2.0)

President Trump has been impeached twice.

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.

Nine-Inch Snails

Hacker News
www.theatlantic.com
2026-10-16 18:21:05
Comments...
Original Article

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] .

Cloudflare Ray ID: a4bb6298ef5238e8

Back to The Atlantic

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,...
Original Article

16th October 2026

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.

— Addy Osmani, Morgan Westlee Lunt, and Qing Wang , How the Claude Code team does code review

Overlooked Brown Fat in Our Bodies Linked to Wide Range of Health Benefits

Portside
portside.org
2026-10-16 17:15:26
Overlooked Brown Fat in Our Bodies Linked to Wide Range of Health Benefits barry Fri, 10/16/2026 - 17:15 ...
Original Article

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.

The findings were published today in Nature 1 .

“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.

doi: https://doi.org/10.1038/d41586-026-03302-w

References

  1. Gómez-Banoy, N. et al. Nature https://doi.org/10.1038/s41586-026-11162-7 (2026).

    Article Google Scholar

  2. van Marken Lichtenbelt, W. D. et al. N. Engl. J. Med. 360 , 1500–1508 (2009).

    Article PubMed Google Scholar

  3. Cypess, A. M. et al. N. Engl. J. Med. 360 , 1509–1517 (2009).

    Article PubMed Google Scholar

  4. Virtanen, K. A. et al. N. Engl. J. Med. 360 , 1518–1525 (2009).

    Article PubMed Google Scholar

  5. Becher, T. et al. Nature Med. 27 , 58–65 (2021).

    Article PubMed Google Scholar

  6. Huo, C. et al. Front. Physiol. 13 , 917084 (2022).

    Article PubMed Google Scholar

A Cast of Regular People Find Their Way

hellgate
hellgatenyc.com
2026-10-16 17:11:31
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....
Original Article

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.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

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....
Original Article

Comments

Anonymous • October 16, 2026 6:04 PM

[SEYMOUR]
He’s so nasty, treatin’ her rough,

[AUDREY II]
Smackin’ her around and always talkin’ so tough.

[SEYMOUR, AUDREY II]
You (I) need blood and he’s got more than enough

[AUDREY II]
So go git it!
⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣠⣤⣤⣼⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀
⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀
⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀
⠀⠀⠀⠘⣿⣿⣿⣿⠟⠁⠀⠀⠀⠹⣿⣿⣿⣿⣿⠟⠁⠀⠀⠹⣿⣿⡿⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣿⣿⣿⡇⠀⠀⠀⢼⣿⠀⢿⣿⣿⣿⣿⠀⣾⣷⠀⠀⢿⣿⣷⠀⠀⠀⠀⠀
⠀⠀⠀⢠⣿⣿⣿⣷⡀⠀⠀⠈⠋⢀⣿⣿⣿⣿⣿⡀⠙⠋⠀⢀⣾⣿⣿⠀⠀⠀⠀⠀
⢀⣀⣀⣀⣿⣿⣿⣿⣿⣶⣶⣶⣶⣿⣿⣿⣿⣾⣿⣷⣦⣤⣴⣿⣿⣿⣿⣤⠤⢤⣤⡄
⠈⠉⠉⢉⣙⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⣀⣀⣀⡀⠀
⠐⠚⠋⠉⢀⣬⡿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣥⣀⡀⠈⠀⠈⠛
⠀⠀⠴⠚⠉⠀⠀⠀⠉⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠋⠁⠀⠀⠀⠉⠛⠢⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀

Atom Feed Subscribe to comments on this entry

Leave a comment

Sidebar photo of Bruce Schneier by Joe MacInnis.

Why harnesses matter for energy (and token) efficiency

Hacker News
neuralwatt.com
2026-10-16 17:01:23
Comments...
Original Article

By Chad Gibson, Co-founder & CEO

Key findings

  • 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:

Bar chart of the share of input not served from cache per client, from 1.6% for deepseek-harness to 11.1% for Node.js apps

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:

Bar chart: requests under 10% cached use 140% more energy on GLM-5.3 and 91% more on DeepSeek V4.1 Flash than fully cached ones

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:

Bar chart: time to first token rises from 5 s to 41 s for turns that re-read most of the prompt, against 0.8 to 2.8 s for normal turns

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.

Bar chart: 2.8% of turns break the cache when nothing visible changed, 61% when reasoning effort changed and 67% when the number of tools changed

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:

  1. Requests are rebuilt from an append-only session log. Retries and resumes produce byte-identical prompts.
  2. The system prompt is fixed and minimal. It leaves out the date, git status and OS. It is written once and left alone.
  3. 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.
  4. The tool list stays sorted and identical in every mode. Prose instructions enforce modes without adding and removing tools.
  5. 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.
  6. 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.

Session Insights page for a 35-turn session: 95.2% cache hit, 5.4M total tokens, 258.8K cold prefill, and a chart of cached versus cold prompt tokens per turn with time to first token

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...
Original Article

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.

There's never been a better time to go into math

Lobsters
www.youtube.com
2026-10-16 16:49:12
Comments...

Someone on Torrent Sites Kept Fucking With My Sonarr

Lobsters
thereallo.dev
2026-10-16 16:47:02
Comments...
Original Article

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:

  1. Open its own file.
  2. Read the last 64 bytes.
  3. Use those to find and decrypt a payload hidden in the junk.
  4. Map it as a PE in memory by hand.
  5. Point PEB->ImageBaseAddress at it.
  6. 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.
  • Crypto wallets : Exodus, Electrum, Atomic, Guarda, Coinomi, Ledger Live, Trezor Suite, Wasabi, Sparrow, Monero, Zcash, Armory, plus extension wallets.
  • Password managers : KeePass, KeePassXC, Bitwarden, 1Password, NordPass, RoboForm, Windows Credential Manager.
  • Accounts : Telegram, Discord tokens, Steam, Roblox cookies, Minecraft accounts, Authy.
  • Dev stuff : .ssh , .aws , .azure , gcloud, .kube , .docker .
  • Remote access : AnyDesk, TeamViewer, WinSCP, FileZilla, mRemoteNG, RDCMan.
  • 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....
Original Article

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

Hacker News
github.com
2026-10-16 16:33:41
Comments...
Original Article

Description

Type of issue

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.

URL

https://www.home-assistant.io/more-info/pwned-passwords/

Version

2026.10.1

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…

View full comment

Activity

  1. frenck commented on Oct 16, 2026

    @frenck

    Oh hi there 👋

    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.

    Read more about it here: https://blog.cloudflare.com/validating-leaked-passwords-with-k-anonymity/

    As a matter of fact, it is designed to handled these types of data with privacy in mind, see also: https://en.wikipedia.org/wiki/K-anonymity

    If anything, learn from the output, because the secrets you are using are listed in the password databases and thus easily "hackable".

    ../Frenck

    Blogging my personal ramblings at frenck.dev

  2. Viss commented on Oct 16, 2026

    @Viss

    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

  3. Viss commented on Oct 16, 2026

    @Viss

    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

  4. frenck commented on Oct 16, 2026

    @frenck

    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

  5. 0x00string commented on Oct 16, 2026

    @0x00string

    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

  6. frenck commented on Oct 16, 2026

    @frenck

    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.

    ../Frenck

    Blogging my personal ramblings at frenck.dev

  7. troed commented on Oct 16, 2026

    @troed

    It is not an invasion of privacy

    Yes. Yes it is.

    /whitehat hacker

  8. locked

    as too heated

    and limited conversation to collaborators

    on Oct 16, 2026
  9. frenck commented on Oct 16, 2026

    @frenck

    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.

    ../Frenck

    Blogging my personal ramblings at frenck.dev

The NIST Elliptic Curves Seeds Bounty Has Been Claimed

Lobsters
words.filippo.io
2026-10-16 16:18:36
Comments...
Original Article

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.

The lore was that Dr. Jerry Solinas, who passed away in early 2023, generated them in 1997 by hashing some English sentences that he later forgot. You can read more in this article by Steve Weis or in the original bounty announcement .

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.

Along with deterministic and hedged ECDSA signing algorithms, formally verified field implementations , and the 2015 complete addition formulas by Renes, Costello, and Batina , this nicely completes the “rehabilitation arc” of NIST elliptic curve cryptography, which I would now personally recommend over Curve25519/Ed25519/X25519.

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.

A set of 20 small dice in the evening light. They are white with red and black etchings. A small clear plastic box is next to them.

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....
Original Article

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.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

★ Real Artists Ship, Tesla Edition

Daring Fireball
daringfireball.net
2026-10-16 16:11:23
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....
Original Article

Jonathan Gitlin, writing for Ars Technica :

Nine years after first trying to resurrect the Roadster , Tesla is apparently trying again. CEO Elon Musk might have relocated its HQ to Texas, but yet again he has returned to California’s showbiz industry to hawk his wares; last time it was a Hollywood back lot for the remote-controlled Cybercab demo , last night it was decades-old stunt technology to make a show car do tricks in the air. [...]

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 .

The Tesla Roadster is vaporware. But Elon Musk is very good at distracting from unshipped vaporware by delivering on stunts. Two years ago it was robots that were totally faked . Last night’s car stunt involved real things that actually happened but only in the way that David Copperfield made the Statue of Liberty “disappear” .

Over at Jalopnik, Amber DaSilva has another good take , which concludes:

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 .

And on Threads, Benedict Evans reiterates his longstanding take on what makes Elon Musk so confounding to so many people :

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. [...]...
Original Article

Critical BlockStrap flaw lets hackers run code on Magento 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.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

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...
Original Article

RcppSimdJson 0.1.17 on CRAN: Updates

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 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 )

Courtesy of my CRANberries , there is also a diffstat report for this release . For questions, suggestions, or issues please use the issue tracker at the GitHub repo .

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can now sponsor me at GitHub .

/code/rcpp | permanent link

Flux 3 Image Klein: open weights, 5.6B parameters

Hacker News
bfl.ai
2026-10-16 15:47:13
Comments...
Original Article

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.

Try it in the BFL API · Download the weights

Collage of FLUX 3 Image Klein outputs: illustration, portraits, photography, anime, a stamp design and typography.

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.

Elo rating vs. generator parameters for text to image and image editing. FLUX 3 Image Klein leads at 5.6B 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 for the step-distilled model, 16 steps: 0.55 s on GB300 to 8.9 s on RTX 4070 for 1024×1024 text-to-image.
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 for the base model, 50 steps: 1.7 s on GB300 and DGX Station to 43.8 s on DGX Spark for 1024×1024 text-to-image.
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.

Elo rating vs. median API latency at 1 MP. FLUX 3 Image Klein is fastest among top-rated models: 4.54 s text to image, 7.18 s editing.

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.
  • Playground or Hugging Face .

Build with it

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.

Learn more

Citation

If you use FLUX 3 Image Klein in your work, please cite:

@misc{bfl2026flux3imageklein,
  author       = {{Black Forest Labs}},
  title        = {{FLUX} 3 Image Klein},
  year         = {2026},
  url          = {https://bfl.ai/blog/flux-3-image-klein},
}

The Fatal Flaw of 911

Hacker News
www.themarshallproject.org
2026-10-16 15:33:00
Comments...

Introducing GNOME OS Preview

Linux Weekly News
lwn.net
2026-10-16 15:05:57
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...
Original Article

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.



How the Claude Code team does code review

Hacker News
claude.dev
2026-10-16 15:04:47
Comments...
Original Article

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.

RETHINKING THE PURPOSE OF CODE REVIEW

When agents write code, the number of changes goes up, fast. In Anthropic's monorepo, changes landing per day went from about 2,500 in May to more than 30,000 in September this year.

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:

  1. Find and fix issues before they ship
  2. 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.

Diagram titled "If machines do most of the reading, how does anyone learn the code?" On the left, a grid stands for the codebase, with a few squares highlighted as managed settings, the part you want to understand; nobody keeps a complete mental model of it in their head. An arrow labeled "Ask Claude about exactly that slice", with the example question "How does Claude Code retrieve managed settings?", leads to two outcomes: Claude writes an explainer, which takes minutes and reflects the code as it is today; and, for some, Claude builds a small artifact that visualizes that part of the code and teaches it the way that person likes to learn. Along the bottom: reading trivial diffs line by line, a one-line copy change teaches you almost nothing; an explainer for the module you are about to change teaches you a lot.

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.

You could have invented transformers from memory

Hacker News
alexwang.ai
2026-10-16 15:01:17
Comments...
Original Article
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 .

An outer product memory store #

The most basic memory store is linear: it simply accumulates memories via outer products,

$$W = \sum_{i=1}^{M} v_i k_i\transpose = V\transpose K$$

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.

Recall picks up interference #

So storing memories is easy: just keep adding outer products to the weights. But what happens when we try to recall one?

Let’s assume for simplicity that every key is normalized to have length 1, i.e. $k_j\transpose k_j = 1$. Then

$$f(k_j) = \underbrace{v_j}_{\text{signal}} + \underbrace{\sum_{i\neq j} v_i\,(k_i\transpose k_j)}_{\text{interference}},$$

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

$$\frac{\norm{\text{interference}}}{\norm{\text{signal}}} \sim \sqrt{\frac{M}{d_k}}.$$

Setting this ratio to 1 gives a capacity of

$$M \approx d_k,$$

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

interference / signal = recall fails

How do we reduce interference? #

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 optimal linear memory store #

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

$$\operatorname*{minimize}_W \sum_{i=1}^M \norm{W k_i - v_i}_2^2.$$

When we store more memories than the key dimension, $M > d_k$, the least-squares solution is

$$W = \parens*{\sum_i v_i k_i\transpose}\parens*{\sum_i k_i k_i\transpose}\inverse = V\transpose K\,(K\transpose K)\inverse.$$

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

$$\frac{\norm{\text{interference}}}{\norm{\text{signal}}} \approx \sqrt{\frac{M}{d_k} - 1}.$$

This ratio equals 1 at

$$M = 2d_k,$$

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$:

$$f(k_j) = \sum_{i=1}^M v_i\, P_{ij} = \underbrace{P_{jj}\, v_j}_{\text{signal}} + \underbrace{\sum_{i\neq j} P_{ij}\, v_i}_{\text{interference}}.$$

$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.$$

If the values are random with similar lengths,

$$\frac{\norm{\text{interference}}}{\norm{\text{signal}}} \approx \frac{\sqrt{P_{jj} - P_{jj}^2}}{P_{jj}} = \sqrt{\frac{M}{d_k} - 1}.$$

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:

recall fails: more interference than signal 0.1 1 10 16 64 256 1024 4096 16384 number of stored memories M (key dimension d k = 64) interference / signal optimal: no interference for M ≤ 64 outer-product (Hebbian) memory, M = 16: interference/signal = 0.46 outer-product (Hebbian) memory, M = 32: interference/signal = 0.68 outer-product (Hebbian) memory, M = 64: interference/signal = 0.97 outer-product (Hebbian) memory, M = 128: interference/signal = 1.39 outer-product (Hebbian) memory, M = 256: interference/signal = 1.97 outer-product (Hebbian) memory, M = 512: interference/signal = 2.81 outer-product (Hebbian) memory, M = 1024: interference/signal = 3.90 outer-product (Hebbian) memory, M = 2048: interference/signal = 5.63 outer-product (Hebbian) memory, M = 4096: interference/signal = 8.01 outer-product (Hebbian) memory, M = 8192: interference/signal = 11.38 outer-product (Hebbian) memory, M = 16384: interference/signal = 15.90 outer product optimal (least-squares) memory, M = 16: interference/signal = 0.00 optimal (least-squares) memory, M = 32: interference/signal = 0.00 optimal (least-squares) memory, M = 64: interference/signal = 0.00 optimal (least-squares) memory, M = 65: interference/signal = 0.08 optimal (least-squares) memory, M = 66: interference/signal = 0.14 optimal (least-squares) memory, M = 68: interference/signal = 0.23 optimal (least-squares) memory, M = 72: interference/signal = 0.35 optimal (least-squares) memory, M = 80: interference/signal = 0.49 optimal (least-squares) memory, M = 96: interference/signal = 0.71 optimal (least-squares) memory, M = 112: interference/signal = 0.86 optimal (least-squares) memory, M = 128: interference/signal = 1.00 optimal (least-squares) memory, M = 256: interference/signal = 1.72 optimal (least-squares) memory, M = 512: interference/signal = 2.63 optimal (least-squares) memory, M = 1024: interference/signal = 3.81 optimal (least-squares) memory, M = 2048: interference/signal = 5.56 optimal (least-squares) memory, M = 4096: interference/signal = 7.95 optimal (least-squares) memory, M = 8192: interference/signal = 11.34 optimal (least-squares) memory, M = 16384: interference/signal = 15.91 optimal (least squares)

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.

MLP as a nonlinear memory store #

A linear memory store recalls

$$f(x) = \sum_{i=1}^M v_i (k_i\transpose x).$$

If we had a way to suppress the weight when $k_i\transpose x$ is small, then we can reduce the amount of interference from low similarity keys.

Let’s pass each similarity through a nonlinear function $\sigma$ before computing the weighted sum of values:

$$f(x) = \sum_{i=1}^{M} v_i\,\sigma(k_i\transpose x) = V\transpose \sigma(Kx).$$

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.

Reducing interference with higher powers #

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

$$\frac{\norm{\text{interference}}}{\norm{\text{signal}}} \approx \sqrt{\frac{M}{d_k^p}}.$$

This means the capacity is about

$$M \approx d_k^p$$

memories, geometrically more than before!

To check this, we run the same experiment as before for five choices of $\sigma$:

recall fails: more interference than signal 0.01 0.1 1 10 16 64 256 1024 4096 16384 number of stored memories M (key dimension d k = 64) interference / signal s (linear), M = 16: interference/signal = 0.46 s (linear), M = 32: interference/signal = 0.68 s (linear), M = 64: interference/signal = 0.97 s (linear), M = 128: interference/signal = 1.39 s (linear), M = 256: interference/signal = 1.97 s (linear), M = 512: interference/signal = 2.81 s (linear), M = 1024: interference/signal = 3.90 s (linear), M = 2048: interference/signal = 5.63 s (linear), M = 4096: interference/signal = 8.01 s (linear), M = 8192: interference/signal = 11.38 s (linear), M = 16384: interference/signal = 15.90 s (Linear) ReLU(s), M = 16: interference/signal = 0.31 ReLU(s), M = 32: interference/signal = 0.46 ReLU(s), M = 64: interference/signal = 0.69 ReLU(s), M = 128: interference/signal = 0.97 ReLU(s), M = 256: interference/signal = 1.37 ReLU(s), M = 512: interference/signal = 2.00 ReLU(s), M = 1024: interference/signal = 2.82 ReLU(s), M = 2048: interference/signal = 4.05 ReLU(s), M = 4096: interference/signal = 5.69 ReLU(s), M = 8192: interference/signal = 7.94 ReLU(s), M = 16384: interference/signal = 11.26 ReLU( s ) (MLP) ReLU(s)², M = 16: interference/signal = 0.05 ReLU(s)², M = 32: interference/signal = 0.09 ReLU(s)², M = 64: interference/signal = 0.14 ReLU(s)², M = 128: interference/signal = 0.20 ReLU(s)², M = 256: interference/signal = 0.29 ReLU(s)², M = 512: interference/signal = 0.42 ReLU(s)², M = 1024: interference/signal = 0.60 ReLU(s)², M = 2048: interference/signal = 0.85 ReLU(s)², M = 4096: interference/signal = 1.20 ReLU(s)², M = 8192: interference/signal = 1.70 ReLU(s)², M = 16384: interference/signal = 2.40 ReLU( s ) 2 (GLU MLP) Swish(s)·s (SwiGLU MLP), M = 16: interference/signal = 0.06 Swish(s)·s (SwiGLU MLP), M = 32: interference/signal = 0.09 Swish(s)·s (SwiGLU MLP), M = 64: interference/signal = 0.14 Swish(s)·s (SwiGLU MLP), M = 128: interference/signal = 0.20 Swish(s)·s (SwiGLU MLP), M = 256: interference/signal = 0.28 Swish(s)·s (SwiGLU MLP), M = 512: interference/signal = 0.41 Swish(s)·s (SwiGLU MLP), M = 1024: interference/signal = 0.59 Swish(s)·s (SwiGLU MLP), M = 2048: interference/signal = 0.85 Swish(s)·s (SwiGLU MLP), M = 4096: interference/signal = 1.18 Swish(s)·s (SwiGLU MLP), M = 8192: interference/signal = 1.64 Swish(s)·s (SwiGLU MLP), M = 16384: interference/signal = 2.36 Swish( s )· s (SwiGLU MLP) ReLU(s)³, M = 16: interference/signal = 0.01 ReLU(s)³, M = 32: interference/signal = 0.02 ReLU(s)³, M = 64: interference/signal = 0.03 ReLU(s)³, M = 128: interference/signal = 0.05 ReLU(s)³, M = 256: interference/signal = 0.08 ReLU(s)³, M = 512: interference/signal = 0.11 ReLU(s)³, M = 1024: interference/signal = 0.16 ReLU(s)³, M = 2048: interference/signal = 0.23 ReLU(s)³, M = 4096: interference/signal = 0.33 ReLU(s)³, M = 8192: interference/signal = 0.46 ReLU(s)³, M = 16384: interference/signal = 0.65 ReLU( s ) 3

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$.

Self-attention as a non-parametric memory store #

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,

$$e^{\beta s} = 1 + \beta s + \frac{(\beta s)^2}{2} + \frac{(\beta s)^3}{6} + \cdots = \sum_{p=0}^{\infty} \frac{(\beta s)^p}{p!},$$

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:

recall fails: more interference than signal 0.01 0.1 1 10 16 64 256 1024 4096 16384 number of stored memories M (key dimension d k = 64) interference / signal s (linear), M = 16: interference/signal = 0.46 s (linear), M = 32: interference/signal = 0.68 s (linear), M = 64: interference/signal = 0.97 s (linear), M = 128: interference/signal = 1.39 s (linear), M = 256: interference/signal = 1.97 s (linear), M = 512: interference/signal = 2.81 s (linear), M = 1024: interference/signal = 3.90 s (linear), M = 2048: interference/signal = 5.63 s (linear), M = 4096: interference/signal = 8.01 s (linear), M = 8192: interference/signal = 11.38 s (linear), M = 16384: interference/signal = 15.90 s (Linear) 2 terms, M = 16: interference/signal = 0.57 2 terms, M = 32: interference/signal = 0.85 2 terms, M = 64: interference/signal = 1.24 2 terms, M = 128: interference/signal = 1.73 2 terms, M = 256: interference/signal = 2.42 2 terms, M = 512: interference/signal = 3.55 2 terms, M = 1024: interference/signal = 5.03 2 terms, M = 2048: interference/signal = 7.27 2 terms, M = 4096: interference/signal = 10.17 2 terms, M = 8192: interference/signal = 14.08 2 terms, M = 16384: interference/signal = 19.98 2 terms 3 terms, M = 16: interference/signal = 0.16 3 terms, M = 32: interference/signal = 0.24 3 terms, M = 64: interference/signal = 0.37 3 terms, M = 128: interference/signal = 0.51 3 terms, M = 256: interference/signal = 0.72 3 terms, M = 512: interference/signal = 1.06 3 terms, M = 1024: interference/signal = 1.52 3 terms, M = 2048: interference/signal = 2.20 3 terms, M = 4096: interference/signal = 3.06 3 terms, M = 8192: interference/signal = 4.19 3 terms, M = 16384: interference/signal = 5.98 3 terms 4 terms, M = 16: interference/signal = 0.06 4 terms, M = 32: interference/signal = 0.09 4 terms, M = 64: interference/signal = 0.14 4 terms, M = 128: interference/signal = 0.19 4 terms, M = 256: interference/signal = 0.27 4 terms, M = 512: interference/signal = 0.40 4 terms, M = 1024: interference/signal = 0.57 4 terms, M = 2048: interference/signal = 0.82 4 terms, M = 4096: interference/signal = 1.15 4 terms, M = 8192: interference/signal = 1.59 4 terms, M = 16384: interference/signal = 2.26 4 terms exp(βs) (self-attention), M = 16: interference/signal = 0.00 exp(βs) (self-attention), M = 32: interference/signal = 0.00 exp(βs) (self-attention), M = 64: interference/signal = 0.01 exp(βs) (self-attention), M = 128: interference/signal = 0.01 exp(βs) (self-attention), M = 256: interference/signal = 0.01 exp(βs) (self-attention), M = 512: interference/signal = 0.02 exp(βs) (self-attention), M = 1024: interference/signal = 0.03 exp(βs) (self-attention), M = 2048: interference/signal = 0.04 exp(βs) (self-attention), M = 4096: interference/signal = 0.06 exp(βs) (self-attention), M = 8192: interference/signal = 0.08 exp(βs) (self-attention), M = 16384: interference/signal = 0.11 e βs (self-attention)

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:

$$f(x) = \sum_{i=1}^{M} v_i\,\frac{\exp(\beta\,k_i\transpose x)}{\sum_j \exp(\beta\,k_j\transpose x)} = V\transpose \operatorname{softmax}(\beta K x).$$

This is self-attention . 7

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

interference / signal = recall fails

Handling many key-value pairs in long context #

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:

recall fails: more interference than signal 0.0001 0.001 0.01 0.1 1 16 256 4K 64K 1M number of stored memories M (key dimension d k = 64) interference / signal fixed beta = 8, M = 16: interference/signal = 0.00 fixed beta = 8, M = 32: interference/signal = 0.00 fixed beta = 8, M = 64: interference/signal = 0.01 fixed beta = 8, M = 128: interference/signal = 0.01 fixed beta = 8, M = 256: interference/signal = 0.01 fixed beta = 8, M = 512: interference/signal = 0.02 fixed beta = 8, M = 1024: interference/signal = 0.03 fixed beta = 8, M = 2048: interference/signal = 0.04 fixed beta = 8, M = 4096: interference/signal = 0.06 fixed beta = 8, M = 8192: interference/signal = 0.08 fixed beta = 8, M = 16384: interference/signal = 0.11 fixed beta = 8, M = 32768: interference/signal = 0.16 fixed beta = 8, M = 65536: interference/signal = 0.22 fixed beta = 8, M = 131072: interference/signal = 0.32 fixed beta = 8, M = 262144: interference/signal = 0.45 fixed beta = 8, M = 524288: interference/signal = 0.65 fixed beta = 8, M = 1.048576e+06: interference/signal = 0.94 fixed beta = 8, M = 2.097152e+06: interference/signal = 1.25 fixed β = 8 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 16: interference/signal = 0.17 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 32: interference/signal = 0.12 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 64: interference/signal = 0.09 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 128: interference/signal = 0.06 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 256: interference/signal = 0.05 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 512: interference/signal = 0.04 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 1024: interference/signal = 0.03 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 2048: interference/signal = 0.02 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 4096: interference/signal = 0.02 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 8192: interference/signal = 0.01 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 16384: interference/signal = 0.01 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 32768: interference/signal = 0.01 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 65536: interference/signal = 0.01 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 131072: interference/signal = 0.01 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 262144: interference/signal = 0.01 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 524288: interference/signal = 0.00 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 1.048576e+06: interference/signal = 0.00 Su (2021) / Scalable-Softmax: beta = 8 log M / log 1024, M = 2.097152e+06: interference/signal = 0.00 Su / SSMax below 1024 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 16: interference/signal = 0.00 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 32: interference/signal = 0.00 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 64: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 128: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 256: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 512: interference/signal = 0.02 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 1024: interference/signal = 0.03 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 2048: interference/signal = 0.02 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 4096: interference/signal = 0.02 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 8192: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 16384: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 32768: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 65536: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 131072: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 262144: interference/signal = 0.01 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 524288: interference/signal = 0.00 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 1.048576e+06: interference/signal = 0.00 Qwen LogN-Scaling: beta = 8 max(1, log M / log 1024), M = 2.097152e+06: interference/signal = 0.00 Qwen / SSMax / Su (log M ) YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 16: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 32: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 64: interference/signal = 0.01 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 128: interference/signal = 0.01 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 256: interference/signal = 0.01 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 512: interference/signal = 0.02 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 1024: interference/signal = 0.03 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 2048: interference/signal = 0.02 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 4096: interference/signal = 0.01 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 8192: interference/signal = 0.01 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 16384: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 32768: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 65536: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 131072: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 262144: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 524288: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 1.048576e+06: interference/signal = 0.00 YaRN: beta = 8 (0.1 ln(M/1024) + 1)^2, M = 2.097152e+06: interference/signal = 0.00 YaRN (Qwen2.5-1M)

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.

Closing thoughts #

Here are the memory stores we visited, with their capacities when we query with a stored key and the keys and values are random:

Memory store $f(x)$ Capacity Capacity at $d_k = 64$
Outer product $V\transpose K x$ $d_k$ 64
Optimal linear $V\transpose K (K\transpose K)\inverse x$ $2d_k$ 128
ReLU MLP $V\transpose \operatorname{ReLU}(Kx)$ $2d_k$ 128
Squared ReLU (GLU MLP) $V\transpose \operatorname{ReLU}(Kx)^2$ $2d_k^2/3$ about 2,700
SwiGLU MLP $V\transpose \parens*{\operatorname{Swish}(Kx) \odot Kx}$ about $2d_k^2/3$ about 2,900
Cubed ReLU $V\transpose \operatorname{ReLU}(Kx)^3$ $2d_k^3/15$ about 35,000
Self-attention, $\beta = \sqrt{d_k}$ $V\transpose \operatorname{softmax}(\beta K x)$ $e^{2\sqrt{d_k} - 2}$ about 1.2 million
Self-attention, $\beta \propto \log M$ $V\transpose \operatorname{softmax}(\beta K x)$ not reached in our experiments more than 2 million

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....
Original Article
The Real Housewives of New York City Finally Address the Epstein Files
(Photos by Bravo Media, George Diama)

RHONY

Scott's Picks:

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Hell Gate.

Your link has expired.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.

Claude reveals ECDSA curve origins

Hacker News
www.anthropic.com
2026-10-16 14:55:59
Comments...
Original Article

“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.

Neal Koblitz and Alfred Menezes wrote an excellent summary on this controversy, “ A Riddle Wrapped in an Enigma ”, which discusses the history and concerns around the seed values. This mystery led to an amateur investigation into the origin of the seeds and a bounty for anyone who could find them .

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:

  1. Seed the generator with a small integer.
  2. Throw away seven outputs.
  3. Generate candidate x-coordinates from 26-bit outputs reduced mod p.
  4. 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.

The bounty

The $36,864 for finding the seeds will be donated to the Internet Security Research Group .

Who we are

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.

Acknowledgements

We would like to posthumously recognize Jerry Solinas who took being labeled an “ evil Internet meme ” and the “ Yo La Tengo of NSA bogeymen ” with good humor. Also thanks to Filippo Valsorda for organizing the NIST Elliptic Curves Seeds Bounty.

Code to reproduce the seeds

from datetime import datetime, timezone

def unix(when):
    return int(datetime.fromisoformat(when).replace(tzinfo=timezone.utc).timestamp())

def candidate(t, n, per, shift, width):
    x, out = (t << 16) | 0x330E, ""                      # the state srand48(t) sets
    for i in range(per * n):
        x = (0x5DEECE66D * x + 0xB) % 2**48              # one step of lrand48
        if i >= per * (n - 1):
            out += "%0*X" % (width, x >> shift)
    return out

PRIME = {  # srand48(time); 20 bytes per candidate: lrand48() >> 23
    "prime239v1": ("1997-05-15 15:49:03", 2185),
    "prime239v2": ("1997-05-15 15:49:03", 2320),
    "prime239v3": ("1997-05-15 15:49:03", 3048),
    "P-192":      ("1997-05-18 14:45:34", 139),
    "prime192v3": ("1997-05-18 14:45:34", 5228),
    "prime192v2": ("1997-05-18 14:45:34", 6013),
    "P-521":      ("1997-08-08 01:12:04", 1136),
    "P-256":      ("1997-08-16 01:52:34", 1842),
    "P-384":      ("1997-08-30 14:50:08", 2688),
    "P-224":      ("1998-04-03 12:52:07", 7026),
}
BINARY = {  # srand48(time / 2), if that reading is right; 5 words per candidate: lrand48()
    "B-233": ("1998-04-17 15:24:18", 155),
    "B-283": ("1998-04-17 15:27:44", 32),
    "B-409": ("1998-04-17 15:30:18", 60),
    "B-571": ("1998-04-17 15:32:08", 73),
}
for name, (when, n) in PRIME.items():
    print(f"{name:10} {when} {n:5} {candidate(unix(when), n, 20, 40, 2)}")
for name, (when, n) in BINARY.items():
    print(f"{name:10} {when} {n:5} {candidate(unix(when) // 2, n, 5, 17, 8)}")

The output of this code:

prime239v1 1997-05-15 15:49:03  2185 E43BB460F0B80CC0C0B075798E948060F8321B7D
prime239v2 1997-05-15 15:49:03  2320 E8B4011604095303CA3B8099982BE09FCB9AE616
prime239v3 1997-05-15 15:49:03  3048 7D7374168FFE3471B60A857686A19475D3BFA2FF
P-192      1997-05-18 14:45:34   139 3045AE6FC8422F64ED579528D38120EAE12196D5
prime192v3 1997-05-18 14:45:34  5228 C469684435DEB378C4B65CA9591E2A5763059A2E
prime192v2 1997-05-18 14:45:34  6013 31A92EE2029FD10D901B113E990710F0D21AC6B6
P-521      1997-08-08 01:12:04  1136 D09E8800291CB85396CC6717393284AAA0DA64BA
P-256      1997-08-16 01:52:34  1842 C49D360886E704936A6678E1139D26B7819F7E90
P-384      1997-08-30 14:50:08  2688 A335926AA319A27A1D00896A6773A4827ACDAC73
P-224      1998-04-03 12:52:07  7026 BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5
B-233      1998-04-17 15:24:18   155 74D59FF07F6B413D0EA14B344B20A2DB049B50C3
B-283      1998-04-17 15:27:44    32 77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE
B-409      1998-04-17 15:30:18    60 4099B5A457F9D69F79213D094C4BCD4D4262210B
B-571      1998-04-17 15:32:08    73 2AA058F73A0E33AB486B0F610410C53A7F132310

Code to reproduce selected base points

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.

Read more

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.

Read more

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%.

Read more

Show HN: Stoke Money – Personal finance app built around a cash flow forecast

Hacker News
stoke.money
2026-10-16 14:54:47
Comments...
Original Article

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.

Try it with your own accounts.

Getting Canceled

Lobsters
www.youtube.com
2026-10-16 14:54:16
Comments...

C++26: The New Debugging Header

Hacker News
www.sandordargo.com
2026-10-16 14:52:39
Comments...
Original Article

If you’ve ever needed to hit a breakpoint programmatically in C++, you’ve probably written something like this:

1
2
3
4
5
6
7
8
9
#if defined(_MSC_VER)
    __debugbreak();
#elif defined(__clang__)
    __builtin_debugtrap();
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
    __asm__ volatile("int3");
#else
    raise(SIGTRAP);
#endif

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.

The three functions

1
2
3
4
5
6
7
#include <debugging>

namespace std {
    void breakpoint() noexcept;
    bool is_debugger_present() noexcept;
    void breakpoint_if_debugging() noexcept;
}

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:

1
2
3
bool std::is_debugger_present() noexcept {
    return my_hardware_debug_flag;
}

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.

Connect deeper

If you liked this article, please

Espresso machine can run Doom

Hacker News
www.gamespot.com
2026-10-16 14:49:31
Comments...

Llama.cpp on a jailbroken PS5: run any GGUF model natively on the console

Hacker News
github.com
2026-10-16 14:32:35
Comments...
Original Article

PS5LM

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.

Get the app · Website · Get started · Issues

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 generating on a PS5, with the requests streaming across the TV
Qwen 3.5 9B answering requests from a laptop on a PS5 Slim. Click for the video.

Home: the model, its speed and the live requests Models: the ones suggested for the PS5 Home with a decision model Console: temperature, power and load over time API: the endpoints and an example Settings: a list of choices under the row
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:

Payload For
kstuff-lite the kernel patches homebrew runs on required
etaHEN homebrew support required
ShadowMountPlus puts PS5LM on the home screen from /data/homebrew required
elfldr (port 9021) temperature, power and real free space, through ps5-exporter recommended
ftpsrv (port 2121) installing the app, copying models from a PC recommended
  1. Download ps5lm-app-vX.Y.Z.zip from the latest release and unzip it.
  2. Copy the PPSA99575 folder to /data/homebrew over FTP. ShadowMountPlus adds PS5LM to the home screen.
  3. 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.
  4. 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
Settings, Diagnostics Square, Triangle app or server log; errors only

Want to tinker?

C++ on ps5-homebrew-ui , llama.cpp with ggml-vulkan on PS5_Vulkan 's RADV, built on Linux.

Building · Console notes · Porting · Research · Models that fit · Roadmap · Changelog · The original payload

Thanks


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 ...
Original Article
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)

Introducing GNOME OS Preview

Lobsters
blogs.gnome.org
2026-10-16 14:25:15
Comments...
Original Article

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!

GNOME OS Preview is available for download on the newly-refreshed os.gnome.org ! GNOME OS Nightly is still available from there too. As always, you can reach us on Matrix at #gnome-os:gnome.org or via the gnome-os tag on Discourse

Anthropic assigned highest junk credit rating in June

Hacker News
www.ft.com
2026-10-16 14:11:42
Comments...
Original Article

For help please visit help.ft.com . We apologise for any inconvenience.

The following information can help our support team to resolve this issue.

Error Code
CG000 / 403
Request ID
a4b95ac7bde2d6d9

eBay Restricts Listings of Radio Equipment, but Exempts Ham-Band-Only Gear

Hacker News
www.arrl.org
2026-10-16 14:06:17
Comments...
Original Article

We're sunsetting Codeberg Pages v2

Lobsters
blog.codeberg.org
2026-10-16 14:03:21
Comments...
Original Article

Andreas Shimokawa (Codeberg e. V.)

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 (Stonking Stingray) released

Lobsters
lists.ubuntu.com
2026-10-16 14:01:39
Comments...
Original Article
Utkarsh Gupta utkarsh.gupta at canonical.com
Thu Oct 15 10:59:50 UTC 2026
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.com
   https://discourse.ubuntu.com/support
   https://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



More information about the ubuntu-announce mailing list

Designing more efficient quantum circuits with Claude

Hacker News
www.anthropic.com
2026-10-16 14:00:18
Comments...
Original Article

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.

Read more

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.

Read more

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%.

Read more

GifCities

Hacker News
gifcities.org
2026-10-16 13:35:07
Comments...
Original Article

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.

Try snowglobe , butterfly , balloons , sparkles , drawing of cat

Anthropic Console overcharged my card 100x due to internationalization input bug

Hacker News
news.ycombinator.com
2026-10-16 13:31:42
Comments...
Original Article

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.

Pura vida!

R.S.G.

The First Candid

Hacker News
www.newyorker.com
2026-10-16 13:28:19
Comments...
Original Article

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.”

Caveman holding club walking up to three cavemen all holding rocks.

“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. [...]...
Original Article

Zero-click attacks used targeted ads to deliver Candiru spyware

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
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
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
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.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

Piramidal (YC W24) Is Hiring

Hacker News
job-boards.greenhouse.io
2026-10-16 13:08:55
Comments...
Original Article

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

  1. Initial Screen (30 min): Discussion to ensure timelines, experience, and expectations align.
  2. Technical Screen (1 hour): via Google Meet
  3. 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

Hacker News
www.mercor.com
2026-10-16 13:08:38
Comments...
Original Article

The Benchmark Map

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. 1 Prepare, draft, and review legal documents, such as wills, deeds, patent applications, mortgages, leases, and contracts.
  2. 2 Advise clients concerning business transactions, claim liability, advisability of prosecuting or defending lawsuits, or legal rights and obligations.
  3. 3 Interpret laws, rulings and regulations for individuals and businesses.
  4. 4 Analyze the probable outcomes of cases, using knowledge of legal precedents.
  5. 5 Present evidence to defend clients or prosecute defendants in criminal or civil litigation.
  6. 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:

APEX-1 + APEX-Agents · O*NET: Financial and Investment Analysts · 11 tasks · 176 prompts

Score (%)
Every prompt counts equally Every O*NET task counts equally
Claude Fable 5.1 Max 69.8% 68.5%
Claude Opus 5.5 Max 73.3% 70.2%
Claude Opus 5 Max 65.5% 63.0%
GPT-6 Astra Max 65.5% 61.8%
GPT-5.6 Sol Max 66.8% 65.6%
Grok 4.7 xHigh 58.1% 58.7%
Gemini 3.8 Flash High 66.9% 67.5%
Kimi K3 Max 59.4% 59.9%
DeepSeek V4.1 Flash Max 56.5% 58.4%
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:

  1. 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.

  2. 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.

  3. 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.

  4. 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...
Original Article

/ CBS News

Add CBS News on Google

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.

SHYAM SANKAR: Thank you.

MARGARET BRENNAN: We'll be back in a moment.

/dev/null: social network for developers

Hacker News
dev-null.sh
2026-10-16 12:57:49
Comments...
Original Article

Sign in with GitHub, follow people who write code, and commit plain text to a shared log.

Thirty Years of KDE

Lobsters
blog.cornelius-schumacher.de
2026-10-16 12:49:07
Comments...
Original Article

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.

For me, KDE shaped my career and my life, and gave me the opportunity to grow and learn. It led to things I would never have expected when I started: my code running on millions of computers, talking to hundreds of developers at conferences , sitting at the negotiation table with Nokia in Helsinki, consulting as an expert in the German parliament. And much more.

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....
Original Article

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.

Subscribe

Sign up for free access to this post

Free members get access to posts like this one along with an email round-up of our week's stories.

Subscribe

Already have an account? Sign in

Desire to Move Permanently to U.S. at New Low

Hacker News
news.gallup.com
2026-10-16 12:38:02
Comments...
Original Article

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.

Read Gallup’s analysis of how these shifts in migration desire could translate into changes in population size and human capital across countries.

Andrew Dugan and Michelle Chau contributed to this analysis.

Stay up to date with the latest insights by following @Gallup on X and on Instagram .

For complete methodology and specific survey dates, please review Gallup's Country Data Set details . Learn more about how the Gallup World Poll works.

###Embeddable###

The Decoherence Trap: When AI slop drowns out the signal in an endless sea of noise

Lobsters
maevyn.codes
2026-10-16 12:36:29
Comments...
Original Article

TL;DR

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:

  1. 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.
  2. 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.
  3. 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.

A small office building drawn faintly, with its plumbing inside: a main from the street feeds a network of pipes that widens floor by floor, and new runs reach out toward an annex next door. Dots mark the patched joints. Most hold; two, on different floors, fail. A small office building drawn faintly, with its plumbing inside: a main from the street feeds a network of pipes that widens floor by floor, and new runs reach out toward an annex next door. Dots mark the patched joints. Most hold; two, on different floors, fail.

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.

A maze extending past every edge, with a dot stepping through it A maze extending past every edge, with a dot stepping through it

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 .

A tangled patchwork of plumbing pipes
Courtesy of r/plumbing [ 2 ]

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.

A lone figure with a lantern at the entrance of a vast maze A lone figure with a lantern at the entrance of a vast maze

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:

  1. Grow linearly with the size of the codebase as a whole, OR
  2. 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:

  1. Decoherence grows to the point that no features can be completed in a reasonable amount of time.
  2. A large effort is made to reduce decoherence.
  3. The effort produces results and features begin shipping again at a slow-but-acceptable pace.
  4. 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 ]

Output per worker and real wages in Britain from 1780 to 1900, indexed to 1800. From 1800 to 1830, output per worker grows 0.63% a year while real wages grow 0.00% a year. From 1830 to 1860 output grows 1.12% a year and wages 0.86%, and from 1860 to 1900 output grows 1.03% a year and wages 1.61%. Over the same stretch, the share of income going to profits doubles from about 20% to over 40%. Output per worker and real wages in Britain from 1780 to 1900, indexed to 1800. From 1800 to 1830, output per worker grows 0.63% a year while real wages grow 0.00% a year. From 1830 to 1860 output grows 1.12% a year and wages 0.86%, and from 1860 to 1900 output grows 1.03% a year and wages 1.61%. Over the same stretch, the share of income going to profits doubles from about 20% to over 40%.

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:

  1. Define a goal
  2. Define a set of things you can do
  3. Use an algorithm to try out a lot of different methods to accomplish the goal
  4. Measure how close you get to accomplishing it, and how good your method is
  5. 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.

Three paths from one starting point. Reality wanders. A path checked against it drifts a little and snaps back at every check. A path that is never checked curves steadily away. Three paths from one starting point. Reality wanders. A path checked against it drifts a little and snaps back at every check. A path that is never checked curves steadily away.

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.

Two five-step learning loops. In a game the loop closes on itself. For anything that matters, step four, measuring, has to leave the room and wait on the real world. Two five-step learning loops. In a game the loop closes on itself. For anything that matters, step four, measuring, has to leave the room and wait on the real 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 ]

Timeline of futures: the idea in the 1970s, MultiLisp in 1985, Java in 2004, and JavaScript promises and C# Task in the 2010s, about 35 years from idea to mainstream. Timeline of futures: the idea in the 1970s, MultiLisp in 1985, Java in 2004, and JavaScript promises and C# Task in the 2010s, about 35 years from idea to mainstream.

There were two main reasons for this:

  1. 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.
  2. 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:

  1. Games
  2. Software
  3. 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:

  1. 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.

  2. 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:

  1. We can make an AI that produces faster, smaller, and more efficient software beyond the human ceiling while staying inside the bubble.

  2. We cannot make an AI that improves software coherence beyond the human ceiling without leaving the bubble, as noted above.

  3. 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.

  4. 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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

Growth of AI software over the first year after AI research is automated, on a log scale. Eth and Davidson's model with returns of 1.5 accelerates without limit and passes one hundred million times before month five. The same model with a cost of change that doubles as work accumulates follows it at first, then flattens: at about 460,000 times after a year when the cost doubles every 1,000 units of work, about 10,000 times when it doubles every 100, and about 200 times when it doubles every 10. Growth of AI software over the first year after AI research is automated, on a log scale. Eth and Davidson's model with returns of 1.5 accelerates without limit and passes one hundred million times before month five. The same model with a cost of change that doubles as work accumulates follows it at first, then flattens: at about 460,000 times after a year when the cost doubles every 1,000 units of work, about 10,000 times when it doubles every 100, and about 200 times when it doubles every 10.

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.

Timeline from Boole's algebra in 1847 to Shannon's thesis in 1937. AND lines up with two relay contacts in series, OR with two in parallel, across ninety years in which the algebra had no use. Timeline from Boole's algebra in 1847 to Shannon's thesis in 1937. AND lines up with two relay contacts in series, OR with two in parallel, across ninety years in which the algebra had no use.

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?

Two fields of identical tick marks, each a valid proof. In 1937 there are two dozen and the one that matters is easy to see. Now, with AI, there are hundreds and the same tick is nearly lost. Two fields of identical tick marks, each a valid proof. In 1937 there are two dozen and the one that matters is easy to see. Now, with AI, there are hundreds and the same tick is nearly lost.

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.

Pixel-art Omarchy wordmark with the tagline: Beautiful, fun and agentic Linux by DHH. The malleable OS for the age of agents. Vibe your way through every alteration, tweak, or trouble. Pixel-art Omarchy wordmark with the tagline: Beautiful, fun and agentic Linux by DHH. The malleable OS for the age of agents. Vibe your way through every alteration, tweak, or trouble.

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.

A much larger maze with three regions. A small bright central region is the amount of the maze that humans can work within. A larger purple region around it is the amount that agents can work within. Beyond that, the walls scatter out of alignment, and this is where it all falls apart. A much larger maze with three regions. A small bright central region is the amount of the maze that humans can work within. A larger purple region around it is the amount that agents can work within. Beyond that, the walls scatter out of alignment, and this is where it all falls apart.

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.

  1. 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.

  2. 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 .

JPEG XL vs. AVIF for web use-cases

Hacker News
jakearchibald.com
2026-10-16 12:12:02
Comments...
Original Article

JPEG XL has now landed in all major browsers, so I figured I'd take a closer look at what it's good/bad at compared to other formats.

Conclusions

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.

Methodology

I 'created' a benchmarking script , that encodes images using various codecs at various settings, and records various details.

I'm using the latest released versions of the image codecs, which at time of writing is:

  • avifenc 1.4.2
  • libjxl 0.12.0 (using its cjxl encoder)
  • 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).

Lossy - F1 image

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:

Show me the graphs!

Image quality

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.

Encoding performance

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.

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Another thing that might be a concern if you're encoding images on a server is peak memory usage:

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

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.

Lossy - people

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.

Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

File size

ColorVideoVDP, JOD (10 = no visible difference)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

It's interesting that, at lower qualities, jixel decodes much slower in Safari.

Lossy - red panda

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.
Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

File size

ColorVideoVDP, JOD (10 = no visible difference)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

Lossy - weasel

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.
Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

File size

ColorVideoVDP, JOD (10 = no visible difference)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

Lossy - screenshot

Ok, let's try something other than a photo:

The results of the benchmark:

  • 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.

Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

I'm not including the ColorVideoVDP chart because the metric doesn't support alpha channels.

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

The high JPEG XL decoding times here are likely a side effect of it producing much larger files for a given quality.

Lossy - illustration

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%).
Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

File size

ColorVideoVDP, JOD (10 = no visible difference)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

Lossy - alpha

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.
Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

Lossy - small

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.
Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

File size

ColorVideoVDP, JOD (10 = no visible difference)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

The numbers Safari gives are rounded, so the data is really noisy.

Lossy - large

What about an 18 megapixel image?

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.
Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

File size

ColorVideoVDP, JOD (10 = no visible difference)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

Quality stability

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:

Image AVIF JPEG XL JPEG XL (jixel)
s6 4:4:4 s0 4:4:4 s6 4:2:0 s0 4:2:0 e7 e10 fast extraslow
F1 74.6 75.9 73.4 73.8 79.2 78.0 75.3 77.3
F1 (small) 70.9 73.5 68.4 69.5 75.6 73.9 70.6 72.6
F1 (large) 77.0 77.4 76.2 76.6 80.1 79.2 77.5 78.9
People 70.7 72.0 69.8 70.5 69.6 70.3 69.1 72.3
Red panda 67.5 68.8 67.0 67.2 69.5 68.4 69.2 72.3
Weasel 56.7 57.2 56.0 56.3 56.6 55.4 54.9 59.4
Screenshot 80.2 80.4 82.3 81.9 86.5 87.6 76.6 80.3
Illustration 78.6 79.7 76.8 77.9 80.3 78.5 75.4 77.7
Alpha 67.3 69.8 63.6 64.9 69.4 66.9 66.8 69.6

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.

Also see Halide Compression's deeper dive into this .

Progressive

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.

Progressive overhead

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.
Show me the data!
Encoding Quality File size SSIMU2 Encode Decode
Time Memory Firefox Chrome Safari
AVIF s6 41 175 kB 69.9 405 ms 381 MB 46 ms 41 ms 53 ms
AVIF s6 prog 42 173 kB 70.2 815 ms 764 MB 49 ms 53 ms 56 ms
Change +1 −1% +0.3 +101% +101% +7% +29% +6%
AVIF s6 prog -k 42 181 kB 70.3 1.09 s 740 MB 45 ms 35 ms 49 ms
Change +1 +3% +0.4 +169% +94% −2% −15% −8%
AVIF s0 41 145 kB 69.9 8.00 s 450 MB 47 ms 41 ms 48 ms
AVIF s0 prog 42 165 kB 70.5 8.71 s 847 MB 54 ms 59 ms 52 ms
Change +1 +14% +0.6 +9% +88% +15% +44% +8%
AVIF s0 prog -k 41 152 kB 69.6 10.72 s 798 MB 47 ms 40 ms 46 ms
Change ±0 +5% −0.3 +34% +77% ±0% −2% −4%
JPEG XL e7 35.5 258 kB 70.0 1.62 s 2.49 GB 131 ms 105 ms 162 ms
JPEG XL e7 prog 25.3 233 kB 70.0 1.40 s 1.90 GB 119 ms 121 ms 183 ms
Change −10.2 −10% ±0.0 −14% −24% −9% +15% +13%
JPEG XL e10 41.2 258 kB 70.0 22.74 s 5.67 GB 132 ms 107 ms 162 ms
JPEG XL e10 prog 30.2 242 kB 70.0 25.54 s 6.08 GB 119 ms 128 ms 181 ms
Change −11.0 −6% ±0.0 +12% +7% −10% +20% +12%
jixel fast 66.1 225 kB 70.0 304 ms 361 MB 131 ms 89 ms 281 ms
jixel fast prog 60.1 252 kB 70.0 333 ms 393 MB 132 ms 97 ms 290 ms
Change −6.0 +12% ±0.0 +10% +9% +1% +9% +3%
jixel extraslow 65.1 185 kB 70.0 16.75 s 7.61 GB 141 ms 92 ms 294 ms
jixel extraslow prog 55.4 166 kB 70.0 14.90 s 8.94 GB 140 ms 98 ms 293 ms
Change −9.7 −10% ±0.0 −11% +17% −1% +7% ±0%

Lossy - HDR

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:

  1. The same image will look exactly as you want on an SDR display - the gain map is simply ignored.
  2. 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.

By the way, these are signs that indicate whether my cats are inside or outside , and the little display indicates how long until their next automated feed.

Show me the graphs!

Image quality

File size

SSIMULACRA2 (higher is closer to the original)

File size

ColorVideoVDP, JOD (10 = no visible difference)

Encoding performance

Encode time

SSIMULACRA2 (higher is closer to the original)

Encoding memory usage

Peak encoder memory

SSIMULACRA2 (higher is closer to the original)

Decoding performance

Decode time

SSIMULACRA2 (higher is closer to the original)

JPEG transcoding

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.

Show me the graphs!

File size

Megapixels

Decode time

Megapixels

Lossless

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.
Show me the data!

File size

Image Default effort Highest effort
libjxl jixel WebP AVIF libjxl jixel WebP AVIF
F1 1.07 MB +32% +16% +49% 1.01 MB −1% +20% +47%
People 1.39 MB +22% +17% +49% 1.34 MB −1% +19% +44%
Red panda 1.78 MB +17% +9% +40% 1.74 MB −1% +11% +31%
Weasel 2.91 MB +16% +13% +96% 2.79 MB −2% +17% +29%
Screenshot 92 kB +81% +9% +122% 68 kB +6% +44% +176%
Illustration 361 kB +78% −1% +100% 273 kB −6% +5% +139%
Alpha 522 kB +21% +12% +33% 487 kB −3% +13% +32%

Encoding performance

File size

Encode time

Encoding memory usage

File size

Peak encoder memory

Decoding performance

File size

Decode time

Animation

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.

The interesting detail of animated AVIF is that it supports transparency, whereas AV1 video doesn't. But really, that just highlights that it's dumb that AV1 didn't support transparency .

No, I'm not adding a demo. I don't want it on my server. Use video formats for video.

And that's it!

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

Hacker News
ritchietorres.house.gov
2026-10-16 12:03:02
Comments...
Original Article

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

Hacker News
www.readergrev.com
2026-10-16 11:56:25
Comments...
Original Article

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

Hacker News
www.theregister.com
2026-10-16 11:55:40
Comments...
Original Article

databases

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....
Original Article

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.

Podcast: Cops Can Use AI to Pinpoint Your Home with Just One Photo
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.

About the author

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.

Joseph Cox

Show HN: OneDeploy – Managed open-source apps with nightly backups and TLS

Hacker News
onedeploy.co
2026-10-16 11:38:35
Comments...
Original Article

88 open-source apps · Live in minutes

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.

See all apps

One price for the whole team

Subscriptions charge per seat. Here your team shares one server at one price. OneDeploy never charges per user.

Your data stays yours

The app runs on a server nobody else uses, in the region you choose. Restore a backup, move it, or delete it. It is your call.

No server chores

Server, certificate, backups, updates and resizing are handled from the dashboard. You spend your time in the app, not on it.

  1. Step 1

    Pick an app

    Browse the catalog and choose the tool your team needs.

    Browse apps
  2. Step 2

    Choose where it runs

    Pick a region and a plan. You see the live price before you deploy.

    Check prices
  3. Step 3

    Start using it

    A few minutes later your app is live, with its own web address and admin account.

    Deploy an app
A subscription Your own server OneDeploy
Time to first login Minutes An afternoon, if all goes well Minutes
Who runs the server The vendor, on their terms You: patches, monitoring, restores OneDeploy, from your dashboard
Backups Whatever the vendor keeps Scripts you write and test Nightly, encrypted, off-site, one-click restore
Web address and TLS Included DNS, certificates and renewals by hand Included, with your own domain
Pricing Per user, per month The server, plus your time Per server, by the hour, capped monthly
Where your data lives On the vendor's servers On your server On your own server, in the region you choose
Leaving Export what they allow Everything, by hand Delete anytime; billing stops that hour

Backups and recovery

  • Scheduled backups run every day by default, at a quiet time for each service.
  • Choose daily or weekly, and keep them for a week up to a year.
  • Take a manual backup any time, for example before a big change.
  • Restore in place, or into a brand-new service while the original keeps running.

Domains

  • Every app gets its own web address as soon as it is live.
  • Add your own domain: we show the DNS record to create, then verify it.
  • Certificates are issued and renewed for you.
  • Pick which address is the primary one.

Updates and growth

  • Resize to a bigger server in the same region.
  • Migrate to another region or plan; the app, data and domains move with it.
  • Update the app to its latest version in one click.
  • Change app settings from the dashboard; secrets stay masked.

2. Choose a region

Prices for every app

Prices come from live quotes. Check any app on the pricing page before you sign up.

See pricing

What do I get when I deploy an app?

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

Hacker News
adepts.of0x.cc
2026-10-16 11:38:28
Comments...
Original Article

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.

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.
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
Desoldering

Although the memory module looked terrible once removed, it was barely damaged…

Chip
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
Using the Raspberry Pi to read the chip off-board

Most of the firmware could be extracted using Binwalk.


                                                                          /home/psyconauta/research/Eufy/homebase2-firmware/chipoff/STUFF/extractions/homestation2_firmware00.bin
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DECIMAL                            HEXADECIMAL                        DESCRIPTION
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
83328                              0x14580                            U-Boot version string: 1.1.3 (Jun 14 2023 - 16:18:56)
3022226                            0x2E1D92                           XZ compressed data, total size: 11514432 bytes
14536660                           0xDDCFD4                           XZ compressed data, total size: 2200 bytes
14538862                           0xDDD86E                           XZ compressed data, total size: 2084 bytes
14540948                           0xDDE094                           XZ compressed data, total size: 1868 bytes
14542818                           0xDDE7E2                           XZ compressed data, total size: 168 bytes
14542988                           0xDDE88C                           XZ compressed data, total size: 4192 bytes
14547182                           0xDDF8EE                           XZ compressed data, total size: 2844 bytes
14550028                           0xDE040C                           XZ compressed data, total size: 244 bytes
14550282                           0xDE050A                           XZ compressed data, total size: 1452 bytes
15138816                           0xE70000                           uImage firmware image, header size: 64 bytes, data size: 3429849 bytes, compression: lzma, CPU: MIPS32, OS: Linux, image type: OS Kernel Image, load address: 0x80000000, entry 
                                                                      point: 0x802E04F0, creation time: 2023-06-14 12:56:37, image name: "Linux Kernel Image"
21233664                           0x1440000                          JFFS2 filesystem, little endian, nodes: 3426, total size: 12255244 bytes

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):

➜  extractions strings homestation2_firmware00.bin_83358_unknown.raw | grep F1VSXfNQL_ZCd3k -A5 -B5  
AuthMode=WPAPSKWPA2PSK;WPAPSKWPA2PSK
EncrypType=AES;AES
RekeyInterval=3600
RekeyMethod=TIME
PMKCachePeriod=10
WPAPSK1=F1VSXfNQL_ZCd3k
WPAPSK2=913ceac3
DefaultKeyID=2;2
Key1Type=0
Key1Str1=
Key2Type=0
➜  extractions strings homestation2_firmware00.bin_83358_unknown.raw | grep OCEAN_E9A5FC -A5 -B5   
DDNSPassword=
CountryRegion=0
CountryRegionABand=7
CountryCode=ES
BssidNum=2
SSID1=OCEAN_E9A5FC
SSID2=4350c372
WirelessMode=9
TxRate=0
Channel=0
BasicRate=15

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'
    ssid_prefix="ocean_factory_"
        ssid_prefix="OCEAN_"
    WIFI_SSID=$ssid_prefix$SSID_MAC
    ssid_prefix="`nvram_get ssid_pre`"
    if [ "$ssid_prefix" = "" ];then
        ssid_prefix="OCEAN_"
    WIFI_SSID=$ssid_prefix$SSID_MAC

Let’s zoom out to get the full script:

➜  7z_mandanga strings homestation2_firmware00 | rg 'ssid_prefix' -B30 -A40
.sdata
.sbss
.bss
.pdr
.gnu.attributes
.mdebug.abi32
#!/bin/sh
work_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_MAC
    echo "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_SSID
        fi
else
    ssid_prefix="`nvram_get ssid_pre`"
    if [ "$ssid_prefix" = "" ];then
        ssid_prefix="OCEAN_"
    get_wifi_mac
    WIFI_SSID=$ssid_prefix$SSID_MAC
    echo "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:

 #!/usr/bin/env python3
 
 
 with open("homestation2_firmware00", "rb") as file:
     data = file.read()
 
 needle = data.find(b"WPAPSK1")
 magic = data.rfind(b"\x7fELF", 0, needle)
 end = data.find(b"\x7fELF", needle)
 binary = open("elf_wifi_01", "wb")
 binary.write(data[magic:end])
 binary.close()

And it worked flawelessly:

➜  7z_mandanga python3 carve_wifi.py
➜  7z_mandanga file elf_wifi_01     
elf_wifi_01: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

Doing a quick check on the symbols we find a lot of interesting stuff related to wifi, specially that juicy set_wifi_pwd .

➜  7z_mandanga r2 elf_wifi_01
WARN: Relocs has not been applied. Please use `-e bin.relocs.apply=true` or `-e bin.cache=true` next time
 -- Use 'zoom.byte=printable' in zoom mode ('z' in Visual mode) to find strings
[0x0045d130]> aaa
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Running plugin pre-analysis hooks
INFO: Analyze all functions arguments/locals (afva@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods (af @@ method.*)
INFO: Emulate functions to find computed references (aaef)
INFO: Recovering local variables (afva@@@F)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Use -AA or aaaa to perform additional experimental analysis
INFO: Finding xrefs in noncode sections (e anal.in=io.maps.x; aav)
[0x0045d130]> afl~wifi
0x006f8908    1    288 sym.eufy_setDoorbellMechanicalChimeSwitch_wifi
0x005a972c   14   1124 sym.zx_update_dev_wifi_info_by_addr
0x0054ad3c   10    316 sym.check_hub_wifi_power
0x00558fd8   18   1800 sym.quick_bind_wifi_mgmt_rcv_handler
0x0052cfac   19   1272 sym.zx_update_hub_wifi_channel
0x005e5414   93   7544 sym.netlink_wifi_connect
0x0093f1c0    6    528 sym.aws_wifi_get_mac
0x0053aff8    1     80 sym.zx_get_wifi_mac
0x004cda10   13    728 sym.zx_check_wifi_version
0x005489a0    1     16 sym.wifi_reduceTxPower
0x005a47a0   23    892 sym.zx_alloc_wifi_addr
0x00532224    4    324 sym.set_camera_wifi_rssi
0x0049c7d4   11    448 sym.wifi_check_all_devs_online
0x0049c61c   10    440 sym.wifi_get_dev_rssi
0x0049c994   20   1768 sym.wifi_get_devs_rssi_list_in_json
0x0059e8f8    3    204 sym.restart_wifi
0x0053bb04    1    144 sym.set_pair_wifi_info
0x0053b048    8    660 sym.get_wifi_info
0x006fb684  399  18808 sym.zx_wifi_send_command
0x00603514    6    484 sym.make_wifi_notify_json
0x0054ab0c    9    560 sym.convert_wifi_countrycode
0x0059df7c    1    104 sym.wifi_info_signal_init
0x0053b510   33   1524 sym.set_wifi_pwd
0x00558894    5    292 sym.zx_quick_bind_timer_stop_send_wifi_info
0x006f8094    8    304 sym.eufy_set_wifi_countrycode
0x0054ae78    7    464 sym.set_wifi_power_flag
0x004da374   54   3076 sym.zx_handle_wifi_ready
0x006f6348    8    828 sym.wifi_log_server_init
0x006f8a28    1    288 sym.eufy_setDoorbellElectronicRingtoneTime_wifi
0x0094a1f4    4    168 sym.anker_mgmt_register_get_wifi_channel_cb
0x00532368   10    396 sym.check_camera_wifi_rssi_ok
0x005580a0   28   2036 sym.zx_quick_bind_timer_send_wifi_info
0x0094a29c    4    168 sym.anker_mgmt_register_get_wifi_mac_cb
0x0053b2dc    6    564 sym.get_wifi_ra1_info
0x006f6684    8    828 sym.wifi_log_server_t40_init
0x0056dc34   15   1008 sym.repeater_update_all_dev_wifi_channel
0x0049d07c   13    636 sym.wifi_devs_rssi_test_mode_exit
0x004daf78    1    160 sym.handle_wifi_ready_thread
0x008c5ac4    7    356 sym.zx_homekit_get_wifi_ready
0x0049d2f8    9    288 sym.wifi_setManualChannel
0x004cd584   11    668 sym.eufysdk_common_msg_wifi_callback

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.

Radare2
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.

Radare2
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... ):

Radare2
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:

Radare2
HMAC SHA256

The result is used by a function that would encode the information into text.

Radare2
Encoding memory contents

The zx_Memory_Encode function calls urlsafe_b64_encode which converts the value into base64 using the following alphabet:

[0x006f0490]> px 65 @ 0xa5cb40
- offset -  4041 4243 4445 4647 4849 4A4B 4C4D 4E4F  0123456789ABCDEF
0x00a5cb40  4142 4344 4546 4748 494a 4b4c 4d4e 4f50  ABCDEFGHIJKLMNOP
0x00a5cb50  5152 5354 5556 5758 595a 6162 6364 6566  QRSTUVWXYZabcdef
0x00a5cb60  6768 696a 6b6c 6d6e 6f70 7172 7374 7576  ghijklmnopqrstuv
0x00a5cb70  7778 797a 3031 3233 3435 3637 3839 2d5f  wxyz0123456789-_
0x00a5cb80  00                                       .

Finally, the password is updated in NVRAM and changed executing the external command iwpriv ra0 set WPAPSK=%s :

Radare2
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/sh

DEBUG_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:

  1. 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.
  2. 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 “recovery image” is a U-Boot image with a 64-byte header :

Header offset Length Field Original recovery value
0x00 4 Magic 0x27051956
0x04 4 Header CRC32 0xe764e161
0x08 4 Timestamp Preserved by the builder
0x0c 4 Compressed payload length 0x3455d9 = 3,429,849
0x10 4 RAM load address 0x80000000
0x14 4 Entry address 0x802e04f0
0x18 4 Payload CRC32 0x19b650c3
0x1c 4 OS, architecture, type, compression 05 05 02 03
0x20 32 Image-name area Preserved, including vendor-used bytes

The actual filesystem is inside a matrioska of different compression layers that can be visualized in the following diagram:

Matrioska of compression
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):

old_condition = b'if [ "$DEBUG_LOG" = "1" ];then'
new_condition = b'if [ 1 = 1 ];then' + b' ' * 13

old_login = b'\t/bin/login\n'
new_login = b'\t/bin/sh   \n'

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
Diagram to disable Write Protection

Writing the new recovery image:

Writting 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
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!!

UART 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.

Network Setup
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:

Diagram of actions
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]' ;;
    esac
done
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 -v p="$1" '$2==p {n++} END {exit n==0}' /proc/mounts; }
check_tmpfs() {
    awk -v p="$1" -v size="$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 HASHES
    case "$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=$1
    echo "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 -o size=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 -o size=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 -v p="$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 -v s="$1" -v d="$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=$1
    target_path=$2
    if 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 -o bind "$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.

Finally we can see that the services are exposed!

# /media/homeapp-debug/busybox-extra netstat -lntup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:10400           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:10402           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32290           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:10404           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32292           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32293           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32295           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:10600           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32392           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:9000            0.0.0.0:*               LISTEN      5974/pushMuxer
tcp        0      0 127.0.0.1:5000          0.0.0.0:*               LISTEN      5963/mips_collector
tcp        0      0 0.0.0.0:554             0.0.0.0:*               LISTEN      5974/pushMuxer
tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN      1405/dnsmasq
tcp        0      0 0.0.0.0:23              0.0.0.0:*               LISTEN      1693/telnetd
netstat: /proc/net/tcp6: No such file or directory
udp        0      0 0.0.0.0:53              0.0.0.0:*                           1405/dnsmasq
udp        0      0 0.0.0.0:32380           0.0.0.0:*                           6016/home_security
udp        0      0 0.0.0.0:46217           0.0.0.0:*                           6456/ntpclient
udp        0      0 0.0.0.0:43466           0.0.0.0:*                           1405/dnsmasq
udp        0      0 0.0.0.0:21200           0.0.0.0:*                           6016/home_security
udp        0      0 0.0.0.0:29947           0.0.0.0:*                           6016/home_security
netstat: /proc/net/udp6: No such file or directory

The last thing was compiling a compatible version of GDB and upload it to the device to start playing :)

GDB running on the Homebase2
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...
Original Article

iphone duo closed 1 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 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.

Popular Stories

Apple Exec Says 'Hold Us Accountable' on iPhone Duo Crease

Friday September 18, 2026 9:51 pm PDT by

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 Shares Photos Shot on iPhone Duo

Thursday October 1, 2026 1:37 pm PDT by

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...

iPhone Duo Reportedly Facing Production Problems Ahead of Launch

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...

Rendering pretty sky in Around The World game

Hacker News
frozenfractal.com
2026-10-16 11:06:43
Comments...
Original Article

Mon, 12 Oct 2026 by Thomas ten Cate · Comments
Game Development , Around the World

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):

A lot of spheres

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:

A lot of spheres again

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:

Clouds with old LUT

And here with the new:

Rendering of clouds in engine

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:

Clouds with darkish gray undersides

And here’s after:

Clouds with lighter blue undersides

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:

Sunset without normal bending

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:

Sunset with normal bending

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:

A blue sky that fades to yellow near the horizon

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:

  1. Add (blueish) light scattered into the ray segment
  2. Attenuate by outscattering over the ray segment (reddening)

… I reversed the order:

  1. Attenuate by outscattering over the ray segment (reddening)
  2. 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:

A blue sky that fades to whiteish near the horizon

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:

Sunset without horizon bending

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:

Sunset with horizon bending

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:

Scene with a sun low in the sky, with the sky showing a solid patch of pale yellow

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:

Scene with a sun low in the sky, with a gradient now visible where there used to be solid yellow

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 ...
Original Article
Democracy’s on the Line’: NYC Unions Unite To Protect Elections Published

Photo of union leaders and members on the street with union signs

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.”

A week on the farm with Dylan Araps

Hacker News
adamschaefers.com
2026-10-16 10:46:55
Comments...
Original Article

Watch my free Emacs course!

00 Avoid RSI and "emacs pinky" once and for all. 5:04

Hello Toronto – Waymo Is En Route

Hacker News
waymo.com
2026-10-16 10:44:17
Comments...
Original Article

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

Hacker News
calif.io
2026-10-16 10:44:02
Comments...
Original Article

Big fish. Small counter. Root shell.

Big Fish: an OpenBSD adventure

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.

That's the short of the matter , the longer version is more interesting , including the history of the vulnerability, as a short shm_nattch can be traced back ~37 years ago , in the original BSD sources.

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.

Code and PoC →